@@ -9412,6 +9412,8 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9412
9412
u64 new_idx = 0 ;
9413
9413
u64 root_objectid ;
9414
9414
int ret ;
9415
+ bool root_log_pinned = false;
9416
+ bool dest_log_pinned = false;
9415
9417
9416
9418
/* we only allow rename subvolume link between subvolumes */
9417
9419
if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest )
@@ -9464,6 +9466,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9464
9466
if (ret )
9465
9467
goto out_fail ;
9466
9468
btrfs_pin_log_trans (root );
9469
+ root_log_pinned = true;
9467
9470
}
9468
9471
9469
9472
/* And now for the dest. */
@@ -9479,6 +9482,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9479
9482
if (ret )
9480
9483
goto out_fail ;
9481
9484
btrfs_pin_log_trans (dest );
9485
+ dest_log_pinned = true;
9482
9486
}
9483
9487
9484
9488
/* Update inode version and ctime/mtime. */
@@ -9557,17 +9561,47 @@ static int btrfs_rename_exchange(struct inode *old_dir,
9557
9561
if (new_inode -> i_nlink == 1 )
9558
9562
BTRFS_I (new_inode )-> dir_index = new_idx ;
9559
9563
9560
- if (old_ino != BTRFS_FIRST_FREE_OBJECTID ) {
9564
+ if (root_log_pinned ) {
9561
9565
parent = new_dentry -> d_parent ;
9562
9566
btrfs_log_new_name (trans , old_inode , old_dir , parent );
9563
9567
btrfs_end_log_trans (root );
9568
+ root_log_pinned = false;
9564
9569
}
9565
- if (new_ino != BTRFS_FIRST_FREE_OBJECTID ) {
9570
+ if (dest_log_pinned ) {
9566
9571
parent = old_dentry -> d_parent ;
9567
9572
btrfs_log_new_name (trans , new_inode , new_dir , parent );
9568
9573
btrfs_end_log_trans (dest );
9574
+ dest_log_pinned = false;
9569
9575
}
9570
9576
out_fail :
9577
+ /*
9578
+ * If we have pinned a log and an error happened, we unpin tasks
9579
+ * trying to sync the log and force them to fallback to a transaction
9580
+ * commit if the log currently contains any of the inodes involved in
9581
+ * this rename operation (to ensure we do not persist a log with an
9582
+ * inconsistent state for any of these inodes or leading to any
9583
+ * inconsistencies when replayed). If the transaction was aborted, the
9584
+ * abortion reason is propagated to userspace when attempting to commit
9585
+ * the transaction. If the log does not contain any of these inodes, we
9586
+ * allow the tasks to sync it.
9587
+ */
9588
+ if (ret && (root_log_pinned || dest_log_pinned )) {
9589
+ if (btrfs_inode_in_log (old_dir , root -> fs_info -> generation ) ||
9590
+ btrfs_inode_in_log (new_dir , root -> fs_info -> generation ) ||
9591
+ btrfs_inode_in_log (old_inode , root -> fs_info -> generation ) ||
9592
+ (new_inode &&
9593
+ btrfs_inode_in_log (new_inode , root -> fs_info -> generation )))
9594
+ btrfs_set_log_full_commit (root -> fs_info , trans );
9595
+
9596
+ if (root_log_pinned ) {
9597
+ btrfs_end_log_trans (root );
9598
+ root_log_pinned = false;
9599
+ }
9600
+ if (dest_log_pinned ) {
9601
+ btrfs_end_log_trans (dest );
9602
+ dest_log_pinned = false;
9603
+ }
9604
+ }
9571
9605
ret = btrfs_end_transaction (trans , root );
9572
9606
out_notrans :
9573
9607
if (new_ino == BTRFS_FIRST_FREE_OBJECTID )
0 commit comments