All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] mkfs/rootdir: refactor and enhancements, part 1
@ 2026-05-18 10:20 Qu Wenruo
  2026-05-18 10:20 ` [PATCH 1/3] btrfs-progs: rename logical bytenr parameter for add_file_item_extent() Qu Wenruo
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Qu Wenruo @ 2026-05-18 10:20 UTC (permalink / raw)
  To: linux-btrfs

We have "--reflink" option introduced for mkfs for a while, and recently
the new get_csums ioctl is also introduced, making
add_file_item_extent() much larger and harder to maintain.

I have some concerns about the larger and larger
add_file_item_extent(), and will address some of them in the series:

- Minor mismatches on some parameter/variable names
  Use more commonly used names to replace them.

- Duplicated partial block handling
  Which not only makes add_file_item_extent() larger but also harder to
  read/maintain.

  To remove those duplicated partial block handling, the idea is to
  shrink the range to block boundary when possible.
  If we can not shrink the range anymore, disable reflink/get_csums.

  So that we do not need to handle partial blocks for reflink/get_csums.
  All the duplicated code can be removed.

- No test case for --reflink nor the latest get_csums option
  A new test case, to verify all above mentioned cases.

Qu Wenruo (3):
  btrfs-progs: rename logical bytenr parameter for
    add_file_item_extent()
  btrfs: mkfs/rootdir: refactor the last block handling
  btrfs-progs: mkfs-tests: add a new one for '--reflink' option

 kernel-shared/extent_io.c                    |  10 +-
 mkfs/rootdir.c                               | 175 ++++++++-----------
 tests/mkfs-tests/043-rootdir-reflink/test.sh |  57 ++++++
 3 files changed, 135 insertions(+), 107 deletions(-)
 create mode 100755 tests/mkfs-tests/043-rootdir-reflink/test.sh

--
2.54.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] btrfs-progs: rename logical bytenr parameter for add_file_item_extent()
  2026-05-18 10:20 [PATCH 0/3] mkfs/rootdir: refactor and enhancements, part 1 Qu Wenruo
@ 2026-05-18 10:20 ` Qu Wenruo
  2026-05-18 10:20 ` [PATCH 2/3] btrfs: mkfs/rootdir: refactor the last block handling Qu Wenruo
  2026-05-18 10:20 ` [PATCH 3/3] btrfs-progs: mkfs-tests: add a new one for '--reflink' option Qu Wenruo
  2 siblings, 0 replies; 4+ messages in thread
From: Qu Wenruo @ 2026-05-18 10:20 UTC (permalink / raw)
  To: linux-btrfs

Inside the function add_file_item_extent(), we use a local variable
@first_block, to record the logical bytenr of the data extent.

However that naming is not common among btrfs, that @first_block looks
more like a block number, other than the logical bytenr in byte.

Change the following variables/parameters to make it more aligned to
btrfs naming:

- @offset parameter of write_data_to_disk()
- @addr parameter of do_reflink_write()
- @logical variable inside add_file_item_extent()

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 kernel-shared/extent_io.c | 10 +++++-----
 mkfs/rootdir.c            | 26 +++++++++++++-------------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/kernel-shared/extent_io.c b/kernel-shared/extent_io.c
index cb48699c2e46..5dcfbd020e75 100644
--- a/kernel-shared/extent_io.c
+++ b/kernel-shared/extent_io.c
@@ -479,7 +479,7 @@ int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 logical,
  * Such data will be written to all mirrors and RAID56 P/Q will also be
  * properly handled.
  */
-int write_data_to_disk(struct btrfs_fs_info *info, const void *buf, u64 offset,
+int write_data_to_disk(struct btrfs_fs_info *info, const void *buf, u64 logical,
 		       u64 bytes)
 {
 	struct btrfs_multi_bio *multi = NULL;
@@ -496,11 +496,11 @@ int write_data_to_disk(struct btrfs_fs_info *info, const void *buf, u64 offset,
 		this_len = bytes_left;
 		dev_nr = 0;
 
-		ret = btrfs_map_block(info, WRITE, offset, &this_len, &multi,
+		ret = btrfs_map_block(info, WRITE, logical, &this_len, &multi,
 				      0, &raid_map);
 		if (ret) {
 			fprintf(stderr, "Couldn't map the block %llu\n",
-				offset);
+				logical);
 			return -EIO;
 		}
 
@@ -519,7 +519,7 @@ int write_data_to_disk(struct btrfs_fs_info *info, const void *buf, u64 offset,
 			}
 
 			memset(eb, 0, sizeof(struct extent_buffer) + this_len);
-			eb->start = offset;
+			eb->start = logical;
 			eb->len = this_len;
 
 			memcpy(eb->data, buf + total_write, this_len);
@@ -562,7 +562,7 @@ int write_data_to_disk(struct btrfs_fs_info *info, const void *buf, u64 offset,
 		BUG_ON(bytes_left < this_len);
 
 		bytes_left -= this_len;
-		offset += this_len;
+		logical += this_len;
 		total_write += this_len;
 
 		kfree(multi);
diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c
index 3e77195356dd..34163e19e2aa 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -709,7 +709,7 @@ struct source_descriptor {
 };
 
 static int do_reflink_write(struct btrfs_fs_info *info,
-			    const struct source_descriptor *source, u64 addr,
+			    const struct source_descriptor *source, u64 logical,
 			    u64 file_pos, u64 bytes, const void *buf)
 {
 	struct btrfs_multi_bio *multi = NULL;
@@ -729,9 +729,9 @@ static int do_reflink_write(struct btrfs_fs_info *info,
 		this_len = bytes_left;
 		dev_nr = 0;
 
-		ret = btrfs_map_block(info, WRITE, addr, &this_len, &multi, 0, NULL);
+		ret = btrfs_map_block(info, WRITE, logical, &this_len, &multi, 0, NULL);
 		if (ret) {
-			error("cannot map the block %llu", addr);
+			error("cannot map the block %llu", logical);
 			return -EIO;
 		}
 
@@ -763,7 +763,7 @@ static int do_reflink_write(struct btrfs_fs_info *info,
 		BUG_ON(bytes_left < this_len);
 
 		bytes_left -= this_len;
-		addr += this_len;
+		logical += this_len;
 		total_write += this_len;
 
 		kfree(multi);
@@ -778,7 +778,7 @@ static int do_reflink_write(struct btrfs_fs_info *info,
 	if (bytes % info->sectorsize) {
 		return write_data_to_disk(info,
 			(char *)buf + round_down(bytes, info->sectorsize),
-			addr, info->sectorsize);
+			logical, info->sectorsize);
 	}
 
 	return 0;
@@ -911,7 +911,7 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 {
 	int ret;
 	u32 sectorsize = root->fs_info->sectorsize;
-	u64 first_block, to_read, to_write;
+	u64 logical, to_read, to_write;
 	struct btrfs_key key;
 	struct btrfs_file_extent_item stack_fi = { 0 };
 	u64 buf_size;
@@ -1124,13 +1124,13 @@ do_write:
 		return ret;
 	}
 
-	first_block = key.objectid;
+	logical = key.objectid;
 
 	if (g_do_reflink) {
-		ret = do_reflink_write(root->fs_info, source, first_block, file_pos,
+		ret = do_reflink_write(root->fs_info, source, logical, file_pos,
 				       to_read, write_buf);
 	} else {
-		ret = write_data_to_disk(root->fs_info, write_buf, first_block, to_write);
+		ret = write_data_to_disk(root->fs_info, write_buf, logical, to_write);
 	}
 
 	if (ret) {
@@ -1154,7 +1154,7 @@ do_write:
 
 			for (unsigned int i = 0; i < last_full; i++) {
 				ret = btrfs_insert_file_block_csum(trans,
-						first_block + (i * sectorsize),
+						logical + (i * sectorsize),
 						BTRFS_EXTENT_CSUM_OBJECTID,
 						root->fs_info->csum_type,
 						fetched_csums + (i * fetched_csum_size));
@@ -1168,7 +1168,7 @@ do_write:
 				u64 partial_off = round_down(to_read, sectorsize);
 
 				ret = btrfs_csum_file_block(trans,
-						first_block + partial_off,
+						logical + partial_off,
 						BTRFS_EXTENT_CSUM_OBJECTID,
 						root->fs_info->csum_type,
 						source->buf + partial_off);
@@ -1180,7 +1180,7 @@ do_write:
 		} else {
 			for (unsigned int i = 0; i < to_write / sectorsize; i++) {
 				ret = btrfs_csum_file_block(trans,
-						first_block + (i * sectorsize),
+						logical + (i * sectorsize),
 						BTRFS_EXTENT_CSUM_OBJECTID,
 						root->fs_info->csum_type,
 						write_buf + (i * sectorsize));
@@ -1193,7 +1193,7 @@ do_write:
 	free(fetched_csums_buf);
 
 	btrfs_set_stack_file_extent_type(&stack_fi, BTRFS_FILE_EXTENT_REG);
-	btrfs_set_stack_file_extent_disk_bytenr(&stack_fi, first_block);
+	btrfs_set_stack_file_extent_disk_bytenr(&stack_fi, logical);
 	btrfs_set_stack_file_extent_disk_num_bytes(&stack_fi, to_write);
 	btrfs_set_stack_file_extent_num_bytes(&stack_fi, round_up(to_read, sectorsize));
 	btrfs_set_stack_file_extent_ram_bytes(&stack_fi, round_up(to_read, sectorsize));
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] btrfs: mkfs/rootdir: refactor the last block handling
  2026-05-18 10:20 [PATCH 0/3] mkfs/rootdir: refactor and enhancements, part 1 Qu Wenruo
  2026-05-18 10:20 ` [PATCH 1/3] btrfs-progs: rename logical bytenr parameter for add_file_item_extent() Qu Wenruo
@ 2026-05-18 10:20 ` Qu Wenruo
  2026-05-18 10:20 ` [PATCH 3/3] btrfs-progs: mkfs-tests: add a new one for '--reflink' option Qu Wenruo
  2 siblings, 0 replies; 4+ messages in thread
From: Qu Wenruo @ 2026-05-18 10:20 UTC (permalink / raw)
  To: linux-btrfs

Currently the function add_file_item_extent() has several call sites
handling the last partial block in different locations, all to handle
reflink and get_csums cases.

Remove those duplication and improve readability by:

- Shrink the range if reflink/get_csums is required
  So that reflink and get_csums handling will no longer needs to bother
  unaligned partial block.

  If the range is already a partial block, disable reflink and get_csums
  for that partial block.

- Add new UASSERT()s in do_reflink_write() and do_get_csums cases

- Introduce a new @do_get_csums to indicate if we need to call get_csums
  ioctl
  This allows us to do a quick local check, and flip the status if the
  range is a partial block.

- Merge read_data: and do_writes: tags into fallback:
  And add a dedicated if () check to determine if we need to read the
  contents, with a proper comment explaining why.

  However this requires all readers of source->buf to check if the
  buffer is already ready. If not they need to read out the buffer.
  This includes the following cases:

  * Non-reflink fallback
    We have to read-out the data before writting them back.

  * Data checksum calculation
    No matter if reflink is done, if we need to generate checksum, we
    have to read out the data anyway.

  Unfortunately I do not have a good way to remove the duplication of
  the above two callsites.

- Remove @write_buf variable
  We always use source->buf.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 mkfs/rootdir.c | 155 ++++++++++++++++++++-----------------------------
 1 file changed, 63 insertions(+), 92 deletions(-)

diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c
index 34163e19e2aa..f2ab8c642f9a 100644
--- a/mkfs/rootdir.c
+++ b/mkfs/rootdir.c
@@ -710,11 +710,12 @@ struct source_descriptor {
 
 static int do_reflink_write(struct btrfs_fs_info *info,
 			    const struct source_descriptor *source, u64 logical,
-			    u64 file_pos, u64 bytes, const void *buf)
+			    u64 file_pos, u64 bytes)
 {
 	struct btrfs_multi_bio *multi = NULL;
 	struct btrfs_device *device;
-	u64 bytes_left;
+	const u32 blocksize = info->sectorsize;
+	u64 bytes_left = bytes;
 	u64 this_len;
 	u64 total_write = 0;
 	u64 dev_bytenr;
@@ -722,8 +723,10 @@ static int do_reflink_write(struct btrfs_fs_info *info,
 	int ret = 0;
 	struct file_clone_range fcr;
 
+	UASSERT(IS_ALIGNED(file_pos, blocksize));
+	UASSERT(IS_ALIGNED(bytes, blocksize));
+
 	fcr.src_fd = source->fd;
-	bytes_left = round_down(bytes, info->sectorsize);
 
 	while (bytes_left > 0) {
 		this_len = bytes_left;
@@ -770,17 +773,6 @@ static int do_reflink_write(struct btrfs_fs_info *info,
 		multi = NULL;
 	}
 
-	/*
-	 * FICLONERANGE can only handle whole sectors. If the file is not a
-	 * multiple of the sector size, we need to write the last sector
-	 * manually.
-	 */
-	if (bytes % info->sectorsize) {
-		return write_data_to_disk(info,
-			(char *)buf + round_down(bytes, info->sectorsize),
-			logical, info->sectorsize);
-	}
-
 	return 0;
 }
 
@@ -915,9 +907,11 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 	struct btrfs_key key;
 	struct btrfs_file_extent_item stack_fi = { 0 };
 	u64 buf_size;
-	char *write_buf;
 	bool do_comp = g_compression != BTRFS_COMPRESS_NONE;
 	bool datasum = true;
+	bool data_ready = false;
+	bool do_reflink = g_do_reflink;
+	bool do_get_csums;
 	u64 flags = btrfs_stack_inode_flags(btrfs_inode);
 	off_t next;
 	u8 *fetched_csums = NULL;
@@ -925,7 +919,7 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 	u64 fetched_num_csums = 0;
 	u16 fetched_csum_size = 0;
 
-	if (g_do_reflink || flags & BTRFS_INODE_NOCOMPRESS)
+	if (do_reflink || flags & BTRFS_INODE_NOCOMPRESS)
 		do_comp = false;
 
 	if ((flags & BTRFS_INODE_NODATACOW) || (flags & BTRFS_INODE_NODATASUM)) {
@@ -983,6 +977,22 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 	buf_size = MAX_EXTENT_SIZE;
 	to_read = min_t(u64, file_pos + buf_size, next) - file_pos;
 
+	do_get_csums = datasum && !do_comp && g_get_csums_supported != 0;
+	/*
+	 * Reflink and get_csums all require block aligned ranges.
+	 * Shrink the range when possible. If it's the last partial block, disable
+	 * reflink and get_csums ioctl.
+	 */
+	if (do_reflink || do_get_csums) {
+		if (to_read < sectorsize) {
+			do_reflink = false;
+			do_get_csums = false;
+		} else {
+			to_read = round_down(to_read, sectorsize);
+		}
+	}
+	to_write = round_up(to_read, sectorsize);
+
 	/*
 	 * Try to get csums from the source filesystem via BTRFS_IOC_GET_CSUMS
 	 * instead of computing them from the data.  This works when the source
@@ -993,17 +1003,19 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 	 * use the pre-computed csums directly.  For non-reflink, the data is
 	 * still read normally but we skip the checksum computation.
 	 */
-	if (datasum && !do_comp && g_get_csums_supported != 0) {
-		u16 csum_size = btrfs_csum_type_size(root->fs_info->csum_type);
-		u64 ioctl_len = round_up(to_read, sectorsize);
-		u64 num_csums = ioctl_len / sectorsize;
-		u64 csums_bytes = num_csums * csum_size;
+	if (do_get_csums) {
+		const u16 csum_size = btrfs_csum_type_size(root->fs_info->csum_type);
+		const u64 num_csums = to_read / sectorsize;
+		const u64 csums_bytes = num_csums * csum_size;
 		size_t alloc_size = sizeof(struct btrfs_ioctl_get_csums_args) +
 				    sizeof(struct btrfs_ioctl_get_csums_entry) +
 				    csums_bytes;
 		struct btrfs_ioctl_get_csums_args *cargs;
 		struct btrfs_ioctl_get_csums_entry *entry;
 
+		/* The range must be block aligned. */
+		UASSERT(IS_ALIGNED(to_read, sectorsize));
+
 		/*
 		 * Check that the source file's filesystem uses the same
 		 * checksum algorithm as the destination.  Cache the result
@@ -1026,14 +1038,14 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 		}
 
 		if (!g_last_csums_dev_ok)
-			goto read_data;
+			goto fallback;
 
 		cargs = calloc(1, alloc_size);
 		if (!cargs)
 			return -ENOMEM;
 
 		cargs->offset = file_pos;
-		cargs->length = ioctl_len;
+		cargs->length = to_read;
 		cargs->buf_size = sizeof(struct btrfs_ioctl_get_csums_entry) +
 				  csums_bytes;
 
@@ -1043,7 +1055,7 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 			if (errno == ENOTTY) {
 				/* Kernel doesn't support the ioctl. */
 				g_get_csums_supported = 0;
-				goto read_data;
+				goto fallback;
 			}
 			error("BTRFS_IOC_GET_CSUMS failed on %s: %m",
 			      source->path_name);
@@ -1060,9 +1072,9 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 
 		if (cargs->length != 0 || cargs->buf_size < sizeof(*entry) ||
 		    entry->type != BTRFS_GET_CSUMS_HAS_CSUMS ||
-		    entry->length != ioctl_len) {
+		    entry->length != to_read) {
 			free(cargs);
-			goto read_data;
+			goto fallback;
 		}
 
 		/*
@@ -1073,50 +1085,9 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
 		fetched_csums_buf = cargs;
 		fetched_num_csums = num_csums;
 		fetched_csum_size = csum_size;
-
-		if (g_do_reflink) {
-			/*
-			 * Reflink fast path: skip reading data entirely.
-			 * Only read the trailing partial sector if needed for
-			 * do_reflink_write()'s zero-padding.
-			 */
-			to_write = ioctl_len;
-			write_buf = source->buf;
-
-			if (to_read % sectorsize) {
-				u64 partial_off = round_down(to_read, sectorsize);
-				ssize_t ret_read;
-
-				memset(source->buf + partial_off, 0, sectorsize);
-				ret_read = pread(source->fd,
-						 source->buf + partial_off,
-						 to_read - partial_off,
-						 file_pos + partial_off);
-				if (ret_read < 0) {
-					error("cannot read %s at offset %llu: %m",
-					      source->path_name,
-					      file_pos + partial_off);
-					free(fetched_csums_buf);
-					fetched_csums_buf = NULL;
-					return -errno;
-				}
-			}
-
-			goto do_write;
-		}
 	}
 
-read_data:
-	ret = read_from_source(root->fs_info, source->path_name, source->fd,
-			       source->buf, file_pos, to_read);
-	if (ret < 0)
-		return ret;
-
-	to_write = round_up(to_read, sectorsize);
-	write_buf = source->buf;
-	memset(write_buf + to_read, 0, to_write - to_read);
-
-do_write:
+fallback:
 	ret = btrfs_reserve_extent(trans, root, to_write, 0, 0,
 				   (u64)-1, &key, 1);
 	if (ret) {
@@ -1126,11 +1097,21 @@ do_write:
 
 	logical = key.objectid;
 
-	if (g_do_reflink) {
+	if (do_reflink) {
 		ret = do_reflink_write(root->fs_info, source, logical, file_pos,
-				       to_read, write_buf);
+				       to_read);
 	} else {
-		ret = write_data_to_disk(root->fs_info, write_buf, logical, to_write);
+		if (!data_ready) {
+			ret = read_from_source(root->fs_info, source->path_name,
+					       source->fd, source->buf, file_pos, to_read);
+			if (ret < 0) {
+				free(fetched_csums_buf);
+				return ret;
+			}
+			memset(source->buf + to_read, 0, to_write - to_read);
+			data_ready = true;
+		}
+		ret = write_data_to_disk(root->fs_info, source->buf, logical, to_write);
 	}
 
 	if (ret) {
@@ -1143,15 +1124,6 @@ do_write:
 		if (fetched_csums) {
 			unsigned int last_full = fetched_num_csums;
 
-			/*
-			 * For the trailing partial sector, compute the csum
-			 * from the data we actually wrote (zero-padded) rather
-			 * than from the ioctl.  The source extent may have
-			 * different data after the file end.
-			 */
-			if (to_read % sectorsize)
-				last_full = fetched_num_csums - 1;
-
 			for (unsigned int i = 0; i < last_full; i++) {
 				ret = btrfs_insert_file_block_csum(trans,
 						logical + (i * sectorsize),
@@ -1163,27 +1135,26 @@ do_write:
 					return ret;
 				}
 			}
-
-			if (last_full < fetched_num_csums) {
-				u64 partial_off = round_down(to_read, sectorsize);
-
-				ret = btrfs_csum_file_block(trans,
-						logical + partial_off,
-						BTRFS_EXTENT_CSUM_OBJECTID,
-						root->fs_info->csum_type,
-						source->buf + partial_off);
-				if (ret) {
+		} else {
+			/* Reflink without prefetched-csums. */
+			if (!data_ready) {
+				ret = read_from_source(root->fs_info,
+						       source->path_name,
+						       source->fd, source->buf,
+						       file_pos, to_read);
+				if (ret < 0) {
 					free(fetched_csums_buf);
 					return ret;
 				}
+				memset(source->buf + to_read, 0, to_write - to_read);
+				data_ready = true;
 			}
-		} else {
 			for (unsigned int i = 0; i < to_write / sectorsize; i++) {
 				ret = btrfs_csum_file_block(trans,
 						logical + (i * sectorsize),
 						BTRFS_EXTENT_CSUM_OBJECTID,
 						root->fs_info->csum_type,
-						write_buf + (i * sectorsize));
+						source->buf + (i * sectorsize));
 				if (ret)
 					return ret;
 			}
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] btrfs-progs: mkfs-tests: add a new one for '--reflink' option
  2026-05-18 10:20 [PATCH 0/3] mkfs/rootdir: refactor and enhancements, part 1 Qu Wenruo
  2026-05-18 10:20 ` [PATCH 1/3] btrfs-progs: rename logical bytenr parameter for add_file_item_extent() Qu Wenruo
  2026-05-18 10:20 ` [PATCH 2/3] btrfs: mkfs/rootdir: refactor the last block handling Qu Wenruo
@ 2026-05-18 10:20 ` Qu Wenruo
  2 siblings, 0 replies; 4+ messages in thread
From: Qu Wenruo @ 2026-05-18 10:20 UTC (permalink / raw)
  To: linux-btrfs

The new reflink option will allow mkfs.btrfs to reflink the aligned
blocks from the source fs to the fs image.

This will allow us to skip the time consuming IO.

The test case create a special layout to exercise the corner cases, the
layout looks like:

 $TEST_MNT
 |- rootdir/
 |  |- aligned	               <--- 16M file, the regular routine.
 |  |- multi_block_unaligned   <--- 65K file, checking the handling of
 |  |                               of the last partial block.
 |  |- partial_block           <--- 2K file, would be inlined.
 |  |- hole                    <--- A hole.
 |- image                      <--- The fs image.

Then create the image using the same rootdir/, but with and without
--reflink option.

Verify both image by checking the contents (through md5sum), and throw
"btrfs check --check-data-csum" on them.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 tests/mkfs-tests/043-rootdir-reflink/test.sh | 57 ++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100755 tests/mkfs-tests/043-rootdir-reflink/test.sh

diff --git a/tests/mkfs-tests/043-rootdir-reflink/test.sh b/tests/mkfs-tests/043-rootdir-reflink/test.sh
new file mode 100755
index 000000000000..ff012ce2db29
--- /dev/null
+++ b/tests/mkfs-tests/043-rootdir-reflink/test.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+# Make sure the --reflink option works.
+
+source "$TEST_TOP/common" || exit
+
+check_prereq mkfs.btrfs
+check_prereq btrfs
+
+setup_root_helper
+prepare_test_dev
+
+verify_fs_image()
+{
+	# Verify the content of the new fs image
+	run_check $SUDO_HELPER mount "$TEST_MNT/image" "$TEST_MNT/rootdir"
+	run_check $SUDO_HELPER md5sum -c "$TEST_MNT/md5sum"
+	run_check $SUDO_HELPER umount "$TEST_MNT/rootdir"
+	run_check $SUDO_HELPER "$TOP/btrfs" check --check-data-csum "$TEST_MNT/image"
+	# Wait for the loopdev of "$TEST_MNT/image" to be completely removed, so that we can
+	# unmount "$TEST_MNT"
+	run_mayfail $SUDO_HELPER udevadm settle
+}
+
+run_check_mkfs_test_dev
+run_check_mount_test_dev -o max_inline=0
+
+# Populate the rootdir
+run_check $SUDO_HELPER mkdir -p "$TEST_MNT/rootdir"
+
+# A regular 16M file, exercising the aligned block handling.
+run_check $SUDO_HELPER dd if=/dev/urandom of="$TEST_MNT/rootdir/aligned" \
+	bs=1M count=16 status=noxfer > /dev/null 2>&1
+
+# A regular 65K file, mixing aligned block handling and the tailing partial block
+# handling.
+run_check $SUDO_HELPER dd if=/dev/urandom of="$TEST_MNT/rootdir/multi_block_unaligned" \
+	bs=1K count=65 status=noxfer > /dev/null 2>&1
+
+# A regular 2K file, should be inlined inside the fs image.
+run_check $SUDO_HELPER dd if=/dev/urandom of="$TEST_MNT/rootdir/partial_block" \
+	bs=1K count=2 status=noxfer > /dev/null 2>&1
+
+# A hole
+run_check $SUDO_HELPER truncate -s 37k "$TEST_MNT/rootdir/hole"
+
+run_check sync
+
+# Generate the md5sum for all above files.
+run_check_stdout $SUDO_HELPER find "$TEST_MNT/rootdir" -type f -exec md5sum {} \+ > "$TEST_MNT/md5sum"
+
+run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_MNT/image" --reflink --rootdir "$TEST_MNT/rootdir"
+verify_fs_image
+
+run_check $SUDO_HELPER "$TOP/mkfs.btrfs" -f "$TEST_MNT/image" --rootdir "$TEST_MNT/rootdir"
+verify_fs_image
+
+run_check $SUDO_HELPER umount "$TEST_MNT"
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-05-18 10:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-18 10:20 [PATCH 0/3] mkfs/rootdir: refactor and enhancements, part 1 Qu Wenruo
2026-05-18 10:20 ` [PATCH 1/3] btrfs-progs: rename logical bytenr parameter for add_file_item_extent() Qu Wenruo
2026-05-18 10:20 ` [PATCH 2/3] btrfs: mkfs/rootdir: refactor the last block handling Qu Wenruo
2026-05-18 10:20 ` [PATCH 3/3] btrfs-progs: mkfs-tests: add a new one for '--reflink' option Qu Wenruo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.