OSDN Git Service

Merge tag 'for-5.8-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
[tomoyo/tomoyo-test1.git] / fs / btrfs / send.c
index 6a92ecf..d9813a5 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;
@@ -4801,17 +4806,12 @@ static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len)
        struct inode *inode;
        struct page *page;
        char *addr;
-       struct btrfs_key key;
        pgoff_t index = offset >> PAGE_SHIFT;
        pgoff_t last_index;
        unsigned pg_offset = offset_in_page(offset);
        ssize_t ret = 0;
 
-       key.objectid = sctx->cur_ino;
-       key.type = BTRFS_INODE_ITEM_KEY;
-       key.offset = 0;
-
-       inode = btrfs_iget(fs_info->sb, &key, root);
+       inode = btrfs_iget(fs_info->sb, sctx->cur_ino, root);
        if (IS_ERR(inode))
                return PTR_ERR(inode);
 
@@ -5107,6 +5107,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 +6030,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 +7083,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;
@@ -7143,11 +7204,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;
@@ -7178,11 +7236,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;