]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
btrfs: do not set mtime/ctime to current time when unlinking for log replay
authorFilipe Manana <fdmanana@suse.com>
Fri, 1 Aug 2025 15:39:49 +0000 (16:39 +0100)
committerDavid Sterba <dsterba@suse.com>
Wed, 13 Aug 2025 12:08:44 +0000 (14:08 +0200)
If we are doing an unlink for log replay, we are updating the directory's
mtime and ctime to the current time, and this is incorrect since it should
stay with the mtime and ctime that were set when the directory was logged.

This is the same as when adding a link to an inode during log replay (with
btrfs_add_link()), where we want the mtime and ctime to be the values that
were in place when the inode was logged.

This was found with generic/547 using LOAD_FACTOR=20 and TIME_FACTOR=20,
where due to large log trees we have longer log replay times and fssum
could detect a mismatch of the mtime and ctime of a directory.

Fix this by skipping the mtime and ctime update at __btrfs_unlink_inode()
if we are in log replay context (just like btrfs_add_link()).

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index d740910e071a329a7bb010d9281332b0e643f491..9e4aec7330cb612711c5840cc35e502a7f993bcc 100644 (file)
@@ -4189,6 +4189,23 @@ int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+static void update_time_after_link_or_unlink(struct btrfs_inode *dir)
+{
+       struct timespec64 now;
+
+       /*
+        * If we are replaying a log tree, we do not want to update the mtime
+        * and ctime of the parent directory with the current time, since the
+        * log replay procedure is responsible for setting them to their correct
+        * values (the ones it had when the fsync was done).
+        */
+       if (test_bit(BTRFS_FS_LOG_RECOVERING, &dir->root->fs_info->flags))
+               return;
+
+       now = inode_set_ctime_current(&dir->vfs_inode);
+       inode_set_mtime_to_ts(&dir->vfs_inode, now);
+}
+
 /*
  * unlink helper that gets used here in inode.c and in the tree logging
  * recovery code.  It remove a link in a directory with a given name, and
@@ -4289,7 +4306,7 @@ skip_backref:
        inode_inc_iversion(&inode->vfs_inode);
        inode_set_ctime_current(&inode->vfs_inode);
        inode_inc_iversion(&dir->vfs_inode);
-       inode_set_mtime_to_ts(&dir->vfs_inode, inode_set_ctime_current(&dir->vfs_inode));
+       update_time_after_link_or_unlink(dir);
 
        return btrfs_update_inode(trans, dir);
 }
@@ -6683,15 +6700,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
        btrfs_i_size_write(parent_inode, parent_inode->vfs_inode.i_size +
                           name->len * 2);
        inode_inc_iversion(&parent_inode->vfs_inode);
-       /*
-        * If we are replaying a log tree, we do not want to update the mtime
-        * and ctime of the parent directory with the current time, since the
-        * log replay procedure is responsible for setting them to their correct
-        * values (the ones it had when the fsync was done).
-        */
-       if (!test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags))
-               inode_set_mtime_to_ts(&parent_inode->vfs_inode,
-                                     inode_set_ctime_current(&parent_inode->vfs_inode));
+       update_time_after_link_or_unlink(parent_inode);
 
        ret = btrfs_update_inode(trans, parent_inode);
        if (ret)