From: Boris Burkov <boris@bur.io>
To: Filipe Manana <fdmanana@kernel.org>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH 16/16] btrfs: cache if we are using free space bitmaps for a block group
Date: Tue, 17 Jun 2025 15:12:15 -0700 [thread overview]
Message-ID: <20250617221215.GA2152829@zen.localdomain> (raw)
In-Reply-To: <CAL3q7H4RGxg7D8hvSC72JnHEKssvdYBanEfxT8fnFX=L26pE+Q@mail.gmail.com>
On Tue, Jun 17, 2025 at 10:59:04PM +0100, Filipe Manana wrote:
> On Tue, Jun 17, 2025 at 10:51 PM Boris Burkov <boris@bur.io> wrote:
> >
> > On Tue, Jun 17, 2025 at 05:13:11PM +0100, fdmanana@kernel.org wrote:
> > > From: Filipe Manana <fdmanana@suse.com>
> > >
> > > Every time we add free space to the free space tree or we remove free
> > > space from the free space tree, we do a lookup for the block group's free
> > > space info item in the free space tree. This takes time, navigating the
> > > btree and we may block either on IO when reading extent buffers from disk
> > > or on extent buffer lock contention due to concurrency.
> > >
> > > Instead of doing this lookup everytime, cache the result in the block
> > > structure and use it after the first lookup. This adds two boolean members
> > > to the block group structure but doesn't increase the structure's size.
> > >
> > > The following script that runs fs_mark was used to measure the time spent
> > > on run_delayed_tree_ref(), since down that call chain we have calls to
> > > add and remove free space to/from the free space tree (calls to
> > > btrfs_add_to_free_space_tree() and btrfs_remove_from_free_space_tree()):
> > >
> > > $ cat test.sh
> > > #!/bin/bash
> > >
> > > DEV=/dev/nullb0
> > > MNT=/mnt
> > > FILES=100000
> > > THREADS=$(nproc --all)
> > >
> > > echo "performance" | \
> > > tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
> > >
> > > umount $DEV &> /dev/null
> > > mkfs.btrfs -f $DEV
> > > mount -o ssd $DEV $MNT
> > >
> > > OPTS="-S 0 -L 5 -n $FILES -s 0 -t $THREADS -k"
> > > for ((i = 1; i <= $THREADS; i++)); do
> > > OPTS="$OPTS -d $MNT/d$i"
> > > done
> > >
> > > fs_mark $OPTS
> > >
> > > umount $MNT
> > >
> > > This is a heavy metadata test as it's exercising only file creation, so a
> > > lot of allocations of metadata extents, creating delayed refs for adding
> > > new metadata extents and dropping existing ones due to COW. The results
> > > of the times it took to execute run_delayed_tree_ref(), in nanoseconds,
> > > are the following.
> > >
> > > Before this change:
> > >
> > > Range: 1868.000 - 6482857.000; Mean: 10231.430; Median: 7005.000; Stddev: 27993.173
> > > Percentiles: 90th: 13342.000; 95th: 23279.000; 99th: 82448.000
> > > 1868.000 - 4222.038: 270696 ############
> > > 4222.038 - 9541.029: 1201327 #####################################################
> > > 9541.029 - 21559.383: 385436 #################
> > > 21559.383 - 48715.063: 64942 ###
> > > 48715.063 - 110073.800: 31454 #
> > > 110073.800 - 248714.944: 8218 |
> > > 248714.944 - 561977.042: 1030 |
> > > 561977.042 - 1269798.254: 295 |
> > > 1269798.254 - 2869132.711: 116 |
> > > 2869132.711 - 6482857.000: 28 |
> > >
> > > After this change:
> > >
> > > Range: 1554.000 - 4557014.000; Mean: 9168.164; Median: 6391.000; Stddev: 21467.060
> > > Percentiles: 90th: 12478.000; 95th: 20964.000; 99th: 72234.000
> > > 1554.000 - 3453.820: 219004 ############
> > > 3453.820 - 7674.743: 980645 #####################################################
> > > 7674.743 - 17052.574: 552486 ##############################
> > > 17052.574 - 37887.762: 68558 ####
> > > 37887.762 - 84178.322: 31557 ##
> > > 84178.322 - 187024.331: 12102 #
> > > 187024.331 - 415522.355: 1364 |
> > > 415522.355 - 923187.626: 256 |
> > > 923187.626 - 2051092.468: 125 |
> > > 2051092.468 - 4557014.000: 21 |
> > >
> > > Signed-off-by: Filipe Manana <fdmanana@suse.com>
> > > ---
> > > fs/btrfs/block-group.h | 5 +++++
> > > fs/btrfs/free-space-tree.c | 12 +++++++++++-
> > > 2 files changed, 16 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
> > > index aa176cc9a324..8a8f1fff7e5b 100644
> > > --- a/fs/btrfs/block-group.h
> > > +++ b/fs/btrfs/block-group.h
> > > @@ -246,6 +246,11 @@ struct btrfs_block_group {
> > > /* Lock for free space tree operations. */
> > > struct mutex free_space_lock;
> > >
> > > + /* Protected by @free_space_lock. */
> > > + bool use_free_space_bitmaps;
> > > + /* Protected by @free_space_lock. */
> > > + bool use_free_space_bitmaps_cached;
> > > +
> > > /*
> > > * Number of extents in this block group used for swap files.
> > > * All accesses protected by the spinlock 'lock'.
> > > diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
> > > index 3c8bb95fa044..1bd07e91fd5a 100644
> > > --- a/fs/btrfs/free-space-tree.c
> > > +++ b/fs/btrfs/free-space-tree.c
> > > @@ -287,6 +287,8 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
> > > leaf = path->nodes[0];
> > > flags = btrfs_free_space_flags(leaf, info);
> > > flags |= BTRFS_FREE_SPACE_USING_BITMAPS;
> > > + block_group->use_free_space_bitmaps = true;
> > > + block_group->use_free_space_bitmaps_cached = true;
> > > btrfs_set_free_space_flags(leaf, info, flags);
> > > expected_extent_count = btrfs_free_space_extent_count(leaf, info);
> > > btrfs_release_path(path);
> > > @@ -434,6 +436,8 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans,
> > > leaf = path->nodes[0];
> > > flags = btrfs_free_space_flags(leaf, info);
> > > flags &= ~BTRFS_FREE_SPACE_USING_BITMAPS;
> > > + block_group->use_free_space_bitmaps = false;
> > > + block_group->use_free_space_bitmaps_cached = true;
> > > btrfs_set_free_space_flags(leaf, info, flags);
> > > expected_extent_count = btrfs_free_space_extent_count(leaf, info);
> > > btrfs_release_path(path);
> > > @@ -796,13 +800,19 @@ static int use_bitmaps(struct btrfs_block_group *bg, struct btrfs_path *path)
> > > struct btrfs_free_space_info *info;
> > > u32 flags;
> > >
> > > + if (bg->use_free_space_bitmaps_cached)
> > > + return bg->use_free_space_bitmaps;
> > > +
> >
> > I'm a little worried about what happens if the reader observes the
> > writes out of order.
> >
> > i.e., say T1 is calling btrfs_convert_free_space_to_bitmaps() and T2 is
> > calling use_bitmaps(). Then if T2 observes use_free_space_bitmaps_cached
> > set to true but not use_free_space_bitmaps set to true, it will get the
> > wrong value.
> >
> > Or is there some higher level locking that I missed protecting us?
>
> Yes, there is. It's the block group's free_space_lock mutex, taken at
> any entry point that modifies the free space tree.
>
> Thanks.
>
Ah, yup, looks good, thanks.
You can add
Reviewed-by: Boris Burkov <boris@bur.io>
to the whole series.
> >
> > Thanks,
> > Boris
> >
> > > info = btrfs_search_free_space_info(NULL, bg, path, 0);
> > > if (IS_ERR(info))
> > > return PTR_ERR(info);
> > > flags = btrfs_free_space_flags(path->nodes[0], info);
> > > btrfs_release_path(path);
> > >
> > > - return (flags & BTRFS_FREE_SPACE_USING_BITMAPS) ? 1 : 0;
> > > + bg->use_free_space_bitmaps = (flags & BTRFS_FREE_SPACE_USING_BITMAPS);
> > > + bg->use_free_space_bitmaps_cached = true;
> > > +
> > > + return bg->use_free_space_bitmaps;
> > > }
> > >
> > > EXPORT_FOR_TESTS
> > > --
> > > 2.47.2
> > >
next prev parent reply other threads:[~2025-06-17 22:10 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-17 16:12 [PATCH 00/16] btrfs: free space tree optimization and cleanups fdmanana
2025-06-17 16:12 ` [PATCH 01/16] btrfs: remove pointless out label from add_new_free_space_info() fdmanana
2025-06-17 16:12 ` [PATCH 02/16] btrfs: remove pointless out label from update_free_space_extent_count() fdmanana
2025-06-17 16:12 ` [PATCH 03/16] btrfs: make extent_buffer_test_bit() return a boolean instead fdmanana
2025-06-17 16:12 ` [PATCH 04/16] btrfs: make free_space_test_bit() " fdmanana
2025-06-17 16:13 ` [PATCH 05/16] btrfs: remove pointless out label from modify_free_space_bitmap() fdmanana
2025-06-17 16:13 ` [PATCH 06/16] btrfs: remove pointless out label from remove_free_space_extent() fdmanana
2025-06-17 16:13 ` [PATCH 07/16] btrfs: remove pointless out label from add_free_space_extent() fdmanana
2025-06-17 16:13 ` [PATCH 08/16] btrfs: remove pointless out label from load_free_space_bitmaps() fdmanana
2025-06-17 16:13 ` [PATCH 09/16] btrfs: remove pointless out label from load_free_space_extents() fdmanana
2025-06-17 16:13 ` [PATCH 10/16] btrfs: add btrfs prefix to free space tree exported functions fdmanana
2025-06-17 16:13 ` [PATCH 11/16] btrfs: rename free_space_set_bits() and make it less confusing fdmanana
2025-06-17 16:13 ` [PATCH 12/16] btrfs: turn remove argument of modify_free_space_bitmap() to boolean fdmanana
2025-06-17 16:13 ` [PATCH 13/16] btrfs: avoid double slot decrement at btrfs_convert_free_space_to_extents() fdmanana
2025-06-17 16:13 ` [PATCH 14/16] btrfs: use fs_info from local variable in btrfs_convert_free_space_to_extents() fdmanana
2025-06-17 16:13 ` [PATCH 15/16] btrfs: add and use helper to determine if using bitmaps in free space tree fdmanana
2025-06-17 21:41 ` Boris Burkov
2025-06-17 16:13 ` [PATCH 16/16] btrfs: cache if we are using free space bitmaps for a block group fdmanana
2025-06-17 21:52 ` Boris Burkov
2025-06-17 21:59 ` Filipe Manana
2025-06-17 22:12 ` Boris Burkov [this message]
2025-06-18 11:50 ` [PATCH 00/16] btrfs: free space tree optimization and cleanups David Sterba
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250617221215.GA2152829@zen.localdomain \
--to=boris@bur.io \
--cc=fdmanana@kernel.org \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox