ext4: Optimization of no-op ext4_truncate triggers
PATCH v3 1/1 ext4: Optimization of no-op ext4_truncate triggers
v2: https://lore.kernel.org/lkml/[email protected]/T/
OR
https://patchwork.ozlabs.org/project/linux-ext4/patch/[email protected]/
Fix from last version:
Clear the EXT4_STATE_TRUNCATED flag at ext4_mb_new_blocks() in order to make sure that every attempt to allocate new blocks, will result in resetting the 'truncated' state of the inode.
Why is this needed? We want the ability to truncate preallocated blocks of an inode by using ext4_truncate(). However, when ftruncate is called from the vfs, the call is blocked (at ext4_setattr()) when used on already-truncated inodes. We want that call to be blocked only if the truncate call is redundant (meanning there is nothing there to truncate).
--- fs/ext4/ext4.h | 1 + fs/ext4/extents.c | 5 +++++ fs/ext4/inode.c | 6 +++++- fs/ext4/mballoc.c | 5 +++++ 4 files changed, 16 insertions(+), 1 deletion(-)
fs/ext4/ext4.h +1 -0
@@ -1915,6 +1915,7 @@ enum {EXT4_STATE_VERITY_IN_PROGRESS ,/* building fs-verity Merkle tree */ EXT4_STATE_FC_COMMITTING ,/* Fast commit ongoing */ EXT4_STATE_ORPHAN_FILE ,/* Inode orphaned in orphan file */ + EXT4_STATE_TRUNCATED, /* Inode is truncated */ };#define EXT4_INODE_BIT_FNS (name, field, offset) \
fs/ext4/extents.c +5 -0
@@ -4782,6 +4782,11 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) ret =ext4_zero_range (file, offset, len, mode); goto exit; } + +if (mode &FALLOC_FL_KEEP_SIZE ) { +ext4_clear_inode_state (inode,EXT4_STATE_TRUNCATED ); + } +trace_ext4_fallocate_enter (inode, offset, len, mode); lblk = offset >> blkbits;
fs/ext4/inode.c +5 -1
@@ -4193,6 +4193,8 @@ int ext4_truncate(struct inode *inode)if (IS_SYNC (inode))ext4_handle_sync (handle); +ext4_set_inode_state (inode,EXT4_STATE_TRUNCATED ); + out_stop:/* * If this was a simple ftruncate() and the file will remain alive,
@@ -5492,7 +5494,9 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,* Call ext4_truncate() even if i_size didn't change to * truncate possible preallocated blocks. */ -if (attr->ia_size <= oldsize) { +if (attr->ia_size < oldsize || + (attr->ia_size == oldsize && + !ext4_test_inode_state (inode,EXT4_STATE_TRUNCATED ))) { rc =ext4_truncate (inode);if (rc) error = rc;
fs/ext4/mballoc.c +5 -0
@@ -6149,6 +6149,11 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, sb = ar->inode->i_sb; sbi =EXT4_SB (sb); +/* Once there is an attempt to allocate new blocks, +* the inode is no longer considered truncated. +*/ +ext4_clear_inode_state (ar->inode,EXT4_STATE_TRUNCATED ); +trace_ext4_request_blocks (ar);if (sbi->s_mount_state &EXT4_FC_REPLAY )return ext4_mb_new_blocks_simple (ar, errp);
Signature · 1 line
2.43.0