#2 Backport 'btrfs-progs: receive: fix a silent data loss bug with encoded writes'
Closed 2 years ago by borisb. Opened 2 years ago by borisb.
rpms/ borisb/btrfs-progs c9s-sig-hyperscale  into  c7

file modified
+2 -2
@@ -1,3 +1,3 @@ 

- 6b9a963a21b6d1f7ebb811d541c378a736a861eb SOURCES/btrfs-progs-v5.12.1.tar.xz

- c6106fc89f975f3a439ee851b522c4adebb0ace6 SOURCES/btrfs-progs-v5.12.1.tar.sign

+ c14de7398dc741c462a0e06aaa1c2b0ba9a0d787 SOURCES/btrfs-progs-v5.16.2.tar.sign

+ 3d5f94b2aeded999fb4cbbab04b91305864955d6 SOURCES/btrfs-progs-v5.16.2.tar.xz

  6b3b5fc33c002d029e83ae4f678089e0d16e6148 SOURCES/gpgkey-F2B41200C54EFB30380C1756C565D5F9D76D583B.gpg

@@ -1,6 +1,6 @@ 

- From da8af64d371e314acb2fec2052f1e1312822fb51 Mon Sep 17 00:00:00 2001

+ From 1338ce1136aea6cc83f7ee6d78c5ca6a07bb38d6 Mon Sep 17 00:00:00 2001

  From: Neal Gompa <ngompa@centosproject.org>

- Date: Fri, 14 May 2021 18:14:37 -0400

+ Date: Wed, 1 Sep 2021 19:25:55 -0400

  Subject: [PATCH] balance, mkfs: Disable raid56 modes

  

  The RAID 5/6 modes in Btrfs are not yet suitable for production use,
@@ -8,15 +8,15 @@ 

  

  Signed-off-by: Neal Gompa <ngompa@centosproject.org>

  ---

-  cmds/balance.c | 33 ++++-----------------------------

+  cmds/balance.c | 35 ++++-------------------------------

   mkfs/main.c    |  4 ++--

-  2 files changed, 6 insertions(+), 31 deletions(-)

+  2 files changed, 6 insertions(+), 33 deletions(-)

  

  diff --git a/cmds/balance.c b/cmds/balance.c

- index 33cbb91c..2e6c3b2d 100644

+ index 7abc69d9..ab86ff36 100644

  --- a/cmds/balance.c

  +++ b/cmds/balance.c

