* [PATCH 1/3] btrfs-progs: restore: handle full block compressed inline extent
2026-09-16 6:52 [PATCH 0/3] btrfs-progs: restore: handler newer inlined Qu Wenruo
@ 2026-09-16 6:52 ` Qu Wenruo
2026-09-16 6:52 ` [PATCH 2/3] btrfs-progs: restore: handle inlined extent larger than 4K Qu Wenruo
2026-09-16 6:52 ` [PATCH 3/3] btrfs-progs: misc-tests: add a test case for btrfs-restore Qu Wenruo
2 siblings, 0 replies; 4+ messages in thread
From: Qu Wenruo @ 2026-09-16 6:52 UTC (permalink / raw)
To: linux-btrfs
Since kernel commit 3eaf5f082c4c ("btrfs: extract inlined creation into a
dedicated delalloc helper"), the creation of compressed inlined extent
has changed to compress the whole block, then truncate the ram_bytes to
isize.
This means the compressed data needs to have a full block as the output
buffer.
This is fine for kernel, as the inlined extent is alwasy decompressed to
a folio which is at least one block sized.
But for progs, if the output buffer is smaller than a block, the
decompression will fail early (not enough output buffer), causing
btrfs-restore to completely skip the content of the inlined extent.
Fix it by always allocating a full block for copy_one_inline().
Issue: #1171
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
cmds/restore.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/cmds/restore.c b/cmds/restore.c
index 7d16cc99fa6a..00471b486ac6 100644
--- a/cmds/restore.c
+++ b/cmds/restore.c
@@ -298,6 +298,7 @@ static int copy_one_inline(struct btrfs_root *root, int fd,
char buf[4096];
char *outbuf;
u64 ram_size;
+ u64 out_buf_len;
ssize_t done;
unsigned long ptr;
int ret;
@@ -324,13 +325,14 @@ static int copy_one_inline(struct btrfs_root *root, int fd,
}
ram_size = btrfs_file_extent_ram_bytes(leaf, fi);
- outbuf = calloc(1, ram_size);
+ out_buf_len = root->fs_info->sectorsize;
+ outbuf = malloc(out_buf_len);
if (!outbuf) {
error_mem(NULL);
return -ENOMEM;
}
- ret = decompress(root, buf, outbuf, inline_item_len, &ram_size,
+ ret = decompress(root, buf, outbuf, inline_item_len, &out_buf_len,
compress);
if (ret) {
free(outbuf);
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/3] btrfs-progs: restore: handle inlined extent larger than 4K
2026-09-16 6:52 [PATCH 0/3] btrfs-progs: restore: handler newer inlined Qu Wenruo
2026-09-16 6:52 ` [PATCH 1/3] btrfs-progs: restore: handle full block compressed inline extent Qu Wenruo
@ 2026-09-16 6:52 ` Qu Wenruo
2026-09-16 6:52 ` [PATCH 3/3] btrfs-progs: misc-tests: add a test case for btrfs-restore Qu Wenruo
2 siblings, 0 replies; 4+ messages in thread
From: Qu Wenruo @ 2026-09-16 6:52 UTC (permalink / raw)
To: linux-btrfs
Most btrfs are already using 4K sectorsize, but for systems with 64K
page size, it's possible to create large inlined extent that is larger
than 4K:
item 6 key (257 EXTENT_DATA 0) itemoff 56802 itemsize 8213
generation 9 type 0 (inline)
inline extent data size 8192 ram_bytes 8192 compression 0 (none)
In that case, btrfs-restore will crash as its input buffer is only 4K
sized.
Enhance btrfs-restore to handle larger block size correctly, by allocate
a block-sized buffer at input buffer.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
cmds/restore.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/cmds/restore.c b/cmds/restore.c
index 00471b486ac6..b982f2de4699 100644
--- a/cmds/restore.c
+++ b/cmds/restore.c
@@ -295,7 +295,8 @@ static int copy_one_inline(struct btrfs_root *root, int fd,
{
struct extent_buffer *leaf = path->nodes[0];
struct btrfs_file_extent_item *fi;
- char buf[4096];
+ const u32 blocksize = root->fs_info->sectorsize;
+ char *inbuf;
char *outbuf;
u64 ram_size;
u64 out_buf_len;
@@ -306,16 +307,23 @@ static int copy_one_inline(struct btrfs_root *root, int fd,
int inline_item_len;
int compress;
+ inbuf = malloc(blocksize);
+ if (!inbuf) {
+ error_mem(NULL);
+ return -ENOMEM;
+ }
+
fi = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_file_extent_item);
ptr = btrfs_file_extent_inline_start(fi);
len = btrfs_file_extent_ram_bytes(leaf, fi);
inline_item_len = btrfs_file_extent_inline_item_len(leaf, path->slots[0]);
- read_extent_buffer(leaf, buf, ptr, inline_item_len);
+ read_extent_buffer(leaf, inbuf, ptr, inline_item_len);
compress = btrfs_file_extent_compression(leaf, fi);
if (compress == BTRFS_COMPRESS_NONE) {
- done = pwrite(fd, buf, len, pos);
+ done = pwrite(fd, inbuf, len, pos);
+ free(inbuf);
if (done < len) {
error("short inline write, wanted %d, did %zd: %m",
len, done);
@@ -329,17 +337,20 @@ static int copy_one_inline(struct btrfs_root *root, int fd,
outbuf = malloc(out_buf_len);
if (!outbuf) {
error_mem(NULL);
+ free(inbuf);
return -ENOMEM;
}
- ret = decompress(root, buf, outbuf, inline_item_len, &out_buf_len,
+ ret = decompress(root, inbuf, outbuf, inline_item_len, &out_buf_len,
compress);
if (ret) {
+ free(inbuf);
free(outbuf);
return ret;
}
done = pwrite(fd, outbuf, ram_size, pos);
+ free(inbuf);
free(outbuf);
if (done < ram_size) {
error("short compressed inline write, wanted %llu, did %zd: %m",
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread