* the commit roots are read only
                 * so we always do read locks
                 */
+               if (p->need_commit_sem)
+                       down_read(&root->fs_info->commit_root_sem);
                b = root->commit_root;
                extent_buffer_get(b);
                level = btrfs_header_level(b);
+               if (p->need_commit_sem)
+                       up_read(&root->fs_info->commit_root_sem);
                if (!p->skip_locking)
                        btrfs_tree_read_lock(b);
        } else {
         *   the right if possible or go up and right.
         */
 
+       down_read(&left_root->fs_info->commit_root_sem);
        left_level = btrfs_header_level(left_root->commit_root);
        left_root_level = left_level;
        left_path->nodes[left_level] = left_root->commit_root;
        right_root_level = right_level;
        right_path->nodes[right_level] = right_root->commit_root;
        extent_buffer_get(right_path->nodes[right_level]);
+       up_read(&left_root->fs_info->commit_root_sem);
 
        if (left_level == 0)
                btrfs_item_key_to_cpu(left_path->nodes[left_level],
 
                return NULL;
        path->search_commit_root = 1;
        path->skip_locking = 1;
+       path->need_commit_sem = 1;
        return path;
 }
 
 /*
  * Helper function to retrieve some fields from an inode item.
  */
-static int get_inode_info(struct btrfs_root *root,
-                         u64 ino, u64 *size, u64 *gen,
-                         u64 *mode, u64 *uid, u64 *gid,
-                         u64 *rdev)
+static int __get_inode_info(struct btrfs_root *root, struct btrfs_path *path,
+                         u64 ino, u64 *size, u64 *gen, u64 *mode, u64 *uid,
+                         u64 *gid, u64 *rdev)
 {
        int ret;
        struct btrfs_inode_item *ii;
        struct btrfs_key key;
-       struct btrfs_path *path;
-
-       path = alloc_path_for_send();
-       if (!path)
-               return -ENOMEM;
 
        key.objectid = ino;
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-       if (ret < 0)
-               goto out;
        if (ret) {
-               ret = -ENOENT;
-               goto out;
+               if (ret > 0)
+                       ret = -ENOENT;
+               return ret;
        }
 
        ii = btrfs_item_ptr(path->nodes[0], path->slots[0],
        if (rdev)
                *rdev = btrfs_inode_rdev(path->nodes[0], ii);
 
-out:
+       return ret;
+}
+
+static int get_inode_info(struct btrfs_root *root,
+                         u64 ino, u64 *size, u64 *gen,
+                         u64 *mode, u64 *uid, u64 *gid,
+                         u64 *rdev)
+{
+       struct btrfs_path *path;
+       int ret;
+
+       path = alloc_path_for_send();
+       if (!path)
+               return -ENOMEM;
+       ret = __get_inode_info(root, path, ino, size, gen, mode, uid, gid,
+                              rdev);
        btrfs_free_path(path);
        return ret;
 }
 struct backref_ctx {
        struct send_ctx *sctx;
 
+       struct btrfs_path *path;
        /* number of total found references */
        u64 found;
 
         * There are inodes that have extents that lie behind its i_size. Don't
         * accept clones from these extents.
         */
-       ret = get_inode_info(found->root, ino, &i_size, NULL, NULL, NULL, NULL,
-                       NULL);
+       ret = __get_inode_info(found->root, bctx->path, ino, &i_size, NULL, NULL,
+                              NULL, NULL, NULL);
+       btrfs_release_path(bctx->path);
        if (ret < 0)
                return ret;
 
        if (!tmp_path)
                return -ENOMEM;
 
+       /* We only use this path under the commit sem */
+       tmp_path->need_commit_sem = 0;
+
        backref_ctx = kmalloc(sizeof(*backref_ctx), GFP_NOFS);
        if (!backref_ctx) {
                ret = -ENOMEM;
                goto out;
        }
 
+       backref_ctx->path = tmp_path;
+
        if (data_offset >= ino_size) {
                /*
                 * There may be extents that lie behind the file's size.