diff options
Diffstat (limited to 'fs/btrfs/send.c')
| -rw-r--r-- | fs/btrfs/send.c | 65 |
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 | */ | ||
| 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 | } |
| @@ -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 | ||
| 4675 | out: | 4714 | out: |
| 4676 | if (filp) | ||
| 4677 | fput(filp); | ||
| 4678 | kfree(arg); | 4715 | kfree(arg); |
| 4679 | vfree(clone_sources_tmp); | 4716 | vfree(clone_sources_tmp); |
| 4680 | 4717 | ||
