Skip to content

Commit

Permalink
exfat: do not fallback to buffered write
Browse files Browse the repository at this point in the history
After commit(11a347f 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: Yuezhang Mo <Yuezhang.Mo@sony.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
  • Loading branch information
Yuezhang Mo authored and Namjae Jeon committed Sep 17, 2024
1 parent fba27cf commit 231eb76
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 74 deletions.
2 changes: 0 additions & 2 deletions fs/exfat/exfat_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 0 additions & 11 deletions fs/exfat/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down
74 changes: 15 additions & 59 deletions fs/exfat/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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;

Expand All @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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().
Expand All @@ -525,8 +479,18 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
} else
size = pos + ret;

/* zero the unwritten part in the partially written block */
if (rw == READ && pos < ei->valid_size && ei->valid_size < size) {
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 */
iov_iter_revert(iter, size - ei->valid_size);
iov_iter_zero(size - ei->valid_size, iter);
}
Expand Down Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion fs/exfat/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion fs/exfat/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 231eb76

Please sign in to comment.