Skip to content

Commit 376e5a5

Browse files
committed
Btrfs: pin logs earlier when doing a rename exchange operation
The btrfs_rename_exchange() started as a copy-paste from btrfs_rename(), which had a race fixed by my previous patch titled "Btrfs: pin log earlier when renaming", and so it suffers from the same problem. We pin the logs of the affected roots after we insert the new inode references, leaving a time window where concurrent tasks logging the inodes can end up logging both the new and old references, resulting in log trees that when replayed can turn the metadata into inconsistent states. This behaviour was added to btrfs_rename() in 2009 without any explanation about why not pinning the logs earlier, just leaving a comment about the posibility for the race. As of today it's perfectly safe and sane to pin the logs before we start doing any of the steps involved in the rename operation. Signed-off-by: Filipe Manana <[email protected]>
1 parent 86e8aa0 commit 376e5a5

File tree

1 file changed

+4
-4
lines changed

1 file changed

+4
-4
lines changed

fs/btrfs/inode.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9458,31 +9458,31 @@ static int btrfs_rename_exchange(struct inode *old_dir,
94589458
/* force full log commit if subvolume involved. */
94599459
btrfs_set_log_full_commit(root->fs_info, trans);
94609460
} else {
9461+
btrfs_pin_log_trans(root);
9462+
root_log_pinned = true;
94619463
ret = btrfs_insert_inode_ref(trans, dest,
94629464
new_dentry->d_name.name,
94639465
new_dentry->d_name.len,
94649466
old_ino,
94659467
btrfs_ino(new_dir), old_idx);
94669468
if (ret)
94679469
goto out_fail;
9468-
btrfs_pin_log_trans(root);
9469-
root_log_pinned = true;
94709470
}
94719471

94729472
/* And now for the dest. */
94739473
if (new_ino == BTRFS_FIRST_FREE_OBJECTID) {
94749474
/* force full log commit if subvolume involved. */
94759475
btrfs_set_log_full_commit(dest->fs_info, trans);
94769476
} else {
9477+
btrfs_pin_log_trans(dest);
9478+
dest_log_pinned = true;
94779479
ret = btrfs_insert_inode_ref(trans, root,
94789480
old_dentry->d_name.name,
94799481
old_dentry->d_name.len,
94809482
new_ino,
94819483
btrfs_ino(old_dir), new_idx);
94829484
if (ret)
94839485
goto out_fail;
9484-
btrfs_pin_log_trans(dest);
9485-
dest_log_pinned = true;
94869486
}
94879487

94889488
/* Update inode version and ctime/mtime. */

0 commit comments

Comments
 (0)