Patch "btrfs: fix warning during log replay when bumping inode link count" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    btrfs: fix warning during log replay when bumping inode link count

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     btrfs-fix-warning-during-log-replay-when-bumping-ino.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 74ce5651401949bf21172a50270715fcde463286
Author: Filipe Manana <fdmanana@xxxxxxxx>
Date:   Mon Aug 1 14:57:52 2022 +0100

    btrfs: fix warning during log replay when bumping inode link count
    
    [ Upstream commit 769030e11847c5412270c0726ff21d3a1f0a3131 ]
    
    During log replay, at add_link(), we may increment the link count of
    another inode that has a reference that conflicts with a new reference
    for the inode currently being processed.
    
    During log replay, at add_link(), we may drop (unlink) a reference from
    some inode in the subvolume tree if that reference conflicts with a new
    reference found in the log for the inode we are currently processing.
    
    After the unlink, If the link count has decreased from 1 to 0, then we
    increment the link count to prevent the inode from being deleted if it's
    evicted by an iput() call, because we may have references to add to that
    inode later on (and we will fixup its link count later during log replay).
    
    However incrementing the link count from 0 to 1 triggers a warning:
    
      $ cat fs/inode.c
      (...)
      void inc_nlink(struct inode *inode)
      {
            if (unlikely(inode->i_nlink == 0)) {
                     WARN_ON(!(inode->i_state & I_LINKABLE));
                     atomic_long_dec(&inode->i_sb->s_remove_count);
            }
      (...)
    
    The I_LINKABLE flag is only set when creating an O_TMPFILE file, so it's
    never set during log replay.
    
    Most of the time, the warning isn't triggered even if we dropped the last
    reference of the conflicting inode, and this is because:
    
    1) The conflicting inode was previously marked for fixup, through a call
       to link_to_fixup_dir(), which increments the inode's link count;
    
    2) And the last iput() on the inode has not triggered eviction of the
       inode, nor was eviction triggered after the iput(). So at add_link(),
       even if we unlink the last reference of the inode, its link count ends
       up being 1 and not 0.
    
    So this means that if eviction is triggered after link_to_fixup_dir() is
    called, at add_link() we will read the inode back from the subvolume tree
    and have it with a correct link count, matching the number of references
    it has on the subvolume tree. So if when we are at add_link() the inode
    has exactly one reference only, its link count is 1, and after the unlink
    its link count becomes 0.
    
    So fix this by using set_nlink() instead of inc_nlink(), as the former
    accepts a transition from 0 to 1 and it's what we use in other similar
    contexts (like at link_to_fixup_dir().
    
    Also make add_inode_ref() use set_nlink() instead of inc_nlink() to
    bump the link count from 0 to 1.
    
    The warning is actually harmless, but it may scare users. Josef also ran
    into it recently.
    
    CC: stable@xxxxxxxxxxxxxxx # 5.1+
    Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
    Reviewed-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index c56a89d224bbb..7272896587302 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1444,7 +1444,7 @@ static int add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 	 * on the inode will not free it. We will fixup the link count later.
 	 */
 	if (other_inode->i_nlink == 0)
-		inc_nlink(other_inode);
+		set_nlink(other_inode, 1);
 add_link:
 	ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
 			     name, namelen, 0, ref_index);
@@ -1587,7 +1587,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
 				 * free it. We will fixup the link count later.
 				 */
 				if (!ret && inode->i_nlink == 0)
-					inc_nlink(inode);
+					set_nlink(inode, 1);
 			}
 			if (ret < 0)
 				goto out;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux