Commit 5998f2bc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull exfat updates from Namjae Jeon:

 - Use generic_write_sync instead of vfs_fsync_range in exfat_file_write_iter.
   It will fix an issue where fdatasync would be set incorrectly.

 - Fix potential infinite loop by the self-linked chain.

* tag 'exfat-for-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: add cluster chain loop check for dir
  exfat: fdatasync flag should be same like generic_write_sync()
parents da23ea19 99f9a97d
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -996,6 +996,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
	struct exfat_hint_femp candi_empty;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	int num_entries = exfat_calc_num_entries(p_uniname);
	unsigned int clu_count = 0;

	if (num_entries < 0)
		return num_entries;
@@ -1133,6 +1134,10 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
		} else {
			if (exfat_get_next_cluster(sb, &clu.dir))
				return -EIO;

			/* break if the cluster chain includes a loop */
			if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi)))
				goto not_found;
		}
	}

@@ -1195,6 +1200,7 @@ int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir)
	int i, count = 0;
	int dentries_per_clu;
	unsigned int entry_type;
	unsigned int clu_count = 0;
	struct exfat_chain clu;
	struct exfat_dentry *ep;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
@@ -1227,6 +1233,12 @@ int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir)
		} else {
			if (exfat_get_next_cluster(sb, &(clu.dir)))
				return -EIO;

			if (unlikely(++clu_count > sbi->used_clusters)) {
				exfat_fs_error(sb, "FAT or bitmap is corrupted");
				return -EIO;
			}

		}
	}

+10 −0
Original line number Diff line number Diff line
@@ -490,5 +490,15 @@ int exfat_count_num_clusters(struct super_block *sb,
	}

	*ret_count = count;

	/*
	 * since exfat_count_used_clusters() is not called, sbi->used_clusters
	 * cannot be used here.
	 */
	if (unlikely(i == sbi->num_clusters && clu != EXFAT_EOF_CLUSTER)) {
		exfat_fs_error(sb, "The cluster chain has a loop");
		return -EIO;
	}

	return 0;
}
+2 −3
Original line number Diff line number Diff line
@@ -622,9 +622,8 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
	if (pos > valid_size)
		pos = valid_size;

	if (iocb_is_dsync(iocb) && iocb->ki_pos > pos) {
		ssize_t err = vfs_fsync_range(file, pos, iocb->ki_pos - 1,
				iocb->ki_flags & IOCB_SYNC);
	if (iocb->ki_pos > pos) {
		ssize_t err = generic_write_sync(iocb, iocb->ki_pos - pos);
		if (err < 0)
			return err;
	}
+5 −0
Original line number Diff line number Diff line
@@ -890,6 +890,7 @@ static int exfat_check_dir_empty(struct super_block *sb,
{
	int i, dentries_per_clu;
	unsigned int type;
	unsigned int clu_count = 0;
	struct exfat_chain clu;
	struct exfat_dentry *ep;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
@@ -926,6 +927,10 @@ static int exfat_check_dir_empty(struct super_block *sb,
		} else {
			if (exfat_get_next_cluster(sb, &(clu.dir)))
				return -EIO;

			/* break if the cluster chain includes a loop */
			if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi)))
				break;
		}
	}

+21 −11
Original line number Diff line number Diff line
@@ -341,13 +341,12 @@ static void exfat_hash_init(struct super_block *sb)
		INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);
}

static int exfat_read_root(struct inode *inode)
static int exfat_read_root(struct inode *inode, struct exfat_chain *root_clu)
{
	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_chain cdir;
	int num_subdirs, num_clu = 0;
	int num_subdirs;

	exfat_chain_set(&ei->dir, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
	ei->entry = -1;
@@ -360,12 +359,9 @@ static int exfat_read_root(struct inode *inode)
	ei->hint_stat.clu = sbi->root_dir;
	ei->hint_femp.eidx = EXFAT_HINT_NONE;

	exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
	if (exfat_count_num_clusters(sb, &cdir, &num_clu))
		return -EIO;
	i_size_write(inode, num_clu << sbi->cluster_size_bits);
	i_size_write(inode, EXFAT_CLU_TO_B(root_clu->size, sbi));

	num_subdirs = exfat_count_dir_entries(sb, &cdir);
	num_subdirs = exfat_count_dir_entries(sb, root_clu);
	if (num_subdirs < 0)
		return -EIO;
	set_nlink(inode, num_subdirs + EXFAT_MIN_SUBDIR);
@@ -578,7 +574,8 @@ static int exfat_verify_boot_region(struct super_block *sb)
}

/* mount the file system volume */
static int __exfat_fill_super(struct super_block *sb)
static int __exfat_fill_super(struct super_block *sb,
		struct exfat_chain *root_clu)
{
	int ret;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
@@ -595,6 +592,18 @@ static int __exfat_fill_super(struct super_block *sb)
		goto free_bh;
	}

	/*
	 * Call exfat_count_num_cluster() before searching for up-case and
	 * bitmap directory entries to avoid infinite loop if they are missing
	 * and the cluster chain includes a loop.
	 */
	exfat_chain_set(root_clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
	ret = exfat_count_num_clusters(sb, root_clu, &root_clu->size);
	if (ret) {
		exfat_err(sb, "failed to count the number of clusters in root");
		goto free_bh;
	}

	ret = exfat_create_upcase_table(sb);
	if (ret) {
		exfat_err(sb, "failed to load upcase table");
@@ -627,6 +636,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
	struct exfat_sb_info *sbi = sb->s_fs_info;
	struct exfat_mount_options *opts = &sbi->options;
	struct inode *root_inode;
	struct exfat_chain root_clu;
	int err;

	if (opts->allow_utime == (unsigned short)-1)
@@ -645,7 +655,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
	sb->s_time_min = EXFAT_MIN_TIMESTAMP_SECS;
	sb->s_time_max = EXFAT_MAX_TIMESTAMP_SECS;

	err = __exfat_fill_super(sb);
	err = __exfat_fill_super(sb, &root_clu);
	if (err) {
		exfat_err(sb, "failed to recognize exfat type");
		goto check_nls_io;
@@ -680,7 +690,7 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)

	root_inode->i_ino = EXFAT_ROOT_INO;
	inode_set_iversion(root_inode, 1);
	err = exfat_read_root(root_inode);
	err = exfat_read_root(root_inode, &root_clu);
	if (err) {
		exfat_err(sb, "failed to initialize root inode");
		goto put_inode;