Commit ad57a102 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'exfat-for-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat

Pull exfat update from Namjae Jeon:
 "Bug fixes:
   - Fix memory leak on mount failure with iocharset= option
   - Fix incorrect update of stream entry
   - Fix cluster range validation error

  Clean-ups:
   - Remove unused code and unneeded assignment
   - Rename variables in exfat structure as specification
   - Reorganize boot sector analysis code
   - Simplify exfat_utf8_d_hash and exfat_utf8_d_cmp()
   - Optimize exfat entry cache functions
   - Improve wording of EXFAT_DEFAULT_IOCHARSET config option

 New Feature:
   - Add boot region verification"

* tag 'exfat-for-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: Fix potential use after free in exfat_load_upcase_table()
  exfat: fix range validation error in alloc and free cluster
  exfat: fix incorrect update of stream entry in __exfat_truncate()
  exfat: fix memory leak in exfat_parse_param()
  exfat: remove unnecessary reassignment of p_uniname->name_len
  exfat: standardize checksum calculation
  exfat: add boot region verification
  exfat: separate the boot sector analysis
  exfat: redefine PBR as boot_sector
  exfat: optimize dir-cache
  exfat: replace 'time_ms' with 'time_cs'
  exfat: remove the assignment of 0 to bool variable
  exfat: Remove unused functions exfat_high_surrogate() and exfat_low_surrogate()
  exfat: Simplify exfat_utf8_d_hash() for code points above U+FFFF
  exfat: Improve wording of EXFAT_DEFAULT_IOCHARSET config option
  exfat: Use a more common logging style
  exfat: Simplify exfat_utf8_d_cmp() for code points above U+FFFF
