diff options
author | Stefan Behrens <sbehrens@giantdisaster.de> | 2013-04-10 19:10:56 +0200 |
---|---|---|
committer | David Sterba <dsterba@suse.cz> | 2013-08-09 14:32:29 +0200 |
commit | 6315410f25497f5700396f487c5fc2ab6762ae56 (patch) | |
tree | 7b7abb6327ade7e4570b95fc37580cdbe7ac046c /cmds-send.c | |
parent | cc94701a735f186295be2617c573ab8f3dc1817d (diff) | |
download | btrfs-progs-6315410f25497f5700396f487c5fc2ab6762ae56.tar.gz btrfs-progs-6315410f25497f5700396f487c5fc2ab6762ae56.tar.bz2 btrfs-progs-6315410f25497f5700396f487c5fc2ab6762ae56.zip |
Btrfs-progs: add send option for using new end-cmd semantic
This commit adds a command line option to enable sending streams
which make use of the new end-cmd semantic if multiple snapshots are
sent back-to-back. The goal is to use the <end cmd> as an indication
to stop reading the input stream. So far, the receiver could only
use EOF to recognize the end.
If the new command line option '-e' is set, this commit requires a
kernel which is able to support the new flags in the send ioctl. New
bits in the flags of the send ioctl will be set which cause EINVAL
on old kernels. However, if the option '-e' is not set, it works
with old and new kernels without any errors or any changed behavior.
This used to be the encoding (with 2 snapshots in this example):
<stream header> + <sequence of commands> + <end cmd> +
<stream header> + <sequence of commands> + <end cmd> + EOF
The new format (if the two new flags are used) is this one:
<stream header> + <sequence of commands> +
<sequence of commands> + <end cmd>
Note that the currently existing receivers treat <end cmd> only as
an indication that a new <stream header> is following. This means,
you can just skip the sequence <end cmd> <stream header> without
loosing compatibility. As long as an EOF is following, the currently
existing receivers handle the new format (if the two new flags are
used) exactly as the old one.
Also note that the kernel interface was changed in a way that is
backward compatible to old btrfs-progs tools. You set one or two bits
in the flags field of the ioctl to enable the new behavior. Old tools
set these flags to zero, thus getting exactly the same as they got
with older kernels. And this is exactly what happens if the new '-e'
option is not set, the new bits in the flags are not set and thus
old kernels and new kernels are both supported.
So what is the benefit of this change? The goal is to be able to use
a single stream (one TCP connection) to multiplex a request/response
handshake plus Btrfs send streams, all in the same stream. In this
case you cannot evaluate an EOF condition as an end of the Btrfs send
stream. You need something else, and the <end cmd> is just perfect
for this purpose.
Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de>
Signed-off-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'cmds-send.c')
-rw-r--r-- | cmds-send.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/cmds-send.c b/cmds-send.c index 0057e6b8..72804a9a 100644 --- a/cmds-send.c +++ b/cmds-send.c @@ -244,7 +244,8 @@ out: return ERR_PTR(ret); } -static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root_id) +static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root_id, + int is_first_subvol, int is_last_subvol) { int ret; pthread_t t_read; @@ -298,11 +299,18 @@ static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root_id) io_send.clone_sources = (__u64*)send->clone_sources; io_send.clone_sources_count = send->clone_sources_count; io_send.parent_root = parent_root_id; + if (!is_first_subvol) + io_send.flags |= BTRFS_SEND_FLAG_OMIT_STREAM_HEADER; + if (!is_last_subvol) + io_send.flags |= BTRFS_SEND_FLAG_OMIT_END_CMD; ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send); if (ret) { ret = -errno; fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret, strerror(-ret)); + if (ret == -EINVAL && (!is_first_subvol || !is_last_subvol)) + fprintf(stderr, + "Try upgrading your kernel or don't use -e.\n"); goto out; } if (g_verbose > 0) @@ -435,15 +443,19 @@ int cmd_send_start(int argc, char **argv) u64 root_id; u64 parent_root_id = 0; int full_send = 1; + int new_end_cmd_semantic = 0; memset(&send, 0, sizeof(send)); send.dump_fd = fileno(stdout); - while ((c = getopt(argc, argv, "vc:f:i:p:")) != -1) { + while ((c = getopt(argc, argv, "vec:f:i:p:")) != -1) { switch (c) { case 'v': g_verbose++; break; + case 'e': + new_end_cmd_semantic = 1; + break; case 'c': subvol = realpath(optarg, NULL); if (!subvol) { @@ -594,6 +606,9 @@ int cmd_send_start(int argc, char **argv) } for (i = optind; i < argc; i++) { + int is_first_subvol; + int is_last_subvol; + free(subvol); subvol = argv[i]; @@ -634,7 +649,17 @@ int cmd_send_start(int argc, char **argv) goto out; } - ret = do_send(&send, root_id, parent_root_id); + if (new_end_cmd_semantic) { + /* require new kernel */ + is_first_subvol = (i == optind); + is_last_subvol = (i == argc - 1); + } else { + /* be compatible to old and new kernel */ + is_first_subvol = 1; + is_last_subvol = 1; + } + ret = do_send(&send, root_id, parent_root_id, + is_first_subvol, is_last_subvol); if (ret < 0) goto out; @@ -664,7 +689,7 @@ static const char * const send_cmd_group_usage[] = { }; const char * const cmd_send_usage[] = { - "btrfs send [-v] [-p <parent>] [-c <clone-src>] <subvol>", + "btrfs send [-ve] [-p <parent>] [-c <clone-src>] <subvol>", "Send the subvolume to stdout.", "Sends the subvolume specified by <subvol> to stdout.", "By default, this will send the whole subvolume. To do an incremental", @@ -679,6 +704,8 @@ const char * const cmd_send_usage[] = { "\n", "-v Enable verbose debug output. Each occurrence of", " this option increases the verbose level more.", + "-e If sending multiple subvols at once, use the new", + " format and omit the end-cmd between the subvols.", "-p <parent> Send an incremental stream from <parent> to", " <subvol>.", "-c <clone-src> Use this snapshot as a clone source for an ", |