- @@ -503,8 +503,7 @@ static const char * const cmd_balance_start_usage[] = {

+ @@ -376,8 +376,7 @@ static const char * const cmd_balance_start_usage[] = {

   	"-d[filters]    act on data chunks",

   	"-m[filters]    act on metadata chunks",

   	"-s[filters]    act on system chunks (only under -f)",
@@ -26,7 +26,7 @@ 

   	"--full-balance do not print warning and do not delay start",

   	"--background|--bg",

   	"               run the balance as a background process",

- @@ -527,7 +526,6 @@ static int cmd_balance_start(const struct cmd_struct *cmd,

+ @@ -400,7 +399,6 @@ static int cmd_balance_start(const struct cmd_struct *cmd,

   	int background = 0;

   	bool enqueue = false;

   	unsigned start_flags = 0;
@@ -34,11 +34,20 @@ 

   	int i;

   

   	memset(&args, 0, sizeof(args));

- @@ -646,33 +644,10 @@ static int cmd_balance_start(const struct cmd_struct *cmd,

+ @@ -507,8 +505,6 @@ static int cmd_balance_start(const struct cmd_struct *cmd,

+  

+  	/* soft makes sense only when convert for corresponding type is set */

+  	for (i = 0; ptrs[i]; i++) {

+ -		int delay = 10;

+ -

+  		if ((ptrs[i]->flags & BTRFS_BALANCE_ARGS_SOFT) &&

+  		    !(ptrs[i]->flags & BTRFS_BALANCE_ARGS_CONVERT)) {

+  			error("'soft' option can be used only when converting profiles");

+ @@ -518,33 +514,10 @@ static int cmd_balance_start(const struct cmd_struct *cmd,

+  		if (!(ptrs[i]->flags & BTRFS_BALANCE_ARGS_CONVERT))

   			continue;

   

-  		if (!(ptrs[i]->target & (BTRFS_BLOCK_GROUP_RAID6 |

- -					   BTRFS_BLOCK_GROUP_RAID5)))

+ -		if (!(ptrs[i]->target & BTRFS_BLOCK_GROUP_RAID56_MASK))

  -			continue;

  -

  -		if (raid56_warned)
@@ -56,36 +65,36 @@ 

  -		if (force) {

  -			printf("\tSafety timeout skipped due to --force\n\n");

  -			continue;

- -		}

+ +		if (ptrs[i]->target & BTRFS_BLOCK_GROUP_RAID56_MASK) {

+ +			error("RAID5/6 support has known problems and is disabled.");

+ +			return 1;

+  		}

  -		printf("\tThe operation will continue in %d seconds.\n", delay);

  -		printf("\tUse Ctrl-C to stop.\n");

  -		while (delay) {

  -			printf("%2d", delay--);

  -			fflush(stdout);

  -			sleep(1);

- +					   BTRFS_BLOCK_GROUP_RAID5))) {

- +			error("\tRAID5/6 support has known problems and is disabled.\n");

- +			return 1;

-  		}

+ -		}

  -		printf("\nStarting conversion to RAID5/6.\n");

   	}

   

   	if (!(start_flags & BALANCE_START_FILTERS) && !(start_flags & BALANCE_START_NOWARN)) {

  diff --git a/mkfs/main.c b/mkfs/main.c

- index d2322faf..81519c6a 100644

+ index f9e8be74..11c0fc26 100644

  --- a/mkfs/main.c

  +++ b/mkfs/main.c

- @@ -1190,8 +1190,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)

-  	if ((data_profile | metadata_profile) &

-  	    (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6)) {

+ @@ -1214,8 +1214,8 @@ int BOX_MAIN(mkfs)(int argc, char **argv)

+  

+  	if ((data_profile | metadata_profile) & BTRFS_BLOCK_GROUP_RAID56_MASK) {

   		features |= BTRFS_FEATURE_INCOMPAT_RAID56;

  -		warning("RAID5/6 support has known problems is strongly discouraged\n"

  -			"\t to be used besides testing or evaluation.\n");

- +		error("RAID5/6 support has known problems and is disabled.\n");

+ +		error("RAID5/6 support has known problems and is disabled.");

  +		exit(1);

   	}

   

   	if ((data_profile | metadata_profile) &

  -- 

- 2.31.1

+ 2.35.1

  

@@ -0,0 +1,85 @@ 

+ From 5a5f05ff7d8b3dec2da3495530b1653d25b6a175 Mon Sep 17 00:00:00 2001

+ From: Omar Sandoval <osandov@fb.com>

+ Date: Tue, 10 Aug 2021 23:24:38 +0200

+ Subject: [PATCH] Require --clowntown for quota enable

+ 

+ ---

+  cmds/quota.c | 35 ++++++++++++++++++++++++++++++-----

+  1 file changed, 30 insertions(+), 5 deletions(-)

+ 

+ diff --git a/cmds/quota.c b/cmds/quota.c

+ index 246dd277..07380726 100644

+ --- a/cmds/quota.c

+ +++ b/cmds/quota.c

+ @@ -16,6 +16,7 @@

+   * Boston, MA 021110-1307, USA.

+   */

+  

+ +#include <getopt.h>

+  #include <sys/ioctl.h>

+  #include <unistd.h>

+  

+ @@ -36,11 +37,11 @@ static int quota_ctl(int cmd, int argc, char **argv)

+  {

+  	int ret = 0;

+  	int fd;

+ -	char *path = argv[1];

+ +	char *path = argv[optind];

+  	struct btrfs_ioctl_quota_ctl_args args;

+  	DIR *dirstream = NULL;

+  

+ -	if (check_argc_exact(argc, 2))

+ +	if (check_argc_exact(argc - optind, 1))

+  		return -1;

+  

+  	memset(&args, 0, sizeof(args));

+ @@ -60,8 +61,11 @@ static int quota_ctl(int cmd, int argc, char **argv)

+  }

+  

+  static const char * const cmd_quota_enable_usage[] = {

+ -	"btrfs quota enable <path>",

+ +	"btrfs quota enable --clowntown <path>",

+  	"Enable subvolume quota support for a filesystem.",

+ +	"FB-ONLY: Btrfs quotas are not supported at Facebook, so you must use",

+ +	"the --clowntown flag to enable quotas.",

+ +	"",

+  	"Any data already present on the filesystem will not count towards",

+  	"the space usage numbers. It is recommended to enable quota for a",

+  	"filesystem before writing any data to it.",

+ @@ -71,10 +75,31 @@ static const char * const cmd_quota_enable_usage[] = {

+  static int cmd_quota_enable(const struct cmd_struct *cmd, int argc, char **argv)

+  {

+  	int ret;

+ +	bool clowntown = false;

+  

+ -	clean_args_no_options(cmd, argc, argv);

+ +	optind = 0;

+ +	while (1) {

+ +		int c;

+ +		static const struct option long_options[] = {

+ +			{ "clowntown", no_argument, NULL, 'c'},

+ +			{ NULL, 0, NULL, 0 }

+ +		};

+ +		c = getopt_long(argc, argv, "", long_options, NULL);

+ +		if (c < 0)

+ +			break;

+ +		switch (c) {

+ +		case 'c':

+ +			clowntown = true;

+ +			break;

+ +		default:

+ +			usage(cmd);

+ +		}

+ +	}

+  

+ -	ret = quota_ctl(BTRFS_QUOTA_CTL_ENABLE, argc, argv);

+ +	if (clowntown)

+ +		ret = quota_ctl(BTRFS_QUOTA_CTL_ENABLE, argc, argv);

+ +	else

+ +		ret = -1;

+  

+  	if (ret < 0)

+  		usage(cmd);

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,113 @@ 

+ From 7e5cd32fbb38103b11a8a87ca5af943d0fb2804a Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <borisb@fb.com>

+ Date: Fri, 21 Aug 2020 00:40:00 -0700

+ Subject: [PATCH] btrfs-progs: receive: support v2 send stream larger tlv_len

+ 

+ An encoded extent can be up to 128K in length, which exceeds the largest

+ value expressible by the current send stream format's 16 bit tlv_len

+ field. Since encoded writes cannot be split into multiple writes by

+ btrfs send, the send stream format must change to accommodate encoded

+ writes.

+ 

+ Supporting this changed format requires retooling how we store the

+ commands we have processed. We currently store pointers to the struct

+ btrfs_tlv_headers in the command buffer. This is not sufficient to

+ represent the new BTRFS_SEND_A_DATA format. Instead, parse the attribute

+ headers and store them in a new struct btrfs_send_attribute which has a

+ 32-bit length field. This is transparent to users of the various TLV_GET

+ macros.

+ 

+ Reviewed-by: Nikolay Borisov <nborisov@suse.com>

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  common/send-stream.c | 34 +++++++++++++++++++++++++---------

+  1 file changed, 25 insertions(+), 9 deletions(-)

+ 

+ diff --git a/common/send-stream.c b/common/send-stream.c

+ index e9be922b..7d182238 100644

+ --- a/common/send-stream.c

+ +++ b/common/send-stream.c

+ @@ -24,13 +24,23 @@

+  #include "crypto/crc32c.h"

+  #include "common/utils.h"

+  

+ +struct btrfs_send_attribute {

+ +	u16 tlv_type;

+ +	/*

+ +	 * Note: in btrfs_tlv_header, this is __le16, but we need 32 bits for

+ +	 * attributes with file data as of version 2 of the send stream format

+ +	 */

+ +	u32 tlv_len;

+ +	char *data;

+ +};

+ +

+  struct btrfs_send_stream {

+  	char read_buf[BTRFS_SEND_BUF_SIZE];

+  	int fd;

+  

+  	int cmd;

+  	struct btrfs_cmd_header *cmd_hdr;

+ -	struct btrfs_tlv_header *cmd_attrs[BTRFS_SEND_A_MAX + 1];

+ +	struct btrfs_send_attribute cmd_attrs[BTRFS_SEND_A_MAX + 1];

+  	u32 version;

+  

+  	/*

+ @@ -152,6 +162,7 @@ static int read_cmd(struct btrfs_send_stream *sctx)

+  		struct btrfs_tlv_header *tlv_hdr;

+  		u16 tlv_type;

+  		u16 tlv_len;

+ +		struct btrfs_send_attribute *send_attr;

+  

+  		tlv_hdr = (struct btrfs_tlv_header *)data;

+  		tlv_type = le16_to_cpu(tlv_hdr->tlv_type);

+ @@ -164,10 +175,15 @@ static int read_cmd(struct btrfs_send_stream *sctx)

+  			goto out;

+  		}

+  

+ -		sctx->cmd_attrs[tlv_type] = tlv_hdr;

+ +		send_attr = &sctx->cmd_attrs[tlv_type];

+ +		send_attr->tlv_type = tlv_type;

+ +		send_attr->tlv_len = tlv_len;

+ +		pos += sizeof(*tlv_hdr);

+ +		data += sizeof(*tlv_hdr);

+  

+ -		data += sizeof(*tlv_hdr) + tlv_len;

+ -		pos += sizeof(*tlv_hdr) + tlv_len;

+ +		send_attr->data = data;

+ +		pos += send_attr->tlv_len;

+ +		data += send_attr->tlv_len;

+  	}

+  

+  	sctx->cmd = cmd;

+ @@ -180,7 +196,7 @@ out:

+  static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *len)

+  {

+  	int ret;

+ -	struct btrfs_tlv_header *hdr;

+ +	struct btrfs_send_attribute *send_attr;

+  

+  	if (attr <= 0 || attr > BTRFS_SEND_A_MAX) {

+  		error("invalid attribute requested, attr = %d", attr);

+ @@ -188,15 +204,15 @@ static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *l

+  		goto out;

+  	}

+  

+ -	hdr = sctx->cmd_attrs[attr];

+ -	if (!hdr) {

+ +	send_attr = &sctx->cmd_attrs[attr];

+ +	if (!send_attr->data) {

+  		error("attribute %d requested but not present", attr);

+  		ret = -ENOENT;

+  		goto out;

+  	}

+  

+ -	*len = le16_to_cpu(hdr->tlv_len);

+ -	*data = hdr + 1;

+ +	*len = send_attr->tlv_len;

+ +	*data = send_attr->data;

+  

+  	ret = 0;

+  

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,171 @@ 

+ From e274c8de61c02f4a65812371bc6f1c2a6ac4d30c Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <boris@bur.io>

+ Date: Fri, 21 Aug 2020 00:40:01 -0700

+ Subject: [PATCH] btrfs-progs: receive: dynamically allocate sctx->read_buf

+ 

+ In send stream v2, write commands can now be an arbitrary size. For that

+ reason, we can no longer allocate a fixed array in sctx for read_cmd.

+ Instead, read_cmd dynamically allocates sctx->read_buf. To avoid

+ needless reallocations, we reuse read_buf between read_cmd calls by also

+ keeping track of the size of the allocated buffer in sctx->read_buf_sz.

+ 

+ We do the first allocation of the old default size at the start of

+ processing the stream, and we only reallocate if we encounter a command

+ that needs a larger buffer.

+ 

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  common/send-stream.c   | 56 ++++++++++++++++++++++++++++--------------

+  kernel-shared/send.h   |  6 ++++-

+  libbtrfs/send-stream.c |  2 +-

+  3 files changed, 43 insertions(+), 21 deletions(-)

+ 

+ diff --git a/common/send-stream.c b/common/send-stream.c

+ index 7d182238..421cd1bb 100644

+ --- a/common/send-stream.c

+ +++ b/common/send-stream.c

+ @@ -35,11 +35,11 @@ struct btrfs_send_attribute {

+  };

+  

+  struct btrfs_send_stream {

+ -	char read_buf[BTRFS_SEND_BUF_SIZE];

+ +	char *read_buf;

+ +	size_t read_buf_sz;

+  	int fd;

+  

+  	int cmd;

+ -	struct btrfs_cmd_header *cmd_hdr;

+  	struct btrfs_send_attribute cmd_attrs[BTRFS_SEND_A_MAX + 1];

+  	u32 version;

+  

+ @@ -111,11 +111,12 @@ static int read_cmd(struct btrfs_send_stream *sctx)

+  	u32 pos;

+  	u32 crc;

+  	u32 crc2;

+ +	struct btrfs_cmd_header *cmd_hdr;

+ +	size_t buf_len;

+  

+  	memset(sctx->cmd_attrs, 0, sizeof(sctx->cmd_attrs));

+  

+ -	ASSERT(sizeof(*sctx->cmd_hdr) <= sizeof(sctx->read_buf));

+ -	ret = read_buf(sctx, sctx->read_buf, sizeof(*sctx->cmd_hdr));

+ +	ret = read_buf(sctx, sctx->read_buf, sizeof(*cmd_hdr));

+  	if (ret < 0)

+  		goto out;

+  	if (ret) {

+ @@ -124,18 +125,25 @@ static int read_cmd(struct btrfs_send_stream *sctx)

+  		goto out;

+  	}

+  

+ -	sctx->cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf;

+ -	cmd = le16_to_cpu(sctx->cmd_hdr->cmd);

+ -	cmd_len = le32_to_cpu(sctx->cmd_hdr->len);

+ +	cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf;

+ +	cmd_len = le32_to_cpu(cmd_hdr->len);

+ +	cmd = le16_to_cpu(cmd_hdr->cmd);

+ +	buf_len = sizeof(*cmd_hdr) + cmd_len;

+ +	if (sctx->read_buf_sz < buf_len) {

+ +		void *new_read_buf;

+  

+ -	if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) {

+ -		ret = -EINVAL;

+ -		error("command length %u too big for buffer %zu",

+ -				cmd_len, sizeof(sctx->read_buf));

+ -		goto out;

+ +		new_read_buf = realloc(sctx->read_buf, buf_len);

+ +		if (!new_read_buf) {

+ +			ret = -ENOMEM;

+ +			error("failed to reallocate read buffer for cmd");

+ +			goto out;

+ +		}

+ +		sctx->read_buf = new_read_buf;

+ +		sctx->read_buf_sz = buf_len;

+ +		/* We need to reset cmd_hdr after realloc of sctx->read_buf */

+ +		cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf;

+  	}

+ -

+ -	data = sctx->read_buf + sizeof(*sctx->cmd_hdr);

+ +	data = sctx->read_buf + sizeof(*cmd_hdr);

+  	ret = read_buf(sctx, data, cmd_len);

+  	if (ret < 0)

+  		goto out;

+ @@ -145,11 +153,12 @@ static int read_cmd(struct btrfs_send_stream *sctx)

+  		goto out;

+  	}

+  

+ -	crc = le32_to_cpu(sctx->cmd_hdr->crc);

+ -	sctx->cmd_hdr->crc = 0;

+ +	crc = le32_to_cpu(cmd_hdr->crc);

+ +	/* in send, crc is computed with header crc = 0, replicate that */

+ +	cmd_hdr->crc = 0;

+  

+  	crc2 = crc32c(0, (unsigned char*)sctx->read_buf,

+ -			sizeof(*sctx->cmd_hdr) + cmd_len);

+ +			sizeof(*cmd_hdr) + cmd_len);

+  

+  	if (crc != crc2) {

+  		ret = -EINVAL;

+ @@ -537,19 +546,28 @@ int btrfs_read_and_process_send_stream(int fd,

+  		goto out;

+  	}

+  

+ +	sctx.read_buf = malloc(BTRFS_SEND_BUF_SIZE_V1);

+ +	if (!sctx.read_buf) {

+ +		ret = -ENOMEM;

+ +		error("unable to allocate send stream read buffer");

+ +		goto out;

+ +	}

+ +	sctx.read_buf_sz = BTRFS_SEND_BUF_SIZE_V1;

+ +

+  	while (1) {

+  		ret = read_and_process_cmd(&sctx);

+  		if (ret < 0) {

+  			last_err = ret;

+  			errors++;

+  			if (max_errors > 0 && errors >= max_errors)

+ -				goto out;

+ +				break;

+  		} else if (ret > 0) {

+  			if (!honor_end_cmd)

+  				ret = 0;

+ -			goto out;

+ +			break;

+  		}

+  	}

+ +	free(sctx.read_buf);

+  

+  out:

+  	if (last_err && !ret)

+ diff --git a/kernel-shared/send.h b/kernel-shared/send.h

+ index e73f09df..e986b6c8 100644

+ --- a/kernel-shared/send.h

+ +++ b/kernel-shared/send.h

+ @@ -33,7 +33,11 @@ extern "C" {

+  #define BTRFS_SEND_STREAM_MAGIC "btrfs-stream"

+  #define BTRFS_SEND_STREAM_VERSION 1

+  

+ -#define BTRFS_SEND_BUF_SIZE  (64 * 1024)

+ +/*

+ + * In send stream v1, no command is larger than 64k. In send stream v2, no limit

+ + * should be assumed.

+ + */

+ +#define BTRFS_SEND_BUF_SIZE_V1 (64 * 1024)

+  #define BTRFS_SEND_READ_SIZE (1024 * 48)

+  

+  enum btrfs_tlv_type {

+ diff --git a/libbtrfs/send-stream.c b/libbtrfs/send-stream.c

+ index 2b21d846..39cbb3ed 100644

+ --- a/libbtrfs/send-stream.c

+ +++ b/libbtrfs/send-stream.c

+ @@ -22,7 +22,7 @@

+  #include "crypto/crc32c.h"

+  

+  struct btrfs_send_stream {

+ -	char read_buf[BTRFS_SEND_BUF_SIZE];

+ +	char read_buf[BTRFS_SEND_BUF_SIZE_V1];

+  	int fd;

+  

+  	int cmd;

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,85 @@ 

+ From 734b41ff166263c364e89518eb46e52310eb070b Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <borisb@fb.com>

+ Date: Fri, 21 Aug 2020 00:40:02 -0700

+ Subject: [PATCH] btrfs-progs: receive: support v2 send stream DATA tlv format

+ 

+ The new format privileges the BTRFS_SEND_A_DATA attribute by

+ guaranteeing it will always be the last attribute in any command that

+ needs it, and by implicitly encoding the data length as the difference

+ between the total command length in the command header and the sizes of

+ the rest of the attributes (and of course the tlv_type identifying the

+ DATA attribute). To parse the new stream, we must read the tlv_type and

+ if it is not DATA, we proceed normally, but if it is DATA, we don't

+ parse a tlv_len but simply compute the length.

+ 

+ In addition, we add some bounds checking when parsing each chunk of

+ data, as well as for the tlv_len itself.

+ 

+ Reviewed-by: Nikolay Borisov <nborisov@suse.com>

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  common/send-stream.c | 36 ++++++++++++++++++++++++++----------

+  1 file changed, 26 insertions(+), 10 deletions(-)

+ 

+ diff --git a/common/send-stream.c b/common/send-stream.c

+ index 421cd1bb..81a830d9 100644

+ --- a/common/send-stream.c

+ +++ b/common/send-stream.c

+ @@ -168,28 +168,44 @@ static int read_cmd(struct btrfs_send_stream *sctx)

+  

+  	pos = 0;

+  	while (pos < cmd_len) {

+ -		struct btrfs_tlv_header *tlv_hdr;

+  		u16 tlv_type;

+ -		u16 tlv_len;

+  		struct btrfs_send_attribute *send_attr;

+  

+ -		tlv_hdr = (struct btrfs_tlv_header *)data;

+ -		tlv_type = le16_to_cpu(tlv_hdr->tlv_type);

+ -		tlv_len = le16_to_cpu(tlv_hdr->tlv_len);

+ +		if (cmd_len - pos < sizeof(__le16)) {

+ +			error("send stream is truncated");

+ +			ret = -EINVAL;

+ +			goto out;

+ +		}

+ +		tlv_type = le16_to_cpu(*(__le16 *)data);

+  

+  		if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX) {

+ -			error("invalid tlv in cmd tlv_type = %hu, tlv_len = %hu",

+ -					tlv_type, tlv_len);

+ +			error("invalid tlv in cmd tlv_type = %hu", tlv_type);

+  			ret = -EINVAL;

+  			goto out;

+  		}

+  

+  		send_attr = &sctx->cmd_attrs[tlv_type];

+  		send_attr->tlv_type = tlv_type;

+ -		send_attr->tlv_len = tlv_len;

+ -		pos += sizeof(*tlv_hdr);

+ -		data += sizeof(*tlv_hdr);

+  

+ +		pos += sizeof(tlv_type);

+ +		data += sizeof(tlv_type);

+ +		if (sctx->version >= 2 && tlv_type == BTRFS_SEND_A_DATA) {

+ +			send_attr->tlv_len = cmd_len - pos;

+ +		} else {

+ +			if (cmd_len - pos < sizeof(__le16)) {

+ +				error("send stream is truncated");

+ +				ret = -EINVAL;

+ +				goto out;

+ +			}

+ +			send_attr->tlv_len = le16_to_cpu(*(__le16 *)data);

+ +			pos += sizeof(__le16);

+ +			data += sizeof(__le16);

+ +		}

+ +		if (cmd_len - pos < send_attr->tlv_len) {

+ +			error("send stream is truncated");

+ +			ret = -EINVAL;

+ +			goto out;

+ +		}

+  		send_attr->data = data;

+  		pos += send_attr->tlv_len;

+  		data += send_attr->tlv_len;

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,194 @@ 

+ From 8ff6d9258385e4a0ae462e0cea8409e4fae05dc1 Mon Sep 17 00:00:00 2001

+ From: Omar Sandoval <osandov@fb.com>

+ Date: Tue, 8 Feb 2022 11:02:02 -0800

+ Subject: [PATCH] btrfs-progs: receive: add send stream v2 cmds and attrs to

+  send.h

+ 

+ Update our copy of send.h from the kernel. This adds the new commands

+ and attributes for v2 as well as explicit enum numbering.

+ 

+ Reviewed-by: Nikolay Borisov <nborisov@suse.com>

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ Signed-off-by: Omar Sandoval <osandov@fb.com>

+ ---

+  kernel-shared/send.h | 138 ++++++++++++++++++++++++++-----------------

+  1 file changed, 85 insertions(+), 53 deletions(-)

+ 

+ diff --git a/kernel-shared/send.h b/kernel-shared/send.h

+ index e986b6c8..b902d054 100644

+ --- a/kernel-shared/send.h

+ +++ b/kernel-shared/send.h

+ @@ -38,7 +38,6 @@ extern "C" {

+   * should be assumed.

+   */

+  #define BTRFS_SEND_BUF_SIZE_V1 (64 * 1024)

+ -#define BTRFS_SEND_READ_SIZE (1024 * 48)

+  

+  enum btrfs_tlv_type {

+  	BTRFS_TLV_U8,

+ @@ -72,77 +71,110 @@ struct btrfs_tlv_header {

+  

+  /* commands */

+  enum btrfs_send_cmd {

+ -	BTRFS_SEND_C_UNSPEC,

+ +	BTRFS_SEND_C_UNSPEC = 0,

+  

+ -	BTRFS_SEND_C_SUBVOL,

+ -	BTRFS_SEND_C_SNAPSHOT,

+ +	/* Version 1 */

+ +	BTRFS_SEND_C_SUBVOL = 1,

+ +	BTRFS_SEND_C_SNAPSHOT = 2,

+  

+ -	BTRFS_SEND_C_MKFILE,

+ -	BTRFS_SEND_C_MKDIR,

+ -	BTRFS_SEND_C_MKNOD,

+ -	BTRFS_SEND_C_MKFIFO,

+ -	BTRFS_SEND_C_MKSOCK,

+ -	BTRFS_SEND_C_SYMLINK,

+ +	BTRFS_SEND_C_MKFILE = 3,

+ +	BTRFS_SEND_C_MKDIR = 4,

+ +	BTRFS_SEND_C_MKNOD = 5,

+ +	BTRFS_SEND_C_MKFIFO = 6,

+ +	BTRFS_SEND_C_MKSOCK = 7,

+ +	BTRFS_SEND_C_SYMLINK = 8,

+  

+ -	BTRFS_SEND_C_RENAME,

+ -	BTRFS_SEND_C_LINK,

+ -	BTRFS_SEND_C_UNLINK,

+ -	BTRFS_SEND_C_RMDIR,

+ +	BTRFS_SEND_C_RENAME = 9,

+ +	BTRFS_SEND_C_LINK = 10,

+ +	BTRFS_SEND_C_UNLINK = 11,

+ +	BTRFS_SEND_C_RMDIR = 12,

+  

+ -	BTRFS_SEND_C_SET_XATTR,

+ -	BTRFS_SEND_C_REMOVE_XATTR,

+ +	BTRFS_SEND_C_SET_XATTR = 13,

+ +	BTRFS_SEND_C_REMOVE_XATTR = 14,

+  

+ -	BTRFS_SEND_C_WRITE,

+ -	BTRFS_SEND_C_CLONE,

+ +	BTRFS_SEND_C_WRITE = 15,

+ +	BTRFS_SEND_C_CLONE = 16,

+  

+ -	BTRFS_SEND_C_TRUNCATE,

+ -	BTRFS_SEND_C_CHMOD,

+ -	BTRFS_SEND_C_CHOWN,

+ -	BTRFS_SEND_C_UTIMES,

+ +	BTRFS_SEND_C_TRUNCATE = 17,

+ +	BTRFS_SEND_C_CHMOD = 18,

+ +	BTRFS_SEND_C_CHOWN = 19,

+ +	BTRFS_SEND_C_UTIMES = 20,

+  

+ -	BTRFS_SEND_C_END,

+ -	BTRFS_SEND_C_UPDATE_EXTENT,

+ -	__BTRFS_SEND_C_MAX,

+ +	BTRFS_SEND_C_END = 21,

+ +	BTRFS_SEND_C_UPDATE_EXTENT = 22,

+ +	BTRFS_SEND_C_MAX_V1 = 22,

+ +

+ +	/* Version 2 */

+ +	BTRFS_SEND_C_FALLOCATE = 23,

+ +	BTRFS_SEND_C_SETFLAGS = 24,

+ +	BTRFS_SEND_C_ENCODED_WRITE = 25,

+ +	BTRFS_SEND_C_MAX_V2 = 25,

+ +

+ +	/* End */

+ +	BTRFS_SEND_C_MAX = 25,

+  };

+ -#define BTRFS_SEND_C_MAX (__BTRFS_SEND_C_MAX - 1)

+  

+  /* attributes in send stream */

+  enum {

+ -	BTRFS_SEND_A_UNSPEC,

+ +	BTRFS_SEND_A_UNSPEC = 0,

+  

+ -	BTRFS_SEND_A_UUID,

+ -	BTRFS_SEND_A_CTRANSID,

+ +	/* Version 1 */

+ +	BTRFS_SEND_A_UUID = 1,

+ +	BTRFS_SEND_A_CTRANSID = 2,

+  

+ -	BTRFS_SEND_A_INO,

+ -	BTRFS_SEND_A_SIZE,

+ -	BTRFS_SEND_A_MODE,

+ -	BTRFS_SEND_A_UID,

+ -	BTRFS_SEND_A_GID,

+ -	BTRFS_SEND_A_RDEV,

+ -	BTRFS_SEND_A_CTIME,

+ -	BTRFS_SEND_A_MTIME,

+ -	BTRFS_SEND_A_ATIME,

+ -	BTRFS_SEND_A_OTIME,

+ +	BTRFS_SEND_A_INO = 3,

+ +	BTRFS_SEND_A_SIZE = 4,

+ +	BTRFS_SEND_A_MODE = 5,

+ +	BTRFS_SEND_A_UID = 6,

+ +	BTRFS_SEND_A_GID = 7,

+ +	BTRFS_SEND_A_RDEV = 8,

+ +	BTRFS_SEND_A_CTIME = 9,

+ +	BTRFS_SEND_A_MTIME = 10,

+ +	BTRFS_SEND_A_ATIME = 11,

+ +	BTRFS_SEND_A_OTIME = 12,

+  

+ -	BTRFS_SEND_A_XATTR_NAME,

+ -	BTRFS_SEND_A_XATTR_DATA,

+ +	BTRFS_SEND_A_XATTR_NAME = 13,

+ +	BTRFS_SEND_A_XATTR_DATA = 14,

+  

+ -	BTRFS_SEND_A_PATH,

+ -	BTRFS_SEND_A_PATH_TO,

+ -	BTRFS_SEND_A_PATH_LINK,

+ +	BTRFS_SEND_A_PATH = 15,

+ +	BTRFS_SEND_A_PATH_TO = 16,

+ +	BTRFS_SEND_A_PATH_LINK = 17,

+  

+ -	BTRFS_SEND_A_FILE_OFFSET,

+ -	BTRFS_SEND_A_DATA,

+ +	BTRFS_SEND_A_FILE_OFFSET = 18,

+ +	/*

+ +	 * As of send stream v2, this attribute is special: it must be the last

+ +	 * attribute in a command, its header contains only the type, and its

+ +	 * length is implicitly the remaining length of the command.

+ +	 */

+ +	BTRFS_SEND_A_DATA = 19,

+  

+ -	BTRFS_SEND_A_CLONE_UUID,

+ -	BTRFS_SEND_A_CLONE_CTRANSID,

+ -	BTRFS_SEND_A_CLONE_PATH,

+ -	BTRFS_SEND_A_CLONE_OFFSET,

+ -	BTRFS_SEND_A_CLONE_LEN,

+ +	BTRFS_SEND_A_CLONE_UUID = 20,

+ +	BTRFS_SEND_A_CLONE_CTRANSID = 21,

+ +	BTRFS_SEND_A_CLONE_PATH = 22,

+ +	BTRFS_SEND_A_CLONE_OFFSET = 23,

+ +	BTRFS_SEND_A_CLONE_LEN = 24,

+  

+ -	__BTRFS_SEND_A_MAX,

+ +	BTRFS_SEND_A_MAX_V1 = 24,

+ +

+ +	/* Version 2 */

+ +	BTRFS_SEND_A_FALLOCATE_MODE = 25,

+ +

+ +	BTRFS_SEND_A_SETFLAGS_FLAGS = 26,

+ +

+ +	BTRFS_SEND_A_UNENCODED_FILE_LEN = 27,

+ +	BTRFS_SEND_A_UNENCODED_LEN = 28,

+ +	BTRFS_SEND_A_UNENCODED_OFFSET = 29,

+ +	/*

+ +	 * COMPRESSION and ENCRYPTION default to NONE (0) if omitted from

+ +	 * BTRFS_SEND_C_ENCODED_WRITE.

+ +	 */

+ +	BTRFS_SEND_A_COMPRESSION = 30,

+ +	BTRFS_SEND_A_ENCRYPTION = 31,

+ +	BTRFS_SEND_A_MAX_V2 = 31,

+ +

+ +	/* End */

+ +	BTRFS_SEND_A_MAX = 31,

+  };

+ -#define BTRFS_SEND_A_MAX (__BTRFS_SEND_A_MAX - 1)

+  

+  #ifdef __cplusplus

+  }

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,361 @@ 

+ From 3523dd761db148a1214269f6d3dd357231dcbcff Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <borisb@fb.com>

+ Date: Fri, 21 Aug 2020 00:40:05 -0700

+ Subject: [PATCH] btrfs-progs: receive: process encoded_write commands

+ 

+ Add a new btrfs_send_op and support for both dumping and proper receive

+ processing which does actual encoded writes.

+ 

+ Encoded writes are only allowed on a file descriptor opened with an

+ extra flag that allows encoded writes, so we also add support for this

+ flag when opening or reusing a file for writing.

+ 

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  cmds/receive-dump.c  |  16 +++++-

+  cmds/receive.c       |  48 ++++++++++++++++

+  common/send-stream.c |  29 ++++++++++

+  common/send-stream.h |   4 ++

+  ioctl.h              | 132 +++++++++++++++++++++++++++++++++++++++++++

+  5 files changed, 228 insertions(+), 1 deletion(-)

+ 

+ diff --git a/cmds/receive-dump.c b/cmds/receive-dump.c

+ index 00ad4fd1..83701b62 100644

+ --- a/cmds/receive-dump.c

+ +++ b/cmds/receive-dump.c

+ @@ -318,6 +318,19 @@ static int print_update_extent(const char *path, u64 offset, u64 len,

+  			  offset, len);

+  }

+  

+ +static int print_encoded_write(const char *path, const void *data, u64 offset,

+ +			       u64 len, u64 unencoded_file_len,

+ +			       u64 unencoded_len, u64 unencoded_offset,

+ +			       u32 compression, u32 encryption, void *user)

+ +{

+ +	return PRINT_DUMP(user, path, "encoded_write",

+ +			  "offset=%llu len=%llu, unencoded_file_len=%llu, "

+ +			  "unencoded_len=%llu, unencoded_offset=%llu, "

+ +			  "compression=%u, encryption=%u",

+ +			  offset, len, unencoded_file_len, unencoded_len,

+ +			  unencoded_offset, compression, encryption);

+ +}

+ +

+  struct btrfs_send_ops btrfs_print_send_ops = {

+  	.subvol = print_subvol,

+  	.snapshot = print_snapshot,

+ @@ -339,5 +352,6 @@ struct btrfs_send_ops btrfs_print_send_ops = {

+  	.chmod = print_chmod,

+  	.chown = print_chown,

+  	.utimes = print_utimes,

+ -	.update_extent = print_update_extent

+ +	.update_extent = print_update_extent,

+ +	.encoded_write = print_encoded_write,

+  };

+ diff --git a/cmds/receive.c b/cmds/receive.c

+ index d106e554..8226ca32 100644

+ --- a/cmds/receive.c

+ +++ b/cmds/receive.c

+ @@ -29,12 +29,14 @@

+  #include <assert.h>

+  #include <getopt.h>

+  #include <limits.h>

+ +#include <errno.h>

+  

+  #include <sys/stat.h>

+  #include <sys/types.h>

+  #include <sys/ioctl.h>

+  #include <sys/time.h>

+  #include <sys/types.h>

+ +#include <sys/uio.h>

+  #include <sys/xattr.h>

+  #include <uuid/uuid.h>

+  

+ @@ -49,6 +51,7 @@

+  #include "cmds/receive-dump.h"

+  #include "common/help.h"

+  #include "common/path-utils.h"

+ +#include "stubs.h"

+  

+  struct btrfs_receive

+  {

+ @@ -982,6 +985,50 @@ static int process_update_extent(const char *path, u64 offset, u64 len,

+  	return 0;

+  }

+  

+ +static int process_encoded_write(const char *path, const void *data, u64 offset,

+ +				 u64 len, u64 unencoded_file_len,

+ +				 u64 unencoded_len, u64 unencoded_offset,

+ +				 u32 compression, u32 encryption, void *user)

+ +{

+ +	int ret;

+ +	struct btrfs_receive *rctx = user;

+ +	char full_path[PATH_MAX];

+ +	struct iovec iov = { (char *)data, len };

+ +	struct btrfs_ioctl_encoded_io_args encoded = {

+ +		.iov = &iov,

+ +		.iovcnt = 1,

+ +		.offset = offset,

+ +		.len = unencoded_file_len,

+ +		.unencoded_len = unencoded_len,

+ +		.unencoded_offset = unencoded_offset,

+ +		.compression = compression,

+ +		.encryption = encryption,

+ +	};

+ +

+ +	if (encryption) {

+ +		error("encoded_write: encryption not supported");

+ +		return -EOPNOTSUPP;

+ +	}

+ +

+ +	ret = path_cat_out(full_path, rctx->full_subvol_path, path);

+ +	if (ret < 0) {

+ +		error("encoded_write: path invalid: %s", path);

+ +		return ret;

+ +	}

+ +

+ +	ret = open_inode_for_write(rctx, full_path);

+ +	if (ret < 0)

+ +		return ret;

+ +

+ +	ret = ioctl(rctx->write_fd, BTRFS_IOC_ENCODED_WRITE, &encoded);

+ +	if (ret < 0) {

+ +		ret = -errno;

+ +		error("encoded_write: writing to %s failed: %m", path);

+ +		return ret;

+ +	}

+ +	return 0;

+ +}

+ +

+  static struct btrfs_send_ops send_ops = {

+  	.subvol = process_subvol,

+  	.snapshot = process_snapshot,

+ @@ -1004,6 +1051,7 @@ static struct btrfs_send_ops send_ops = {

+  	.chown = process_chown,

+  	.utimes = process_utimes,

+  	.update_extent = process_update_extent,

+ +	.encoded_write = process_encoded_write,

+  };

+  

+  static int do_receive(struct btrfs_receive *rctx, const char *tomnt,

+ diff --git a/common/send-stream.c b/common/send-stream.c

+ index 81a830d9..ce7c40f5 100644

+ --- a/common/send-stream.c

+ +++ b/common/send-stream.c

+ @@ -357,6 +357,8 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)

+  	struct timespec mt;

+  	u8 uuid[BTRFS_UUID_SIZE];

+  	u8 clone_uuid[BTRFS_UUID_SIZE];

+ +	u32 compression;

+ +	u32 encryption;

+  	u64 tmp;

+  	u64 tmp2;

+  	u64 ctransid;

+ @@ -366,6 +368,9 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)

+  	u64 clone_offset;

+  	u64 offset;

+  	u64 ino;

+ +	u64 unencoded_file_len;

+ +	u64 unencoded_len;

+ +	u64 unencoded_offset;

+  	int len;

+  	int xattr_len;

+  

+ @@ -452,6 +457,30 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)

+  		TLV_GET(sctx, BTRFS_SEND_A_DATA, &data, &len);

+  		ret = sctx->ops->write(path, data, offset, len, sctx->user);

+  		break;

+ +	case BTRFS_SEND_C_ENCODED_WRITE:

+ +		TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);

+ +		TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);

+ +		TLV_GET_U64(sctx, BTRFS_SEND_A_UNENCODED_FILE_LEN,

+ +			    &unencoded_file_len);

+ +		TLV_GET_U64(sctx, BTRFS_SEND_A_UNENCODED_LEN, &unencoded_len);

+ +		TLV_GET_U64(sctx, BTRFS_SEND_A_UNENCODED_OFFSET,

+ +			    &unencoded_offset);

+ +		/* Compression and encryption default to none if omitted. */

+ +		if (sctx->cmd_attrs[BTRFS_SEND_A_COMPRESSION].data)

+ +			TLV_GET_U32(sctx, BTRFS_SEND_A_COMPRESSION, &compression);

+ +		else

+ +			compression = BTRFS_ENCODED_IO_COMPRESSION_NONE;

+ +		if (sctx->cmd_attrs[BTRFS_SEND_A_ENCRYPTION].data)

+ +			TLV_GET_U32(sctx, BTRFS_SEND_A_ENCRYPTION, &encryption);

+ +		else

+ +			encryption = BTRFS_ENCODED_IO_ENCRYPTION_NONE;

+ +		TLV_GET(sctx, BTRFS_SEND_A_DATA, &data, &len);

+ +		ret = sctx->ops->encoded_write(path, data, offset, len,

+ +					       unencoded_file_len,

+ +					       unencoded_len, unencoded_offset,

+ +					       compression, encryption,

+ +					       sctx->user);

+ +		break;

+  	case BTRFS_SEND_C_CLONE:

+  		TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);

+  		TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);

+ diff --git a/common/send-stream.h b/common/send-stream.h

+ index 2de51eac..44abbc9d 100644

+ --- a/common/send-stream.h

+ +++ b/common/send-stream.h

+ @@ -53,6 +53,10 @@ struct btrfs_send_ops {

+  		      struct timespec *mt, struct timespec *ct,

+  		      void *user);

+  	int (*update_extent)(const char *path, u64 offset, u64 len, void *user);

+ +	int (*encoded_write)(const char *path, const void *data, u64 offset,

+ +			     u64 len, u64 unencoded_file_len, u64 unencoded_len,

+ +			     u64 unencoded_offset, u32 compression,

+ +			     u32 encryption, void *user);

+  };

+  

+  int btrfs_read_and_process_send_stream(int fd,

+ diff --git a/ioctl.h b/ioctl.h

+ index 368a87b2..8adf63c2 100644

+ --- a/ioctl.h

+ +++ b/ioctl.h

+ @@ -777,6 +777,134 @@ struct btrfs_ioctl_get_subvol_rootref_args {

+  };

+  BUILD_ASSERT(sizeof(struct btrfs_ioctl_get_subvol_rootref_args) == 4096);

+  

+ +/*

+ + * Data and metadata for an encoded read or write.

+ + *

+ + * Encoded I/O bypasses any encoding automatically done by the filesystem (e.g.,

+ + * compression). This can be used to read the compressed contents of a file or

+ + * write pre-compressed data directly to a file.

+ + *

+ + * BTRFS_IOC_ENCODED_READ and BTRFS_IOC_ENCODED_WRITE are essentially

+ + * preadv/pwritev with additional metadata about how the data is encoded and the

+ + * size of the unencoded data.

+ + *

+ + * BTRFS_IOC_ENCODED_READ fills the given iovecs with the encoded data, fills

+ + * the metadata fields, and returns the size of the encoded data. It reads one

+ + * extent per call. It can also read data which is not encoded.

+ + *

+ + * BTRFS_IOC_ENCODED_WRITE uses the metadata fields, writes the encoded data

+ + * from the iovecs, and returns the size of the encoded data. Note that the

+ + * encoded data is not validated when it is written; if it is not valid (e.g.,

+ + * it cannot be decompressed), then a subsequent read may return an error.

+ + *

+ + * Since the filesystem page cache contains decoded data, encoded I/O bypasses

+ + * the page cache. Encoded I/O requires CAP_SYS_ADMIN.

+ + */

+ +struct btrfs_ioctl_encoded_io_args {

+ +	/* Input parameters for both reads and writes. */

+ +

+ +	/*

+ +	 * iovecs containing encoded data.

+ +	 *

+ +	 * For reads, if the size of the encoded data is larger than the sum of

+ +	 * iov[n].iov_len for 0 <= n < iovcnt, then the ioctl fails with

+ +	 * ENOBUFS.

+ +	 *

+ +	 * For writes, the size of the encoded data is the sum of iov[n].iov_len

+ +	 * for 0 <= n < iovcnt. This must be less than 128 KiB (this limit may

+ +	 * increase in the future). This must also be less than or equal to

+ +	 * unencoded_len.

+ +	 */

+ +	const struct iovec __user *iov;

+ +	/* Number of iovecs. */

+ +	unsigned long iovcnt;

+ +	/*

+ +	 * Offset in file.

+ +	 *

+ +	 * For writes, must be aligned to the sector size of the filesystem.

+ +	 */

+ +	__s64 offset;

+ +	/* Currently must be zero. */

+ +	__u64 flags;

+ +

+ +	/*

+ +	 * For reads, the following members are output parameters that will

+ +	 * contain the returned metadata for the encoded data.

+ +	 * For writes, the following members must be set to the metadata for the

+ +	 * encoded data.

+ +	 */

+ +

+ +	/*

+ +	 * Length of the data in the file.

+ +	 *

+ +	 * Must be less than or equal to unencoded_len - unencoded_offset. For

+ +	 * writes, must be aligned to the sector size of the filesystem unless

+ +	 * the data ends at or beyond the current end of the file.

+ +	 */

+ +	__u64 len;

+ +	/*

+ +	 * Length of the unencoded (i.e., decrypted and decompressed) data.

+ +	 *

+ +	 * For writes, must be no more than 128 KiB (this limit may increase in

+ +	 * the future). If the unencoded data is actually longer than

+ +	 * unencoded_len, then it is truncated; if it is shorter, then it is

+ +	 * extended with zeroes.

+ +	 */

+ +	__u64 unencoded_len;

+ +	/*

+ +	 * Offset from the first byte of the unencoded data to the first byte of

+ +	 * logical data in the file.

+ +	 *

+ +	 * Must be less than unencoded_len.

+ +	 */

+ +	__u64 unencoded_offset;

+ +	/*

+ +	 * BTRFS_ENCODED_IO_COMPRESSION_* type.

+ +	 *

+ +	 * For writes, must not be BTRFS_ENCODED_IO_COMPRESSION_NONE.

+ +	 */

+ +	__u32 compression;

+ +	/* Currently always BTRFS_ENCODED_IO_ENCRYPTION_NONE. */

+ +	__u32 encryption;

+ +	/*

+ +	 * Reserved for future expansion.

+ +	 *

+ +	 * For reads, always returned as zero. Users should check for non-zero

+ +	 * bytes. If there are any, then the kernel has a newer version of this

+ +	 * structure with additional information that the user definition is

+ +	 * missing.

+ +	 *

+ +	 * For writes, must be zeroed.

+ +	 */

+ +	__u8 reserved[64];

+ +};

+ +

+ +/* Data is not compressed. */

+ +#define BTRFS_ENCODED_IO_COMPRESSION_NONE 0

+ +/* Data is compressed as a single zlib stream. */

+ +#define BTRFS_ENCODED_IO_COMPRESSION_ZLIB 1

+ +/*

+ + * Data is compressed as a single zstd frame with the windowLog compression

+ + * parameter set to no more than 17.

+ + */

+ +#define BTRFS_ENCODED_IO_COMPRESSION_ZSTD 2

+ +/*

+ + * Data is compressed sector by sector (using the sector size indicated by the

+ + * name of the constant) with LZO1X and wrapped in the format documented in

+ + * fs/btrfs/lzo.c. For writes, the compression sector size must match the

+ + * filesystem sector size.

+ + */

+ +#define BTRFS_ENCODED_IO_COMPRESSION_LZO_4K 3

+ +#define BTRFS_ENCODED_IO_COMPRESSION_LZO_8K 4

+ +#define BTRFS_ENCODED_IO_COMPRESSION_LZO_16K 5

+ +#define BTRFS_ENCODED_IO_COMPRESSION_LZO_32K 6

+ +#define BTRFS_ENCODED_IO_COMPRESSION_LZO_64K 7

+ +#define BTRFS_ENCODED_IO_COMPRESSION_TYPES 8

+ +

+ +/* Data is not encrypted. */

+ +#define BTRFS_ENCODED_IO_ENCRYPTION_NONE 0

+ +#define BTRFS_ENCODED_IO_ENCRYPTION_TYPES 1

+ +

+  /* Error codes as returned by the kernel */

+  enum btrfs_err_code {

+  	notused,

+ @@ -951,6 +1079,10 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)

+  				struct btrfs_ioctl_ino_lookup_user_args)

+  #define BTRFS_IOC_SNAP_DESTROY_V2 _IOW(BTRFS_IOCTL_MAGIC, 63, \

+  				   struct btrfs_ioctl_vol_args_v2)

+ +#define BTRFS_IOC_ENCODED_READ _IOR(BTRFS_IOCTL_MAGIC, 64, \

+ +				    struct btrfs_ioctl_encoded_io_args)

+ +#define BTRFS_IOC_ENCODED_WRITE _IOW(BTRFS_IOCTL_MAGIC, 64, \

+ +				     struct btrfs_ioctl_encoded_io_args)

+  

+  #ifdef __cplusplus

+  }

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,373 @@ 

+ From 8f5d9e7c4a6b9e923a02c1677854e2792822574a Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <boris@bur.io>

+ Date: Fri, 21 Aug 2020 00:40:06 -0700

+ Subject: [PATCH] btrfs-progs: receive: encoded_write fallback to explicit

+  decode and write

+ 

+ An encoded_write can fail if the file system it is being applied to does

+ not support encoded writes or if it can't find enough contiguous space

+ to accommodate the encoded extent. In those cases, we can likely still

+ process an encoded_write by explicitly decoding the data and doing a

+ normal write.

+ 

+ Add the necessary fallback path for decoding data compressed with zlib,

+ lzo, or zstd. zlib and zstd have reusable decoding context data

+ structures which we cache in the receive context so that we don't have

+ to recreate them on every encoded_write.

+ 

+ Finally, add a command line flag for force-decompress which causes

+ receive to always use the fallback path rather than first attempting the

+ encoded write.

+ 

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  Documentation/btrfs-receive.rst |   5 +

+  cmds/receive.c                  | 261 +++++++++++++++++++++++++++++++-

+  2 files changed, 259 insertions(+), 7 deletions(-)

+ 

+ diff --git a/Documentation/btrfs-receive.rst b/Documentation/btrfs-receive.rst

+ index 86ffdcc6..b9a3cad6 100644

+ --- a/Documentation/btrfs-receive.rst

+ +++ b/Documentation/btrfs-receive.rst

+ @@ -57,6 +57,11 @@ A subvolume is made read-only after the receiving process finishes successfully

+          If */proc* is not accessible, eg. in a chroot environment, use this option to

+          tell us where this filesystem is mounted.

+  

+ +--force-decompress

+ +        if the stream contains compressed data (see *--compressed-data* in

+ +        ``btrfs-send(8)``), always decompress it instead of writing it with

+ +        encoded I/O

+ +

+  --dump

+          dump the stream metadata, one line per operation

+  

+ diff --git a/cmds/receive.c b/cmds/receive.c

+ index 8226ca32..5fd939ce 100644

+ --- a/cmds/receive.c

+ +++ b/cmds/receive.c

+ @@ -40,6 +40,10 @@

+  #include <sys/xattr.h>

+  #include <uuid/uuid.h>

+  

+ +#include <lzo/lzo1x.h>

+ +#include <zlib.h>

+ +#include <zstd.h>

+ +

+  #include "kernel-shared/ctree.h"

+  #include "ioctl.h"

+  #include "cmds/commands.h"

+ @@ -75,6 +79,12 @@ struct btrfs_receive

+  	char cur_subvol_path[PATH_MAX];

+  

+  	int honor_end_cmd;

+ +

+ +	bool force_decompress;

+ +

+ +	/* Reuse stream objects for encoded_write decompression fallback */

+ +	ZSTD_DStream *zstd_dstream;

+ +	z_stream *zlib_stream;

+  };

+  

+  static int finish_subvol(struct btrfs_receive *rctx)

+ @@ -985,6 +995,219 @@ static int process_update_extent(const char *path, u64 offset, u64 len,

+  	return 0;

+  }

+  

+ +static int decompress_zlib(struct btrfs_receive *rctx, const char *encoded_data,

+ +			   u64 encoded_len, char *unencoded_data,

+ +			   u64 unencoded_len)

+ +{

+ +	bool init = false;

+ +	int ret;

+ +

+ +	if (!rctx->zlib_stream) {

+ +		init = true;

+ +		rctx->zlib_stream = malloc(sizeof(z_stream));

+ +		if (!rctx->zlib_stream) {

+ +			error("failed to allocate zlib stream %m");

+ +			return -ENOMEM;

+ +		}

+ +	}

+ +	rctx->zlib_stream->next_in = (void *)encoded_data;

+ +	rctx->zlib_stream->avail_in = encoded_len;

+ +	rctx->zlib_stream->next_out = (void *)unencoded_data;

+ +	rctx->zlib_stream->avail_out = unencoded_len;

+ +

+ +	if (init) {

+ +		rctx->zlib_stream->zalloc = Z_NULL;

+ +		rctx->zlib_stream->zfree = Z_NULL;

+ +		rctx->zlib_stream->opaque = Z_NULL;

+ +		ret = inflateInit(rctx->zlib_stream);

+ +	} else {

+ +		ret = inflateReset(rctx->zlib_stream);

+ +	}

+ +	if (ret != Z_OK) {

+ +		error("zlib inflate init failed: %d", ret);

+ +		return -EIO;

+ +	}

+ +

+ +	while (rctx->zlib_stream->avail_in > 0 &&

+ +	       rctx->zlib_stream->avail_out > 0) {

+ +		ret = inflate(rctx->zlib_stream, Z_FINISH);

+ +		if (ret == Z_STREAM_END) {

+ +			break;

+ +		} else if (ret != Z_OK) {

+ +			error("zlib inflate failed: %d", ret);

+ +			return -EIO;

+ +		}

+ +	}

+ +	return 0;

+ +}

+ +

+ +static int decompress_zstd(struct btrfs_receive *rctx, const char *encoded_buf,

+ +			   u64 encoded_len, char *unencoded_buf,

+ +			   u64 unencoded_len)

+ +{

+ +	ZSTD_inBuffer in_buf = {

+ +		.src = encoded_buf,

+ +		.size = encoded_len

+ +	};

+ +	ZSTD_outBuffer out_buf = {

+ +		.dst = unencoded_buf,

+ +		.size = unencoded_len

+ +	};

+ +	size_t ret;

+ +

+ +	if (!rctx->zstd_dstream) {

+ +		rctx->zstd_dstream = ZSTD_createDStream();

+ +		if (!rctx->zstd_dstream) {

+ +			error("failed to create zstd dstream");

+ +			return -ENOMEM;

+ +		}

+ +	}

+ +	ret = ZSTD_initDStream(rctx->zstd_dstream);

+ +	if (ZSTD_isError(ret)) {

+ +		error("failed to init zstd stream: %s", ZSTD_getErrorName(ret));

+ +		return -EIO;

+ +	}

+ +	while (in_buf.pos < in_buf.size && out_buf.pos < out_buf.size) {

+ +		ret = ZSTD_decompressStream(rctx->zstd_dstream, &out_buf, &in_buf);

+ +		if (ret == 0) {

+ +			break;

+ +		} else if (ZSTD_isError(ret)) {

+ +			error("failed to decompress zstd stream: %s",

+ +			      ZSTD_getErrorName(ret));

+ +			return -EIO;

+ +		}

+ +	}

+ +	return 0;

+ +}

+ +

+ +static int decompress_lzo(const char *encoded_data, u64 encoded_len,

+ +			  char *unencoded_data, u64 unencoded_len,

+ +			  unsigned int sector_size)

+ +{

+ +	uint32_t total_len;

+ +	size_t in_pos, out_pos;

+ +

+ +	if (encoded_len < 4) {

+ +		error("lzo header is truncated");

+ +		return -EIO;

+ +	}

+ +	memcpy(&total_len, encoded_data, 4);

+ +	total_len = le32toh(total_len);

+ +	if (total_len > encoded_len) {

+ +		error("lzo header is invalid");

+ +		return -EIO;

+ +	}

+ +

+ +	in_pos = 4;

+ +	out_pos = 0;

+ +	while (in_pos < total_len && out_pos < unencoded_len) {

+ +		size_t sector_remaining;

+ +		uint32_t src_len;

+ +		lzo_uint dst_len;

+ +		int ret;

+ +

+ +		sector_remaining = -in_pos % sector_size;

+ +		if (sector_remaining < 4) {

+ +			if (total_len - in_pos <= sector_remaining)

+ +				break;

+ +			in_pos += sector_remaining;

+ +		}

+ +

+ +		if (total_len - in_pos < 4) {

+ +			error("lzo segment header is truncated");

+ +			return -EIO;

+ +		}

+ +

+ +		memcpy(&src_len, encoded_data + in_pos, 4);

+ +		src_len = le32toh(src_len);

+ +		in_pos += 4;

+ +		if (src_len > total_len - in_pos) {

+ +			error("lzo segment header is invalid");

+ +			return -EIO;

+ +		}

+ +

+ +		dst_len = sector_size;

+ +		ret = lzo1x_decompress_safe((void *)(encoded_data + in_pos),

+ +					    src_len,

+ +					    (void *)(unencoded_data + out_pos),

+ +					    &dst_len, NULL);

+ +		if (ret != LZO_E_OK) {

+ +			error("lzo1x_decompress_safe failed: %d", ret);

+ +			return -EIO;

+ +		}

+ +

+ +		in_pos += src_len;

+ +		out_pos += dst_len;

+ +	}

+ +	return 0;

+ +}

+ +

+ +static int decompress_and_write(struct btrfs_receive *rctx,

+ +				const char *encoded_data, u64 offset,

+ +				u64 encoded_len, u64 unencoded_file_len,

+ +				u64 unencoded_len, u64 unencoded_offset,

+ +				u32 compression)

+ +{

+ +	int ret = 0;

+ +	size_t pos;

+ +	ssize_t w;

+ +	char *unencoded_data;

+ +	int sector_shift;

+ +

+ +	unencoded_data = calloc(unencoded_len, 1);

+ +	if (!unencoded_data) {

+ +		error("allocating space for unencoded data failed: %m");

+ +		return -errno;

+ +	}

+ +

+ +	switch (compression) {

+ +	case BTRFS_ENCODED_IO_COMPRESSION_ZLIB:

+ +		ret = decompress_zlib(rctx, encoded_data, encoded_len,

+ +				      unencoded_data, unencoded_len);

+ +		if (ret)

+ +			goto out;

+ +		break;

+ +	case BTRFS_ENCODED_IO_COMPRESSION_ZSTD:

+ +		ret = decompress_zstd(rctx, encoded_data, encoded_len,

+ +				      unencoded_data, unencoded_len);

+ +		if (ret)

+ +			goto out;

+ +		break;

+ +	case BTRFS_ENCODED_IO_COMPRESSION_LZO_4K:

+ +	case BTRFS_ENCODED_IO_COMPRESSION_LZO_8K:

+ +	case BTRFS_ENCODED_IO_COMPRESSION_LZO_16K:

+ +	case BTRFS_ENCODED_IO_COMPRESSION_LZO_32K:

+ +	case BTRFS_ENCODED_IO_COMPRESSION_LZO_64K:

+ +		sector_shift =

+ +			compression - BTRFS_ENCODED_IO_COMPRESSION_LZO_4K + 12;

+ +		ret = decompress_lzo(encoded_data, encoded_len, unencoded_data,

+ +				     unencoded_len, 1U << sector_shift);

+ +		if (ret)

+ +			goto out;

+ +		break;

+ +	default:

+ +		error("unknown compression: %d", compression);

+ +		ret = -EOPNOTSUPP;

+ +		goto out;

+ +	}

+ +

+ +	pos = unencoded_offset;

+ +	while (pos < unencoded_file_len) {

+ +		w = pwrite(rctx->write_fd, unencoded_data + pos,

+ +			   unencoded_file_len - pos, offset);

+ +		if (w < 0) {

+ +			ret = -errno;

+ +			error("writing unencoded data failed: %m");

+ +			goto out;

+ +		}

+ +		pos += w;

+ +		offset += w;

+ +	}

+ +out:

+ +	free(unencoded_data);

+ +	return ret;

+ +}

+ +

+  static int process_encoded_write(const char *path, const void *data, u64 offset,

+  				 u64 len, u64 unencoded_file_len,

+  				 u64 unencoded_len, u64 unencoded_offset,

+ @@ -1020,13 +1243,21 @@ static int process_encoded_write(const char *path, const void *data, u64 offset,

+  	if (ret < 0)

+  		return ret;

+  

+ -	ret = ioctl(rctx->write_fd, BTRFS_IOC_ENCODED_WRITE, &encoded);

+ -	if (ret < 0) {

+ -		ret = -errno;

+ -		error("encoded_write: writing to %s failed: %m", path);

+ -		return ret;

+ +	if (!rctx->force_decompress) {

+ +		ret = ioctl(rctx->write_fd, BTRFS_IOC_ENCODED_WRITE, &encoded);

+ +		if (ret >= 0)

+ +			return 0;

+ +		/* Fall back for these errors, fail hard for anything else. */

+ +		if (errno != ENOSPC && errno != ENOTTY && errno != EINVAL) {

+ +			ret = -errno;

+ +			error("encoded_write: writing to %s failed: %m", path);

+ +			return ret;

+ +		}

+  	}

+ -	return 0;

+ +

+ +	return decompress_and_write(rctx, data, offset, len, unencoded_file_len,

+ +				    unencoded_len, unencoded_offset,

+ +				    compression);

+  }

+  

+  static struct btrfs_send_ops send_ops = {

+ @@ -1204,6 +1435,12 @@ out:

+  		close(rctx->dest_dir_fd);

+  		rctx->dest_dir_fd = -1;

+  	}

+ +	if (rctx->zstd_dstream)

+ +		ZSTD_freeDStream(rctx->zstd_dstream);

+ +	if (rctx->zlib_stream) {

+ +		inflateEnd(rctx->zlib_stream);

+ +		free(rctx->zlib_stream);

+ +	}

+  

+  	return ret;

+  }

+ @@ -1234,6 +1471,9 @@ static const char * const cmd_receive_usage[] = {

+  	"-m ROOTMOUNT     the root mount point of the destination filesystem.",

+  	"                 If /proc is not accessible, use this to tell us where",

+  	"                 this file system is mounted.",

+ +	"--force-decompress",

+ +	"                 if the stream contains compressed data, always",

+ +	"                 decompress it instead of writing it with encoded I/O",

+  	"--dump           dump stream metadata, one line per operation,",

+  	"                 does not require the MOUNT parameter",

+  	"-v               deprecated, alias for global -v option",

+ @@ -1277,12 +1517,16 @@ static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)

+  	optind = 0;

+  	while (1) {

+  		int c;

+ -		enum { GETOPT_VAL_DUMP = 257 };

+ +		enum {

+ +			GETOPT_VAL_DUMP = 257,

+ +			GETOPT_VAL_FORCE_DECOMPRESS,

+ +		};

+  		static const struct option long_opts[] = {

+  			{ "max-errors", required_argument, NULL, 'E' },

+  			{ "chroot", no_argument, NULL, 'C' },

+  			{ "dump", no_argument, NULL, GETOPT_VAL_DUMP },

+  			{ "quiet", no_argument, NULL, 'q' },

+ +			{ "force-decompress", no_argument, NULL, GETOPT_VAL_FORCE_DECOMPRESS },

+  			{ NULL, 0, NULL, 0 }

+  		};

+  

+ @@ -1325,6 +1569,9 @@ static int cmd_receive(const struct cmd_struct *cmd, int argc, char **argv)

+  		case GETOPT_VAL_DUMP:

+  			dump = 1;

+  			break;

+ +		case GETOPT_VAL_FORCE_DECOMPRESS:

+ +			rctx.force_decompress = true;

+ +			break;

+  		default:

+  			usage_unknown_option(cmd, argv);

+  		}

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,130 @@ 

+ From 3e92b1e0b97146516f4287f5e42428a3b7dc4a3d Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <boris@bur.io>

+ Date: Fri, 21 Aug 2020 00:40:07 -0700

+ Subject: [PATCH] btrfs-progs: receive: process fallocate commands

+ 

+ Send stream v2 can emit fallocate commands, so receive must support them

+ as well. The implementation simply passes along the arguments to the

+ syscall. Note that mode is encoded as a u32 in send stream but fallocate

+ takes an int, so there is a unsigned->signed conversion there.

+ 

+ Reviewed-by: Nikolay Borisov <nborisov@suse.com>

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  cmds/receive-dump.c  |  9 +++++++++

+  cmds/receive.c       | 25 +++++++++++++++++++++++++

+  common/send-stream.c |  9 +++++++++

+  common/send-stream.h |  2 ++

+  4 files changed, 45 insertions(+)

+ 

+ diff --git a/cmds/receive-dump.c b/cmds/receive-dump.c

+ index 83701b62..fa397bcf 100644

+ --- a/cmds/receive-dump.c

+ +++ b/cmds/receive-dump.c

+ @@ -331,6 +331,14 @@ static int print_encoded_write(const char *path, const void *data, u64 offset,

+  			  unencoded_offset, compression, encryption);

+  }

+  

+ +static int print_fallocate(const char *path, int mode, u64 offset, u64 len,

+ +			   void *user)

+ +{

+ +	return PRINT_DUMP(user, path, "fallocate",

+ +			  "mode=%d offset=%llu len=%llu",

+ +			  mode, offset, len);

+ +}

+ +

+  struct btrfs_send_ops btrfs_print_send_ops = {

+  	.subvol = print_subvol,

+  	.snapshot = print_snapshot,

+ @@ -354,4 +362,5 @@ struct btrfs_send_ops btrfs_print_send_ops = {

+  	.utimes = print_utimes,

+  	.update_extent = print_update_extent,

+  	.encoded_write = print_encoded_write,

+ +	.fallocate = print_fallocate,

+  };

+ diff --git a/cmds/receive.c b/cmds/receive.c

+ index 5fd939ce..4893d693 100644

+ --- a/cmds/receive.c

+ +++ b/cmds/receive.c

+ @@ -1260,6 +1260,30 @@ static int process_encoded_write(const char *path, const void *data, u64 offset,

+  				    compression);

+  }

+  

+ +static int process_fallocate(const char *path, int mode, u64 offset, u64 len,

+ +			     void *user)

+ +{

+ +	int ret;

+ +	struct btrfs_receive *rctx = user;

+ +	char full_path[PATH_MAX];

+ +

+ +	ret = path_cat_out(full_path, rctx->full_subvol_path, path);

+ +	if (ret < 0) {

+ +		error("fallocate: path invalid: %s", path);

+ +		return ret;

+ +	}

+ +	ret = open_inode_for_write(rctx, full_path);

+ +	if (ret < 0)

+ +		return ret;

+ +	ret = fallocate(rctx->write_fd, mode, offset, len);

+ +	if (ret < 0) {

+ +		ret = -errno;

+ +		error("fallocate: fallocate on %s failed: %m", path);

+ +		return ret;

+ +	}

+ +	return 0;

+ +}

+ +

+  static struct btrfs_send_ops send_ops = {

+  	.subvol = process_subvol,

+  	.snapshot = process_snapshot,

+ @@ -1283,6 +1307,7 @@ static struct btrfs_send_ops send_ops = {

+  	.utimes = process_utimes,

+  	.update_extent = process_update_extent,

+  	.encoded_write = process_encoded_write,

+ +	.fallocate = process_fallocate,

+  };

+  

+  static int do_receive(struct btrfs_receive *rctx, const char *tomnt,

+ diff --git a/common/send-stream.c b/common/send-stream.c

+ index ce7c40f5..2d0aa624 100644

+ --- a/common/send-stream.c

+ +++ b/common/send-stream.c

+ @@ -373,6 +373,7 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)

+  	u64 unencoded_offset;

+  	int len;

+  	int xattr_len;

+ +	int fallocate_mode;

+  

+  	ret = read_cmd(sctx);

+  	if (ret)

+ @@ -537,6 +538,14 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)

+  	case BTRFS_SEND_C_END:

+  		ret = 1;

+  		break;

+ +	case BTRFS_SEND_C_FALLOCATE:

+ +		TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);

+ +		TLV_GET_U32(sctx, BTRFS_SEND_A_FALLOCATE_MODE, &fallocate_mode);

+ +		TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);

+ +		TLV_GET_U64(sctx, BTRFS_SEND_A_SIZE, &tmp);

+ +		ret = sctx->ops->fallocate(path, fallocate_mode, offset, tmp,

+ +					   sctx->user);

+ +		break;

+  	}

+  

+  tlv_get_failed:

+ diff --git a/common/send-stream.h b/common/send-stream.h

+ index 44abbc9d..61a88d3d 100644

+ --- a/common/send-stream.h

+ +++ b/common/send-stream.h

+ @@ -57,6 +57,8 @@ struct btrfs_send_ops {

+  			     u64 len, u64 unencoded_file_len, u64 unencoded_len,

+  			     u64 unencoded_offset, u32 compression,

+  			     u32 encryption, void *user);

+ +	int (*fallocate)(const char *path, int mode, u64 offset, u64 len,

+ +			 void *user);

+  };

