@@ -4915,14 +4915,27 @@ static inline u64 max_send_read_size(const 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) {
+ /*
+ * In v2, the data attribute header doesn't include a length; it
+ * is implicitly to the end of the command.
+ */
+ if (sctx->send_max_size - sctx->send_size < 2 + len)
+ return -EOVERFLOW;
+ put_unaligned_le16(BTRFS_SEND_A_DATA,
+ sctx->send_buf + sctx->send_size);
+ sctx->send_size += 2;
+ } 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);
- put_unaligned_le16(BTRFS_SEND_A_DATA, &hdr->tlv_type);
- put_unaligned_le16(len, &hdr->tlv_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);
+ put_unaligned_le16(BTRFS_SEND_A_DATA, &hdr->tlv_type);
+ put_unaligned_le16(len, &hdr->tlv_len);
+ sctx->send_size += sizeof(*hdr);
+ }
return 0;
}
@@ -7267,7 +7280,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;