]> 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)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 26 Sep 2025 12:36:08 +0000 (08:36 -0400)
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>
fs/ext4/ext4.h
fs/ext4/file.c
fs/ext4/inode.c
fs/ext4/orphan.c
fs/ext4/super.c

index a31cf47681b9d2e4de86cbbefe0a7edec2c59420..24c414605b0875fd62135144675aa964727ace0e 100644 (file)
@@ -1995,6 +1995,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 59014e16fb9441ac9ba44b8498fd0978b393e631..f9e4ac87211ec108c58f5e313a374647e0cc2e03 100644 (file)
@@ -4719,7 +4719,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 7e4f48c15c2e7252976c5a8461ef18ef76c0e017..33c3a89396b18b3c6ece0dab9e0f7cd7a252cf0f 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 5988440460c8b87ccb05e1a41f40acbeb5f1c97d..894529f9b0cc8e1e7896a0fe21aa9e6fdb8b5d12 100644 (file)
@@ -1447,9 +1447,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),