@@ -474,6 +474,7 @@ static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)
int full_send = 1;
int new_end_cmd_semantic = 0;
u64 send_flags = 0;
+ long stream_version = 0;
memset(&send, 0, sizeof(send));
send.dump_fd = fileno(stdout);
@@ -492,11 +493,17 @@ static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)
optind = 0;
while (1) {
- enum { GETOPT_VAL_SEND_NO_DATA = 256 };
+ enum {
+ GETOPT_VAL_SEND_NO_DATA = 256,
+ GETOPT_VAL_SEND_STREAM_V2,
+ GETOPT_VAL_SEND_COMPRESSED
+ };
static const struct option long_options[] = {
{ "verbose", no_argument, NULL, 'v' },
{ "quiet", no_argument, NULL, 'q' },
- { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA }
+ { "no-data", no_argument, NULL, GETOPT_VAL_SEND_NO_DATA },
+ { "stream-version", required_argument, NULL, GETOPT_VAL_SEND_STREAM_V2 },
+ { "compressed", no_argument, NULL, GETOPT_VAL_SEND_COMPRESSED }
};
int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);
@@ -584,10 +591,38 @@ static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)
case GETOPT_VAL_SEND_NO_DATA:
send_flags |= BTRFS_SEND_FLAG_NO_FILE_DATA;
break;
+ case GETOPT_VAL_SEND_STREAM_V2:
+ stream_version = strtol(optarg, NULL, 10);
+ if (stream_version < 1 || stream_version > 2) {
+ ret = 1;
+ error("invalid --stream-version. valid values: {1, 2}");
+ goto out;
+ }
+ if (stream_version == 2)
+ send_flags |= BTRFS_SEND_FLAG_STREAM_V2;
+ break;
+ case GETOPT_VAL_SEND_COMPRESSED:
+ send_flags |= BTRFS_SEND_FLAG_COMPRESSED;
+ /*
+ * We want to default to stream v2 if only compressed is
+ * set. If stream_version is explicitly set to 0, that
+ * will trigger its own error condition for being an
+ * invalid version.
+ */
+ if (stream_version == 0) {
+ stream_version = 2;
+ send_flags |= BTRFS_SEND_FLAG_STREAM_V2;
+ }
+ break;
default:
usage_unknown_option(cmd, argv);
}
}
+ if (stream_version < 2 && (send_flags & BTRFS_SEND_FLAG_COMPRESSED)) {
+ ret = 1;
+ error("--compressed requires --stream-version >= 2");
+ goto out;
+ }
if (check_argc_min(argc - optind, 1))
return 1;
@@ -653,10 +653,25 @@ BUILD_ASSERT(sizeof(struct btrfs_ioctl_received_subvol_args_32) == 192);
*/
#define BTRFS_SEND_FLAG_OMIT_END_CMD 0x4
+/*
+ * Use version 2 of the send stream, which adds new commands and supports larger
+ * writes.
+ */
+#define BTRFS_SEND_FLAG_STREAM_V2 0x8
+
+/*
+ * Send compressed data using the ENCODED_WRITE command instead of decompressing
+ * the data and sending it with the WRITE command. This requires
+ * BTRFS_SEND_FLAG_STREAM_V2.
+ */
+#define BTRFS_SEND_FLAG_COMPRESSED 0x10
+
#define BTRFS_SEND_FLAG_MASK \
(BTRFS_SEND_FLAG_NO_FILE_DATA | \
BTRFS_SEND_FLAG_OMIT_STREAM_HEADER | \
- BTRFS_SEND_FLAG_OMIT_END_CMD)
+ BTRFS_SEND_FLAG_OMIT_END_CMD | \
+ BTRFS_SEND_FLAG_STREAM_V2 | \
+ BTRFS_SEND_FLAG_COMPRESSED)
struct btrfs_ioctl_send_args {
__s64 send_fd; /* in */
@@ -731,10 +731,25 @@ struct btrfs_ioctl_received_subvol_args {
*/
#define BTRFS_SEND_FLAG_OMIT_END_CMD 0x4
+/*
+ * Use version 2 of the send stream, which adds new commands and supports larger
+ * writes.
+ */
+#define BTRFS_SEND_FLAG_STREAM_V2 0x8
+
+/*
+ * Send compressed data using the ENCODED_WRITE command instead of decompressing
+ * the data and sending it with the WRITE command. This requires
+ * BTRFS_SEND_FLAG_STREAM_V2.
+ */
+#define BTRFS_SEND_FLAG_COMPRESSED 0x10
+
#define BTRFS_SEND_FLAG_MASK \
(BTRFS_SEND_FLAG_NO_FILE_DATA | \
BTRFS_SEND_FLAG_OMIT_STREAM_HEADER | \
- BTRFS_SEND_FLAG_OMIT_END_CMD)
+ BTRFS_SEND_FLAG_OMIT_END_CMD | \
+ BTRFS_SEND_FLAG_STREAM_V2 | \
+ BTRFS_SEND_FLAG_COMPRESSED)
struct btrfs_ioctl_send_args {
__s64 send_fd; /* in */
@@ -31,7 +31,7 @@ extern "C" {
#endif
#define BTRFS_SEND_STREAM_MAGIC "btrfs-stream"
-#define BTRFS_SEND_STREAM_VERSION 1
+#define BTRFS_SEND_STREAM_VERSION 2
#define BTRFS_SEND_BUF_SIZE_V1 SZ_64K
#define BTRFS_SEND_READ_SIZE (1024 * 48)