lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20241204090225.721618-1-linmaxi@gmail.com>
Date: Wed,  4 Dec 2024 11:02:25 +0200
From: Max Brener <linmaxi@...il.com>
To: tytso@....edu
Cc: adilger.kernel@...ger.ca,
	linux-ext4@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Max Brener <linmaxi@...il.com>
Subject: [PATCH v3] ext4: Optimization of no-op ext4_truncate triggers

Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219306
v2: https://lore.kernel.org/lkml/20241001082459.14580-1-linmaxi@gmail.com/T/
OR
	https://patchwork.ozlabs.org/project/linux-ext4/patch/20241016111624.5229-1-linmaxi@gmail.com/

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(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 44b0d418143c..032e51f2a92b 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -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)				\
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 34e25eee6521..531fa0f2ccd3 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -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;
 
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 54bdd4884fe6..cbdad3253920 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -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;
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index d73e38323879..4f0dbd53b3df 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -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);
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