Skip to content

Port #402: ranged fiemap queries in the dedupe phase - #13

Merged
martinus merged 2 commits into
masterfrom
upstream/402-ranged-fiemap
Jul 15, 2026
Merged

Port #402: ranged fiemap queries in the dedupe phase#13
martinus merged 2 commits into
masterfrom
upstream/402-ranged-fiemap

Conversation

@martinus

Copy link
Copy Markdown
Owner

Ports markfasheh/duperemove#402 by ElXreno (@ElXreno).

During dedupe, fiemap_count_shared() and fiemap_scan_extent() called do_fiemap(), which fetches the file's entire extent map even though they only need the extent(s) at one offset. On large/fragmented files that enumerates every extent on every call and dominates the dedupe phase.

Adds do_fiemap_range() (maps only [start, start+length)) and uses it in both callers; fiemap_scan_extent() now reads fm_extents[0] directly since the range starts at the target offset.

Measured on a 1395-extent duplicated file: dedupe 3.6s → 1.3s (~2.7×). Upstream reports far larger wins on 200 GB+/200K-extent images. Correctness unchanged; 39 integration tests pass (the existing @requires_reflink dedupe tests exercise both patched functions).

Reviewed via /simplify:

  • merged the near-duplicate fiemap_count_extents helper into one range-aware version;
  • documented that do_fiemap_range() returns NULL for an empty range (hole) as well as on error — which is exactly why fiemap_count_shared() now treats NULL as "0 shared", preserving the old whole-file behaviour for holes.

(Noted follow-up, not done here: fiemap_scan_extent() only reads the first extent, so it could skip the count ioctl entirely with a fixed size-1 query — a further ~2× syscall cut on that path.)

🤖 Generated with Claude Code

martinus and others added 2 commits July 15, 2026 16:23
Ports markfasheh#405 by Tobias Klausmann.

With --skip-zeroes, process_blocks() ran is_block_zeroed() on
buffer->buf + buffer->dl_offset - always block 0 - instead of block #i,
so it skipped either every block or none depending only on whether the
first block happened to be zero. Check the block actually being hashed
(matching the offset already passed to process_block() just below).

Adds an integration test that scans a two-block file with block hashing
and --skip-zeroes and asserts which block survives, catching the bug in
both directions (leading and trailing zero block).

Co-authored-by: Tobias Klausmann <klausman@schwarzvogel.de>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports markfasheh#402 by ElXreno.

During dedupe, fiemap_count_shared() and fiemap_scan_extent() called
do_fiemap(), which fetches the file's ENTIRE extent map even though they
only need the extent(s) at one offset. On large/fragmented files that
enumerates every extent per call and dominates the dedupe phase.

Add do_fiemap_range(), which sets fm_start/fm_length to map only the
requested byte range, and use it in both callers. fiemap_scan_extent()
now reads fm_extents[0] directly (the range starts at e_loff, so the
first returned extent is the target) instead of walking the whole map.

Measured on a 1395-extent duplicated file: dedupe 3.6s -> 1.3s (~2.7x).
Correctness unchanged; 39 integration tests pass.

Reviewed via /simplify: merged the duplicate fiemap_count_extents helper
into one range-aware version, and documented that do_fiemap_range()
returns NULL for an empty range as well as on error (which is why
fiemap_count_shared() now treats NULL as "0 shared", matching the old
whole-file behaviour for holes).

Co-authored-by: ElXreno <elxreno@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@martinus
martinus merged commit 7881cbe into master Jul 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant