Re: [PATCH 4/6] btrfs: defrag: use auto kfree in defrag_one_range() for folios array

Filipe Manana <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <CAL3q7H4NKQgF2rn==D+828EM=cLzRFCj19Zx=GiaLh=7S9DiKQ@mail.gmail.com>
On Tue, Jun 30, 2026 at 9:05 PM David Sterba <[email protected]> wrote:
>
> On Tue, Jun 30, 2026 at 10:53:54AM +0100, Filipe Manana wrote:
> > On Mon, Jun 29, 2026 at 11:55 PM David Sterba <[email protected]> wrote:
> > > > @@ -1251,7 +1249,6 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
> > > >               folio_unlock(folios[i]);
> > > >               folio_put(folios[i]);
> > > >       }
> > > > -     kfree(folios);
> > >
> > > There's non-trivial work following this freeing, down from
> >
> > I'd rather disagree it's non-trivial work.
> > Everything below kfree() is trivial, and it was placed there in patch
> > 1 by chance.
>
> See a rough call graph of functions below the removed kfree, that's far
> beyond trivial. We follow the principle of not holding resources for
> longer than necessary, this applies to memory too.

It's still fast stuff. We hold the inode's vfs lock higher up the call
chain, so the inode's block reserve spinlocks are very unlikely to be
busy.

Also, you are concerned about slightly delayed memory release, but why
is that more important than releasing excess space first? Holding
excess space for longer can have an heavy impact - blocking tasks and
triggering async reclaim (running delayed refs, delayed items, commit
transactions, etc).

If it were a path-freeing operation, I could agree, since we would be
holding locks on a btree and impacting concurrency.
But in this case, deciding between releasing memory first or releasing
excess space (and most of the time we won't have excess space to
release, as we checked for holes before locking the extent range,
etc), it's not clear what is most beneficial.

>
> What I count as trivial is:
>
> - several asignments of local variables, ponter dererences are ok
> - one shallow function call
> - called functions do simple expressions only
>
> Indicators of what's not trivial:
>
> - spin locks
> - structure traversal
> - unbounded calls like waiting
> - more allocations
> - nesting deeper than 2 calls
>
>
> defrag_one_range:
>
>   btrfs_delalloc_release_extents
>     spin_lock inode
>       btrfs_mod_outstanding_extents - minor things, trace point call
>       btrfs_calculate_inode_block_rsv_size
>         - several clculations
>         - block rsv spin lock
>     spin_unlock
>     btrfs_inode_rsv_release (1)
>       btrfs_block_rsv_release
>         block_rsv_release_bytes
>           spin lock block group
>           spin lock space info
>           - lots of assignments, pointer derefs, calculations
>       btrfs_qgroup_free_meta_prealloc (branched on qgroups)
>         - qgroup calculations, spin locks taken
>         btrfs_qgroup_free_refroot (2)
>           - spin locks for qgroups
>           find_qgroup_rb
>           - qgroup list traversal
>       btrfs_qgroup_convert_reserved_meta
>         - spin locks for qgroups
>         qgroup_convert_meta
>           - spin locks for qgroups
>           - qgroup iteration
>           - resource releases
>         add_root_meta_rsv
>           - spin lock for reservations
>
>   btrfs_delalloc_release_space
>     btrfs_delalloc_release_metadata
>       - spin lock of inode
>       btrfs_calculate_inode_block_rsv_size
>         - calculations, spin locks
>       btrfs_inode_rsv_release
>         - see (1)
>     btrfs_free_reserved_data_space
>       btrfs_free_reserved_data_space_noquota
>         btrfs_space_info_free_bytes_may_use
>           - spin lock for space info
>           btrfs_try_granting_tickets
>             - reservation processing
>       btrfs_qgroup_free_data
>         __btrfs_qgroup_release_data
>           btrfs_clear_record_extent_bits (no qgroups) (3)
>             btrfs_clear_extent_bit_changeset
>               - tree traversal
>           qgroup_free_reserved_data
>             - ulist traversal
>             btrfs_clear_record_extent_bits
>               - see (3)
>             btrfs_qgroup_free_refroot
>               - see (2)
>           btrfs_clear_record_extent_bits (qgroups)
>             - see (3)
>             btrfs_clear_extent_bit_changeset
>               - tree traversal
>           btrfs_qgroup_free_refroot
>             - see (2)
>
>   extent_changeset_free
>     ulist_release
>       - enumerate nodes, kfree
>     kfree
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.