btrfs: simplify root lookup by id
[linux-2.6-block.git] / fs / btrfs / send.c
index c5f41bd86765f4452408e2e6b634dd02a2de3dd1..3ddd3b9778c755a363bf497b35060c2da1b41303 100644 (file)
@@ -23,6 +23,7 @@
 #include "btrfs_inode.h"
 #include "transaction.h"
 #include "compression.h"
+#include "xattr.h"
 
 /*
  * Maximum number of references an extent can have in order for us to attempt to
@@ -4545,6 +4546,10 @@ static int __process_new_xattr(int num, struct btrfs_key *di_key,
        struct fs_path *p;
        struct posix_acl_xattr_header dummy_acl;
 
+       /* Capabilities are emitted by finish_inode_if_needed */
+       if (!strncmp(name, XATTR_NAME_CAPS, name_len))
+               return 0;
+
        p = fs_path_alloc();
        if (!p)
                return -ENOMEM;
@@ -5107,6 +5112,64 @@ static int send_extent_data(struct send_ctx *sctx,
        return 0;
 }
 
+/*
+ * Search for a capability xattr related to sctx->cur_ino. If the capability is
+ * found, call send_set_xattr function to emit it.
+ *
+ * Return 0 if there isn't a capability, or when the capability was emitted
+ * successfully, or < 0 if an error occurred.
+ */
+static int send_capabilities(struct send_ctx *sctx)
+{
+       struct fs_path *fspath = NULL;
+       struct btrfs_path *path;
+       struct btrfs_dir_item *di;
+       struct extent_buffer *leaf;
+       unsigned long data_ptr;
+       char *buf = NULL;
+       int buf_len;
+       int ret = 0;
+
+       path = alloc_path_for_send();
+       if (!path)
+               return -ENOMEM;
+
+       di = btrfs_lookup_xattr(NULL, sctx->send_root, path, sctx->cur_ino,
+                               XATTR_NAME_CAPS, strlen(XATTR_NAME_CAPS), 0);
+       if (!di) {
+               /* There is no xattr for this inode */
+               goto out;
+       } else if (IS_ERR(di)) {
+               ret = PTR_ERR(di);
+               goto out;
+       }
+
+       leaf = path->nodes[0];
+       buf_len = btrfs_dir_data_len(leaf, di);
+
+       fspath = fs_path_alloc();
+       buf = kmalloc(buf_len, GFP_KERNEL);
+       if (!fspath || !buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, fspath);
+       if (ret < 0)
+               goto out;
+
+       data_ptr = (unsigned long)(di + 1) + btrfs_dir_name_len(leaf, di);
+       read_extent_buffer(leaf, buf, data_ptr, buf_len);
+
+       ret = send_set_xattr(sctx, fspath, XATTR_NAME_CAPS,
+                       strlen(XATTR_NAME_CAPS), buf, buf_len);
+out:
+       kfree(buf);
+       fs_path_free(fspath);
+       btrfs_free_path(path);
+       return ret;
+}
+
 static int clone_range(struct send_ctx *sctx,
                       struct clone_root *clone_root,
                       const u64 disk_byte,
@@ -5972,6 +6035,10 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
                        goto out;
        }
 
+       ret = send_capabilities(sctx);
+       if (ret < 0)
+               goto out;
+
        /*
         * If other directory inodes depended on our current directory
         * inode's move/rename, now do their move/rename operations.
@@ -7021,7 +7088,6 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
        struct btrfs_root *send_root = BTRFS_I(file_inode(mnt_file))->root;
        struct btrfs_fs_info *fs_info = send_root->fs_info;
        struct btrfs_root *clone_root;
-       struct btrfs_key key;
        struct send_ctx *sctx = NULL;
        u32 i;
        u64 *clone_sources_tmp = NULL;
@@ -7150,11 +7216,8 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
                }
 
                for (i = 0; i < arg->clone_sources_count; i++) {
-                       key.objectid = clone_sources_tmp[i];
-                       key.type = BTRFS_ROOT_ITEM_KEY;
-                       key.offset = (u64)-1;
-
-                       clone_root = btrfs_get_fs_root(fs_info, &key, true);
+                       clone_root = btrfs_get_fs_root(fs_info,
+                                               clone_sources_tmp[i], true);
                        if (IS_ERR(clone_root)) {
                                ret = PTR_ERR(clone_root);
                                goto out;
@@ -7185,11 +7248,8 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
        }
 
        if (arg->parent_root) {
-               key.objectid = arg->parent_root;
-               key.type = BTRFS_ROOT_ITEM_KEY;
-               key.offset = (u64)-1;
-
-               sctx->parent_root = btrfs_get_fs_root(fs_info, &key, true);
+               sctx->parent_root = btrfs_get_fs_root(fs_info, arg->parent_root,
+                                                     true);
                if (IS_ERR(sctx->parent_root)) {
                        ret = PTR_ERR(sctx->parent_root);
                        goto out;