]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ext4: fix checks for orphan inodes
authorJan Kara <jack@suse.cz>
Thu, 25 Sep 2025 12:30:39 +0000 (14:30 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 15 Oct 2025 10:00:22 +0000 (12:00 +0200)
commit acf943e9768ec9d9be80982ca0ebc4bfd6b7631e upstream.

When orphan file feature is enabled, inode can be tracked as orphan
either in the standard orphan list or in the orphan file. The first can
be tested by checking ei->i_orphan list head, the second is recorded by
EXT4_STATE_ORPHAN_FILE inode state flag. There are several places where
we want to check whether inode is tracked as orphan and only some of
them properly check for both possibilities. Luckily the consequences are
mostly minor, the worst that can happen is that we track an inode as
orphan although we don't need to and e2fsck then complains (resulting in
occasional ext4/307 xfstest failures). Fix the problem by introducing a
helper for checking whether an inode is tracked as orphan and use it in
appropriate places.

Fixes: 4a79a98c7b19 ("ext4: Improve scalability of ext4 orphan file handling")
Cc: stable@kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Message-ID: <20250925123038.20264-2-jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/ext4.h
fs/ext4/file.c
fs/ext4/inode.c
fs/ext4/orphan.c
fs/ext4/super.c

index d8120b88fa00e97430351ba191105bc7fb333c24..37e18e654f715bd9bc5e337c02c0b74a3c2d3d33 100644 (file)
@@ -1969,6 +1969,16 @@ static inline bool ext4_verity_in_progress(struct inode *inode)
 
 #define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
 
+/*
+ * Check whether the inode is tracked as orphan (either in orphan file or
+ * orphan list).
+ */
+static inline bool ext4_inode_orphan_tracked(struct inode *inode)
+{
+       return ext4_test_inode_state(inode, EXT4_STATE_ORPHAN_FILE) ||
+               !list_empty(&EXT4_I(inode)->i_orphan);
+}
+
 /*
  * Codes for operating systems
  */
index 6c692151b0d6c5bef74e88f77df0b9bb375de96c..7d949ed0ab5fac841bf9829df96285ff4774f264 100644 (file)
@@ -354,7 +354,7 @@ static void ext4_inode_extension_cleanup(struct inode *inode, bool need_trunc)
         * to cleanup the orphan list in ext4_handle_inode_extension(). Do it
         * now.
         */
-       if (!list_empty(&EXT4_I(inode)->i_orphan) && inode->i_nlink) {
+       if (ext4_inode_orphan_tracked(inode) && inode->i_nlink) {
                handle_t *handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
 
                if (IS_ERR(handle)) {
index 7923602271ad0a1d83e43a3c53fadf8f2fbf6d01..558a585c5df513400e39c410b4cd4fc565e22585 100644 (file)
@@ -4330,7 +4330,7 @@ static int ext4_fill_raw_inode(struct inode *inode, struct ext4_inode *raw_inode
                 * old inodes get re-used with the upper 16 bits of the
                 * uid/gid intact.
                 */
-               if (ei->i_dtime && list_empty(&ei->i_orphan)) {
+               if (ei->i_dtime && !ext4_inode_orphan_tracked(inode)) {
                        raw_inode->i_uid_high = 0;
                        raw_inode->i_gid_high = 0;
                } else {
index a23b0c01f8096d43adb0efb661018ff0df22337a..c53918768cb256fd96dba56ea00bbf0da0feae79 100644 (file)
@@ -109,11 +109,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
 
        WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) &&
                     !inode_is_locked(inode));
-       /*
-        * Inode orphaned in orphan file or in orphan list?
-        */
-       if (ext4_test_inode_state(inode, EXT4_STATE_ORPHAN_FILE) ||
-           !list_empty(&EXT4_I(inode)->i_orphan))
+       if (ext4_inode_orphan_tracked(inode))
                return 0;
 
        /*
index 58d125ad23714363798c3e854872d9d36cafc8b3..cbb65e61c4926fb1a415ff01f27f9b73050b8e9e 100644 (file)
@@ -1461,9 +1461,9 @@ static void ext4_free_in_core_inode(struct inode *inode)
 
 static void ext4_destroy_inode(struct inode *inode)
 {
-       if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
+       if (ext4_inode_orphan_tracked(inode)) {
                ext4_msg(inode->i_sb, KERN_ERR,
-                        "Inode %lu (%p): orphan list check failed!",
+                        "Inode %lu (%p): inode tracked as orphan!",
                         inode->i_ino, EXT4_I(inode));
                print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
                                EXT4_I(inode), sizeof(struct ext4_inode_info),