Btrfs-progs: btrfs-receive optionally honors the end-cmd
A new option is added to btrfs-receive to change the behavior when an <end cmd> is received in the Btrfs send stream. The traditional behavior (which still is the default) is to continue to read the stream until an EOF condition is encountered. If an <end cmd> is received, afterwards either an EOF or a new <stream header> is expected. The new behavior (if the -e option is set on the command line) is to terminate after an <end cmd> is read without the need for an EOF. This allows the stream (e.g. a single TCP stream) to carry additional data or even multiple Btrfs send streams. Old btrfs-send tools used to encode multiple snapshots like this (with 2 snapshots in this example): <stream header> + <sequence of commands> + <end cmd> + <stream header> + <sequence of commands> + <end cmd> + EOF If the new -e option is set, the expected format is like this: <stream header> + <sequence of commands> + <sequence of commands> + <end cmd> The btrfs-send tool is changed in a seperate commit to always use the new format, i.e. to send an <end cmd> only at the end. 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. The goal of changing the semantic of <end cmd> 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>
This commit is contained in:
parent
147525f11b
commit
46de1a6ec3
|
@ -66,6 +66,8 @@ struct btrfs_receive
|
||||||
struct subvol_info *cur_subvol;
|
struct subvol_info *cur_subvol;
|
||||||
|
|
||||||
struct subvol_uuid_search sus;
|
struct subvol_uuid_search sus;
|
||||||
|
|
||||||
|
int honor_end_cmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int finish_subvol(struct btrfs_receive *r)
|
static int finish_subvol(struct btrfs_receive *r)
|
||||||
|
@ -810,7 +812,8 @@ int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
while (!end) {
|
while (!end) {
|
||||||
ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
|
ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
|
||||||
|
r->honor_end_cmd);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -863,7 +866,7 @@ static int do_cmd_receive(int argc, char **argv)
|
||||||
r.mnt_fd = -1;
|
r.mnt_fd = -1;
|
||||||
r.write_fd = -1;
|
r.write_fd = -1;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "vf:")) != -1) {
|
while ((c = getopt(argc, argv, "evf:")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'v':
|
case 'v':
|
||||||
g_verbose++;
|
g_verbose++;
|
||||||
|
@ -871,6 +874,9 @@ static int do_cmd_receive(int argc, char **argv)
|
||||||
case 'f':
|
case 'f':
|
||||||
fromfile = optarg;
|
fromfile = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
r.honor_end_cmd = 1;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ERROR: receive args invalid.\n");
|
fprintf(stderr, "ERROR: receive args invalid.\n");
|
||||||
|
@ -904,7 +910,7 @@ static const char * const receive_cmd_group_usage[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const char * const cmd_receive_usage[] = {
|
const char * const cmd_receive_usage[] = {
|
||||||
"btrfs receive [-v] [-f <infile>] <mount>",
|
"btrfs receive [-ve] [-f <infile>] <mount>",
|
||||||
"Receive subvolumes from stdin.",
|
"Receive subvolumes from stdin.",
|
||||||
"Receives one or more subvolumes that were previously ",
|
"Receives one or more subvolumes that were previously ",
|
||||||
"sent with btrfs send. The received subvolumes are stored",
|
"sent with btrfs send. The received subvolumes are stored",
|
||||||
|
@ -920,6 +926,10 @@ const char * const cmd_receive_usage[] = {
|
||||||
"-f <infile> By default, btrfs receive uses stdin",
|
"-f <infile> By default, btrfs receive uses stdin",
|
||||||
" to receive the subvolumes. Use this",
|
" to receive the subvolumes. Use this",
|
||||||
" option to specify a file to use instead.",
|
" option to specify a file to use instead.",
|
||||||
|
"-e Terminate after receiving an <end cmd>",
|
||||||
|
" in the data stream. Without this option,",
|
||||||
|
" the receiver terminates only if an error",
|
||||||
|
" is recognized or on EOF.",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -439,7 +439,8 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_read_and_process_send_stream(int fd,
|
int btrfs_read_and_process_send_stream(int fd,
|
||||||
struct btrfs_send_ops *ops, void *user)
|
struct btrfs_send_ops *ops, void *user,
|
||||||
|
int honor_end_cmd)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct btrfs_send_stream s;
|
struct btrfs_send_stream s;
|
||||||
|
@ -476,7 +477,8 @@ int btrfs_read_and_process_send_stream(int fd,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = 0;
|
if (!honor_end_cmd)
|
||||||
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,8 @@ struct btrfs_send_ops {
|
||||||
};
|
};
|
||||||
|
|
||||||
int btrfs_read_and_process_send_stream(int fd,
|
int btrfs_read_and_process_send_stream(int fd,
|
||||||
struct btrfs_send_ops *ops, void *user);
|
struct btrfs_send_ops *ops, void *user,
|
||||||
|
int honor_end_cmd);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue