]> 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:04:20 +0000 (12:04 +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 01a6e2de7fc3ef0e20b039d3200b9c9bd656f59f..72e02df72c4c94a21d66d2f6a7914dbace863e52 100644 (file)
@@ -1981,6 +1981,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 93240e35ee363e85e4c08e00e7bb3a51c7e89c11..7a8b3093218921f26a7f8962f94739ba49431230 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 5b7a15db4953a36686509f132c42b783dab2ffa8..5230452e29dd8bcdfe8e5264314ea91b22433339 100644 (file)
@@ -4748,7 +4748,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 524d4658fa408d4259507c12c333a43d522c467d..0fbcce67ffd4e42e85850deb908c920f7461a5fb 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 699c15db28a82f26809bf68533454a242596f0fd..ba497387b9c863bdc9e88d47a33ae368ba0045a1 100644 (file)
@@ -1438,9 +1438,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),