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.c65
1 files changed, 51 insertions, 14 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 321b7fb4e441..c85e7c6b4598 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
@@ -3709,6 +3710,39 @@ out:
3709 return ret; 3710 return ret;
3710} 3711}
3711 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
3712static int send_write_or_clone(struct send_ctx *sctx, 3746static int send_write_or_clone(struct send_ctx *sctx,
3713 struct btrfs_path *path, 3747 struct btrfs_path *path,
3714 struct btrfs_key *key, 3748 struct btrfs_key *key,
@@ -3744,7 +3778,11 @@ static int send_write_or_clone(struct send_ctx *sctx,
3744 goto out; 3778 goto out;
3745 } 3779 }
3746 3780
3747 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 {
3748 while (pos < len) { 3786 while (pos < len) {
3749 l = len - pos; 3787 l = len - pos;
3750 if (l > BTRFS_SEND_READ_SIZE) 3788 if (l > BTRFS_SEND_READ_SIZE)
@@ -3757,10 +3795,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
3757 pos += ret; 3795 pos += ret;
3758 } 3796 }
3759 ret = 0; 3797 ret = 0;
3760 } else {
3761 ret = send_clone(sctx, offset, len, clone_root);
3762 } 3798 }
3763
3764out: 3799out:
3765 return ret; 3800 return ret;
3766} 3801}
@@ -3910,12 +3945,10 @@ static int is_extent_unchanged(struct send_ctx *sctx,
3910 found_key.type != key.type) { 3945 found_key.type != key.type) {
3911 key.offset += right_len; 3946 key.offset += right_len;
3912 break; 3947 break;
3913 } else { 3948 }
3914 if (found_key.offset != key.offset + right_len) { 3949 if (found_key.offset != key.offset + right_len) {
3915 /* Should really not happen */ 3950 ret = 0;
3916 ret = -EIO; 3951 goto out;
3917 goto out;
3918 }
3919 } 3952 }
3920 key = found_key; 3953 key = found_key;
3921 } 3954 }
@@ -4536,7 +4569,6 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4536 struct btrfs_fs_info *fs_info; 4569 struct btrfs_fs_info *fs_info;
4537 struct btrfs_ioctl_send_args *arg = NULL; 4570 struct btrfs_ioctl_send_args *arg = NULL;
4538 struct btrfs_key key; 4571 struct btrfs_key key;
4539 struct file *filp = NULL;
4540 struct send_ctx *sctx = NULL; 4572 struct send_ctx *sctx = NULL;
4541 u32 i; 4573 u32 i;
4542 u64 *clone_sources_tmp = NULL; 4574 u64 *clone_sources_tmp = NULL;
@@ -4544,7 +4576,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4544 if (!capable(CAP_SYS_ADMIN)) 4576 if (!capable(CAP_SYS_ADMIN))
4545 return -EPERM; 4577 return -EPERM;
4546 4578
4547 send_root = BTRFS_I(fdentry(mnt_file)->d_inode)->root; 4579 send_root = BTRFS_I(file_inode(mnt_file))->root;
4548 fs_info = send_root->fs_info; 4580 fs_info = send_root->fs_info;
4549 4581
4550 arg = memdup_user(arg_, sizeof(*arg)); 4582 arg = memdup_user(arg_, sizeof(*arg));
@@ -4561,6 +4593,11 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4561 goto out; 4593 goto out;
4562 } 4594 }
4563 4595
4596 if (arg->flags & ~BTRFS_SEND_FLAG_NO_FILE_DATA) {
4597 ret = -EINVAL;
4598 goto out;
4599 }
4600
4564 sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS); 4601 sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS);
4565 if (!sctx) { 4602 if (!sctx) {
4566 ret = -ENOMEM; 4603 ret = -ENOMEM;
@@ -4572,6 +4609,8 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4572 INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS); 4609 INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS);
4573 INIT_LIST_HEAD(&sctx->name_cache_list); 4610 INIT_LIST_HEAD(&sctx->name_cache_list);
4574 4611
4612 sctx->flags = arg->flags;
4613
4575 sctx->send_filp = fget(arg->send_fd); 4614 sctx->send_filp = fget(arg->send_fd);
4576 if (IS_ERR(sctx->send_filp)) { 4615 if (IS_ERR(sctx->send_filp)) {
4577 ret = PTR_ERR(sctx->send_filp); 4616 ret = PTR_ERR(sctx->send_filp);
@@ -4673,8 +4712,6 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
4673 goto out; 4712 goto out;
4674 4713
4675out: 4714out:
4676 if (filp)
4677 fput(filp);
4678 kfree(arg); 4715 kfree(arg);
4679 vfree(clone_sources_tmp); 4716 vfree(clone_sources_tmp);
4680 4717