aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 54454542ad40..f7a8b861058b 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -85,6 +85,7 @@ struct send_ctx {
85 u32 send_max_size; 85 u32 send_max_size;
86 u64 total_send_size; 86 u64 total_send_size;
87 u64 cmd_send_size[BTRFS_SEND_C_MAX + 1]; 87 u64 cmd_send_size[BTRFS_SEND_C_MAX + 1];
88 u64 flags; /* 'flags' member of btrfs_ioctl_send_args is u64 */
88 89
89 struct vfsmount *mnt; 90 struct vfsmount *mnt;
90 91
@@ -1814,8 +1815,10 @@ static int name_cache_insert(struct send_ctx *sctx,
1814 (unsigned long)nce->ino); 1815 (unsigned long)nce->ino);
1815 if (!nce_head) { 1816 if (!nce_head) {
1816 nce_head = kmalloc(sizeof(*nce_head), GFP_NOFS); 1817 nce_head = kmalloc(sizeof(*nce_head), GFP_NOFS);
1817 if (!nce_head) 1818 if (!nce_head) {
1819 kfree(nce);
1818 return -ENOMEM; 1820 return -ENOMEM;
1821 }
1819 INIT_LIST_HEAD(nce_head); 1822 INIT_LIST_HEAD(nce_head);
1820 1823
1821 ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head); 1824 ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
@@ -3707,6 +3710,39 @@ out:
3707 return ret; 3710 return ret;
3708} 3711}
3709 3712
3713/*
3714 * Send an update extent command to user space.
3715 */
3716static int send_update_extent(struct send_ctx *sctx,
3717 u64 offset, u32 len)
3718{
3719 int ret = 0;
3720 struct fs_path *p;
3721
3722 p = fs_path_alloc(sctx);
3723 if (!p)
3724 return -ENOMEM;
3725
3726 ret = begin_cmd(sctx, BTRFS_SEND_C_UPDATE_EXTENT);
3727 if (ret < 0)
3728 goto out;
3729
3730 ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p);
3731 if (ret < 0)
3732 goto out;
3733
3734 TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p);
3735 TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset);
3736 TLV_PUT_U64(sctx, BTRFS_SEND_A_SIZE, len);
3737
3738 ret = send_cmd(sctx);
3739
3740tlv_put_failure:
3741out:
3742 fs_path_free(sctx, p);
3743 return ret;
3744}
3745
3710static int send_write_or_clone(struct send_ctx *sctx, 3746static int send_write_or_clone(struct send_ctx *sctx,
3711 struct btrfs_path *path, 3747 struct btrfs_path *path,
3712 struct btrfs_key *key, 3748 struct btrfs_key *key,
@@ -3742,7 +3778,11 @@ static int send_write_or_clone(struct send_ctx *sctx,
3742 goto out; 3778 goto out;
3743 } 3779 }
3744 3780
3745 if (!clone_root) { 3781 if (clone_root) {
3782 ret = send_clone(sctx, offset, len, clone_root);
3783 } else if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) {
3784 ret = send_update_extent(sctx, offset, len);
3785 } else {
3746 while (pos < len) { 3786 while (pos < len) {
3747 l = len - pos; 3787 l = len - pos;
3748 if (l > BTRFS_SEND_READ_SIZE) 3788 if (l > BTRFS_SEND_READ_SIZE)
@@ -3755,10 +3795,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
3755 pos += ret; 3795 pos += ret;
3756 } 3796 }
3757 ret = 0; 3797 ret = 0;
3758 } else {
3759 ret = send_clone(sctx, offset, len, clone_root);
3760 } 3798 }
3761
3762out: 3799out:
3763 return ret; 3800 return ret;
3764} 3801}
@@ -4534,7 +4571,6 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4534 struct btrfs_fs_info *fs_info; 4571 struct btrfs_fs_info *fs_info;
4535 struct btrfs_ioctl_send_args *arg = NULL; 4572 struct btrfs_ioctl_send_args *arg = NULL;
4536 struct btrfs_key key; 4573 struct btrfs_key key;
4537 struct file *filp = NULL;
4538 struct send_ctx *sctx = NULL; 4574 struct send_ctx *sctx = NULL;
4539 u32 i; 4575 u32 i;
4540 u64 *clone_sources_tmp = NULL; 4576 u64 *clone_sources_tmp = NULL;
@@ -4542,7 +4578,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4542 if (!capable(CAP_SYS_ADMIN)) 4578 if (!capable(CAP_SYS_ADMIN))
4543 return -EPERM; 4579 return -EPERM;
4544 4580
4545 send_root = BTRFS_I(fdentry(mnt_file)->d_inode)->root; 4581 send_root = BTRFS_I(file_inode(mnt_file))->root;
4546 fs_info = send_root->fs_info; 4582 fs_info = send_root->fs_info;
4547 4583
4548 arg = memdup_user(arg_, sizeof(*arg)); 4584 arg = memdup_user(arg_, sizeof(*arg));
@@ -4559,6 +4595,11 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4559 goto out; 4595 goto out;
4560 } 4596 }
4561 4597
4598 if (arg->flags & ~BTRFS_SEND_FLAG_NO_FILE_DATA) {
4599 ret = -EINVAL;
4600 goto out;
4601 }
4602
4562 sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS); 4603 sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS);
4563 if (!sctx) { 4604 if (!sctx) {
4564 ret = -ENOMEM; 4605 ret = -ENOMEM;
@@ -4570,6 +4611,8 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4570 INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS); 4611 INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS);
4571 INIT_LIST_HEAD(&sctx->name_cache_list); 4612 INIT_LIST_HEAD(&sctx->name_cache_list);
4572 4613
4614 sctx->flags = arg->flags;
4615
4573 sctx->send_filp = fget(arg->send_fd); 4616 sctx->send_filp = fget(arg->send_fd);
4574 if (IS_ERR(sctx->send_filp)) { 4617 if (IS_ERR(sctx->send_filp)) {
4575 ret = PTR_ERR(sctx->send_filp); 4618 ret = PTR_ERR(sctx->send_filp);
@@ -4671,8 +4714,6 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4671 goto out; 4714 goto out;
4672 4715
4673out: 4716out:
4674 if (filp)
4675 fput(filp);
4676 kfree(arg); 4717 kfree(arg);
4677 vfree(clone_sources_tmp); 4718 vfree(clone_sources_tmp);
4678 4719