aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2016-05-04 21:08:56 -0400
committerFilipe Manana <fdmanana@suse.com>2016-05-12 20:59:28 -0400
commit376e5a57bf7f1466031a957d04bf8b8f6801ee6d (patch)
treed51e2907047414f8b9798a0122e1a344b024781d /fs/btrfs
parent86e8aa0e772caba5f0e0471d5f836b2b997dcb3e (diff)
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 <fdmanana@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/inode.c8
1 files changed, 4 insertions, 4 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index c92d9b83bb38..a7db3ed6ac88 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -9458,6 +9458,8 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9458 /* force full log commit if subvolume involved. */ 9458 /* force full log commit if subvolume involved. */
9459 btrfs_set_log_full_commit(root->fs_info, trans); 9459 btrfs_set_log_full_commit(root->fs_info, trans);
9460 } else { 9460 } else {
9461 btrfs_pin_log_trans(root);
9462 root_log_pinned = true;
9461 ret = btrfs_insert_inode_ref(trans, dest, 9463 ret = btrfs_insert_inode_ref(trans, dest,
9462 new_dentry->d_name.name, 9464 new_dentry->d_name.name,
9463 new_dentry->d_name.len, 9465 new_dentry->d_name.len,
@@ -9465,8 +9467,6 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9465 btrfs_ino(new_dir), old_idx); 9467 btrfs_ino(new_dir), old_idx);
9466 if (ret) 9468 if (ret)
9467 goto out_fail; 9469 goto out_fail;
9468 btrfs_pin_log_trans(root);
9469 root_log_pinned = true;
9470 } 9470 }
9471 9471
9472 /* And now for the dest. */ 9472 /* And now for the dest. */
@@ -9474,6 +9474,8 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9474 /* force full log commit if subvolume involved. */ 9474 /* force full log commit if subvolume involved. */
9475 btrfs_set_log_full_commit(dest->fs_info, trans); 9475 btrfs_set_log_full_commit(dest->fs_info, trans);
9476 } else { 9476 } else {
9477 btrfs_pin_log_trans(dest);
9478 dest_log_pinned = true;
9477 ret = btrfs_insert_inode_ref(trans, root, 9479 ret = btrfs_insert_inode_ref(trans, root,
9478 old_dentry->d_name.name, 9480 old_dentry->d_name.name,
9479 old_dentry->d_name.len, 9481 old_dentry->d_name.len,
@@ -9481,8 +9483,6 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9481 btrfs_ino(old_dir), new_idx); 9483 btrfs_ino(old_dir), new_idx);
9482 if (ret) 9484 if (ret)
9483 goto out_fail; 9485 goto out_fail;
9484 btrfs_pin_log_trans(dest);
9485 dest_log_pinned = true;
9486 } 9486 }
9487 9487
9488 /* Update inode version and ctime/mtime. */ 9488 /* Update inode version and ctime/mtime. */