Skip to content

Commit 5338e43

Browse files
fdmananakdave
authored andcommitted
Btrfs: fix wrong ctime and mtime of a directory after log replay
When replaying a log that contains a new file or directory name that needs to be added to its parent directory, we end up updating the mtime and the ctime of the parent directory to the current time after we have set their values to the correct ones (set at fsync time), efectivelly losing them. Sample reproducer: $ mkfs.btrfs -f /dev/sdb $ mount /dev/sdb /mnt $ mkdir /mnt/dir $ touch /mnt/dir/file # fsync of the directory is optional, not needed $ xfs_io -c fsync /mnt/dir $ xfs_io -c fsync /mnt/dir/file $ stat -c %Y /mnt/dir 1557856079 <power failure> $ sleep 3 $ mount /dev/sdb /mnt $ stat -c %Y /mnt/dir 1557856082 --> should have been 1557856079, the mtime is updated to the current time when replaying the log Fix this by not updating the mtime and ctime to the current time at btrfs_add_link() when we are replaying a log tree. This could be triggered by my recent fsync fuzz tester for fstests, for which an fstests patch exists titled "fstests: generic, fsync fuzz tester with fsstress". Fixes: e02119d ("Btrfs: Add a write ahead tree log to optimize synchronous operations") CC: [email protected] # 4.4+ Reviewed-by: Nikolay Borisov <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 60d9f50 commit 5338e43

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

fs/btrfs/inode.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6433,8 +6433,18 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
64336433
btrfs_i_size_write(parent_inode, parent_inode->vfs_inode.i_size +
64346434
name_len * 2);
64356435
inode_inc_iversion(&parent_inode->vfs_inode);
6436-
parent_inode->vfs_inode.i_mtime = parent_inode->vfs_inode.i_ctime =
6437-
current_time(&parent_inode->vfs_inode);
6436+
/*
6437+
* If we are replaying a log tree, we do not want to update the mtime
6438+
* and ctime of the parent directory with the current time, since the
6439+
* log replay procedure is responsible for setting them to their correct
6440+
* values (the ones it had when the fsync was done).
6441+
*/
6442+
if (!test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags)) {
6443+
struct timespec64 now = current_time(&parent_inode->vfs_inode);
6444+
6445+
parent_inode->vfs_inode.i_mtime = now;
6446+
parent_inode->vfs_inode.i_ctime = now;
6447+
}
64386448
ret = btrfs_update_inode(trans, root, &parent_inode->vfs_inode);
64396449
if (ret)
64406450
btrfs_abort_transaction(trans, ret);

0 commit comments

Comments
 (0)