Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[firefly-linux-kernel-4.4.55.git] / fs / btrfs / ioctl.c
index a21a4ac537b768842c3ce150428c23621e63c688..0d321c23069a0aa9ea1aeac570bdf837cf208d24 100644 (file)
@@ -643,7 +643,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
                return -EINVAL;
 
        atomic_inc(&root->will_be_snapshoted);
-       smp_mb__after_atomic_inc();
+       smp_mb__after_atomic();
        btrfs_wait_nocow_write(root);
 
        ret = btrfs_start_delalloc_inodes(root, 0);
@@ -712,6 +712,35 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
        if (ret)
                goto fail;
 
+       /*
+        * If orphan cleanup did remove any orphans, it means the tree was
+        * modified and therefore the commit root is not the same as the
+        * current root anymore. This is a problem, because send uses the
+        * commit root and therefore can see inode items that don't exist
+        * in the current root anymore, and for example make calls to
+        * btrfs_iget, which will do tree lookups based on the current root
+        * and not on the commit root. Those lookups will fail, returning a
+        * -ESTALE error, and making send fail with that error. So make sure
+        * a send does not see any orphans we have just removed, and that it
+        * will see the same inodes regardless of whether a transaction
+        * commit happened before it started (meaning that the commit root
+        * will be the same as the current root) or not.
+        */
+       if (readonly && pending_snapshot->snap->node !=
+           pending_snapshot->snap->commit_root) {
+               trans = btrfs_join_transaction(pending_snapshot->snap);
+               if (IS_ERR(trans) && PTR_ERR(trans) != -ENOENT) {
+                       ret = PTR_ERR(trans);
+                       goto fail;
+               }
+               if (!IS_ERR(trans)) {
+                       ret = btrfs_commit_transaction(trans,
+                                                      pending_snapshot->snap);
+                       if (ret)
+                               goto fail;
+               }
+       }
+
        inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
        if (IS_ERR(inode)) {
                ret = PTR_ERR(inode);
@@ -1503,11 +1532,12 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        sizestr = vol_args->name;
        devstr = strchr(sizestr, ':');
        if (devstr) {
-               char *end;
                sizestr = devstr + 1;
                *devstr = '\0';
                devstr = vol_args->name;
-               devid = simple_strtoull(devstr, &end, 10);
+               ret = kstrtoull(devstr, 10, &devid);
+               if (ret)
+                       goto out_free;
                if (!devid) {
                        ret = -EINVAL;
                        goto out_free;
@@ -1563,7 +1593,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                new_size = old_size - new_size;
        } else if (mod > 0) {
                if (new_size > ULLONG_MAX - old_size) {
-                       ret = -EINVAL;
+                       ret = -ERANGE;
                        goto out_free;
                }
                new_size = old_size + new_size;
@@ -1927,7 +1957,8 @@ static noinline int copy_to_sk(struct btrfs_root *root,
                               struct btrfs_path *path,
                               struct btrfs_key *key,
                               struct btrfs_ioctl_search_key *sk,
-                              char *buf,
+                              size_t *buf_size,
+                              char __user *ubuf,
                               unsigned long *sk_offset,
                               int *num_found)
 {
@@ -1959,13 +1990,25 @@ static noinline int copy_to_sk(struct btrfs_root *root,
                if (!key_in_sk(key, sk))
                        continue;
 
-               if (sizeof(sh) + item_len > BTRFS_SEARCH_ARGS_BUFSIZE)
+               if (sizeof(sh) + item_len > *buf_size) {
+                       if (*num_found) {
+                               ret = 1;
+                               goto out;
+                       }
+
+                       /*
+                        * return one empty item back for v1, which does not
+                        * handle -EOVERFLOW
+                        */
+
+                       *buf_size = sizeof(sh) + item_len;
                        item_len = 0;
+                       ret = -EOVERFLOW;
+               }
 
-               if (sizeof(sh) + item_len + *sk_offset >
-                   BTRFS_SEARCH_ARGS_BUFSIZE) {
+               if (sizeof(sh) + item_len + *sk_offset > *buf_size) {
                        ret = 1;
-                       goto overflow;
+                       goto out;
                }
 
                sh.objectid = key->objectid;
@@ -1975,20 +2018,33 @@ static noinline int copy_to_sk(struct btrfs_root *root,
                sh.transid = found_transid;
 
                /* copy search result header */
-               memcpy(buf + *sk_offset, &sh, sizeof(sh));
+               if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
                *sk_offset += sizeof(sh);
 
                if (item_len) {
-                       char *p = buf + *sk_offset;
+                       char __user *up = ubuf + *sk_offset;
                        /* copy the item */
-                       read_extent_buffer(leaf, p,
-                                          item_off, item_len);
+                       if (read_extent_buffer_to_user(leaf, up,
+                                                      item_off, item_len)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+
                        *sk_offset += item_len;
                }
                (*num_found)++;
 
-               if (*num_found >= sk->nr_items)
-                       break;
+               if (ret) /* -EOVERFLOW from above */
+                       goto out;
+
+               if (*num_found >= sk->nr_items) {
+                       ret = 1;
+                       goto out;
+               }
        }
 advance_key:
        ret = 0;
@@ -2003,22 +2059,37 @@ advance_key:
                key->objectid++;
        } else
                ret = 1;
-overflow:
+out:
+       /*
+        *  0: all items from this leaf copied, continue with next
+        *  1: * more items can be copied, but unused buffer is too small
+        *     * all items were found
+        *     Either way, it will stops the loop which iterates to the next
+        *     leaf
+        *  -EOVERFLOW: item was to large for buffer
+        *  -EFAULT: could not copy extent buffer back to userspace
+        */
        return ret;
 }
 
 static noinline int search_ioctl(struct inode *inode,
-                                struct btrfs_ioctl_search_args *args)
+                                struct btrfs_ioctl_search_key *sk,
+                                size_t *buf_size,
+                                char __user *ubuf)
 {
        struct btrfs_root *root;
        struct btrfs_key key;
        struct btrfs_path *path;
-       struct btrfs_ioctl_search_key *sk = &args->key;
        struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
        int ret;
        int num_found = 0;
        unsigned long sk_offset = 0;
 
+       if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) {
+               *buf_size = sizeof(struct btrfs_ioctl_search_header);
+               return -EOVERFLOW;
+       }
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -2052,14 +2123,15 @@ static noinline int search_ioctl(struct inode *inode,
                                ret = 0;
                        goto err;
                }
-               ret = copy_to_sk(root, path, &key, sk, args->buf,
+               ret = copy_to_sk(root, path, &key, sk, buf_size, ubuf,
                                 &sk_offset, &num_found);
                btrfs_release_path(path);
-               if (ret || num_found >= sk->nr_items)
+               if (ret)
                        break;
 
        }
-       ret = 0;
+       if (ret > 0)
+               ret = 0;
 err:
        sk->nr_items = num_found;
        btrfs_free_path(path);
@@ -2069,22 +2141,73 @@ err:
 static noinline int btrfs_ioctl_tree_search(struct file *file,
                                           void __user *argp)
 {
-        struct btrfs_ioctl_search_args *args;
-        struct inode *inode;
-        int ret;
+       struct btrfs_ioctl_search_args __user *uargs;
+       struct btrfs_ioctl_search_key sk;
+       struct inode *inode;
+       int ret;
+       size_t buf_size;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       args = memdup_user(argp, sizeof(*args));
-       if (IS_ERR(args))
-               return PTR_ERR(args);
+       uargs = (struct btrfs_ioctl_search_args __user *)argp;
+
+       if (copy_from_user(&sk, &uargs->key, sizeof(sk)))
+               return -EFAULT;
+
+       buf_size = sizeof(uargs->buf);
 
        inode = file_inode(file);
-       ret = search_ioctl(inode, args);
-       if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
+       ret = search_ioctl(inode, &sk, &buf_size, uargs->buf);
+
+       /*
+        * In the origin implementation an overflow is handled by returning a
+        * search header with a len of zero, so reset ret.
+        */
+       if (ret == -EOVERFLOW)
+               ret = 0;
+
+       if (ret == 0 && copy_to_user(&uargs->key, &sk, sizeof(sk)))
                ret = -EFAULT;
-       kfree(args);
+       return ret;
+}
+
+static noinline int btrfs_ioctl_tree_search_v2(struct file *file,
+                                              void __user *argp)
+{
+       struct btrfs_ioctl_search_args_v2 __user *uarg;
+       struct btrfs_ioctl_search_args_v2 args;
+       struct inode *inode;
+       int ret;
+       size_t buf_size;
+       const size_t buf_limit = 16 * 1024 * 1024;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /* copy search header and buffer size */
+       uarg = (struct btrfs_ioctl_search_args_v2 __user *)argp;
+       if (copy_from_user(&args, uarg, sizeof(args)))
+               return -EFAULT;
+
+       buf_size = args.buf_size;
+
+       if (buf_size < sizeof(struct btrfs_ioctl_search_header))
+               return -EOVERFLOW;
+
+       /* limit result size to 16MB */
+       if (buf_size > buf_limit)
+               buf_size = buf_limit;
+
+       inode = file_inode(file);
+       ret = search_ioctl(inode, &args.key, &buf_size,
+                          (char *)(&uarg->buf[0]));
+       if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key)))
+               ret = -EFAULT;
+       else if (ret == -EOVERFLOW &&
+               copy_to_user(&uarg->buf_size, &buf_size, sizeof(buf_size)))
+               ret = -EFAULT;
+
        return ret;
 }
 
@@ -2311,16 +2434,16 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
         * again is not run concurrently.
         */
        spin_lock(&dest->root_item_lock);
-       root_flags = btrfs_root_flags(&root->root_item);
-       if (root->send_in_progress == 0) {
-               btrfs_set_root_flags(&root->root_item,
+       root_flags = btrfs_root_flags(&dest->root_item);
+       if (dest->send_in_progress == 0) {
+               btrfs_set_root_flags(&dest->root_item,
                                root_flags | BTRFS_ROOT_SUBVOL_DEAD);
                spin_unlock(&dest->root_item_lock);
        } else {
                spin_unlock(&dest->root_item_lock);
                btrfs_warn(root->fs_info,
                        "Attempt to delete subvolume %llu during send",
-                       root->root_key.objectid);
+                       dest->root_key.objectid);
                err = -EPERM;
                goto out_dput;
        }
@@ -2415,8 +2538,8 @@ out_up_write:
 out_unlock:
        if (err) {
                spin_lock(&dest->root_item_lock);
-               root_flags = btrfs_root_flags(&root->root_item);
-               btrfs_set_root_flags(&root->root_item,
+               root_flags = btrfs_root_flags(&dest->root_item);
+               btrfs_set_root_flags(&dest->root_item,
                                root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
                spin_unlock(&dest->root_item_lock);
        }
@@ -2699,10 +2822,15 @@ static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
                lock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
                ordered = btrfs_lookup_first_ordered_extent(inode,
                                                            off + len - 1);
-               if (!ordered &&
+               if ((!ordered ||
+                    ordered->file_offset + ordered->len <= off ||
+                    ordered->file_offset >= off + len) &&
                    !test_range_bit(&BTRFS_I(inode)->io_tree, off,
-                                   off + len - 1, EXTENT_DELALLOC, 0, NULL))
+                                   off + len - 1, EXTENT_DELALLOC, 0, NULL)) {
+                       if (ordered)
+                               btrfs_put_ordered_extent(ordered);
                        break;
+               }
                unlock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
                if (ordered)
                        btrfs_put_ordered_extent(ordered);
@@ -2977,6 +3105,91 @@ out:
        return ret;
 }
 
+static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
+                                    struct inode *inode,
+                                    u64 endoff,
+                                    const u64 destoff,
+                                    const u64 olen)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       inode_inc_iversion(inode);
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       /*
+        * We round up to the block size at eof when determining which
+        * extents to clone above, but shouldn't round up the file size.
+        */
+       if (endoff > destoff + olen)
+               endoff = destoff + olen;
+       if (endoff > inode->i_size)
+               btrfs_i_size_write(inode, endoff);
+
+       ret = btrfs_update_inode(trans, root, inode);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               btrfs_end_transaction(trans, root);
+               goto out;
+       }
+       ret = btrfs_end_transaction(trans, root);
+out:
+       return ret;
+}
+
+static void clone_update_extent_map(struct inode *inode,
+                                   const struct btrfs_trans_handle *trans,
+                                   const struct btrfs_path *path,
+                                   struct btrfs_file_extent_item *fi,
+                                   const u64 hole_offset,
+                                   const u64 hole_len)
+{
+       struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       struct extent_map *em;
+       int ret;
+
+       em = alloc_extent_map();
+       if (!em) {
+               set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                       &BTRFS_I(inode)->runtime_flags);
+               return;
+       }
+
+       if (fi) {
+               btrfs_extent_item_to_extent_map(inode, path, fi, false, em);
+               em->generation = -1;
+               if (btrfs_file_extent_type(path->nodes[0], fi) ==
+                   BTRFS_FILE_EXTENT_INLINE)
+                       set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                               &BTRFS_I(inode)->runtime_flags);
+       } else {
+               em->start = hole_offset;
+               em->len = hole_len;
+               em->ram_bytes = em->len;
+               em->orig_start = hole_offset;
+               em->block_start = EXTENT_MAP_HOLE;
+               em->block_len = 0;
+               em->orig_block_len = 0;
+               em->compress_type = BTRFS_COMPRESS_NONE;
+               em->generation = trans->transid;
+       }
+
+       while (1) {
+               write_lock(&em_tree->lock);
+               ret = add_extent_mapping(em_tree, em, 1);
+               write_unlock(&em_tree->lock);
+               if (ret != -EEXIST) {
+                       free_extent_map(em);
+                       break;
+               }
+               btrfs_drop_extent_cache(inode, em->start,
+                                       em->start + em->len - 1, 0);
+       }
+
+       if (unlikely(ret))
+               set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                       &BTRFS_I(inode)->runtime_flags);
+}
+
 /**
  * btrfs_clone() - clone a range from inode file to another
  *
@@ -2989,7 +3202,8 @@ out:
  * @destoff: Offset within @inode to start clone
  */
 static int btrfs_clone(struct inode *src, struct inode *inode,
-                      u64 off, u64 olen, u64 olen_aligned, u64 destoff)
+                      const u64 off, const u64 olen, const u64 olen_aligned,
+                      const u64 destoff)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_path *path = NULL;
@@ -3001,8 +3215,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
        int slot;
        int ret;
        int no_quota;
-       u64 len = olen_aligned;
+       const u64 len = olen_aligned;
        u64 last_disko = 0;
+       u64 last_dest_end = destoff;
 
        ret = -ENOMEM;
        buf = vmalloc(btrfs_level_size(root, 0));
@@ -3019,7 +3234,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
        /* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
-       key.offset = 0;
+       key.offset = off;
 
        while (1) {
                /*
@@ -3031,6 +3246,17 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
                                0, 0);
                if (ret < 0)
                        goto out;
+               /*
+                * First search, if no extent item that starts at offset off was
+                * found but the previous item is an extent item, it's possible
+                * it might overlap our target range, therefore process it.
+                */
+               if (key.offset == off && ret > 0 && path->slots[0] > 0) {
+                       btrfs_item_key_to_cpu(path->nodes[0], &key,
+                                             path->slots[0] - 1);
+                       if (key.type == BTRFS_EXTENT_DATA_KEY)
+                               path->slots[0]--;
+               }
 
                nritems = btrfs_header_nritems(path->nodes[0]);
 process_slot:
@@ -3059,7 +3285,7 @@ process_slot:
                        u64 disko = 0, diskl = 0;
                        u64 datao = 0, datal = 0;
                        u8 comp;
-                       u64 endoff;
+                       u64 drop_start;
 
                        extent = btrfs_item_ptr(leaf, slot,
                                                struct btrfs_file_extent_item);
@@ -3080,10 +3306,16 @@ process_slot:
                                                                    extent);
                        }
 
-                       if (key.offset + datal <= off ||
-                           key.offset >= off + len - 1) {
+                       /*
+                        * The first search might have left us at an extent
+                        * item that ends before our target range's start, can
+                        * happen if we have holes and NO_HOLES feature enabled.
+                        */
+                       if (key.offset + datal <= off) {
                                path->slots[0]++;
                                goto process_slot;
+                       } else if (key.offset >= off + len) {
+                               break;
                        }
 
                        size = btrfs_item_size_nr(leaf, slot);
@@ -3101,6 +3333,18 @@ process_slot:
                        else
                                new_key.offset = destoff;
 
+                       /*
+                        * Deal with a hole that doesn't have an extent item
+                        * that represents it (NO_HOLES feature enabled).
+                        * This hole is either in the middle of the cloning
+                        * range or at the beginning (fully overlaps it or
+                        * partially overlaps it).
+                        */
+                       if (new_key.offset != last_dest_end)
+                               drop_start = last_dest_end;
+                       else
+                               drop_start = new_key.offset;
+
                        /*
                         * 1 - adjusting old extent (we may have to split it)
                         * 1 - add new extent
@@ -3119,18 +3363,18 @@ process_slot:
                                 * | ------------- extent ------------- |
                                 */
 
-                               /* substract range b */
+                               /* subtract range b */
                                if (key.offset + datal > off + len)
                                        datal = off + len - key.offset;
 
-                               /* substract range a */
+                               /* subtract range a */
                                if (off > key.offset) {
                                        datao += off - key.offset;
                                        datal -= off - key.offset;
                                }
 
                                ret = btrfs_drop_extents(trans, root, inode,
-                                                        new_key.offset,
+                                                        drop_start,
                                                         new_key.offset + datal,
                                                         1);
                                if (ret) {
@@ -3231,7 +3475,7 @@ process_slot:
                                aligned_end = ALIGN(new_key.offset + datal,
                                                    root->sectorsize);
                                ret = btrfs_drop_extents(trans, root, inode,
-                                                        new_key.offset,
+                                                        drop_start,
                                                         aligned_end,
                                                         1);
                                if (ret) {
@@ -3264,40 +3508,69 @@ process_slot:
                                            btrfs_item_ptr_offset(leaf, slot),
                                            size);
                                inode_add_bytes(inode, datal);
+                               extent = btrfs_item_ptr(leaf, slot,
+                                               struct btrfs_file_extent_item);
                        }
 
+                       /* If we have an implicit hole (NO_HOLES feature). */
+                       if (drop_start < new_key.offset)
+                               clone_update_extent_map(inode, trans,
+                                               path, NULL, drop_start,
+                                               new_key.offset - drop_start);
+
+                       clone_update_extent_map(inode, trans, path,
+                                               extent, 0, 0);
+
                        btrfs_mark_buffer_dirty(leaf);
                        btrfs_release_path(path);
 
-                       inode_inc_iversion(inode);
-                       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-
-                       /*
-                        * we round up to the block size at eof when
-                        * determining which extents to clone above,
-                        * but shouldn't round up the file size
-                        */
-                       endoff = new_key.offset + datal;
-                       if (endoff > destoff+olen)
-                               endoff = destoff+olen;
-                       if (endoff > inode->i_size)
-                               btrfs_i_size_write(inode, endoff);
-
-                       ret = btrfs_update_inode(trans, root, inode);
-                       if (ret) {
-                               btrfs_abort_transaction(trans, root, ret);
-                               btrfs_end_transaction(trans, root);
+                       last_dest_end = new_key.offset + datal;
+                       ret = clone_finish_inode_update(trans, inode,
+                                                       last_dest_end,
+                                                       destoff, olen);
+                       if (ret)
                                goto out;
-                       }
-                       ret = btrfs_end_transaction(trans, root);
+                       if (new_key.offset + datal >= destoff + len)
+                               break;
                }
                btrfs_release_path(path);
                key.offset++;
        }
        ret = 0;
 
