Loading fs/exfat/balloc.c +5 −10 Original line number Diff line number Diff line Loading @@ -58,8 +58,7 @@ 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)", exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)", need_map_size, map_size); /* * Only allowed when bogus allocation Loading Loading @@ -91,7 +90,6 @@ static int exfat_allocate_bitmap(struct super_block *sb, } } sbi->pbr_bh = NULL; return 0; } Loading Loading @@ -137,8 +135,6 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi) { int i; brelse(sbi->pbr_bh); for (i = 0; i < sbi->map_sectors; i++) __brelse(sbi->vol_amap[i]); Loading @@ -162,7 +158,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu) b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); set_bit_le(b, sbi->vol_amap[i]->b_data); exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); return 0; } Loading @@ -184,7 +180,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu) b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); clear_bit_le(b, sbi->vol_amap[i]->b_data); exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); if (opts->discard) { int ret_discard; Loading @@ -195,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; } } Loading fs/exfat/cache.c +0 −11 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ #include "exfat_raw.h" #include "exfat_fs.h" #define EXFAT_CACHE_VALID 0 #define EXFAT_MAX_CACHE 16 struct exfat_cache { Loading Loading @@ -61,16 +60,6 @@ void exfat_cache_shutdown(void) kmem_cache_destroy(exfat_cachep); } void exfat_cache_init_inode(struct inode *inode) { struct exfat_inode_info *ei = EXFAT_I(inode); spin_lock_init(&ei->cache_lru_lock); ei->nr_caches = 0; ei->cache_valid_id = EXFAT_CACHE_VALID + 1; INIT_LIST_HEAD(&ei->cache_lru); } static inline struct exfat_cache *exfat_cache_alloc(void) { return kmem_cache_alloc(exfat_cachep, GFP_NOFS); Loading fs/exfat/dir.c +117 −166 Original line number Diff line number Diff line Loading @@ -32,41 +32,36 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb, struct exfat_chain *p_dir, int entry, unsigned short *uniname) { int i; struct exfat_dentry *ep; struct exfat_entry_set_cache *es; es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES); if (!es) return; if (es->num_entries < 3) goto free_es; ep += 2; /* * First entry : file entry * Second entry : stream-extension entry * Third entry : first file-name entry * So, the index of first file-name dentry should start from 2. */ for (i = 2; i < es->num_entries; i++, ep++) { for (i = 2; i < es->num_entries; i++) { struct exfat_dentry *ep = exfat_get_dentry_cached(es, i); /* end of name entry */ if (exfat_get_entry_type(ep) != TYPE_EXTEND) goto free_es; break; exfat_extract_uni_name(ep, uniname); uniname += EXFAT_FILE_NAME_LEN; } free_es: kfree(es); exfat_free_dentry_set(es, false); } /* read a directory entry from the opened directory */ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry) { int i, dentries_per_clu, dentries_per_clu_bits = 0; int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext; unsigned int type, clu_offset; sector_t sector; struct exfat_chain dir, clu; Loading @@ -75,7 +70,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_inode_info *ei = EXFAT_I(inode); unsigned int dentry = ei->rwoffset & 0xFFFFFFFF; unsigned int dentry = EXFAT_B_TO_DEN(*cpos) & 0xFFFFFFFF; struct buffer_head *bh; /* check if the given file ID is opened */ Loading Loading @@ -132,17 +127,18 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) continue; } num_ext = ep->dentry.file.num_ext; dir_entry->attr = le16_to_cpu(ep->dentry.file.attr); exfat_get_entry_time(sbi, &dir_entry->crtime, 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, &dir_entry->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, &dir_entry->atime, ep->dentry.file.access_tz, ep->dentry.file.access_time, Loading @@ -162,12 +158,13 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) return -EIO; dir_entry->size = le64_to_cpu(ep->dentry.stream.valid_size); dir_entry->entry = dentry; brelse(bh); ei->hint_bmap.off = dentry >> dentries_per_clu_bits; ei->hint_bmap.clu = clu.dir; ei->rwoffset = ++dentry; *cpos = EXFAT_DEN_TO_B(dentry + 1 + num_ext); return 0; } Loading @@ -183,7 +180,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) } dir_entry->namebuf.lfn[0] = '\0'; ei->rwoffset = dentry; *cpos = EXFAT_DEN_TO_B(dentry); return 0; } Loading Loading @@ -247,12 +244,10 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) if (err) goto unlock; get_new: ei->rwoffset = EXFAT_B_TO_DEN(cpos); if (cpos >= i_size_read(inode)) goto end_of_dir; err = exfat_readdir(inode, &de); err = exfat_readdir(inode, &cpos, &de); if (err) { /* * At least we tried to read a sector. Move cpos to next sector Loading @@ -267,13 +262,10 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) goto end_of_dir; } cpos = EXFAT_DEN_TO_B(ei->rwoffset); if (!nb->lfn[0]) goto end_of_dir; i_pos = ((loff_t)ei->start_clu << 32) | ((ei->rwoffset - 1) & 0xffffffff); i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff); tmp = exfat_iget(sb, i_pos); if (tmp) { inum = tmp->i_ino; Loading Loading @@ -314,7 +306,7 @@ const struct file_operations exfat_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .iterate = exfat_iterate, .fsync = generic_file_fsync, .fsync = exfat_file_fsync, }; int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu) Loading Loading @@ -430,10 +422,12 @@ static void exfat_init_name_entry(struct exfat_dentry *ep, ep->dentry.name.flags = 0x0; for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { if (*uniname != 0x0) { ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname); if (*uniname == 0x0) break; uniname++; } else { ep->dentry.name.unicode_0_14[i] = 0x0; } } } Loading Loading @@ -461,19 +455,19 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, &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, &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); exfat_set_entry_time(sbi, &ts, &ep->dentry.file.access_tz, &ep->dentry.file.access_time, &ep->dentry.file.access_date, NULL); exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); exfat_update_bh(bh, IS_DIRSYNC(inode)); brelse(bh); ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); Loading @@ -483,7 +477,7 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, exfat_init_stream_entry(ep, (type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN, start_clu, size); exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); exfat_update_bh(bh, IS_DIRSYNC(inode)); brelse(bh); return 0; Loading @@ -496,7 +490,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, int ret = 0; int i, num_entries; sector_t sector; unsigned short chksum; u16 chksum; struct exfat_dentry *ep, *fep; struct buffer_head *fbh, *bh; Loading @@ -505,7 +499,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, return -EIO; num_entries = fep->dentry.file.num_ext + 1; chksum = exfat_calc_chksum_2byte(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY); chksum = exfat_calc_chksum16(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY); for (i = 1; i < num_entries; i++) { ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, NULL); Loading @@ -513,13 +507,13 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, ret = -EIO; goto release_fbh; } chksum = exfat_calc_chksum_2byte(ep, DENTRY_SIZE, chksum, chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum, CS_DEFAULT); brelse(bh); } fep->dentry.file.checksum = cpu_to_le16(chksum); exfat_update_bh(sb, fbh, IS_DIRSYNC(inode)); exfat_update_bh(fbh, IS_DIRSYNC(inode)); release_fbh: brelse(fbh); return ret; Loading @@ -541,7 +535,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, return -EIO; ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); exfat_update_bh(sb, bh, sync); exfat_update_bh(bh, sync); brelse(bh); ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); Loading @@ -550,7 +544,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, ep->dentry.stream.name_len = p_uniname->name_len; ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash); exfat_update_bh(sb, bh, sync); exfat_update_bh(bh, sync); brelse(bh); for (i = EXFAT_FIRST_CLUSTER; i < num_entries; i++) { Loading @@ -559,7 +553,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, return -EIO; exfat_init_name_entry(ep, uniname); exfat_update_bh(sb, bh, sync); exfat_update_bh(bh, sync); brelse(bh); uniname += EXFAT_FILE_NAME_LEN; } Loading @@ -583,69 +577,44 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, return -EIO; exfat_set_entry_type(ep, TYPE_DELETED); exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); exfat_update_bh(bh, IS_DIRSYNC(inode)); brelse(bh); } return 0; } 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) { struct exfat_sb_info *sbi = EXFAT_SB(sb); struct buffer_head *bh; sector_t sec = es->sector; unsigned int off = es->offset; int chksum_type = CS_DIR_ENTRY, i, num_entries = es->num_entries; unsigned int buf_off = (off - es->offset); unsigned int remaining_byte_in_sector, copy_entries, clu; int chksum_type = CS_DIR_ENTRY, i; unsigned short chksum = 0; struct exfat_dentry *ep; for (i = 0; i < num_entries; i++) { chksum = exfat_calc_chksum_2byte(&es->entries[i], DENTRY_SIZE, chksum, chksum_type); for (i = 0; i < es->num_entries; i++) { ep = exfat_get_dentry_cached(es, i); chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum, chksum_type); chksum_type = CS_DEFAULT; } ep = exfat_get_dentry_cached(es, 0); ep->dentry.file.checksum = cpu_to_le16(chksum); es->modified = true; } es->entries[0].dentry.file.checksum = cpu_to_le16(chksum); int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync) { int i, err = 0; while (num_entries) { /* write per sector base */ remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off; copy_entries = min_t(int, EXFAT_B_TO_DEN(remaining_byte_in_sector), num_entries); bh = sb_bread(sb, sec); if (!bh) goto err_out; memcpy(bh->b_data + off, (unsigned char *)&es->entries[0] + buf_off, EXFAT_DEN_TO_B(copy_entries)); exfat_update_bh(sb, bh, sync); brelse(bh); num_entries -= copy_entries; if (es->modified) err = exfat_update_bhs(es->bh, es->num_bh, sync); if (num_entries) { /* get next sector */ if (exfat_is_last_sector_in_cluster(sbi, sec)) { clu = exfat_sector_to_cluster(sbi, sec); if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) clu++; else if (exfat_get_next_cluster(sb, &clu)) goto err_out; sec = exfat_cluster_to_sector(sbi, clu); } else { sec++; } off = 0; buf_off += EXFAT_DEN_TO_B(copy_entries); } } return 0; err_out: return -EIO; for (i = 0; i < es->num_bh; i++) if (err) bforget(es->bh[i]); else brelse(es->bh[i]); kfree(es); return err; } static int exfat_walk_fat_chain(struct super_block *sb, Loading Loading @@ -720,8 +689,7 @@ static int exfat_dir_readahead(struct super_block *sb, sector_t sec) return 0; if (sec < sbi->data_start_sector) { exfat_msg(sb, KERN_ERR, "requested sector is invalid(sect:%llu, root:%llu)", exfat_err(sb, "requested sector is invalid(sect:%llu, root:%llu)", (unsigned long long)sec, sbi->data_start_sector); return -EIO; } Loading Loading @@ -750,7 +718,7 @@ struct exfat_dentry *exfat_get_dentry(struct super_block *sb, sector_t sec; if (p_dir->dir == DIR_DELETED) { exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry\n"); exfat_err(sb, "abnormal access to deleted dentry"); return NULL; } Loading Loading @@ -821,39 +789,45 @@ static bool exfat_validate_entry(unsigned int type, } } struct exfat_dentry *exfat_get_dentry_cached( struct exfat_entry_set_cache *es, int num) { int off = es->start_off + num * DENTRY_SIZE; struct buffer_head *bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)]; char *p = bh->b_data + EXFAT_BLK_OFFSET(off, es->sb); return (struct exfat_dentry *)p; } /* * Returns a set of dentries for a file or dir. * * Note that this is a copy (dump) of dentries so that user should * call write_entry_set() to apply changes made in this entry set * to the real device. * Note It provides a direct pointer to bh->data via exfat_get_dentry_cached(). * User should call exfat_get_dentry_set() after setting 'modified' to apply * changes made in this entry set to the real device. * * in: * sb+p_dir+entry: indicates a file/dir * type: specifies how many dentries should be included. * out: * file_ep: will point the first dentry(= file dentry) on success * return: * pointer of entry set on success, * NULL on failure. */ 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) { int ret; int ret, i, num_bh; unsigned int off, byte_offset, clu = 0; unsigned int entry_type; sector_t sec; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_entry_set_cache *es; struct exfat_dentry *ep, *pos; unsigned char num_entries; struct exfat_dentry *ep; int num_entries; enum exfat_validate_dentry_mode mode = ES_MODE_STARTED; struct buffer_head *bh; if (p_dir->dir == DIR_DELETED) { exfat_msg(sb, KERN_ERR, "access to deleted dentry\n"); exfat_err(sb, "access to deleted dentry"); return NULL; } Loading @@ -862,11 +836,18 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, if (ret) return NULL; es = kzalloc(sizeof(*es), GFP_KERNEL); if (!es) return NULL; es->sb = sb; es->modified = false; /* byte offset in cluster */ byte_offset = EXFAT_CLU_OFFSET(byte_offset, sbi); /* byte offset in sector */ off = EXFAT_BLK_OFFSET(byte_offset, sb); es->start_off = off; /* sector offset in cluster */ sec = EXFAT_B_TO_BLK(byte_offset, sb); Loading @@ -874,42 +855,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, bh = sb_bread(sb, sec); if (!bh) return NULL; ep = (struct exfat_dentry *)(bh->b_data + off); entry_type = exfat_get_entry_type(ep); goto free_es; es->bh[es->num_bh++] = bh; if (entry_type != TYPE_FILE && entry_type != TYPE_DIR) goto release_bh; ep = exfat_get_dentry_cached(es, 0); if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) goto free_es; num_entries = type == ES_ALL_ENTRIES ? ep->dentry.file.num_ext + 1 : type; es = kmalloc(struct_size(es, entries, num_entries), GFP_KERNEL); if (!es) goto release_bh; es->num_entries = num_entries; es->sector = sec; es->offset = off; es->alloc_flag = p_dir->flags; pos = &es->entries[0]; while (num_entries) { if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) goto free_es; /* copy dentry */ memcpy(pos, ep, sizeof(struct exfat_dentry)); if (--num_entries == 0) break; if (((off + DENTRY_SIZE) & (sb->s_blocksize - 1)) < (off & (sb->s_blocksize - 1))) { num_bh = EXFAT_B_TO_BLK_ROUND_UP(off + num_entries * DENTRY_SIZE, sb); for (i = 1; i < num_bh; i++) { /* get the next sector */ if (exfat_is_last_sector_in_cluster(sbi, sec)) { if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) if (p_dir->flags == ALLOC_NO_FAT_CHAIN) clu++; else if (exfat_get_next_cluster(sb, &clu)) goto free_es; Loading @@ -918,28 +879,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, sec++; } brelse(bh); bh = sb_bread(sb, sec); if (!bh) goto free_es; off = 0; ep = (struct exfat_dentry *)bh->b_data; } else { ep++; off += DENTRY_SIZE; } pos++; es->bh[es->num_bh++] = bh; } if (file_ep) *file_ep = &es->entries[0]; brelse(bh); /* validiate cached dentries */ for (i = 1; i < num_entries; i++) { ep = exfat_get_dentry_cached(es, i); if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) goto free_es; } return es; free_es: kfree(es); release_bh: brelse(bh); exfat_free_dentry_set(es, false); return NULL; } Loading @@ -953,7 +908,6 @@ enum { /* * return values: * >= 0 : return dir entiry position with the name in dir * -EEXIST : (root dir, ".") it is the root dir itself * -ENOENT : entry with the name does not exist * -EIO : I/O error */ Loading Loading @@ -1021,11 +975,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, if (ei->hint_femp.eidx == EXFAT_HINT_NONE || candi_empty.eidx <= ei->hint_femp.eidx) { memcpy(&ei->hint_femp, &candi_empty, sizeof(candi_empty)); } ei->hint_femp.eidx) ei->hint_femp = candi_empty; } brelse(bh); Loading @@ -1048,7 +999,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, } if (entry_type == TYPE_STREAM) { unsigned short name_hash; u16 name_hash; if (step != DIRENT_STEP_STRM) { step = DIRENT_STEP_FILE; Loading Loading @@ -1158,7 +1109,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, ret = exfat_get_next_cluster(sb, &clu.dir); } if (ret || clu.dir != EXFAT_EOF_CLUSTER) { if (ret || clu.dir == EXFAT_EOF_CLUSTER) { /* just initialized hint_stat */ hint_stat->clu = p_dir->dir; hint_stat->eidx = 0; Loading fs/exfat/exfat_fs.h +37 −34 Original line number Diff line number Diff line Loading @@ -13,8 +13,6 @@ #define EXFAT_SUPER_MAGIC 0x2011BAB0UL #define EXFAT_ROOT_INO 1 #define EXFAT_SB_DIRTY 0 #define EXFAT_CLUSTERS_UNTRACKED (~0u) /* Loading Loading @@ -71,10 +69,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 Loading Loading @@ -132,14 +128,14 @@ enum { struct exfat_dentry_namebuf { char *lfn; int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */ int lfnbuf_len; /* usually MAX_UNINAME_BUF_SIZE */ }; /* unicode name structure */ 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; }; Loading Loading @@ -170,14 +166,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 { Loading Loading @@ -230,8 +224,9 @@ struct exfat_sb_info { unsigned int num_FAT_sectors; /* num of FAT sectors */ 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 */ unsigned int vol_flags; /* volume flags */ unsigned int vol_flags_persistent; /* volume flags to retain */ 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 */ Loading @@ -242,7 +237,6 @@ struct exfat_sb_info { unsigned int clu_srch_ptr; /* cluster search pointer */ unsigned int used_clusters; /* number of used clusters */ unsigned long s_state; struct mutex s_lock; /* superblock lock */ struct exfat_mount_options options; struct nls_table *nls_io; /* Charset used for input and display */ Loading @@ -254,6 +248,8 @@ struct exfat_sb_info { struct rcu_head rcu; }; #define EXFAT_CACHE_VALID 0 /* * EXFAT file system inode in-memory data */ Loading @@ -269,8 +265,6 @@ struct exfat_inode_info { * the validation of hint_stat. */ unsigned int version; /* file offset or dentry index for readdir */ loff_t rwoffset; /* hint for cluster last accessed */ struct exfat_hint hint_bmap; Loading Loading @@ -375,7 +369,7 @@ static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi, static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi, unsigned int clus) { return ((clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) + return ((sector_t)(clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) + sbi->data_start_sector; } Loading @@ -387,7 +381,8 @@ static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi, } /* super.c */ int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag); int exfat_set_volume_dirty(struct super_block *sb); int exfat_clear_volume_dirty(struct super_block *sb); /* fatent.c */ #define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu) Loading Loading @@ -424,6 +419,7 @@ void exfat_truncate(struct inode *inode, loff_t size); int exfat_setattr(struct dentry *dentry, struct iattr *attr); int exfat_getattr(const struct path *path, struct kstat *stat, unsigned int request_mask, unsigned int query_flags); int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); /* namei.c */ extern const struct dentry_operations exfat_dentry_ops; Loading @@ -432,7 +428,6 @@ extern const struct dentry_operations exfat_utf8_dentry_ops; /* cache.c */ int exfat_cache_init(void); void exfat_cache_shutdown(void); void exfat_cache_init_inode(struct inode *inode); void exfat_cache_inval_inode(struct inode *inode); int exfat_get_cluster(struct inode *inode, unsigned int cluster, unsigned int *fclus, unsigned int *dclus, Loading @@ -451,8 +446,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, Loading @@ -463,9 +457,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); int 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 */ Loading @@ -492,8 +488,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, ...) Loading @@ -505,13 +499,22 @@ 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); void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync); 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 buffer_head *bh, int sync); int exfat_update_bhs(struct buffer_head **bhs, int nr_bhs, int sync); void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, unsigned int size, unsigned char flags); void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec); Loading fs/exfat/exfat_raw.h +34 −54 Original line number Diff line number Diff line Loading @@ -8,12 +8,14 @@ #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 VOLUME_DIRTY 0x0002 #define MEDIA_FAILURE 0x0004 #define EXFAT_EOF_CLUSTER 0xFFFFFFFFu #define EXFAT_BAD_CLUSTER 0xFFFFFFF7u Loading Loading @@ -55,7 +57,7 @@ /* checksum types */ #define CS_DIR_ENTRY 0 #define CS_PBR_SECTOR 1 #define CS_BOOT_SECTOR 1 #define CS_DEFAULT 2 /* file attributes */ Loading @@ -69,22 +71,18 @@ #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; /* 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; Loading @@ -92,32 +90,14 @@ struct bsx64 { __le32 clu_count; __le32 root_cluster; __le32 vol_serial; __u8 fs_version[2]; __u8 fs_revision[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 drv_sel; __u8 percent_in_use; __u8 reserved[7]; __u8 boot_code[390]; __le16 signature; } __packed; Loading @@ -136,8 +116,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; Loading Loading
fs/exfat/balloc.c +5 −10 Original line number Diff line number Diff line Loading @@ -58,8 +58,7 @@ 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)", exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)", need_map_size, map_size); /* * Only allowed when bogus allocation Loading Loading @@ -91,7 +90,6 @@ static int exfat_allocate_bitmap(struct super_block *sb, } } sbi->pbr_bh = NULL; return 0; } Loading Loading @@ -137,8 +135,6 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi) { int i; brelse(sbi->pbr_bh); for (i = 0; i < sbi->map_sectors; i++) __brelse(sbi->vol_amap[i]); Loading @@ -162,7 +158,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu) b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); set_bit_le(b, sbi->vol_amap[i]->b_data); exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); return 0; } Loading @@ -184,7 +180,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu) b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); clear_bit_le(b, sbi->vol_amap[i]->b_data); exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode)); exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); if (opts->discard) { int ret_discard; Loading @@ -195,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; } } Loading
fs/exfat/cache.c +0 −11 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ #include "exfat_raw.h" #include "exfat_fs.h" #define EXFAT_CACHE_VALID 0 #define EXFAT_MAX_CACHE 16 struct exfat_cache { Loading Loading @@ -61,16 +60,6 @@ void exfat_cache_shutdown(void) kmem_cache_destroy(exfat_cachep); } void exfat_cache_init_inode(struct inode *inode) { struct exfat_inode_info *ei = EXFAT_I(inode); spin_lock_init(&ei->cache_lru_lock); ei->nr_caches = 0; ei->cache_valid_id = EXFAT_CACHE_VALID + 1; INIT_LIST_HEAD(&ei->cache_lru); } static inline struct exfat_cache *exfat_cache_alloc(void) { return kmem_cache_alloc(exfat_cachep, GFP_NOFS); Loading
fs/exfat/dir.c +117 −166 Original line number Diff line number Diff line Loading @@ -32,41 +32,36 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb, struct exfat_chain *p_dir, int entry, unsigned short *uniname) { int i; struct exfat_dentry *ep; struct exfat_entry_set_cache *es; es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES); if (!es) return; if (es->num_entries < 3) goto free_es; ep += 2; /* * First entry : file entry * Second entry : stream-extension entry * Third entry : first file-name entry * So, the index of first file-name dentry should start from 2. */ for (i = 2; i < es->num_entries; i++, ep++) { for (i = 2; i < es->num_entries; i++) { struct exfat_dentry *ep = exfat_get_dentry_cached(es, i); /* end of name entry */ if (exfat_get_entry_type(ep) != TYPE_EXTEND) goto free_es; break; exfat_extract_uni_name(ep, uniname); uniname += EXFAT_FILE_NAME_LEN; } free_es: kfree(es); exfat_free_dentry_set(es, false); } /* read a directory entry from the opened directory */ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry) { int i, dentries_per_clu, dentries_per_clu_bits = 0; int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext; unsigned int type, clu_offset; sector_t sector; struct exfat_chain dir, clu; Loading @@ -75,7 +70,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_inode_info *ei = EXFAT_I(inode); unsigned int dentry = ei->rwoffset & 0xFFFFFFFF; unsigned int dentry = EXFAT_B_TO_DEN(*cpos) & 0xFFFFFFFF; struct buffer_head *bh; /* check if the given file ID is opened */ Loading Loading @@ -132,17 +127,18 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) continue; } num_ext = ep->dentry.file.num_ext; dir_entry->attr = le16_to_cpu(ep->dentry.file.attr); exfat_get_entry_time(sbi, &dir_entry->crtime, 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, &dir_entry->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, &dir_entry->atime, ep->dentry.file.access_tz, ep->dentry.file.access_time, Loading @@ -162,12 +158,13 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) return -EIO; dir_entry->size = le64_to_cpu(ep->dentry.stream.valid_size); dir_entry->entry = dentry; brelse(bh); ei->hint_bmap.off = dentry >> dentries_per_clu_bits; ei->hint_bmap.clu = clu.dir; ei->rwoffset = ++dentry; *cpos = EXFAT_DEN_TO_B(dentry + 1 + num_ext); return 0; } Loading @@ -183,7 +180,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry) } dir_entry->namebuf.lfn[0] = '\0'; ei->rwoffset = dentry; *cpos = EXFAT_DEN_TO_B(dentry); return 0; } Loading Loading @@ -247,12 +244,10 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) if (err) goto unlock; get_new: ei->rwoffset = EXFAT_B_TO_DEN(cpos); if (cpos >= i_size_read(inode)) goto end_of_dir; err = exfat_readdir(inode, &de); err = exfat_readdir(inode, &cpos, &de); if (err) { /* * At least we tried to read a sector. Move cpos to next sector Loading @@ -267,13 +262,10 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx) goto end_of_dir; } cpos = EXFAT_DEN_TO_B(ei->rwoffset); if (!nb->lfn[0]) goto end_of_dir; i_pos = ((loff_t)ei->start_clu << 32) | ((ei->rwoffset - 1) & 0xffffffff); i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff); tmp = exfat_iget(sb, i_pos); if (tmp) { inum = tmp->i_ino; Loading Loading @@ -314,7 +306,7 @@ const struct file_operations exfat_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .iterate = exfat_iterate, .fsync = generic_file_fsync, .fsync = exfat_file_fsync, }; int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu) Loading Loading @@ -430,10 +422,12 @@ static void exfat_init_name_entry(struct exfat_dentry *ep, ep->dentry.name.flags = 0x0; for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) { if (*uniname != 0x0) { ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname); if (*uniname == 0x0) break; uniname++; } else { ep->dentry.name.unicode_0_14[i] = 0x0; } } } Loading Loading @@ -461,19 +455,19 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, &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, &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); exfat_set_entry_time(sbi, &ts, &ep->dentry.file.access_tz, &ep->dentry.file.access_time, &ep->dentry.file.access_date, NULL); exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); exfat_update_bh(bh, IS_DIRSYNC(inode)); brelse(bh); ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); Loading @@ -483,7 +477,7 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir, exfat_init_stream_entry(ep, (type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN, start_clu, size); exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); exfat_update_bh(bh, IS_DIRSYNC(inode)); brelse(bh); return 0; Loading @@ -496,7 +490,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, int ret = 0; int i, num_entries; sector_t sector; unsigned short chksum; u16 chksum; struct exfat_dentry *ep, *fep; struct buffer_head *fbh, *bh; Loading @@ -505,7 +499,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, return -EIO; num_entries = fep->dentry.file.num_ext + 1; chksum = exfat_calc_chksum_2byte(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY); chksum = exfat_calc_chksum16(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY); for (i = 1; i < num_entries; i++) { ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, NULL); Loading @@ -513,13 +507,13 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, ret = -EIO; goto release_fbh; } chksum = exfat_calc_chksum_2byte(ep, DENTRY_SIZE, chksum, chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum, CS_DEFAULT); brelse(bh); } fep->dentry.file.checksum = cpu_to_le16(chksum); exfat_update_bh(sb, fbh, IS_DIRSYNC(inode)); exfat_update_bh(fbh, IS_DIRSYNC(inode)); release_fbh: brelse(fbh); return ret; Loading @@ -541,7 +535,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, return -EIO; ep->dentry.file.num_ext = (unsigned char)(num_entries - 1); exfat_update_bh(sb, bh, sync); exfat_update_bh(bh, sync); brelse(bh); ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, §or); Loading @@ -550,7 +544,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, ep->dentry.stream.name_len = p_uniname->name_len; ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash); exfat_update_bh(sb, bh, sync); exfat_update_bh(bh, sync); brelse(bh); for (i = EXFAT_FIRST_CLUSTER; i < num_entries; i++) { Loading @@ -559,7 +553,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, return -EIO; exfat_init_name_entry(ep, uniname); exfat_update_bh(sb, bh, sync); exfat_update_bh(bh, sync); brelse(bh); uniname += EXFAT_FILE_NAME_LEN; } Loading @@ -583,69 +577,44 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, return -EIO; exfat_set_entry_type(ep, TYPE_DELETED); exfat_update_bh(sb, bh, IS_DIRSYNC(inode)); exfat_update_bh(bh, IS_DIRSYNC(inode)); brelse(bh); } return 0; } 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) { struct exfat_sb_info *sbi = EXFAT_SB(sb); struct buffer_head *bh; sector_t sec = es->sector; unsigned int off = es->offset; int chksum_type = CS_DIR_ENTRY, i, num_entries = es->num_entries; unsigned int buf_off = (off - es->offset); unsigned int remaining_byte_in_sector, copy_entries, clu; int chksum_type = CS_DIR_ENTRY, i; unsigned short chksum = 0; struct exfat_dentry *ep; for (i = 0; i < num_entries; i++) { chksum = exfat_calc_chksum_2byte(&es->entries[i], DENTRY_SIZE, chksum, chksum_type); for (i = 0; i < es->num_entries; i++) { ep = exfat_get_dentry_cached(es, i); chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum, chksum_type); chksum_type = CS_DEFAULT; } ep = exfat_get_dentry_cached(es, 0); ep->dentry.file.checksum = cpu_to_le16(chksum); es->modified = true; } es->entries[0].dentry.file.checksum = cpu_to_le16(chksum); int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync) { int i, err = 0; while (num_entries) { /* write per sector base */ remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off; copy_entries = min_t(int, EXFAT_B_TO_DEN(remaining_byte_in_sector), num_entries); bh = sb_bread(sb, sec); if (!bh) goto err_out; memcpy(bh->b_data + off, (unsigned char *)&es->entries[0] + buf_off, EXFAT_DEN_TO_B(copy_entries)); exfat_update_bh(sb, bh, sync); brelse(bh); num_entries -= copy_entries; if (es->modified) err = exfat_update_bhs(es->bh, es->num_bh, sync); if (num_entries) { /* get next sector */ if (exfat_is_last_sector_in_cluster(sbi, sec)) { clu = exfat_sector_to_cluster(sbi, sec); if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) clu++; else if (exfat_get_next_cluster(sb, &clu)) goto err_out; sec = exfat_cluster_to_sector(sbi, clu); } else { sec++; } off = 0; buf_off += EXFAT_DEN_TO_B(copy_entries); } } return 0; err_out: return -EIO; for (i = 0; i < es->num_bh; i++) if (err) bforget(es->bh[i]); else brelse(es->bh[i]); kfree(es); return err; } static int exfat_walk_fat_chain(struct super_block *sb, Loading Loading @@ -720,8 +689,7 @@ static int exfat_dir_readahead(struct super_block *sb, sector_t sec) return 0; if (sec < sbi->data_start_sector) { exfat_msg(sb, KERN_ERR, "requested sector is invalid(sect:%llu, root:%llu)", exfat_err(sb, "requested sector is invalid(sect:%llu, root:%llu)", (unsigned long long)sec, sbi->data_start_sector); return -EIO; } Loading Loading @@ -750,7 +718,7 @@ struct exfat_dentry *exfat_get_dentry(struct super_block *sb, sector_t sec; if (p_dir->dir == DIR_DELETED) { exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry\n"); exfat_err(sb, "abnormal access to deleted dentry"); return NULL; } Loading Loading @@ -821,39 +789,45 @@ static bool exfat_validate_entry(unsigned int type, } } struct exfat_dentry *exfat_get_dentry_cached( struct exfat_entry_set_cache *es, int num) { int off = es->start_off + num * DENTRY_SIZE; struct buffer_head *bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)]; char *p = bh->b_data + EXFAT_BLK_OFFSET(off, es->sb); return (struct exfat_dentry *)p; } /* * Returns a set of dentries for a file or dir. * * Note that this is a copy (dump) of dentries so that user should * call write_entry_set() to apply changes made in this entry set * to the real device. * Note It provides a direct pointer to bh->data via exfat_get_dentry_cached(). * User should call exfat_get_dentry_set() after setting 'modified' to apply * changes made in this entry set to the real device. * * in: * sb+p_dir+entry: indicates a file/dir * type: specifies how many dentries should be included. * out: * file_ep: will point the first dentry(= file dentry) on success * return: * pointer of entry set on success, * NULL on failure. */ 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) { int ret; int ret, i, num_bh; unsigned int off, byte_offset, clu = 0; unsigned int entry_type; sector_t sec; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_entry_set_cache *es; struct exfat_dentry *ep, *pos; unsigned char num_entries; struct exfat_dentry *ep; int num_entries; enum exfat_validate_dentry_mode mode = ES_MODE_STARTED; struct buffer_head *bh; if (p_dir->dir == DIR_DELETED) { exfat_msg(sb, KERN_ERR, "access to deleted dentry\n"); exfat_err(sb, "access to deleted dentry"); return NULL; } Loading @@ -862,11 +836,18 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, if (ret) return NULL; es = kzalloc(sizeof(*es), GFP_KERNEL); if (!es) return NULL; es->sb = sb; es->modified = false; /* byte offset in cluster */ byte_offset = EXFAT_CLU_OFFSET(byte_offset, sbi); /* byte offset in sector */ off = EXFAT_BLK_OFFSET(byte_offset, sb); es->start_off = off; /* sector offset in cluster */ sec = EXFAT_B_TO_BLK(byte_offset, sb); Loading @@ -874,42 +855,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, bh = sb_bread(sb, sec); if (!bh) return NULL; ep = (struct exfat_dentry *)(bh->b_data + off); entry_type = exfat_get_entry_type(ep); goto free_es; es->bh[es->num_bh++] = bh; if (entry_type != TYPE_FILE && entry_type != TYPE_DIR) goto release_bh; ep = exfat_get_dentry_cached(es, 0); if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) goto free_es; num_entries = type == ES_ALL_ENTRIES ? ep->dentry.file.num_ext + 1 : type; es = kmalloc(struct_size(es, entries, num_entries), GFP_KERNEL); if (!es) goto release_bh; es->num_entries = num_entries; es->sector = sec; es->offset = off; es->alloc_flag = p_dir->flags; pos = &es->entries[0]; while (num_entries) { if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) goto free_es; /* copy dentry */ memcpy(pos, ep, sizeof(struct exfat_dentry)); if (--num_entries == 0) break; if (((off + DENTRY_SIZE) & (sb->s_blocksize - 1)) < (off & (sb->s_blocksize - 1))) { num_bh = EXFAT_B_TO_BLK_ROUND_UP(off + num_entries * DENTRY_SIZE, sb); for (i = 1; i < num_bh; i++) { /* get the next sector */ if (exfat_is_last_sector_in_cluster(sbi, sec)) { if (es->alloc_flag == ALLOC_NO_FAT_CHAIN) if (p_dir->flags == ALLOC_NO_FAT_CHAIN) clu++; else if (exfat_get_next_cluster(sb, &clu)) goto free_es; Loading @@ -918,28 +879,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, sec++; } brelse(bh); bh = sb_bread(sb, sec); if (!bh) goto free_es; off = 0; ep = (struct exfat_dentry *)bh->b_data; } else { ep++; off += DENTRY_SIZE; } pos++; es->bh[es->num_bh++] = bh; } if (file_ep) *file_ep = &es->entries[0]; brelse(bh); /* validiate cached dentries */ for (i = 1; i < num_entries; i++) { ep = exfat_get_dentry_cached(es, i); if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode)) goto free_es; } return es; free_es: kfree(es); release_bh: brelse(bh); exfat_free_dentry_set(es, false); return NULL; } Loading @@ -953,7 +908,6 @@ enum { /* * return values: * >= 0 : return dir entiry position with the name in dir * -EEXIST : (root dir, ".") it is the root dir itself * -ENOENT : entry with the name does not exist * -EIO : I/O error */ Loading Loading @@ -1021,11 +975,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, if (ei->hint_femp.eidx == EXFAT_HINT_NONE || candi_empty.eidx <= ei->hint_femp.eidx) { memcpy(&ei->hint_femp, &candi_empty, sizeof(candi_empty)); } ei->hint_femp.eidx) ei->hint_femp = candi_empty; } brelse(bh); Loading @@ -1048,7 +999,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, } if (entry_type == TYPE_STREAM) { unsigned short name_hash; u16 name_hash; if (step != DIRENT_STEP_STRM) { step = DIRENT_STEP_FILE; Loading Loading @@ -1158,7 +1109,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, ret = exfat_get_next_cluster(sb, &clu.dir); } if (ret || clu.dir != EXFAT_EOF_CLUSTER) { if (ret || clu.dir == EXFAT_EOF_CLUSTER) { /* just initialized hint_stat */ hint_stat->clu = p_dir->dir; hint_stat->eidx = 0; Loading
fs/exfat/exfat_fs.h +37 −34 Original line number Diff line number Diff line Loading @@ -13,8 +13,6 @@ #define EXFAT_SUPER_MAGIC 0x2011BAB0UL #define EXFAT_ROOT_INO 1 #define EXFAT_SB_DIRTY 0 #define EXFAT_CLUSTERS_UNTRACKED (~0u) /* Loading Loading @@ -71,10 +69,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 Loading Loading @@ -132,14 +128,14 @@ enum { struct exfat_dentry_namebuf { char *lfn; int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */ int lfnbuf_len; /* usually MAX_UNINAME_BUF_SIZE */ }; /* unicode name structure */ 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; }; Loading Loading @@ -170,14 +166,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 { Loading Loading @@ -230,8 +224,9 @@ struct exfat_sb_info { unsigned int num_FAT_sectors; /* num of FAT sectors */ 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 */ unsigned int vol_flags; /* volume flags */ unsigned int vol_flags_persistent; /* volume flags to retain */ 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 */ Loading @@ -242,7 +237,6 @@ struct exfat_sb_info { unsigned int clu_srch_ptr; /* cluster search pointer */ unsigned int used_clusters; /* number of used clusters */ unsigned long s_state; struct mutex s_lock; /* superblock lock */ struct exfat_mount_options options; struct nls_table *nls_io; /* Charset used for input and display */ Loading @@ -254,6 +248,8 @@ struct exfat_sb_info { struct rcu_head rcu; }; #define EXFAT_CACHE_VALID 0 /* * EXFAT file system inode in-memory data */ Loading @@ -269,8 +265,6 @@ struct exfat_inode_info { * the validation of hint_stat. */ unsigned int version; /* file offset or dentry index for readdir */ loff_t rwoffset; /* hint for cluster last accessed */ struct exfat_hint hint_bmap; Loading Loading @@ -375,7 +369,7 @@ static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi, static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi, unsigned int clus) { return ((clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) + return ((sector_t)(clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) + sbi->data_start_sector; } Loading @@ -387,7 +381,8 @@ static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi, } /* super.c */ int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag); int exfat_set_volume_dirty(struct super_block *sb); int exfat_clear_volume_dirty(struct super_block *sb); /* fatent.c */ #define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu) Loading Loading @@ -424,6 +419,7 @@ void exfat_truncate(struct inode *inode, loff_t size); int exfat_setattr(struct dentry *dentry, struct iattr *attr); int exfat_getattr(const struct path *path, struct kstat *stat, unsigned int request_mask, unsigned int query_flags); int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync); /* namei.c */ extern const struct dentry_operations exfat_dentry_ops; Loading @@ -432,7 +428,6 @@ extern const struct dentry_operations exfat_utf8_dentry_ops; /* cache.c */ int exfat_cache_init(void); void exfat_cache_shutdown(void); void exfat_cache_init_inode(struct inode *inode); void exfat_cache_inval_inode(struct inode *inode); int exfat_get_cluster(struct inode *inode, unsigned int cluster, unsigned int *fclus, unsigned int *dclus, Loading @@ -451,8 +446,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, Loading @@ -463,9 +457,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); int 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 */ Loading @@ -492,8 +488,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, ...) Loading @@ -505,13 +499,22 @@ 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); void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync); 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 buffer_head *bh, int sync); int exfat_update_bhs(struct buffer_head **bhs, int nr_bhs, int sync); void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, unsigned int size, unsigned char flags); void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec); Loading
fs/exfat/exfat_raw.h +34 −54 Original line number Diff line number Diff line Loading @@ -8,12 +8,14 @@ #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 VOLUME_DIRTY 0x0002 #define MEDIA_FAILURE 0x0004 #define EXFAT_EOF_CLUSTER 0xFFFFFFFFu #define EXFAT_BAD_CLUSTER 0xFFFFFFF7u Loading Loading @@ -55,7 +57,7 @@ /* checksum types */ #define CS_DIR_ENTRY 0 #define CS_PBR_SECTOR 1 #define CS_BOOT_SECTOR 1 #define CS_DEFAULT 2 /* file attributes */ Loading @@ -69,22 +71,18 @@ #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; /* 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; Loading @@ -92,32 +90,14 @@ struct bsx64 { __le32 clu_count; __le32 root_cluster; __le32 vol_serial; __u8 fs_version[2]; __u8 fs_revision[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 drv_sel; __u8 percent_in_use; __u8 reserved[7]; __u8 boot_code[390]; __le16 signature; } __packed; Loading @@ -136,8 +116,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; Loading