diff mbox series

[6/9] btrfs: send: write larger chunks when using stream v2

Message ID eebf24d3b42ef50a19ba9bc38ed5210d0cc87157.1597994106.git.osandov@osandov.com
State New, archived
Headers show
Series btrfs: implement send/receive of compressed extents without decompressing | expand

Commit Message

Omar Sandoval Aug. 21, 2020, 7:39 a.m. UTC
From: Omar Sandoval <osandov@fb.com>

The length field of the send stream TLV header is 16 bits. This means
that the maximum amount of data that can be sent for one write is 64k
minus one. However, encoded writes must be able to send the maximum
compressed extent (128k) in one command. To support this, send stream
version 2 encodes the DATA attribute differently: it has no length
field, and the length is implicitly up to the end of containing command
(which has a 32-bit length field). Although this is necessary for
encoded writes, normal writes can benefit from it, too.

For v2, let's bump up the send buffer to the maximum compressed extent
size plus 16k for the other metadata (144k total). Since this will most
likely be vmalloc'd (and always will be after the next commit), we round
it up to the next page since we might as well use the rest of the page
on systems with >16k pages.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/send.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

Comments

Josef Bacik Aug. 24, 2020, 5:57 p.m. UTC | #1
On 8/21/20 3:39 AM, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
> 
> The length field of the send stream TLV header is 16 bits. This means
> that the maximum amount of data that can be sent for one write is 64k
> minus one. However, encoded writes must be able to send the maximum
> compressed extent (128k) in one command. To support this, send stream
> version 2 encodes the DATA attribute differently: it has no length
> field, and the length is implicitly up to the end of containing command
> (which has a 32-bit length field). Although this is necessary for
> encoded writes, normal writes can benefit from it, too.
> 
> For v2, let's bump up the send buffer to the maximum compressed extent
> size plus 16k for the other metadata (144k total). Since this will most
> likely be vmalloc'd (and always will be after the next commit), we round
> it up to the next page since we might as well use the rest of the page
> on systems with >16k pages.
> 
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
>   fs/btrfs/send.c | 34 ++++++++++++++++++++++++++--------
>   1 file changed, 26 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
> index e25c3391fc02..c0f81d302f49 100644
> --- a/fs/btrfs/send.c
> +++ b/fs/btrfs/send.c
> @@ -4799,14 +4799,27 @@ static u64 max_send_read_size(struct send_ctx *sctx)
>   
>   static int put_data_header(struct send_ctx *sctx, u32 len)
>   {
> -	struct btrfs_tlv_header *hdr;
> +	if (sctx->flags & BTRFS_SEND_FLAG_STREAM_V2) {
> +		__le16 tlv_type;
> +
> +		if (sctx->send_max_size - sctx->send_size <
> +		    sizeof(tlv_type) + len)
> +			return -EOVERFLOW;
> +		tlv_type = cpu_to_le16(BTRFS_SEND_A_DATA);
> +		memcpy(sctx->send_buf + sctx->send_size, &tlv_type,
> +		       sizeof(tlv_type));
> +		sctx->send_size += sizeof(tlv_type);

Can we add a comment for implied length thing here?  I was reviewing this in 
vimdiff without the commit message so missed the implied length detail.  Thanks,

Josef
diff mbox series

Patch

diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index e25c3391fc02..c0f81d302f49 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -4799,14 +4799,27 @@  static u64 max_send_read_size(struct send_ctx *sctx)
 
 static int put_data_header(struct send_ctx *sctx, u32 len)
 {
-	struct btrfs_tlv_header *hdr;
+	if (sctx->flags & BTRFS_SEND_FLAG_STREAM_V2) {
+		__le16 tlv_type;
+
+		if (sctx->send_max_size - sctx->send_size <
+		    sizeof(tlv_type) + len)
+			return -EOVERFLOW;
+		tlv_type = cpu_to_le16(BTRFS_SEND_A_DATA);
+		memcpy(sctx->send_buf + sctx->send_size, &tlv_type,
+		       sizeof(tlv_type));
+		sctx->send_size += sizeof(tlv_type);
+	} else {
+		struct btrfs_tlv_header *hdr;
 
-	if (sctx->send_max_size - sctx->send_size < sizeof(*hdr) + len)
-		return -EOVERFLOW;
-	hdr = (struct btrfs_tlv_header *)(sctx->send_buf + sctx->send_size);
-	hdr->tlv_type = cpu_to_le16(BTRFS_SEND_A_DATA);
-	hdr->tlv_len = cpu_to_le16(len);
-	sctx->send_size += sizeof(*hdr);
+		if (sctx->send_max_size - sctx->send_size < sizeof(*hdr) + len)
+			return -EOVERFLOW;
+		hdr = (struct btrfs_tlv_header *)(sctx->send_buf +
+						  sctx->send_size);
+		hdr->tlv_type = cpu_to_le16(BTRFS_SEND_A_DATA);
+		hdr->tlv_len = cpu_to_le16(len);
+		sctx->send_size += sizeof(*hdr);
+	}
 	return 0;
 }
 
@@ -7136,7 +7149,12 @@  long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
 
 	sctx->clone_roots_cnt = arg->clone_sources_count;
 
-	sctx->send_max_size = BTRFS_SEND_BUF_SIZE_V1;
+	if (sctx->flags & BTRFS_SEND_FLAG_STREAM_V2) {
+		sctx->send_max_size = ALIGN(SZ_16K + BTRFS_MAX_COMPRESSED,
+					    PAGE_SIZE);
+	} else {
+		sctx->send_max_size = BTRFS_SEND_BUF_SIZE_V1;
+	}
 	sctx->send_buf = kvmalloc(sctx->send_max_size, GFP_KERNEL);
 	if (!sctx->send_buf) {
 		ret = -ENOMEM;