diff options
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r-- | fs/btrfs/send.c | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 614da0d44d56..68da757615ae 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 | */ | ||
3716 | static 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 | |||
3740 | tlv_put_failure: | ||
3741 | out: | ||
3742 | fs_path_free(sctx, p); | ||
3743 | return ret; | ||
3744 | } | ||
3745 | |||
3712 | static int send_write_or_clone(struct send_ctx *sctx, | 3746 | static 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 | |||
3764 | out: | 3799 | out: |
3765 | return ret; | 3800 | return ret; |
3766 | } | 3801 | } |
@@ -4560,6 +4595,11 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
4560 | goto out; | 4595 | goto out; |
4561 | } | 4596 | } |
4562 | 4597 | ||
4598 | if (arg->flags & ~BTRFS_SEND_FLAG_NO_FILE_DATA) { | ||
4599 | ret = -EINVAL; | ||
4600 | goto out; | ||
4601 | } | ||
4602 | |||
4563 | sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS); | 4603 | sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS); |
4564 | if (!sctx) { | 4604 | if (!sctx) { |
4565 | ret = -ENOMEM; | 4605 | ret = -ENOMEM; |
@@ -4571,6 +4611,8 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
4571 | INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS); | 4611 | INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS); |
4572 | INIT_LIST_HEAD(&sctx->name_cache_list); | 4612 | INIT_LIST_HEAD(&sctx->name_cache_list); |
4573 | 4613 | ||
4614 | sctx->flags = arg->flags; | ||
4615 | |||
4574 | sctx->send_filp = fget(arg->send_fd); | 4616 | sctx->send_filp = fget(arg->send_fd); |
4575 | if (IS_ERR(sctx->send_filp)) { | 4617 | if (IS_ERR(sctx->send_filp)) { |
4576 | ret = PTR_ERR(sctx->send_filp); | 4618 | ret = PTR_ERR(sctx->send_filp); |