osandov / rpms / btrfs-progs

Forked from rpms/btrfs-progs 2 years ago
Clone

Blame SOURCES/1102-btrfs-progs-receive-support-v2-send-stream-larger-tl.patch

dbfe2d
From 7e5cd32fbb38103b11a8a87ca5af943d0fb2804a Mon Sep 17 00:00:00 2001
dbfe2d
From: Boris Burkov <borisb@fb.com>
dbfe2d
Date: Fri, 21 Aug 2020 00:40:00 -0700
dbfe2d
Subject: [PATCH] btrfs-progs: receive: support v2 send stream larger tlv_len
dbfe2d
dbfe2d
An encoded extent can be up to 128K in length, which exceeds the largest
dbfe2d
value expressible by the current send stream format's 16 bit tlv_len
dbfe2d
field. Since encoded writes cannot be split into multiple writes by
dbfe2d
btrfs send, the send stream format must change to accommodate encoded
dbfe2d
writes.
dbfe2d
dbfe2d
Supporting this changed format requires retooling how we store the
dbfe2d
commands we have processed. We currently store pointers to the struct
dbfe2d
btrfs_tlv_headers in the command buffer. This is not sufficient to
dbfe2d
represent the new BTRFS_SEND_A_DATA format. Instead, parse the attribute
dbfe2d
headers and store them in a new struct btrfs_send_attribute which has a
dbfe2d
32-bit length field. This is transparent to users of the various TLV_GET
dbfe2d
macros.
dbfe2d
dbfe2d
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
dbfe2d
Signed-off-by: Boris Burkov <boris@bur.io>
dbfe2d
---
dbfe2d
 common/send-stream.c | 34 +++++++++++++++++++++++++---------
dbfe2d
 1 file changed, 25 insertions(+), 9 deletions(-)
dbfe2d
dbfe2d
diff --git a/common/send-stream.c b/common/send-stream.c
dbfe2d
index e9be922b..7d182238 100644
dbfe2d
--- a/common/send-stream.c
dbfe2d
+++ b/common/send-stream.c
dbfe2d
@@ -24,13 +24,23 @@
dbfe2d
 #include "crypto/crc32c.h"
dbfe2d
 #include "common/utils.h"
dbfe2d
 
dbfe2d
+struct btrfs_send_attribute {
dbfe2d
+	u16 tlv_type;
dbfe2d
+	/*
dbfe2d
+	 * Note: in btrfs_tlv_header, this is __le16, but we need 32 bits for
dbfe2d
+	 * attributes with file data as of version 2 of the send stream format
dbfe2d
+	 */
dbfe2d
+	u32 tlv_len;
dbfe2d
+	char *data;
dbfe2d
+};
dbfe2d
+
dbfe2d
 struct btrfs_send_stream {
dbfe2d
 	char read_buf[BTRFS_SEND_BUF_SIZE];
dbfe2d
 	int fd;
dbfe2d
 
dbfe2d
 	int cmd;
dbfe2d
 	struct btrfs_cmd_header *cmd_hdr;
dbfe2d
-	struct btrfs_tlv_header *cmd_attrs[BTRFS_SEND_A_MAX + 1];
dbfe2d
+	struct btrfs_send_attribute cmd_attrs[BTRFS_SEND_A_MAX + 1];
dbfe2d
 	u32 version;
dbfe2d
 
dbfe2d
 	/*
dbfe2d
@@ -152,6 +162,7 @@ static int read_cmd(struct btrfs_send_stream *sctx)
dbfe2d
 		struct btrfs_tlv_header *tlv_hdr;
dbfe2d
 		u16 tlv_type;
dbfe2d
 		u16 tlv_len;
dbfe2d
+		struct btrfs_send_attribute *send_attr;
dbfe2d
 
dbfe2d
 		tlv_hdr = (struct btrfs_tlv_header *)data;
dbfe2d
 		tlv_type = le16_to_cpu(tlv_hdr->tlv_type);
dbfe2d
@@ -164,10 +175,15 @@ static int read_cmd(struct btrfs_send_stream *sctx)
dbfe2d
 			goto out;
dbfe2d
 		}
dbfe2d
 
dbfe2d
-		sctx->cmd_attrs[tlv_type] = tlv_hdr;
dbfe2d
+		send_attr = &sctx->cmd_attrs[tlv_type];
dbfe2d
+		send_attr->tlv_type = tlv_type;
dbfe2d
+		send_attr->tlv_len = tlv_len;
dbfe2d
+		pos += sizeof(*tlv_hdr);
dbfe2d
+		data += sizeof(*tlv_hdr);
dbfe2d
 
dbfe2d
-		data += sizeof(*tlv_hdr) + tlv_len;
dbfe2d
-		pos += sizeof(*tlv_hdr) + tlv_len;
dbfe2d
+		send_attr->data = data;
dbfe2d
+		pos += send_attr->tlv_len;
dbfe2d
+		data += send_attr->tlv_len;
dbfe2d
 	}
dbfe2d
 
dbfe2d
 	sctx->cmd = cmd;
dbfe2d
@@ -180,7 +196,7 @@ out:
dbfe2d
 static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *len)
dbfe2d
 {
dbfe2d
 	int ret;
dbfe2d
-	struct btrfs_tlv_header *hdr;
dbfe2d
+	struct btrfs_send_attribute *send_attr;
dbfe2d
 
dbfe2d
 	if (attr <= 0 || attr > BTRFS_SEND_A_MAX) {
dbfe2d
 		error("invalid attribute requested, attr = %d", attr);
dbfe2d
@@ -188,15 +204,15 @@ static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *l
dbfe2d
 		goto out;
dbfe2d
 	}
dbfe2d
 
dbfe2d
-	hdr = sctx->cmd_attrs[attr];
dbfe2d
-	if (!hdr) {
dbfe2d
+	send_attr = &sctx->cmd_attrs[attr];
dbfe2d
+	if (!send_attr->data) {
dbfe2d
 		error("attribute %d requested but not present", attr);
dbfe2d
 		ret = -ENOENT;
dbfe2d
 		goto out;
dbfe2d
 	}
dbfe2d
 
dbfe2d
-	*len = le16_to_cpu(hdr->tlv_len);
dbfe2d
-	*data = hdr + 1;
dbfe2d
+	*len = send_attr->tlv_len;
dbfe2d
+	*data = send_attr->data;
dbfe2d
 
dbfe2d
 	ret = 0;
dbfe2d
 
dbfe2d
-- 
dbfe2d
2.35.1
dbfe2d