+  

+  int btrfs_read_and_process_send_stream(int fd,

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,132 @@ 

+ From 6e8d60a8c9ab22c489c0707ffd854bf1db9852f4 Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <boris@bur.io>

+ Date: Fri, 21 Aug 2020 00:40:08 -0700

+ Subject: [PATCH] btrfs-progs: receive: process setflags ioctl commands

+ 

+ In send stream v2, send can emit a command for setting inode flags via

+ the setflags ioctl. Pass the flags attribute through to the ioctl call

+ in receive.

+ 

+ Reviewed-by: Nikolay Borisov <nborisov@suse.com>

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  cmds/receive-dump.c  |  6 ++++++

+  cmds/receive.c       | 25 +++++++++++++++++++++++++

+  common/send-stream.c |  7 +++++++

+  common/send-stream.h |  1 +

+  4 files changed, 39 insertions(+)

+ 

+ diff --git a/cmds/receive-dump.c b/cmds/receive-dump.c

+ index fa397bcf..df5991e1 100644

+ --- a/cmds/receive-dump.c

+ +++ b/cmds/receive-dump.c

+ @@ -339,6 +339,11 @@ static int print_fallocate(const char *path, int mode, u64 offset, u64 len,

+  			  mode, offset, len);

+  }

+  

+ +static int print_setflags(const char *path, int flags, void *user)

