Skip to content

Commit

Permalink
Merge tag 'exfat-for-6.13-rc1' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/linkinjeon/exfat

Pull exfat updates from Namjae Jeon:

 - If the start cluster of stream entry is invalid, treat it as the
   empty directory

 - Valid size of steam entry cannot be greater than data size. If
   valid_size is invalid, use data_size

 - Move Direct-IO alignment check to before extending the valid size

 - Fix uninit-value issue reported by syzbot

 - Optimize finding directory entry-set in write_inode, rename, unlink

* tag 'exfat-for-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: reduce FAT chain traversal
  exfat: code cleanup for exfat_readdir()
  exfat: remove argument 'p_dir' from exfat_add_entry()
  exfat: move exfat_chain_set() out of __exfat_resolve_path()
  exfat: add exfat_get_dentry_set_by_ei() helper
  exfat: rename argument name for exfat_move_file and exfat_rename_file
  exfat: remove unnecessary read entry in __exfat_rename()
  exfat: fix file being changed by unaligned direct write
  exfat: fix uninit-value in __exfat_get_dentry_set
  exfat: fix out-of-bounds access of directory entries
  • Loading branch information
torvalds committed Nov 28, 2024
2 parents b86545e + 8a3f571 commit 8170a99
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 128 deletions.
29 changes: 5 additions & 24 deletions fs/exfat/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
if (ei->type != TYPE_DIR)
return -EPERM;

if (ei->entry == -1)
exfat_chain_set(&dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
else
exfat_chain_set(&dir, ei->start_clu,
EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags);
exfat_chain_set(&dir, ei->start_clu,
EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags);

dentries_per_clu = sbi->dentries_per_clu;
max_dentries = (unsigned int)min_t(u64, MAX_EXFAT_DENTRIES,
Expand Down Expand Up @@ -135,21 +132,6 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent

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_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_cs);
exfat_get_entry_time(sbi, &dir_entry->atime,
ep->dentry.file.access_tz,
ep->dentry.file.access_time,
ep->dentry.file.access_date,
0);

*uni_name.name = 0x0;
err = exfat_get_uniname_from_ext_entry(sb, &clu, i,
Expand All @@ -166,9 +148,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
ep = exfat_get_dentry(sb, &clu, i + 1, &bh);
if (!ep)
return -EIO;
dir_entry->size =
le64_to_cpu(ep->dentry.stream.valid_size);
dir_entry->entry = dentry;
dir_entry->entry = i;
dir_entry->dir = clu;
brelse(bh);

ei->hint_bmap.off = EXFAT_DEN_TO_CLU(dentry, sbi);
Expand Down Expand Up @@ -276,7 +257,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
if (!nb->lfn[0])
goto end_of_dir;

i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff);
i_pos = ((loff_t)de.dir.dir << 32) | (de.entry & 0xffffffff);
tmp = exfat_iget(sb, i_pos);
if (tmp) {
inum = tmp->i_ino;
Expand Down
6 changes: 6 additions & 0 deletions fs/exfat/exfat_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ struct exfat_entry_set_cache {
#define IS_DYNAMIC_ES(es) ((es)->__bh != (es)->bh)

struct exfat_dir_entry {
/* the cluster where file dentry is located */
struct exfat_chain dir;
/* the index of file dentry in ->dir */
int entry;
unsigned int type;
unsigned int start_clu;
Expand Down Expand Up @@ -290,7 +292,9 @@ struct exfat_sb_info {
* EXFAT file system inode in-memory data
*/
struct exfat_inode_info {
/* the cluster where file dentry is located */
struct exfat_chain dir;
/* the index of file dentry in ->dir */
int entry;
unsigned int type;
unsigned short attr;
Expand Down Expand Up @@ -508,6 +512,8 @@ struct exfat_dentry *exfat_get_dentry_cached(struct exfat_entry_set_cache *es,
int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
struct super_block *sb, struct exfat_chain *p_dir, int entry,
unsigned int num_entries);
#define exfat_get_dentry_set_by_ei(es, sb, ei) \
exfat_get_dentry_set(es, sb, &(ei)->dir, (ei)->entry, ES_ALL_ENTRIES)
int exfat_get_empty_dentry_set(struct exfat_entry_set_cache *es,
struct super_block *sb, struct exfat_chain *p_dir, int entry,
unsigned int num_entries);
Expand Down
10 changes: 10 additions & 0 deletions fs/exfat/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,16 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
if (ret < 0)
goto unlock;

if (iocb->ki_flags & IOCB_DIRECT) {
unsigned long align = pos | iov_iter_alignment(iter);

if (!IS_ALIGNED(align, i_blocksize(inode)) &&
!IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev))) {
ret = -EINVAL;
goto unlock;
}
}

if (pos > valid_size) {
ret = exfat_extend_valid_size(file, pos);
if (ret < 0 && ret != -ENOSPC) {
Expand Down
2 changes: 1 addition & 1 deletion fs/exfat/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ int __exfat_write_inode(struct inode *inode, int sync)
exfat_set_volume_dirty(sb);

/* get the directory entry of given file or directory */
if (exfat_get_dentry_set(&es, sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES))
if (exfat_get_dentry_set_by_ei(&es, sb, ei))
return -EIO;
ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
ep2 = exfat_get_dentry_cached(&es, ES_IDX_STREAM);
Expand Down
Loading

0 comments on commit 8170a99

Please sign in to comment.