Commit 231eb762 authored by Yuezhang Mo's avatar Yuezhang Mo Committed by Namjae Jeon
Browse files

exfat: do not fallback to buffered write



After commit(11a347fb exfat: change to get file size from
DataLength), the remaining area or hole had been filled with
zeros before calling exfat_direct_IO(), so there is no need to
fallback to buffered write, and ->i_size_aligned is no longer
needed, drop it.

Signed-off-by: default avatarYuezhang Mo <Yuezhang.Mo@sony.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
parent fba27cf0
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -309,8 +309,6 @@ struct exfat_inode_info {
	/* for avoiding the race between alloc and free */
	unsigned int cache_valid_id;

	/* block-aligned i_size (used in cont_write_begin) */
	loff_t i_size_aligned;
	/* on-disk position of directory entry or 0 */
	loff_t i_pos;
	loff_t valid_size;
+0 −11
Original line number Diff line number Diff line
@@ -74,7 +74,6 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
	/* Expanded range not zeroed, do not update valid_size */
	i_size_write(inode, size);

	ei->i_size_aligned = round_up(size, sb->s_blocksize);
	inode->i_blocks = round_up(size, sbi->cluster_size) >> 9;
	mark_inode_dirty(inode);

@@ -244,8 +243,6 @@ void exfat_truncate(struct inode *inode)
	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 blocksize = i_blocksize(inode);
	loff_t aligned_size;
	int err;

	mutex_lock(&sbi->s_lock);
@@ -263,14 +260,6 @@ void exfat_truncate(struct inode *inode)

	inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
write_size:
	aligned_size = i_size_read(inode);
	if (aligned_size & (blocksize - 1)) {
		aligned_size |= (blocksize - 1);
		aligned_size++;
	}

	if (ei->i_size_aligned > i_size_read(inode))
		ei->i_size_aligned = aligned_size;
	mutex_unlock(&sbi->s_lock);
}

+15 −59
Original line number Diff line number Diff line
@@ -258,21 +258,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
	return 0;
}

static int exfat_map_new_buffer(struct exfat_inode_info *ei,
		struct buffer_head *bh, loff_t pos)
{
	if (buffer_delay(bh) && pos > ei->i_size_aligned)
		return -EIO;
	set_buffer_new(bh);

	/*
	 * Adjust i_size_aligned if ondisk_size is bigger than it.
	 */
	if (exfat_ondisk_size(&ei->vfs_inode) > ei->i_size_aligned)
		ei->i_size_aligned = exfat_ondisk_size(&ei->vfs_inode);
	return 0;
}

static int exfat_get_block(struct inode *inode, sector_t iblock,
		struct buffer_head *bh_result, int create)
{
@@ -286,7 +271,6 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
	sector_t last_block;
	sector_t phys = 0;
	sector_t valid_blks;
	loff_t pos;

	mutex_lock(&sbi->s_lock);
	last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb);
@@ -314,8 +298,6 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
	mapped_blocks = sbi->sect_per_clus - sec_offset;
	max_blocks = min(mapped_blocks, max_blocks);

	pos = EXFAT_BLK_TO_B((iblock + 1), sb);

	map_bh(bh_result, sb, phys);
	if (buffer_delay(bh_result))
		clear_buffer_delay(bh_result);
@@ -336,13 +318,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
		}

		/* The area has not been written, map and mark as new. */
		err = exfat_map_new_buffer(ei, bh_result, pos);
		if (err) {
			exfat_fs_error(sb,
					"requested for bmap out of range(pos : (%llu) > i_size_aligned(%llu)\n",
					pos, ei->i_size_aligned);
			goto unlock_ret;
		}
		set_buffer_new(bh_result);

		ei->valid_size = EXFAT_BLK_TO_B(iblock + max_blocks, sb);
		mark_inode_dirty(inode);
@@ -365,7 +341,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
			 * The block has been partially written,
			 * zero the unwritten part and map the block.
			 */
			loff_t size, off;
			loff_t size, off, pos;

			max_blocks = 1;

@@ -376,7 +352,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
			if (!bh_result->b_folio)
				goto done;

			pos -= sb->s_blocksize;
			pos = EXFAT_BLK_TO_B(iblock, sb);
			size = ei->valid_size - pos;
			off = pos & (PAGE_SIZE - 1);

@@ -463,14 +439,6 @@ static int exfat_write_end(struct file *file, struct address_space *mapping,
	int err;

	err = generic_write_end(file, mapping, pos, len, copied, folio, fsdata);

	if (ei->i_size_aligned < i_size_read(inode)) {
		exfat_fs_error(inode->i_sb,
			"invalid size(size(%llu) > aligned(%llu)\n",
			i_size_read(inode), ei->i_size_aligned);
		return -EIO;
	}

	if (err < len)
		exfat_write_failed(mapping, pos+len);

@@ -498,20 +466,6 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
	int rw = iov_iter_rw(iter);
	ssize_t ret;

	if (rw == WRITE) {
		/*
		 * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
		 * so we need to update the ->i_size_aligned to block boundary.
		 *
		 * But we must fill the remaining area or hole by nul for
		 * updating ->i_size_aligned
		 *
		 * Return 0, and fallback to normal buffered write.
		 */
		if (EXFAT_I(inode)->i_size_aligned < size)
			return 0;
	}

	/*
	 * Need to use the DIO_LOCKING for avoiding the race
	 * condition of exfat_get_block() and ->truncate().
@@ -525,8 +479,18 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
	} else
		size = pos + ret;

	if (rw == WRITE) {
		/*
		 * If the block had been partially written before this write,
		 * ->valid_size will not be updated in exfat_get_block(),
		 * update it here.
		 */
		if (ei->valid_size < size) {
			ei->valid_size = size;
			mark_inode_dirty(inode);
		}
	} else if (pos < ei->valid_size && ei->valid_size < size) {
		/* zero the unwritten part in the partially written block */
	if (rw == READ && pos < ei->valid_size && ei->valid_size < size) {
		iov_iter_revert(iter, size - ei->valid_size);
		iov_iter_zero(size - ei->valid_size, iter);
	}
@@ -661,14 +625,6 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)

	i_size_write(inode, size);

	/* ondisk and aligned size should be aligned with block size */
	if (size & (inode->i_sb->s_blocksize - 1)) {
		size |= (inode->i_sb->s_blocksize - 1);
		size++;
	}

	ei->i_size_aligned = size;

	exfat_save_attr(inode, info->attr);

	inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
+0 −1
Original line number Diff line number Diff line
@@ -372,7 +372,6 @@ static int exfat_find_empty_entry(struct inode *inode,

		/* directory inode should be updated in here */
		i_size_write(inode, size);
		ei->i_size_aligned += sbi->cluster_size;
		ei->valid_size += sbi->cluster_size;
		ei->flags = p_dir->flags;
		inode->i_blocks += sbi->cluster_size >> 9;
+0 −1
Original line number Diff line number Diff line
@@ -370,7 +370,6 @@ static int exfat_read_root(struct inode *inode)

	inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
	ei->i_pos = ((loff_t)sbi->root_dir << 32) | 0xffffffff;
	ei->i_size_aligned = i_size_read(inode);

	exfat_save_attr(inode, EXFAT_ATTR_SUBDIR);
	ei->i_crtime = simple_inode_init_ts(inode);