+ +{

+ +	return PRINT_DUMP(user, path, "setflags", "flags=%d", flags);

+ +}

+ +

+  struct btrfs_send_ops btrfs_print_send_ops = {

+  	.subvol = print_subvol,

+  	.snapshot = print_snapshot,

+ @@ -363,4 +368,5 @@ struct btrfs_send_ops btrfs_print_send_ops = {

+  	.update_extent = print_update_extent,

+  	.encoded_write = print_encoded_write,

+  	.fallocate = print_fallocate,

+ +	.setflags = print_setflags,

+  };

+ diff --git a/cmds/receive.c b/cmds/receive.c

+ index 4893d693..7f76a04f 100644

+ --- a/cmds/receive.c

+ +++ b/cmds/receive.c

+ @@ -38,6 +38,7 @@

+  #include <sys/types.h>

+  #include <sys/uio.h>

+  #include <sys/xattr.h>

+ +#include <linux/fs.h>

+  #include <uuid/uuid.h>

+  

+  #include <lzo/lzo1x.h>

+ @@ -1284,6 +1285,29 @@ static int process_fallocate(const char *path, int mode, u64 offset, u64 len,

+  	return 0;

+  }

+  

+ +static int process_setflags(const char *path, int flags, void *user)

+ +{

+ +	int ret;

+ +	struct btrfs_receive *rctx = user;

+ +	char full_path[PATH_MAX];

+ +

+ +	ret = path_cat_out(full_path, rctx->full_subvol_path, path);

+ +	if (ret < 0) {

+ +		error("setflags: path invalid: %s", path);

+ +		return ret;

+ +	}

+ +	ret = open_inode_for_write(rctx, full_path);

+ +	if (ret < 0)

+ +		return ret;

+ +	ret = ioctl(rctx->write_fd, FS_IOC_SETFLAGS, &flags);

+ +	if (ret < 0) {

+ +		ret = -errno;

+ +		error("setflags: setflags ioctl on %s failed: %m", path);

+ +		return ret;

+ +	}

+ +	return 0;

+ +}

+ +

+  static struct btrfs_send_ops send_ops = {

+  	.subvol = process_subvol,

+  	.snapshot = process_snapshot,

+ @@ -1308,6 +1332,7 @@ static struct btrfs_send_ops send_ops = {

+  	.update_extent = process_update_extent,

+  	.encoded_write = process_encoded_write,

+  	.fallocate = process_fallocate,

+ +	.setflags = process_setflags,

+  };

+  

+  static int do_receive(struct btrfs_receive *rctx, const char *tomnt,

+ diff --git a/common/send-stream.c b/common/send-stream.c

+ index 2d0aa624..21295cbb 100644

+ --- a/common/send-stream.c

+ +++ b/common/send-stream.c

+ @@ -374,6 +374,7 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)

+  	int len;

+  	int xattr_len;

+  	int fallocate_mode;

+ +	int setflags_flags;

+  

+  	ret = read_cmd(sctx);

+  	if (ret)

+ @@ -546,8 +547,14 @@ static int read_and_process_cmd(struct btrfs_send_stream *sctx)

+  		ret = sctx->ops->fallocate(path, fallocate_mode, offset, tmp,

+  					   sctx->user);

+  		break;

+ +	case BTRFS_SEND_C_SETFLAGS:

+ +		TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);

+ +		TLV_GET_U32(sctx, BTRFS_SEND_A_SETFLAGS_FLAGS, &setflags_flags);

+ +		ret = sctx->ops->setflags(path, setflags_flags, sctx->user);

+ +		break;

+  	}