parents 3beff76b fc961522
......@@ -16,6 +16,7 @@ config EXFAT_DEFAULT_IOCHARSET
depends on EXFAT_FS
help
Set this to the default input/output character set to use for
converting between the encoding is used for user visible filename and
UTF-16 character that exfat filesystem use, and can be overridden with
the "iocharset" mount option for exFAT filesystems.
converting between the encoding that is used for user visible
filenames and the UTF-16 character encoding that the exFAT
filesystem uses. This can be overridden with the "iocharset" mount
option for the exFAT filesystems.
......@@ -58,9 +58,8 @@ static int exfat_allocate_bitmap(struct super_block *sb,
need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE)
+ 1;
if (need_map_size != map_size) {
exfat_msg(sb, KERN_ERR,
"bogus allocation bitmap size(need : %u, cur : %lld)",
need_map_size, map_size);
exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)",
need_map_size, map_size);
/*
* Only allowed when bogus allocation
* bitmap size is large
......@@ -192,8 +191,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
(1 << sbi->sect_per_clus_bits), GFP_NOFS, 0);
if (ret_discard == -EOPNOTSUPP) {
exfat_msg(sb, KERN_ERR,
"discard not supported by device, disabling");
exfat_err(sb, "discard not supported by device, disabling");
opts->discard = 0;
}
}
......
This diff is collapsed.
......@@ -71,10 +71,8 @@ enum {
#define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */
#define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE)
#define FAT_CACHE_SIZE 128
#define FAT_CACHE_HASH_SIZE 64
#define BUF_CACHE_SIZE 256
#define BUF_CACHE_HASH_SIZE 64
/* Enough size to hold 256 dentry (even 512 Byte sector) */
#define DIR_CACHE_SIZE (256*sizeof(struct exfat_dentry)/512+1)
#define EXFAT_HINT_NONE -1
#define EXFAT_MIN_SUBDIR 2
......@@ -139,7 +137,7 @@ struct exfat_dentry_namebuf {
struct exfat_uni_name {
/* +3 for null and for converting */
unsigned short name[MAX_NAME_LENGTH + 3];
unsigned short name_hash;
u16 name_hash;
unsigned char name_len;
};
......@@ -170,14 +168,12 @@ struct exfat_hint {
};
struct exfat_entry_set_cache {
/* sector number that contains file_entry */
sector_t sector;
/* byte offset in the sector */
unsigned int offset;
/* flag in stream entry. 01 for cluster chain, 03 for contig. */
int alloc_flag;
struct super_block *sb;
bool modified;
unsigned int start_off;
int num_bh;
struct buffer_head *bh[DIR_CACHE_SIZE];
unsigned int num_entries;
struct exfat_dentry entries[];
};
struct exfat_dir_entry {
......@@ -231,7 +227,7 @@ struct exfat_sb_info {
unsigned int root_dir; /* root dir cluster */
unsigned int dentries_per_clu; /* num of dentries per cluster */
unsigned int vol_flag; /* volume dirty flag */
struct buffer_head *pbr_bh; /* buffer_head of PBR sector */
struct buffer_head *boot_bh; /* buffer_head of BOOT sector */
unsigned int map_clu; /* allocation bitmap start cluster */
unsigned int map_sectors; /* num of allocation bitmap sectors */
......@@ -451,8 +447,7 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
int entry, int order, int num_entries);
int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
int entry);
int exfat_update_dir_chksum_with_entry_set(struct super_block *sb,
struct exfat_entry_set_cache *es, int sync);
void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
......@@ -463,9 +458,11 @@ int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
struct exfat_chain *p_dir, int entry, struct buffer_head **bh,
sector_t *sector);
struct exfat_dentry *exfat_get_dentry_cached(struct exfat_entry_set_cache *es,
int num);
struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
struct exfat_chain *p_dir, int entry, unsigned int type,
struct exfat_dentry **file_ep);
struct exfat_chain *p_dir, int entry, unsigned int type);
void exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync);
int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir);
/* inode.c */
......@@ -492,8 +489,6 @@ int exfat_nls_to_utf16(struct super_block *sb,
struct exfat_uni_name *uniname, int *p_lossy);
int exfat_create_upcase_table(struct super_block *sb);
void exfat_free_upcase_table(struct exfat_sb_info *sbi);
unsigned short exfat_high_surrogate(unicode_t u);
unsigned short exfat_low_surrogate(unicode_t u);
/* exfat/misc.c */
void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
......@@ -505,13 +500,20 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
fmt, ## args)
void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
__printf(3, 4) __cold;
#define exfat_err(sb, fmt, ...) \
exfat_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)
#define exfat_warn(sb, fmt, ...) \
exfat_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__)
#define exfat_info(sb, fmt, ...) \
exfat_msg(sb, KERN_INFO, fmt, ##__VA_ARGS__)
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 tz, __le16 time, __le16 date, u8 time_ms);
u8 tz, __le16 time, __le16 date, u8 time_cs);
void exfat_truncate_atime(struct timespec64 *ts);
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms);
unsigned short exfat_calc_chksum_2byte(void *data, int len,
unsigned short chksum, int type);
u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type);
u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type);
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync);
void exfat_chain_set(struct exfat_chain *ec, unsigned int dir,
unsigned int size, unsigned char flags);
......
......@@ -8,12 +8,15 @@
#include <linux/types.h>
#define PBR_SIGNATURE 0xAA55
#define BOOT_SIGNATURE 0xAA55
#define EXBOOT_SIGNATURE 0xAA550000
#define STR_EXFAT "EXFAT " /* size should be 8 */
#define EXFAT_MAX_FILE_LEN 255
#define VOL_CLEAN 0x0000
#define VOL_DIRTY 0x0002
#define ERR_MEDIUM 0x0004
#define EXFAT_EOF_CLUSTER 0xFFFFFFFFu
#define EXFAT_BAD_CLUSTER 0xFFFFFFF7u
......@@ -55,7 +58,7 @@
/* checksum types */
#define CS_DIR_ENTRY 0
#define CS_PBR_SECTOR 1
#define CS_BOOT_SECTOR 1
#define CS_DEFAULT 2
/* file attributes */
......@@ -69,57 +72,35 @@
#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
ATTR_SUBDIR | ATTR_ARCHIVE)
#define PBR64_JUMP_BOOT_LEN 3
#define PBR64_OEM_NAME_LEN 8
#define PBR64_RESERVED_LEN 53
#define BOOTSEC_JUMP_BOOT_LEN 3
#define BOOTSEC_FS_NAME_LEN 8
#define BOOTSEC_OLDBPB_LEN 53
#define EXFAT_FILE_NAME_LEN 15
/* EXFAT BIOS parameter block (64 bytes) */
struct bpb64 {
__u8 jmp_boot[PBR64_JUMP_BOOT_LEN];
__u8 oem_name[PBR64_OEM_NAME_LEN];
__u8 res_zero[PBR64_RESERVED_LEN];
} __packed;
/* EXFAT EXTEND BIOS parameter block (56 bytes) */
struct bsx64 {
__le64 vol_offset;
__le64 vol_length;
__le32 fat_offset;
__le32 fat_length;
__le32 clu_offset;
__le32 clu_count;
__le32 root_cluster;
__le32 vol_serial;
__u8 fs_version[2];
__le16 vol_flags;
__u8 sect_size_bits;
__u8 sect_per_clus_bits;
__u8 num_fats;
__u8 phy_drv_no;
__u8 perc_in_use;
__u8 reserved2[7];
} __packed;
/* EXFAT PBR[BPB+BSX] (120 bytes) */
struct pbr64 {
struct bpb64 bpb;
struct bsx64 bsx;
} __packed;
/* Common PBR[Partition Boot Record] (512 bytes) */
struct pbr {
union {
__u8 raw[64];
struct bpb64 f64;
} bpb;
union {
__u8 raw[56];
struct bsx64 f64;
} bsx;
__u8 boot_code[390];
__le16 signature;
/* EXFAT: Main and Backup Boot Sector (512 bytes) */
struct boot_sector {
__u8 jmp_boot[BOOTSEC_JUMP_BOOT_LEN];
__u8 fs_name[BOOTSEC_FS_NAME_LEN];
__u8 must_be_zero[BOOTSEC_OLDBPB_LEN];
__le64 partition_offset;
__le64 vol_length;
__le32 fat_offset;
__le32 fat_length;
__le32 clu_offset;
__le32 clu_count;
__le32 root_cluster;
__le32 vol_serial;
__u8 fs_revision[2];
__le16 vol_flags;
__u8 sect_size_bits;
__u8 sect_per_clus_bits;
__u8 num_fats;
__u8 drv_sel;
__u8 percent_in_use;
__u8 reserved[7];
__u8 boot_code[390];
__le16 signature;
} __packed;
struct exfat_dentry {
......@@ -136,8 +117,8 @@ struct exfat_dentry {
__le16 modify_date;
__le16 access_time;
__le16 access_date;
__u8 create_time_ms;
__u8 modify_time_ms;
__u8 create_time_cs;
__u8 modify_time_cs;
__u8 create_tz;
__u8 modify_tz;
__u8 access_tz;
......
......@@ -169,9 +169,8 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
return 0;
/* check cluster validation */
if (p_chain->dir < 2 && p_chain->dir >= sbi->num_clusters) {
exfat_msg(sb, KERN_ERR, "invalid start cluster (%u)",
p_chain->dir);
if (!is_valid_cluster(sbi, p_chain->dir)) {
exfat_err(sb, "invalid start cluster (%u)", p_chain->dir);
return -EIO;
}
......@@ -305,8 +304,7 @@ int exfat_zeroed_cluster(struct inode *dir, unsigned int clu)
return 0;
release_bhs:
exfat_msg(sb, KERN_ERR, "failed zeroed sect %llu\n",
(unsigned long long)blknr);
exfat_err(sb, "failed zeroed sect %llu\n", (unsigned long long)blknr);
for (i = 0; i < n; i++)
bforget(bhs[i]);
return err;
......@@ -337,9 +335,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
/* find new cluster */
if (hint_clu == EXFAT_EOF_CLUSTER) {
if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) {
exfat_msg(sb, KERN_ERR,
"sbi->clu_srch_ptr is invalid (%u)\n",
sbi->clu_srch_ptr);
exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)\n",
sbi->clu_srch_ptr);
sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER;
}
......@@ -349,8 +346,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
}
/* check cluster validation */
if (hint_clu < EXFAT_FIRST_CLUSTER && hint_clu >= sbi->num_clusters) {
exfat_msg(sb, KERN_ERR, "hint_cluster is invalid (%u)\n",
if (!is_valid_cluster(sbi, hint_clu)) {
exfat_err(sb, "hint_cluster is invalid (%u)",
hint_clu);
hint_clu = EXFAT_FIRST_CLUSTER;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
......
......@@ -96,11 +96,9 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
unsigned int num_clusters_new, num_clusters_phys;
unsigned int last_clu = EXFAT_FREE_CLUSTER;
struct exfat_chain clu;
struct exfat_dentry *ep, *ep2;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(inode);
struct exfat_entry_set_cache *es = NULL;
int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0;
/* check if the given file ID is opened */
......@@ -153,28 +151,31 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
/* update the directory entry */
if (!evict) {
struct timespec64 ts;
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es;
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry,
ES_ALL_ENTRIES, &ep);
ES_ALL_ENTRIES);
if (!es)
return -EIO;
ep2 = ep + 1;
ep = exfat_get_dentry_cached(es, 0);
ep2 = exfat_get_dentry_cached(es, 1);
ts = current_time(inode);
exfat_set_entry_time(sbi, &ts,
&ep->dentry.file.modify_tz,
&ep->dentry.file.modify_time,
&ep->dentry.file.modify_date,
&ep->dentry.file.modify_time_ms);
&ep->dentry.file.modify_time_cs);
ep->dentry.file.attr = cpu_to_le16(ei->attr);
/* File size should be zero if there is no cluster allocated */
if (ei->start_clu == EXFAT_EOF_CLUSTER) {
ep->dentry.stream.valid_size = 0;
ep->dentry.stream.size = 0;
ep2->dentry.stream.valid_size = 0;
ep2->dentry.stream.size = 0;
} else {
ep->dentry.stream.valid_size = cpu_to_le64(new_size);
ep->dentry.stream.size = ep->dentry.stream.valid_size;
ep2->dentry.stream.valid_size = cpu_to_le64(new_size);
ep2->dentry.stream.size = ep->dentry.stream.valid_size;
}
if (new_size == 0) {
......@@ -185,10 +186,8 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
}
if (exfat_update_dir_chksum_with_entry_set(sb, es,
inode_needs_sync(inode)))
return -EIO;
kfree(es);
exfat_update_dir_chksum_with_entry_set(es);
exfat_free_dentry_set(es, inode_needs_sync(inode));
}
/* cut off from the FAT chain */
......
......@@ -19,7 +19,6 @@
static int __exfat_write_inode(struct inode *inode, int sync)
{
int ret = -EIO;
unsigned long long on_disk_size;
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es = NULL;
......@@ -43,11 +42,11 @@ static int __exfat_write_inode(struct inode *inode, int sync)
exfat_set_vol_flags(sb, VOL_DIRTY);
/* get the directory entry of given file or directory */
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES,
&ep);
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES);
if (!es)
return -EIO;
ep2 = ep + 1;
ep = exfat_get_dentry_cached(es, 0);
ep2 = exfat_get_dentry_cached(es, 1);
ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode));
......@@ -56,12 +55,12 @@ static int __exfat_write_inode(struct inode *inode, int sync)
&ep->dentry.file.create_tz,
&ep->dentry.file.create_time,
&ep->dentry.file.create_date,
&ep->dentry.file.create_time_ms);
&ep->dentry.file.create_time_cs);
exfat_set_entry_time(sbi, &inode->i_mtime,
&ep->dentry.file.modify_tz,
&ep->dentry.file.modify_time,
&ep->dentry.file.modify_date,
&ep->dentry.file.modify_time_ms);
&ep->dentry.file.modify_time_cs);
exfat_set_entry_time(sbi, &inode->i_atime,
&ep->dentry.file.access_tz,
&ep->dentry.file.access_time,
......@@ -77,9 +76,9 @@ static int __exfat_write_inode(struct inode *inode, int sync)
ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size);
ep2->dentry.stream.size = ep2->dentry.stream.valid_size;
ret = exfat_update_dir_chksum_with_entry_set(sb, es, sync);
kfree(es);
return ret;
exfat_update_dir_chksum_with_entry_set(es);
exfat_free_dentry_set(es, sync);
return 0;
}
int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
......@@ -110,8 +109,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
int ret, modified = false;
unsigned int last_clu;
struct exfat_chain new_clu;
struct exfat_dentry *ep;
struct exfat_entry_set_cache *es = NULL;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(inode);
......@@ -222,34 +219,28 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
num_clusters += num_to_be_allocated;
*clu = new_clu.dir;
if (ei->dir.dir != DIR_DELETED) {
if (ei->dir.dir != DIR_DELETED && modified) {
struct exfat_dentry *ep;
struct exfat_entry_set_cache *es;
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry,
ES_ALL_ENTRIES, &ep);
ES_ALL_ENTRIES);
if (!es)
return -EIO;
/* get stream entry */
ep++;
ep = exfat_get_dentry_cached(es, 1);
/* update directory entry */
if (modified) {
if (ep->dentry.stream.flags != ei->flags)
ep->dentry.stream.flags = ei->flags;
if (le32_to_cpu(ep->dentry.stream.start_clu) !=
ei->start_clu)
ep->dentry.stream.start_clu =
cpu_to_le32(ei->start_clu);
ep->dentry.stream.valid_size =
cpu_to_le64(i_size_read(inode));
ep->dentry.stream.size =
ep->dentry.stream.valid_size;
}
if (exfat_update_dir_chksum_with_entry_set(sb, es,
inode_needs_sync(inode)))
return -EIO;
kfree(es);
ep->dentry.stream.flags = ei->flags;
ep->dentry.stream.start_clu =
cpu_to_le32(ei->start_clu);
ep->dentry.stream.valid_size =
cpu_to_le64(i_size_read(inode));
ep->dentry.stream.size =
ep->dentry.stream.valid_size;
exfat_update_dir_chksum_with_entry_set(es);
exfat_free_dentry_set(es, inode_needs_sync(inode));
} /* end of if != DIR_DELETED */
......
......@@ -32,7 +32,7 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
exfat_msg(sb, KERN_ERR, "error, %pV\n", &vaf);
exfat_err(sb, "error, %pV", &vaf);
va_end(args);
}
......@@ -41,7 +41,7 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
sb->s_id);
} else if (opts->errors == EXFAT_ERRORS_RO && !sb_rdonly(sb)) {
sb->s_flags |= SB_RDONLY;
exfat_msg(sb, KERN_ERR, "Filesystem has been set read-only");
exfat_err(sb, "Filesystem has been set read-only");
}
}
......@@ -75,7 +75,7 @@ static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off)
/* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 tz, __le16 time, __le16 date, u8 time_ms)
u8 tz, __le16 time, __le16 date, u8 time_cs)
{
u16 t = le16_to_cpu(time);
u16 d = le16_to_cpu(date);
......@@ -84,10 +84,10 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1);
/* time_ms field represent 0 ~ 199(1990 ms) */
if (time_ms) {
ts->tv_sec += time_ms / 100;
ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC;
/* time_cs field represent 0 ~ 199cs(1990 ms) */
if (time_cs) {
ts->tv_sec += time_cs / 100;
ts->tv_nsec = (time_cs % 100) * 10 * NSEC_PER_MSEC;
} else
ts->tv_nsec = 0;
......@@ -101,7 +101,7 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
/* Convert linear UNIX date to a EXFAT time/date pair. */
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms)
u8 *tz, __le16 *time, __le16 *date, u8 *time_cs)
{
struct tm tm;
u16 t, d;
......@@ -113,9 +113,9 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
*time = cpu_to_le16(t);
*date = cpu_to_le16(d);
/* time_ms field represent 0 ~ 199(1990 ms) */
if (time_ms)
*time_ms = (tm.tm_sec & 1) * 100 +
/* time_cs field represent 0 ~ 199cs(1990 ms) */
if (time_cs)
*time_cs = (tm.tm_sec & 1) * 100 +
ts->tv_nsec / (10 * NSEC_PER_MSEC);
/*
......@@ -136,17 +136,29 @@ void exfat_truncate_atime(struct timespec64 *ts)
ts->tv_nsec = 0;
}
unsigned short exfat_calc_chksum_2byte(void *data, int len,
unsigned short chksum, int type)
u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type)
{
int i;
unsigned char *c = (unsigned char *)data;
u8 *c = (u8 *)data;
for (i = 0; i < len; i++, c++) {
if (((i == 2) || (i == 3)) && (type == CS_DIR_ENTRY))
if (unlikely(type == CS_DIR_ENTRY && (i == 2 || i == 3)))
continue;
chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) +
(unsigned short)*c;
chksum = ((chksum << 15) | (chksum >> 1)) + *c;
}
return chksum;
}
u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type)
{
int i;
u8 *c = (u8 *)data;
for (i = 0; i < len; i++, c++) {
if (unlikely(type == CS_BOOT_SECTOR &&
(i == 106 || i == 107 || i == 112)))
continue;
chksum = ((chksum << 31) | (chksum >> 1)) + *c;
}
return chksum;
}
......
......@@ -147,16 +147,10 @@ static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr)
return charlen;
/*
* Convert to UTF-16: code points above U+FFFF are encoded as
* surrogate pairs.
* exfat_toupper() works only for code points up to the U+FFFF.
*/
if (u > 0xFFFF) {
hash = partial_name_hash(exfat_high_surrogate(u), hash);
hash = partial_name_hash(exfat_low_surrogate(u), hash);
} else {
hash = partial_name_hash(exfat_toupper(sb, u), hash);
}
hash = partial_name_hash(u <= 0xFFFF ? exfat_toupper(sb, u) : u,
hash);
}
qstr->hash = end_name_hash(hash);
......@@ -185,14 +179,9 @@ static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len,
if (u_a <= 0xFFFF && u_b <= 0xFFFF) {
if (exfat_toupper(sb, u_a) != exfat_toupper(sb, u_b))
return 1;
} else if (u_a > 0xFFFF && u_b > 0xFFFF) {
if (exfat_low_surrogate(u_a) !=
exfat_low_surrogate(u_b) ||
exfat_high_surrogate(u_a) !=
exfat_high_surrogate(u_b))
return 1;
} else {
return 1;
if (u_a != u_b)
return 1;
}
}
......@@ -611,8 +600,6 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
int ret, dentry, num_entries, count;
struct exfat_chain cdir;
struct exfat_uni_name uni_name;
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es = NULL;
struct super_block *sb = dir->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(dir);
......@@ -671,10 +658,14 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
info->num_subdirs = count;
} else {
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES, &ep);
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es;
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
if (!es)
return -EIO;
ep2 = ep + 1;
ep = exfat_get_dentry_cached(es, 0);
ep2 = exfat_get_dentry_cached(es, 1);
info->type = exfat_get_entry_type(ep);
info->attr = le16_to_cpu(ep->dentry.file.attr);
......@@ -692,7 +683,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
exfat_fs_error(sb,
"non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)",
i_size_read(dir), ei->dir.dir, ei->entry);
kfree(es);
exfat_free_dentry_set(es, false);
return -EIO;
}
......@@ -700,18 +691,18 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
ep->dentry.file.create_tz,
ep->dentry.file.create_time,
ep->dentry.file.create_date,
ep->dentry.file.create_time_ms);
ep->dentry.file.create_time_cs);
exfat_get_entry_time(sbi, &info->mtime,
ep->dentry.file.modify_tz,
ep->dentry.file.modify_time,
ep->dentry.file.modify_date,
ep->dentry.file.modify_time_ms);
ep->dentry.file.modify_time_cs);
exfat_get_entry_time(sbi, &info->atime,
ep->dentry.file.access_tz,
ep->dentry.file.access_time,
ep->dentry.file.access_date,
0);
kfree(es);
exfat_free_dentry_set(es, false);
if (info->type == TYPE_DIR) {
exfat_chain_set(&cdir, info->start_clu,
......@@ -778,8 +769,8 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
if (d_unhashed(alias)) {
WARN_ON(alias->d_name.hash_len !=
dentry->d_name.hash_len);
exfat_msg(sb, KERN_INFO,
"rehashed a dentry(%p) in read lookup", alias);
exfat_info(sb, "rehashed a dentry(%p) in read lookup",
alias);
d_drop(dentry);
d_rehash(alias);
} else if (!S_ISDIR(i_mode)) {
......@@ -824,7 +815,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
exfat_chain_dup(&cdir, &ei->dir);
entry = ei->entry;
if (ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry");
exfat_err(sb, "abnormal access to deleted dentry");
err = -ENOENT;
goto unlock;
}
......@@ -979,7 +970,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
entry = ei->entry;
if (ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry");
exfat_err(sb, "abnormal access to deleted dentry");
err = -ENOENT;
goto unlock;
}
......@@ -991,9 +982,8 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
err = exfat_check_dir_empty(sb, &clu_to_free);
if (err) {
if (err == -EIO)
exfat_msg(sb, KERN_ERR,
"failed to exfat_check_dir_empty : err(%d)",
err);
exfat_err(sb, "failed to exfat_check_dir_empty : err(%d)",
err);
goto unlock;
}
......@@ -1014,9 +1004,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries);
if (err) {
exfat_msg(sb, KERN_ERR,
"failed to exfat_remove_entries : err(%d)",
err);
exfat_err(sb, "failed to exfat_remove_entries : err(%d)", err);
goto unlock;
}
ei->dir.dir = DIR_DELETED;
......@@ -1245,8 +1233,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
return -EINVAL;
if (ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR,
"abnormal access to deleted source dentry");
exfat_err(sb, "abnormal access to deleted source dentry");
return -ENOENT;
}
......@@ -1268,8 +1255,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
new_ei = EXFAT_I(new_inode);
if (new_ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR,
"abnormal access to deleted target dentry");
exfat_err(sb, "abnormal access to deleted target dentry");
goto out;
}
......@@ -1431,8 +1417,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
if (S_ISDIR(new_inode->i_mode))
drop_nlink(new_inode);
} else {
exfat_msg(sb, KERN_WARNING,
"abnormal access to an inode dropped");
exfat_warn(sb, "abnormal access to an inode dropped");
WARN_ON(new_inode->i_nlink == 0);
}
new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime =
......
......@@ -503,21 +503,17 @@ static int exfat_utf8_to_utf16(struct super_block *sb,
unilen = utf8s_to_utf16s(p_cstring, len, UTF16_HOST_ENDIAN,
(wchar_t *)uniname, MAX_NAME_LENGTH + 2);
if (unilen < 0) {
exfat_msg(sb, KERN_ERR,
"failed to %s (err : %d) nls len : %d",
__func__, unilen, len);
exfat_err(sb, "failed to %s (err : %d) nls len : %d",
__func__, unilen, len);
return unilen;
}
if (unilen > MAX_NAME_LENGTH) {
exfat_msg(sb, KERN_ERR,
"failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d",
__func__, len, unilen, MAX_NAME_LENGTH);
exfat_err(sb, "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d",
__func__, len, unilen, MAX_NAME_LENGTH);
return -ENAMETOOLONG;
}
p_uniname->name_len = unilen & 0xFF;
for (i = 0; i < unilen; i++) {
if (*uniname < 0x0020 ||
exfat_wstrchr(bad_uni_chars, *uniname))
......@@ -529,7 +525,7 @@ static int exfat_utf8_to_utf16(struct super_block *sb,
*uniname = '\0';
p_uniname->name_len = unilen;
p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0,
p_uniname->name_hash = exfat_calc_chksum16(upname, unilen << 1, 0,
CS_DEFAULT);
if (p_lossy)
......@@ -537,22 +533,9 @@ static int exfat_utf8_to_utf16(struct super_block *sb,
return unilen;
}
#define PLANE_SIZE 0x00010000
#define SURROGATE_MASK 0xfffff800
#define SURROGATE_PAIR 0x0000d800
#define SURROGATE_LOW 0x00000400
#define SURROGATE_BITS 0x000003ff
unsigned short exfat_high_surrogate(unicode_t u)
{
return ((u - PLANE_SIZE) >> 10) + SURROGATE_PAIR;
}
unsigned short exfat_low_surrogate(unicode_t u)
{
return ((u - PLANE_SIZE) & SURROGATE_BITS) | SURROGATE_PAIR |
SURROGATE_LOW;
}
static int __exfat_utf16_to_nls(struct super_block *sb,
struct exfat_uni_name *p_uniname, unsigned char *p_cstring,
......@@ -638,7 +621,7 @@ static int exfat_nls_to_ucs2(struct super_block *sb,
*uniname = '\0';
p_uniname->name_len = unilen;
p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0,
p_uniname->name_hash = exfat_calc_chksum16(upname, unilen << 1, 0,
CS_DEFAULT);
if (p_lossy)
......@@ -670,7 +653,8 @@ static int exfat_load_upcase_table(struct super_block *sb,
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned int sect_size = sb->s_blocksize;
unsigned int i, index = 0, checksum = 0;
unsigned int i, index = 0;
u32 chksum = 0;
int ret;
unsigned char skip = false;
unsigned short *upcase_table;
......@@ -687,9 +671,8 @@ static int exfat_load_upcase_table(struct super_block *sb,
bh = sb_bread(sb, sector);
if (!bh) {
exfat_msg(sb, KERN_ERR,
"failed to read sector(0x%llx)\n",
(unsigned long long)sector);
exfat_err(sb, "failed to read sector(0x%llx)\n",
(unsigned long long)sector);
ret = -EIO;
goto free_table;
}
......@@ -697,13 +680,6 @@ static int exfat_load_upcase_table(struct super_block *sb,
for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
unsigned short uni = get_unaligned_le16(bh->b_data + i);
checksum = ((checksum & 1) ? 0x80000000 : 0) +
(checksum >> 1) +
*(((unsigned char *)bh->b_data) + i);
checksum = ((checksum & 1) ? 0x80000000 : 0) +
(checksum >> 1) +
*(((unsigned char *)bh->b_data) + (i + 1));
if (skip) {
index += uni;
skip = false;
......@@ -716,15 +692,15 @@ static int exfat_load_upcase_table(struct super_block *sb,
index++;
}
}
chksum = exfat_calc_chksum32(bh->b_data, i, chksum, CS_DEFAULT);
brelse(bh);
}
if (index >= 0xFFFF && utbl_checksum == checksum)
if (index >= 0xFFFF && utbl_checksum == chksum)
return 0;
exfat_msg(sb, KERN_ERR,
"failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)\n",
index, checksum, utbl_checksum);
exfat_err(sb, "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)",
index, chksum, utbl_checksum);
ret = -EINVAL;
free_table:
exfat_free_upcase_table(sbi);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment