Commit cb95e7bf authored by Mark Fasheh's avatar Mark Fasheh Committed by Josef Bacik

btrfs: add "no file data" flag to btrfs send ioctl

This patch adds the flag, BTRFS_SEND_FLAG_NO_FILE_DATA to the btrfs send
ioctl code. When this flag is set, the btrfs send code will never write file
data into the stream (thus also avoiding expensive reads of that data in the
first place). BTRFS_SEND_C_UPDATE_EXTENT commands will be sent (instead of
BTRFS_SEND_C_WRITE) with an offset, length pair indicating the extent in
question.

This patch does not affect the operation of BTRFS_SEND_C_CLONE commands -
they will continue to be sent when a search finds an appropriate extent to
clone from.
Signed-off-by: default avatarMark Fasheh <mfasheh@suse.de>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent 2f697dc6
...@@ -85,6 +85,7 @@ struct send_ctx { ...@@ -85,6 +85,7 @@ struct send_ctx {
u32 send_max_size; u32 send_max_size;
u64 total_send_size; u64 total_send_size;
u64 cmd_send_size[BTRFS_SEND_C_MAX + 1]; u64 cmd_send_size[BTRFS_SEND_C_MAX + 1];
u64 flags; /* 'flags' member of btrfs_ioctl_send_args is u64 */
struct vfsmount *mnt; struct vfsmount *mnt;
...@@ -3709,6 +3710,39 @@ verbose_printk("btrfs: send_clone offset=%llu, len=%d, clone_root=%llu, " ...@@ -3709,6 +3710,39 @@ verbose_printk("btrfs: send_clone offset=%llu, len=%d, clone_root=%llu, "
return ret; return ret;
} }
/*
* Send an update extent command to user space.
*/
static int send_update_extent(struct send_ctx *sctx,
u64 offset, u32 len)
{
int ret = 0;
struct fs_path *p;
p = fs_path_alloc(sctx);
if (!p)
return -ENOMEM;
ret = begin_cmd(sctx, BTRFS_SEND_C_UPDATE_EXTENT);
if (ret < 0)
goto out;
ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p);
if (ret < 0)
goto out;
TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p);
TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset);
TLV_PUT_U64(sctx, BTRFS_SEND_A_SIZE, len);
ret = send_cmd(sctx);
tlv_put_failure:
out:
fs_path_free(sctx, p);
return ret;
}
static int send_write_or_clone(struct send_ctx *sctx, static int send_write_or_clone(struct send_ctx *sctx,
struct btrfs_path *path, struct btrfs_path *path,
struct btrfs_key *key, struct btrfs_key *key,
...@@ -3744,7 +3778,11 @@ static int send_write_or_clone(struct send_ctx *sctx, ...@@ -3744,7 +3778,11 @@ static int send_write_or_clone(struct send_ctx *sctx,
goto out; goto out;
} }
if (!clone_root) { if (clone_root) {
ret = send_clone(sctx, offset, len, clone_root);
} else if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) {
ret = send_update_extent(sctx, offset, len);
} else {
while (pos < len) { while (pos < len) {
l = len - pos; l = len - pos;
if (l > BTRFS_SEND_READ_SIZE) if (l > BTRFS_SEND_READ_SIZE)
...@@ -3757,10 +3795,7 @@ static int send_write_or_clone(struct send_ctx *sctx, ...@@ -3757,10 +3795,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
pos += ret; pos += ret;
} }
ret = 0; ret = 0;
} else {
ret = send_clone(sctx, offset, len, clone_root);
} }
out: out:
return ret; return ret;
} }
...@@ -4560,6 +4595,11 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) ...@@ -4560,6 +4595,11 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
goto out; goto out;
} }
if (arg->flags & ~BTRFS_SEND_FLAG_NO_FILE_DATA) {
ret = -EINVAL;
goto out;
}
sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS); sctx = kzalloc(sizeof(struct send_ctx), GFP_NOFS);
if (!sctx) { if (!sctx) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -4571,6 +4611,8 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) ...@@ -4571,6 +4611,8 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS); INIT_RADIX_TREE(&sctx->name_cache, GFP_NOFS);
INIT_LIST_HEAD(&sctx->name_cache_list); INIT_LIST_HEAD(&sctx->name_cache_list);
sctx->flags = arg->flags;
sctx->send_filp = fget(arg->send_fd); sctx->send_filp = fget(arg->send_fd);
if (IS_ERR(sctx->send_filp)) { if (IS_ERR(sctx->send_filp)) {
ret = PTR_ERR(sctx->send_filp); ret = PTR_ERR(sctx->send_filp);
......
...@@ -86,6 +86,7 @@ enum btrfs_send_cmd { ...@@ -86,6 +86,7 @@ enum btrfs_send_cmd {
BTRFS_SEND_C_UTIMES, BTRFS_SEND_C_UTIMES,
BTRFS_SEND_C_END, BTRFS_SEND_C_END,
BTRFS_SEND_C_UPDATE_EXTENT,
__BTRFS_SEND_C_MAX, __BTRFS_SEND_C_MAX,
}; };
#define BTRFS_SEND_C_MAX (__BTRFS_SEND_C_MAX - 1) #define BTRFS_SEND_C_MAX (__BTRFS_SEND_C_MAX - 1)
......
...@@ -407,6 +407,13 @@ struct btrfs_ioctl_received_subvol_args { ...@@ -407,6 +407,13 @@ struct btrfs_ioctl_received_subvol_args {
__u64 reserved[16]; /* in */ __u64 reserved[16]; /* in */
}; };
/*
* Caller doesn't want file data in the send stream, even if the
* search of clone sources doesn't find an extent. UPDATE_EXTENT
* commands will be sent instead of WRITE commands.
*/
#define BTRFS_SEND_FLAG_NO_FILE_DATA 0x1
struct btrfs_ioctl_send_args { struct btrfs_ioctl_send_args {
__s64 send_fd; /* in */ __s64 send_fd; /* in */
__u64 clone_sources_count; /* in */ __u64 clone_sources_count; /* in */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment