Re: [PATCH 1/2] btrfs: use proper inclusive end in extent_fiemap()

Daniel Vacek <[email protected]> Tue, 28 Jul 2026 11:47:09 +0200
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <CAPjX3FesY+U9BMUVjUM3Cbwsdbac0-4RK4pH9WR5-5nvKoTH1w@mail.gmail.com>
On Tue, 28 Jul 2026 at 11:17, Daniel Vacek <[email protected]> wrote:
> On Tue, 28 Jul 2026 at 10:40, Qu Wenruo <[email protected]> wrote:
> > 在 2026/7/28 17:35, Daniel Vacek 写道:
> > > On Tue, 28 Jul 2026 at 08:46, Qu Wenruo <[email protected]> wrote:
> > >> The @end parameter for all extent io tree helpers is inclusive, but
> > >> the call site in extent_fiemap() is passing exclusive end.
> > >>
> > >> Fix it to follow the common pattern.
> > >>
> > >> Fixes: ac3c0d36a2a2 ("btrfs: make fiemap more efficient and accurate reporting extent sharedness")
> > >> Signed-off-by: Qu Wenruo <[email protected]>
> > >> ---
> > >>   fs/btrfs/fiemap.c | 8 ++++----
> > >>   1 file changed, 4 insertions(+), 4 deletions(-)
> > >>
> > >> diff --git a/fs/btrfs/fiemap.c b/fs/btrfs/fiemap.c
> > >> index ba6a360074c0..2f2ae0b76799 100644
> > >> --- a/fs/btrfs/fiemap.c
> > >> +++ b/fs/btrfs/fiemap.c
> > >> @@ -657,7 +657,7 @@ static int extent_fiemap(struct btrfs_inode *inode,
> > >>
> > >>   restart:
> > >>          range_start = round_down(start, sectorsize);
> > >> -       range_end = round_up(start + len, sectorsize);
> > >> +       range_end = round_up(start + len, sectorsize) - 1;
> > >>          prev_extent_end = range_start;
> > >>
> > >>          btrfs_lock_extent(&inode->io_tree, range_start, range_end, &cached_state);
> > >> @@ -710,7 +710,7 @@ static int extent_fiemap(struct btrfs_inode *inode,
> > >>
> > >>                  /* We have in implicit hole (NO_HOLES feature enabled). */
> > >>                  if (prev_extent_end < key.offset) {
> > >> -                       const u64 hole_end = min(key.offset, range_end) - 1;
> > >> +                       const u64 hole_end = min(key.offset - 1, range_end);
> > >>
> > >>                          ret = fiemap_process_hole(inode, fieinfo, &cache,
> > >>                                                    &delalloc_cached_state,
> > >> @@ -812,10 +812,10 @@ static int extent_fiemap(struct btrfs_inode *inode,
> > >>          if (!stopped && prev_extent_end < range_end) {
> > >>                  ret = fiemap_process_hole(inode, fieinfo, &cache,
> > >>                                            &delalloc_cached_state, backref_ctx,
> > >> -                                         0, 0, 0, prev_extent_end, range_end - 1);
> > >> +                                         0, 0, 0, prev_extent_end, range_end);
> > >>                  if (ret < 0)
> > >>                          goto out_unlock;
> > >> -               prev_extent_end = range_end;
> > >> +               prev_extent_end = range_end + 1;
> > >>          }
> > >>
> > >>          if (cache.cached && cache.offset + cache.len >= last_extent_end) {
> > >> --
> > >> 2.54.0
> > >
> > > I don't really get why you left out these:
> > >
> > > @@ -680,7 +680,7 @@ static int extent_fiemap(struct btrfs_inode *inode,
> > >                  goto check_eof_delalloc;
> > >          }
> > >
> > > -       while (prev_extent_end < range_end) {
> > > +       while (prev_extent_end <= range_end) {
> > >                  struct extent_buffer *leaf = path->nodes[0];
> > >                  struct btrfs_file_extent_item *ei;
> > >                  struct btrfs_key key;
> > > @@ -809,13 +809,13 @@ static int extent_fiemap(struct btrfs_inode *inode,
> > >          }
> > >
> > >   check_eof_delalloc:
> > > -       if (!stopped && prev_extent_end < range_end) {
> > > +       if (!stopped && prev_extent_end <= range_end) {
> > >                  ret = fiemap_process_hole(inode, fieinfo, &cache,
> > >                                            &delalloc_cached_state, backref_ctx,
> > >
> > > Am I missing something?
> >
> > Because we won't reach the == case at all.
> >
> > The start is always increased by a value aligned to sectorsize.
>
> I understand round_down() possibly decreases not increases. So if
> start and start + len - 1 fall into the same block you get the ==
> case. Am I wrong?

Of course I am, as it's not divided, just rounded. For some reason I
imagined these were block numbers not bytes. My bad.
Sorry about the noise.

> > For inclusive range_end, we either completely pass it by 1, or smaller
> > than it.
> >
> > So that "==" will never be hit.>
> > > --nX
> >