diff options
Diffstat (limited to 'fs/btrfs/send.c')
| -rw-r--r-- | fs/btrfs/send.c | 53 |
1 files changed, 46 insertions, 7 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index f4ab7a9260eb..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 | ||
| @@ -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 | } |
| @@ -4536,7 +4571,6 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
| 4536 | struct btrfs_fs_info *fs_info; | 4571 | struct btrfs_fs_info *fs_info; |
| 4537 | struct btrfs_ioctl_send_args *arg = NULL; | 4572 | struct btrfs_ioctl_send_args *arg = NULL; |
| 4538 | struct btrfs_key key; | 4573 | struct btrfs_key key; |
| 4539 | struct file *filp = NULL; | ||
| 4540 | struct send_ctx *sctx = NULL; | 4574 | struct send_ctx *sctx = NULL; |
| 4541 | u32 i; | 4575 | u32 i; |
| 4542 | u64 *clone_sources_tmp = NULL; | 4576 | u64 *clone_sources_tmp = NULL; |
| @@ -4561,6 +4595,11 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
| 4561 | goto out; | 4595 | goto out; |
| 4562 | } | 4596 | } |
| 4563 | 4597 | ||
| 4598 | if (arg->flags & ~BTRFS_SEND_FLAG_NO_FILE_DATA) { | ||
| 4599 | ret = -EINVAL; | ||
| 4600 | goto out; | ||
| 4601 | } | ||
| 4602 | |||
| 4564 | sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS); | 4603 | sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS); |
| 4565 | if (!sctx) { | 4604 | if (!sctx) { |
| 4566 | ret = -ENOMEM; | 4605 | ret = -ENOMEM; |
| @@ -4572,6 +4611,8 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
| 4572 | INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS); | 4611 | INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS); |
| 4573 | INIT_LIST_HEAD(&sctx->name_cache_list); | 4612 | INIT_LIST_HEAD(&sctx->name_cache_list); |
| 4574 | 4613 | ||
| 4614 | sctx->flags = arg->flags; | ||
| 4615 | |||
| 4575 | sctx->send_filp = fget(arg->send_fd); | 4616 | sctx->send_filp = fget(arg->send_fd); |
| 4576 | if (IS_ERR(sctx->send_filp)) { | 4617 | if (IS_ERR(sctx->send_filp)) { |
| 4577 | ret = PTR_ERR(sctx->send_filp); | 4618 | ret = PTR_ERR(sctx->send_filp); |
| @@ -4673,8 +4714,6 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
| 4673 | goto out; | 4714 | goto out; |
| 4674 | 4715 | ||
| 4675 | out: | 4716 | out: |
| 4676 | if (filp) | ||
| 4677 | fput(filp); | ||
| 4678 | kfree(arg); | 4717 | kfree(arg); |
| 4679 | vfree(clone_sources_tmp); | 4718 | vfree(clone_sources_tmp); |
| 4680 | 4719 | ||