+  

+ +

+  tlv_get_failed:

+  out:

+  	free(path);

+ diff --git a/common/send-stream.h b/common/send-stream.h

+ index 61a88d3d..3189f889 100644

+ --- a/common/send-stream.h

+ +++ b/common/send-stream.h

+ @@ -59,6 +59,7 @@ struct btrfs_send_ops {

+  			     u32 encryption, void *user);

+  	int (*fallocate)(const char *path, int mode, u64 offset, u64 len,

+  			 void *user);

+ +	int (*setflags)(const char *path, int flags, void *user);

+  };

+  

+  int btrfs_read_and_process_send_stream(int fd,

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,297 @@ 

+ From caaa44c482a3aae46d8a883cc60b6caf2d47bc75 Mon Sep 17 00:00:00 2001

+ From: Omar Sandoval <osandov@fb.com>

+ Date: Wed, 9 Feb 2022 17:10:59 -0800

+ Subject: [PATCH] btrfs-progs: send: stream v2 ioctl flags

+ 

+ First, add a --proto option to allow specifying the desired send

+ protocol version. It defaults to one, the original version. In a couple

+ of releases once people are aware that protocol revisions are happening,

+ we can change it to default to zero, which means the latest version

+ supported by the kernel. This is based on Dave Sterba's patch.

+ 

+ Also add a --compressed-data flag to instruct the kernel to use

+ encoded_write commands for compressed extents. This requires an explicit

+ opt in separate from the protocol version because:

+ 

+ 1. The user may not want compression on the receiving side, or may want

+    a different compression algorithm/level on the receiving side.

+ 2. It has a soft requirement for kernel support on the receiving side

+    (btrfs-progs can fall back to decompressing and writing if the kernel

+    doesn't support BTRFS_IOC_ENCODED_WRITE, but the user may not be

+    prepared to pay that CPU cost). Going forward, since it's easier to

+    update progs than the kernel, I think we'll want to make new send

+    features that require kernel support opt-in, whereas anything that

+    only requires a progs update can happen automatically.

+ 

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ Signed-off-by: Omar Sandoval <osandov@fb.com>

+ ---

+  Documentation/btrfs-send.rst |  22 ++++++++

+  cmds/send.c                  | 100 ++++++++++++++++++++++++++++++++++-

+  ioctl.h                      |  19 ++++++-

+  kernel-shared/send.h         |   2 +-

+  4 files changed, 138 insertions(+), 5 deletions(-)

+ 

+ diff --git a/Documentation/btrfs-send.rst b/Documentation/btrfs-send.rst

+ index 4526532e..291c537e 100644

+ --- a/Documentation/btrfs-send.rst

+ +++ b/Documentation/btrfs-send.rst

+ @@ -60,6 +60,28 @@ please see section *SUBVOLUME FLAGS* in ``btrfs-subvolume(8)``.

+          used to transfer changes. This mode is faster and is useful to show the

+          differences in metadata.

+  

+ +--proto <N>

+ +        use send protocol version N

+ +

+ +        The default is 1, which was the original protocol version. Version 2

+ +        encodes file data slightly more efficiently; it is also required for

+ +        sending compressed data directly (see *--compressed-data*). Version 2

+ +        requires at least btrfs-progs 5.18 on both the sender and receiver and

+ +        at least Linux 5.18 on the sender. Passing 0 means to use the highest

+ +        version supported by the running kernel.

+ +

+ +--compressed-data

+ +        send data that is compressed on the filesystem directly without

+ +        decompressing it

+ +

+ +        If the receiver supports the *BTRFS_IOC_ENCODED_WRITE* ioctl (added in

+ +        Linux 5.18), it can also write it directly without decompressing it.

+ +        Otherwise, the receiver will fall back to decompressing it and writing

+ +        it normally.

+ +

+ +        This requires protocol version 2 or higher. If *--proto* was not used,

+ +        then *--compressed-data* implies *--proto 2*.

+ +

+  -q|--quiet

+          (deprecated) alias for global *-q* option

+  

+ diff --git a/cmds/send.c b/cmds/send.c

+ index 087af05c..b1adfeca 100644

+ --- a/cmds/send.c

+ +++ b/cmds/send.c

+ @@ -57,6 +57,8 @@ struct btrfs_send {

+  	u64 clone_sources_count;

+  

+  	char *root_path;

+ +	u32 proto;

+ +	u32 proto_supported;

+  };

+  

+  static int get_root_id(struct btrfs_send *sctx, const char *path, u64 *root_id)

+ @@ -259,6 +261,16 @@ static int do_send(struct btrfs_send *send, u64 parent_root_id,

+  	memset(&io_send, 0, sizeof(io_send));

+  	io_send.send_fd = pipefd[1];

+  	send->send_fd = pipefd[0];

+ +	io_send.flags = flags;

+ +

+ +	if (send->proto_supported > 1) {

+ +		/*

+ +		 * Versioned stream supported, requesting default or specific

+ +		 * number.

+ +		 */

+ +		io_send.version = send->proto;

+ +		io_send.flags |= BTRFS_SEND_FLAG_VERSION;

+ +	}

+  

+  	if (!ret)

+  		ret = pthread_create(&t_read, NULL, read_sent_data, send);

+ @@ -269,7 +281,6 @@ static int do_send(struct btrfs_send *send, u64 parent_root_id,

+  		goto out;

+  	}

+  

+ -	io_send.flags = flags;

+  	io_send.clone_sources = (__u64*)send->clone_sources;

+  	io_send.clone_sources_count = send->clone_sources_count;

+  	io_send.parent_root = parent_root_id;

+ @@ -421,6 +432,36 @@ static void free_send_info(struct btrfs_send *sctx)

+  	sctx->root_path = NULL;

+  }

+  

+ +static u32 get_sysfs_proto_supported(void)

+ +{

+ +	int fd;

+ +	int ret;

+ +	char buf[32] = {};

+ +	char *end = NULL;

+ +	u64 version;

+ +

+ +	fd = sysfs_open_file("features/send_stream_version");

+ +	if (fd < 0) {

+ +		/*

+ +		 * No file is either no version support or old kernel with just

+ +		 * v1.

+ +		 */

+ +		return 1;

+ +	}

+ +	ret = sysfs_read_file(fd, buf, sizeof(buf));

+ +	close(fd);

+ +	if (ret <= 0)

+ +		return 1;

+ +	version = strtoull(buf, &end, 10);

+ +	if (version == ULLONG_MAX && errno == ERANGE)

+ +		return 1;

+ +	if (version > U32_MAX) {

+ +		warning("sysfs/send_stream_version too big: %llu", version);

+ +		version = 1;

+ +	}

+ +	return version;

+ +}

+ +

+  static const char * const cmd_send_usage[] = {

+  	"btrfs send [-ve] [-p <parent>] [-c <clone-src>] [-f <outfile>] <subvol> [<subvol>...]",

+  	"Send the subvolume(s) to stdout.",

+ @@ -449,6 +490,11 @@ static const char * const cmd_send_usage[] = {

+  	"                 does not contain any file data and thus cannot be used",

+  	"                 to transfer changes. This mode is faster and useful to",

+  	"                 show the differences in metadata.",

+ +	"--proto N        use protocol version N, or 0 to use the highest version",

+ +	"                 supported by the sending kernel (default: 1)",

+ +	"--compressed-data",

+ +	"                 send data that is compressed on the filesystem directly",

+ +	"                 without decompressing it",

+  	"-v|--verbose     deprecated, alias for global -v option",

+  	"-q|--quiet       deprecated, alias for global -q option",

+  	HELPINFO_INSERT_GLOBALS,

+ @@ -471,9 +517,11 @@ 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;

+ +	u64 proto = 0;

+  

+  	memset(&send, 0, sizeof(send));

+  	send.dump_fd = fileno(stdout);

+ +	send.proto = 1;

+  	outname[0] = 0;

+  

+  	/*

+ @@ -489,11 +537,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_PROTO,

+ +			GETOPT_VAL_COMPRESSED_DATA,

+ +		};

+  		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 },

+ +			{ "proto", required_argument, NULL, GETOPT_VAL_PROTO },

+ +			{ "compressed-data", no_argument, NULL, GETOPT_VAL_COMPRESSED_DATA },

+  			{ NULL, 0, NULL, 0 }

+  		};

+  		int c = getopt_long(argc, argv, "vqec:f:i:p:", long_options, NULL);

+ @@ -582,6 +636,18 @@ 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_PROTO:

+ +			proto = arg_strtou64(optarg);

+ +			if (proto > U32_MAX) {

+ +				error("protocol version number too big %llu", proto);

+ +				ret = 1;

+ +				goto out;

+ +			}

+ +			send.proto = proto;

+ +			break;

+ +		case GETOPT_VAL_COMPRESSED_DATA:

+ +			send_flags |= BTRFS_SEND_FLAG_COMPRESSED;

+ +			break;

+  		default:

+  			usage_unknown_option(cmd, argv);

+  		}

+ @@ -689,6 +755,36 @@ static int cmd_send(const struct cmd_struct *cmd, int argc, char **argv)

+  	if ((send_flags & BTRFS_SEND_FLAG_NO_FILE_DATA) && bconf.verbose > 1)

+  		if (bconf.verbose > 1)

+  			fprintf(stderr, "Mode NO_FILE_DATA enabled\n");

+ +	send.proto_supported = get_sysfs_proto_supported();

+ +	if (send.proto_supported == 1) {

+ +		if (send.proto > send.proto_supported) {

+ +			error("requested version %u but kernel supports only %u",

+ +			      send.proto, send.proto_supported);

+ +			ret = -EPROTO;

+ +			goto out;

+ +		}

+ +	}

+ +	if (send_flags & BTRFS_SEND_FLAG_COMPRESSED) {

+ +		/*

+ +		 * If no protocol version was explicitly requested, then

+ +		 * --compressed-data implies --proto 2.

+ +		 */

+ +		if (send.proto == 1 && !proto)

+ +			send.proto = 2;

+ +

+ +		if (send.proto == 1) {

+ +			error("--compressed-data requires protocol version >= 2 (requested 1)");

+ +			ret = -EINVAL;

+ +			goto out;

+ +		} else if (send.proto == 0 && send.proto_supported < 2) {

+ +			error("kernel does not support --compressed-data");

+ +			ret = -EINVAL;

+ +			goto out;

+ +		}

+ +	}

+ +	if (bconf.verbose > 1)

+ +		fprintf(stderr, "Protocol version requested: %u (supported %u)\n",

+ +			send.proto, send.proto_supported);

+  

+  	for (i = optind; i < argc; i++) {

+  		int is_first_subvol;

+ diff --git a/ioctl.h b/ioctl.h

+ index 8adf63c2..f19695e3 100644

+ --- a/ioctl.h

+ +++ b/ioctl.h

+ @@ -655,10 +655,24 @@ BUILD_ASSERT(sizeof(struct btrfs_ioctl_received_subvol_args_32) == 192);

+   */

+  #define BTRFS_SEND_FLAG_OMIT_END_CMD		0x4

+  

+ +/*

+ + * Read the protocol version in the structure

+ + */

+ +#define BTRFS_SEND_FLAG_VERSION			0x8

+ +

+ +/*

+ + * Send compressed data using the ENCODED_WRITE command instead of decompressing

+ + * the data and sending it with the WRITE command. This requires protocol

+ + * version >= 2.

+ + */

+ +#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_VERSION | \

+ +	 BTRFS_SEND_FLAG_COMPRESSED)

+  

+  struct btrfs_ioctl_send_args {

+  	__s64 send_fd;			/* in */

+ @@ -666,7 +680,8 @@ struct btrfs_ioctl_send_args {

+  	__u64 __user *clone_sources;	/* in */

+  	__u64 parent_root;		/* in */

+  	__u64 flags;			/* in */

+ -	__u64 reserved[4];		/* in */

+ +	__u32 version;			/* in */

+ +	__u8 reserved[28];		/* in */

+  };

+  /*

+   * Size of structure depends on pointer width, was not caught in the early

+ diff --git a/kernel-shared/send.h b/kernel-shared/send.h

+ index b902d054..1f20d01a 100644

+ --- a/kernel-shared/send.h

+ +++ b/kernel-shared/send.h

+ @@ -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

+  

+  /*

+   * In send stream v1, no command is larger than 64k. In send stream v2, no limit

+ -- 

+ 2.35.1

+ 

@@ -0,0 +1,141 @@ 

+ From 6b974c6b3235cb83eb3e8c30a47706529f88d197 Mon Sep 17 00:00:00 2001

+ From: Boris Burkov <boris@bur.io>

+ Date: Fri, 21 Aug 2020 00:40:10 -0700

+ Subject: [PATCH] btrfs-progs: receive: add tests for basic encoded_write

+  send/receive

+ 

+ Adapt the existing send/receive tests by passing '-o compress-force' to

+ the mount commands in a new test. After writing a few files in the

+ various compression formats, send/receive them with and without

+ --force-decompress to test both the encoded_write path and the fallback

+ to decode+write.

+ 

+ Signed-off-by: Boris Burkov <boris@bur.io>

+ ---

+  .../052-receive-write-encoded/test.sh         | 114 ++++++++++++++++++

+  1 file changed, 114 insertions(+)

+  create mode 100755 tests/misc-tests/052-receive-write-encoded/test.sh

+ 

+ diff --git a/tests/misc-tests/052-receive-write-encoded/test.sh b/tests/misc-tests/052-receive-write-encoded/test.sh

+ new file mode 100755

+ index 00000000..47330281

+ --- /dev/null

+ +++ b/tests/misc-tests/052-receive-write-encoded/test.sh

+ @@ -0,0 +1,114 @@

+ +#!/bin/bash

+ +#

+ +# test that we can send and receive encoded writes for three modes of

+ +# transparent compression: zlib, lzo, and zstd.

+ +

+ +source "$TEST_TOP/common"

+ +

+ +check_prereq mkfs.btrfs

+ +check_prereq btrfs

+ +

+ +setup_root_helper

+ +prepare_test_dev

+ +

+ +here=`pwd`

+ +

+ +# assumes the filesystem exists, and does mount, write, snapshot, send, unmount

+ +# for the specified encoding option

+ +send_one() {

+ +	local str

+ +	local subv

+ +	local snap

+ +

+ +	algorithm="$1"

+ +	shift

+ +	str="$1"

+ +	shift

+ +

+ +	subv="subv-$algorithm"

+ +	snap="snap-$algorithm"

+ +

+ +	run_check_mount_test_dev "-o" "compress-force=$algorithm"

+ +	cd "$TEST_MNT" || _fail "cannot chdir to TEST_MNT"

+ +

+ +	run_check $SUDO_HELPER "$TOP/btrfs" subvolume create "$subv"

+ +	run_check $SUDO_HELPER dd if=/dev/zero of="$subv/file1" bs=1M count=1

+ +	run_check $SUDO_HELPER dd if=/dev/zero of="$subv/file2" bs=500K count=1

+ +	run_check $SUDO_HELPER "$TOP/btrfs" subvolume snapshot -r "$subv" "$snap"

+ +	run_check $SUDO_HELPER "$TOP/btrfs" send -f "$str" "$snap" "$@"

+ +

+ +	cd "$here" || _fail "cannot chdir back to test directory"

+ +	run_check_umount_test_dev

+ +}

+ +

+ +receive_one() {

+ +	local str

+ +	str="$1"

+ +	shift

+ +

+ +	run_check_mkfs_test_dev

+ +	run_check_mount_test_dev

+ +	run_check $SUDO_HELPER "$TOP/btrfs" receive "$@" -v -f "$str" "$TEST_MNT"

+ +	run_check_umount_test_dev

+ +	run_check rm -f -- "$str"

+ +}

+ +

+ +test_one_write_encoded() {

+ +	local str

+ +	local algorithm

+ +	algorithm="$1"

+ +	shift

+ +	str="$here/stream-$algorithm.stream"

+ +

+ +	run_check_mkfs_test_dev

+ +	send_one "$algorithm" "$str" --compressed-data

+ +	receive_one "$str" "$@"

+ +}

+ +

+ +test_one_stream_v1() {

+ +	local str

+ +	local algorithm

+ +	algorithm="$1"

+ +	shift

+ +	str="$here/stream-$algorithm.stream"

+ +

+ +	run_check_mkfs_test_dev

+ +	send_one "$algorithm" "$str" --proto 1

+ +	receive_one "$str" "$@"

+ +}

+ +

+ +test_mix_write_encoded() {

+ +	local strzlib

+ +	local strlzo

+ +	local strzstd

+ +	strzlib="$here/stream-zlib.stream"

+ +	strlzo="$here/stream-lzo.stream"

+ +	strzstd="$here/stream-zstd.stream"

+ +

+ +	run_check_mkfs_test_dev

+ +

+ +	send_one "zlib" "$strzlib" --compressed-data

+ +	send_one "lzo" "$strlzo" --compressed-data

+ +	send_one "zstd" "$strzstd" --compressed-data

+ +

+ +	receive_one "$strzlib"

+ +	receive_one "$strlzo"

+ +	receive_one "$strzstd"

+ +}

+ +

+ +test_one_write_encoded "zlib"

+ +test_one_write_encoded "lzo"

+ +test_one_write_encoded "zstd"

+ +

+ +# with decompression forced

+ +test_one_write_encoded "zlib" "--force-decompress"

+ +test_one_write_encoded "lzo" "--force-decompress"

+ +test_one_write_encoded "zstd" "--force-decompress"

+ +

+ +# send stream v1

+ +test_one_stream_v1 "zlib"

+ +test_one_stream_v1 "lzo"

+ +test_one_stream_v1 "zstd"

+ +

+ +# files use a mix of compression algorithms

+ +test_mix_write_encoded

+ -- 

+ 2.35.1

+ 

file modified
+79 -2
@@ -1,6 +1,6 @@ 

  Name:           btrfs-progs

- Version:        5.12.1

- Release:        2%{?dist}

+ Version:        5.16.2

+ Release:        1.1%{?dist}

  Summary:        Userspace programs for btrfs

  

  License:        GPLv2
@@ -15,6 +15,19 @@ 

  

  # Patches not for upstream (1000-1400)

  Patch1001:      1001-balance-mkfs-Disable-raid56-modes.patch

+ %if 0%{?facebook}

+ Patch1101:      1101-Require-clowntown-for-quota-enable.patch

+ Patch1102:      1102-btrfs-progs-receive-support-v2-send-stream-larger-tl.patch

+ Patch1103:      1103-btrfs-progs-receive-dynamically-allocate-sctx-read_b.patch

+ Patch1104:      1104-btrfs-progs-receive-support-v2-send-stream-DATA-tlv-.patch

+ Patch1105:      1105-btrfs-progs-receive-add-send-stream-v2-cmds-and-attr.patch

+ Patch1106:      1106-btrfs-progs-receive-process-encoded_write-commands.patch

+ Patch1107:      1107-btrfs-progs-receive-encoded_write-fallback-to-explic.patch

+ Patch1108:      1108-btrfs-progs-receive-process-fallocate-commands.patch

+ Patch1109:      1109-btrfs-progs-receive-process-setflags-ioctl-commands.patch

+ Patch1110:      1110-btrfs-progs-send-stream-v2-ioctl-flags.patch

+ Patch1111:      1111-btrfs-progs-receive-add-tests-for-basic-encoded_writ.patch

+ %endif

  

  BuildRequires:  gnupg2

  BuildRequires:  gcc, autoconf, automake, make
@@ -23,6 +36,7 @@ 

  BuildRequires:  pkgconfig(blkid)

  BuildRequires:  pkgconfig(uuid)

  BuildRequires:  pkgconfig(zlib)

+ BuildRequires:  pkgconfig(libudev)

  BuildRequires:  pkgconfig(libzstd) >= 1.0.0

  BuildRequires:  asciidoc, xmlto

  BuildRequires:  systemd
@@ -36,6 +50,8 @@ 

  %package -n libbtrfs

  Summary:        btrfs filesystem-specific runtime libraries

  License:        GPLv2

+ # Upstream deprecated this library

+ Provides:       deprecated()

  # This was not properly split out before

  Conflicts:      %{name} < 4.20.2

  
@@ -123,6 +139,7 @@ 

  %{_mandir}/man5/*

  %{_mandir}/man8/*

  %{_udevrulesdir}/64-btrfs-dm.rules

+ %{_udevrulesdir}/64-btrfs-zoned.rules

  %{_datadir}/bash-completion/completions/btrfs

  

  %files -n libbtrfs
@@ -145,6 +162,66 @@ 

  %{python3_sitearch}/btrfsutil-*.egg-info/

  

  %changelog

+ * Mon Apr 04 2022 Omar Sandoval <osandov@osandov.com> - 5.16.2-1.1

+ - Adapt for CentOS Hyperscale

+ - Add compressed send/receive patches to Facebook build

+ 

+ * Wed Feb 16 2022 Neal Gompa <ngompa@fedoraproject.org> - 5.16.2-1

+ - Update to 5.16.2

+ 

+ * Sat Feb 05 2022 Igor Raits <igor.raits@gmail.com> - 5.16.1-1

+ - Update to 5.16.1

+ 

+ * Wed Jan 19 2022 Fedora Release Engineering <releng@fedoraproject.org> - 5.16-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild

+ 

+ * Mon Jan 17 2022 Neal Gompa <ngompa@fedoraproject.org> - 5.16-1

+ - Update to 5.16

+ 

+ * Sat Jan 15 2022 Neal Gompa <ngompa@centosproject.org> - 5.14.2-1.1

+ - Adapt for CentOS Hyperscale

+ - Refresh patch for disabling raid56 mode

+ 

+ * Mon Nov 22 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.15.1-1

+ - Update to 5.15.1

+ 

+ * Fri Nov 05 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.15-1

+ - Update to 5.15

+ 

+ * Sat Oct 30 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.14.91-1

+ - Update to 5.14.91 (5.15~rc1)

+ 

+ * Sat Oct 09 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.14.2-1

+ - Update to 5.14.2

+ 

+ * Mon Sep 20 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.14.1-1

+ - Update to 5.14.1

+ 

+ * Fri Sep 10 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.14-2

+ - Mark libbtrfs as deprecated, per upstream release notes

+ 

+ * Fri Sep 10 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.14-1

+ - Update to 5.14

+ 

+ * Wed Sep 01 2021 Neal Gompa <ngompa@centosproject.org> - 5.13.1-2

+ - Refresh patch for disabling raid56 mode with fixes from Omar Sandoval

+ 

+ * Tue Aug 10 2021 Omar Sandoval <osandov@osandov.com> - 5.13.1-1

+ - Update to 5.13.1 for CentOS Hyperscale

+ - Add Facebook-only patch to require extra flag for quota enable

+ 

+ * Fri Jul 30 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.13.1-1

+ - Update to 5.13.1

+ 

+ * Wed Jul 21 2021 Fedora Release Engineering <releng@fedoraproject.org> - 5.13-2

+ - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild

+ 

+ * Tue Jul 13 2021 Neal Gompa <ngompa@fedoraproject.org> - 5.13-1

+ - Update to 5.13

+ 

+ * Fri Jun 04 2021 Python Maint <python-maint@redhat.com> - 5.12.1-2

+ - Rebuilt for Python 3.10

+ 

  * Mon May 17 2021 Neal Gompa <ngompa@centosproject.org> - 5.12.1-2

  - Adapt for CentOS Hyperscale

  - Add downstream patch to disable raid56 modes

Backport the fix found here:
https://lore.kernel.org/linux-btrfs/abf83660318efd4ceafaa3cea98371c1e6e9fa25.camel@scientia.org/T/#ma2ff58f2ee932c39e01a018aa4b08ec8f42687c3

Partially, unaligned-size reflinked files sent and received as compressed send streams can result in data corruption on the receive side.

Pull-Request has been closed by borisb

2 years ago