Skip to content

Commit

Permalink
exfat: do not zero the extended part
Browse files Browse the repository at this point in the history
Since the read operation beyond the ValidDataLength returns zero,
if we just extend the size of the file, we don't need to zero the
extended part, but only change the DataLength without changing
the ValidDataLength.

Signed-off-by: Yuezhang Mo <[email protected]>
Reviewed-by: Andy Wu <[email protected]>
Reviewed-by: Aoyama Wataru <[email protected]>
Signed-off-by: Namjae Jeon <[email protected]>
  • Loading branch information
YuezhangMo authored and namjaejeon committed Dec 11, 2023
1 parent 202e869 commit f21584e
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 21 deletions.
77 changes: 57 additions & 20 deletions file.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,51 @@

static int exfat_cont_expand(struct inode *inode, loff_t size)
{
struct address_space *mapping = inode->i_mapping;
loff_t start = i_size_read(inode), count = size - i_size_read(inode);
int err, err2;
int ret;
unsigned int num_clusters, new_num_clusters, last_clu;
struct exfat_inode_info *ei = EXFAT_I(inode);
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_chain clu;

err = generic_cont_expand_simple(inode, size);
if (err)
return err;
ret = inode_newsize_ok(inode, size);
if (ret)
return ret;

num_clusters = EXFAT_B_TO_CLU_ROUND_UP(ei->i_size_ondisk, sbi);
new_num_clusters = EXFAT_B_TO_CLU_ROUND_UP(size, sbi);

if (new_num_clusters == num_clusters)
goto out;

exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
ret = exfat_find_last_cluster(sb, &clu, &last_clu);
if (ret)
return ret;

clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
EXFAT_EOF_CLUSTER : last_clu + 1;
clu.size = 0;
clu.flags = ei->flags;

ret = exfat_alloc_cluster(inode, new_num_clusters - num_clusters,
&clu, IS_DIRSYNC(inode));
if (ret)
return ret;

/* Append new clusters to chain */
if (clu.flags != ei->flags) {
exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters);
ei->flags = ALLOC_FAT_CHAIN;
}
if (clu.flags == ALLOC_FAT_CHAIN)
if (exfat_ent_set(sb, last_clu, clu.dir))
goto free_clu;

if (num_clusters == 0)
ei->start_clu = clu.dir;

out:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
Expand All @@ -37,23 +74,23 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
#else
inode->i_ctime = inode->i_mtime = current_time(inode);
#endif
EXFAT_I(inode)->valid_size = size;
mark_inode_dirty(inode);
/* Expanded range not zeroed, do not update valid_size */
i_size_write(inode, size);

if (!IS_SYNC(inode))
return 0;
ei->i_size_aligned = round_up(size, sb->s_blocksize);
ei->i_size_ondisk = ei->i_size_aligned;
inode->i_blocks = round_up(size, sbi->cluster_size) >> 9;

err = filemap_fdatawrite_range(mapping, start, start + count - 1);
err2 = sync_mapping_buffers(mapping);
if (!err)
err = err2;
err2 = write_inode_now(inode, 1);
if (!err)
err = err2;
if (err)
return err;
if (IS_DIRSYNC(inode))
return write_inode_now(inode, 1);

mark_inode_dirty(inode);

return 0;

return filemap_fdatawait_range(mapping, start, start + count - 1);
free_clu:
exfat_free_cluster(inode, &clu);
return -EIO;
}

static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode)
Expand Down
14 changes: 13 additions & 1 deletion inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,17 @@ int __exfat_write_inode(struct inode *inode, int sync)
if (ei->start_clu == EXFAT_EOF_CLUSTER)
on_disk_size = 0;

ep2->dentry.stream.valid_size = cpu_to_le64(ei->valid_size);
ep2->dentry.stream.size = cpu_to_le64(on_disk_size);
/*
* mmap write does not use exfat_write_end(), valid_size may be
* extended to the sector-aligned length in exfat_get_block().
* So we need to fixup valid_size to the writren length.
*/
if (on_disk_size < ei->valid_size)
ep2->dentry.stream.valid_size = ep2->dentry.stream.size;
else
ep2->dentry.stream.valid_size = cpu_to_le64(ei->valid_size);

if (on_disk_size) {
ep2->dentry.stream.flags = ei->flags;
ep2->dentry.stream.start_clu = cpu_to_le32(ei->start_clu);
Expand Down Expand Up @@ -372,6 +381,9 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
pos, ei->i_size_aligned);
goto unlock_ret;
}

ei->valid_size = EXFAT_BLK_TO_B(iblock + max_blocks, sb);
mark_inode_dirty(inode);
} else {
valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb);

Expand Down

0 comments on commit f21584e

Please sign in to comment.