+       if (last_dest_end < destoff + len) {
+               /*
+                * We have an implicit hole (NO_HOLES feature is enabled) that
+                * fully or partially overlaps our cloning range at its end.
+                */
+               btrfs_release_path(path);
+
+               /*
+                * 1 - remove extent(s)
+                * 1 - inode update
+                */
+               trans = btrfs_start_transaction(root, 2);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       goto out;
+               }
+               ret = btrfs_drop_extents(trans, root, inode,
+                                        last_dest_end, destoff + len, 1);
+               if (ret) {
+                       if (ret != -EOPNOTSUPP)
+                               btrfs_abort_transaction(trans, root, ret);
+                       btrfs_end_transaction(trans, root);
+                       goto out;
+               }
+               ret = clone_finish_inode_update(trans, inode, destoff + len,
+                                               destoff, olen);
+               if (ret)
+                       goto out;
+               clone_update_extent_map(inode, trans, path, NULL, last_dest_end,
+                                       destoff + len - last_dest_end);
+       }
+
 out:
-       btrfs_release_path(path);
        btrfs_free_path(path);
        vfree(buf);
        return ret;
@@ -3409,15 +3682,41 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        goto out_unlock;
        }
 
-       /* truncate page cache pages from target inode range */
-       truncate_inode_pages_range(&inode->i_data, destoff,
-                                  PAGE_CACHE_ALIGN(destoff + len) - 1);
+       /*
+        * Lock the target range too. Right after we replace the file extent
+        * items in the fs tree (which now point to the cloned data), we might
+        * have a worker replace them with extent items relative to a write
+        * operation that was issued before this clone operation (i.e. confront
+        * with inode.c:btrfs_finish_ordered_io).
+        */
+       if (same_inode) {
+               u64 lock_start = min_t(u64, off, destoff);
+               u64 lock_len = max_t(u64, off, destoff) + len - lock_start;
 
-       lock_extent_range(src, off, len);
+               lock_extent_range(src, lock_start, lock_len);
+       } else {
+               lock_extent_range(src, off, len);
+               lock_extent_range(inode, destoff, len);
+       }
 
        ret = btrfs_clone(src, inode, off, olen, len, destoff);
 
-       unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
+       if (same_inode) {
+               u64 lock_start = min_t(u64, off, destoff);
+               u64 lock_end = max_t(u64, off, destoff) + len - 1;
+
+               unlock_extent(&BTRFS_I(src)->io_tree, lock_start, lock_end);
+       } else {
+               unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
+               unlock_extent(&BTRFS_I(inode)->io_tree, destoff,
+                             destoff + len - 1);
+       }
+       /*
+        * Truncate page cache pages so that future reads will see the cloned
+        * data immediately and not the previous data.
+        */
+       truncate_inode_pages_range(&inode->i_data, destoff,
+                                  PAGE_CACHE_ALIGN(destoff + len) - 1);
 out_unlock:
        if (!same_inode) {
                if (inode < src) {
@@ -4992,6 +5291,8 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_trans_end(file);
        case BTRFS_IOC_TREE_SEARCH:
                return btrfs_ioctl_tree_search(file, argp);
+       case BTRFS_IOC_TREE_SEARCH_V2:
+               return btrfs_ioctl_tree_search_v2(file, argp);
        case BTRFS_IOC_INO_LOOKUP:
                return btrfs_ioctl_ino_lookup(file, argp);
        case BTRFS_IOC_INO_PATHS: