u64 new_idx = 0;
        u64 root_objectid;
        int ret;
+       bool root_log_pinned = false;
+       bool dest_log_pinned = false;
 
        /* we only allow rename subvolume link between subvolumes */
        if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
                if (ret)
                        goto out_fail;
                btrfs_pin_log_trans(root);
+               root_log_pinned = true;
        }
 
        /* And now for the dest. */
                if (ret)
                        goto out_fail;
                btrfs_pin_log_trans(dest);
+               dest_log_pinned = true;
        }
 
        /* Update inode version and ctime/mtime. */
        if (new_inode->i_nlink == 1)
                BTRFS_I(new_inode)->dir_index = new_idx;
 
-       if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
+       if (root_log_pinned) {
                parent = new_dentry->d_parent;
                btrfs_log_new_name(trans, old_inode, old_dir, parent);
                btrfs_end_log_trans(root);
+               root_log_pinned = false;
        }
-       if (new_ino != BTRFS_FIRST_FREE_OBJECTID) {
+       if (dest_log_pinned) {
                parent = old_dentry->d_parent;
                btrfs_log_new_name(trans, new_inode, new_dir, parent);
                btrfs_end_log_trans(dest);
+               dest_log_pinned = false;
        }
 out_fail:
+       /*
+        * If we have pinned a log and an error happened, we unpin tasks
+        * trying to sync the log and force them to fallback to a transaction
+        * commit if the log currently contains any of the inodes involved in
+        * this rename operation (to ensure we do not persist a log with an
+        * inconsistent state for any of these inodes or leading to any
+        * inconsistencies when replayed). If the transaction was aborted, the
+        * abortion reason is propagated to userspace when attempting to commit
+        * the transaction. If the log does not contain any of these inodes, we
+        * allow the tasks to sync it.
+        */
+       if (ret && (root_log_pinned || dest_log_pinned)) {
+               if (btrfs_inode_in_log(old_dir, root->fs_info->generation) ||
+                   btrfs_inode_in_log(new_dir, root->fs_info->generation) ||
+                   btrfs_inode_in_log(old_inode, root->fs_info->generation) ||
+                   (new_inode &&
+                    btrfs_inode_in_log(new_inode, root->fs_info->generation)))
+                   btrfs_set_log_full_commit(root->fs_info, trans);
+
+               if (root_log_pinned) {
+                       btrfs_end_log_trans(root);
+                       root_log_pinned = false;
+               }
+               if (dest_log_pinned) {
+                       btrfs_end_log_trans(dest);
+                       dest_log_pinned = false;
+               }
+       }
        ret = btrfs_end_transaction(trans, root);
 out_notrans:
        if (new_ino == BTRFS_FIRST_FREE_OBJECTID)