]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: remove locked subpage bitmap
authorQu Wenruo <wqu@suse.com>
Sat, 9 May 2026 09:06:31 +0000 (18:36 +0930)
committerDavid Sterba <dsterba@suse.com>
Mon, 8 Jun 2026 13:53:32 +0000 (15:53 +0200)
Currently there are two members inside btrfs_folio_state that are related
to locked bitmap:

- locked sub-bitmap inside btrfs_folio_state::bitmaps[]
  The enum btrfs_bitmap_nr_locked determines the sub-bitmap.

- btrfs_folio_state::nr_locked
  Which records how many blocks are locked inside the folio.

The locked sub-bitmap is a btrfs specific per-block tracking mechanism,
which is mostly for async-submission, utilized by compressed writes.

The sub-bitmap itself is a super set of nr_locked, as it can provide a
more reliable tracking.

But the sub-bitmap itself can be pretty large for the incoming huge
folio, 2M sized folio for 4K page size, meaning 512 bits for one
sub-bitmap.

Furthermore, in the long run compression will be reworked to get rid of
async-submission completely, there is not much need for a full
sub-bitmap to track the locked status.

This patch removes the locked sub-bitmap and only relies on @nr_locked
atomic to do the tracking.
This can also save 64 bytes from btrfs_folio_state::bitmaps[] for a huge
folio.

This will reduce some safety checks, as previously if a block is not
locked, btrfs_folio_end_lock()/btrfs_folio_end_lock_bitmap() will find
out that, and skip reducing @nr_locked for that block, and avoid
under-flow.

But this safety net itself shouldn't be necessary in the first place.
If we're unlocking a block that is not locked, it's a bug in the logic,
and we should catch it, not silently ignoring it.
Thus I believe the removal of the extra safety net should not be a
problem.

Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/subpage.c
fs/btrfs/subpage.h

index 8a09f34ea31ec22035fba8ccff68292158edde4a..ff68e79fe72d3d3833462dbb449a04ff5da105ad 100644 (file)
@@ -224,11 +224,8 @@ static bool btrfs_subpage_end_and_test_lock(const struct btrfs_fs_info *fs_info,
                                            struct folio *folio, u64 start, u32 len)
 {
        struct btrfs_folio_state *bfs = folio_get_private(folio);
-       const int start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
        const int nbits = (len >> fs_info->sectorsize_bits);
        unsigned long flags;
-       unsigned int cleared = 0;
-       int bit = start_bit;
        bool last;
 
        btrfs_subpage_assert(fs_info, folio, start, len);
@@ -245,15 +242,10 @@ static bool btrfs_subpage_end_and_test_lock(const struct btrfs_fs_info *fs_info,
                spin_unlock_irqrestore(&bfs->lock, flags);
                return true;
        }
-
-       for_each_set_bit_from(bit, bfs->bitmaps, start_bit + nbits) {
-               clear_bit(bit, bfs->bitmaps);
-               cleared++;
-       }
-       ASSERT(atomic_read(&bfs->nr_locked) >= cleared,
-              "atomic_read(&bfs->nr_locked)=%d cleared=%d",
-              atomic_read(&bfs->nr_locked), cleared);
-       last = atomic_sub_and_test(cleared, &bfs->nr_locked);
+       ASSERT(atomic_read(&bfs->nr_locked) >= nbits,
+              "atomic_read(&bfs->nr_locked)=%d nbits=%d",
+              atomic_read(&bfs->nr_locked), nbits);
+       last = atomic_sub_and_test(nbits, &bfs->nr_locked);
        spin_unlock_irqrestore(&bfs->lock, flags);
        return last;
 }
@@ -309,11 +301,9 @@ void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
 {
        struct btrfs_folio_state *bfs = folio_get_private(folio);
        const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
-       const int start_bit = blocks_per_folio * btrfs_bitmap_nr_locked;
+       const unsigned int nbits = bitmap_weight(&bitmap, blocks_per_folio);
        unsigned long flags;
        bool last = false;
-       int cleared = 0;
-       int bit;
 
        if (!btrfs_is_subpage(fs_info, folio)) {
                folio_unlock(folio);
@@ -327,14 +317,10 @@ void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
        }
 
        spin_lock_irqsave(&bfs->lock, flags);
-       for_each_set_bit(bit, &bitmap, blocks_per_folio) {
-               if (test_and_clear_bit(bit + start_bit, bfs->bitmaps))
-                       cleared++;
-       }
-       ASSERT(atomic_read(&bfs->nr_locked) >= cleared,
-              "atomic_read(&bfs->nr_locked)=%d cleared=%d",
-              atomic_read(&bfs->nr_locked), cleared);
-       last = atomic_sub_and_test(cleared, &bfs->nr_locked);
+       ASSERT(atomic_read(&bfs->nr_locked) >= nbits,
+              "atomic_read(&bfs->nr_locked)=%d nbits=%d",
+              atomic_read(&bfs->nr_locked), nbits);
+       last = atomic_sub_and_test(nbits, &bfs->nr_locked);
        spin_unlock_irqrestore(&bfs->lock, flags);
        if (last)
                folio_unlock(folio);
@@ -696,7 +682,6 @@ void btrfs_folio_set_lock(const struct btrfs_fs_info *fs_info,
 {
        struct btrfs_folio_state *bfs;
        unsigned long flags;
-       unsigned int start_bit;
        unsigned int nbits;
        int ret;
 
@@ -705,15 +690,8 @@ void btrfs_folio_set_lock(const struct btrfs_fs_info *fs_info,
                return;
 
        bfs = folio_get_private(folio);
-       start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
        nbits = len >> fs_info->sectorsize_bits;
        spin_lock_irqsave(&bfs->lock, flags);
-       /* Target range should not yet be locked. */
-       if (unlikely(!bitmap_test_range_all_zero(bfs->bitmaps, start_bit, nbits))) {
-               SUBPAGE_DUMP_BITMAP(fs_info, folio, locked, start, len);
-               ASSERT(bitmap_test_range_all_zero(bfs->bitmaps, start_bit, nbits));
-       }
-       bitmap_set(bfs->bitmaps, start_bit, nbits);
        ret = atomic_add_return(nbits, &bfs->nr_locked);
        ASSERT(ret <= btrfs_blocks_per_folio(fs_info, folio));
        spin_unlock_irqrestore(&bfs->lock, flags);
@@ -750,7 +728,6 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
        unsigned long dirty_bitmap;
        unsigned long writeback_bitmap;
        unsigned long ordered_bitmap;
-       unsigned long locked_bitmap;
        unsigned long flags;
 
        ASSERT(folio_test_private(folio) && folio_get_private(folio));
@@ -762,16 +739,14 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
        GET_SUBPAGE_BITMAP(fs_info, folio, dirty, &dirty_bitmap);
        GET_SUBPAGE_BITMAP(fs_info, folio, writeback, &writeback_bitmap);
        GET_SUBPAGE_BITMAP(fs_info, folio, ordered, &ordered_bitmap);
-       GET_SUBPAGE_BITMAP(fs_info, folio, locked, &locked_bitmap);
        spin_unlock_irqrestore(&bfs->lock, flags);
 
        dump_page(folio_page(folio, 0), "btrfs folio state dump");
        btrfs_warn(fs_info,
-"start=%llu len=%u page=%llu, bitmaps uptodate=%*pbl dirty=%*pbl locked=%*pbl writeback=%*pbl ordered=%*pbl",
+"start=%llu len=%u page=%llu, bitmaps uptodate=%*pbl dirty=%*pbl writeback=%*pbl ordered=%*pbl",
                    start, len, folio_pos(folio),
                    blocks_per_folio, &uptodate_bitmap,
                    blocks_per_folio, &dirty_bitmap,
-                   blocks_per_folio, &locked_bitmap,
                    blocks_per_folio, &writeback_bitmap,
                    blocks_per_folio, &ordered_bitmap);
 }
index fdea0b605bfc7e531e346ed85b94436ffb32d3ca..ccdb817381dd5f66d1ec2c2fe8e47e5f75692016 100644 (file)
@@ -45,16 +45,6 @@ enum {
         */
        btrfs_bitmap_nr_ordered,
 
-       /*
-        * The locked bit is for async delalloc range (compression), currently
-        * async extent is queued with the range locked, until the compression
-        * is done.
-        * So an async extent can unlock the range at any random timing.
-        *
-        * This will need a rework on the async extent lifespan (mark writeback
-        * and do compression) before deprecating this flag.
-        */
-       btrfs_bitmap_nr_locked,
        btrfs_bitmap_nr_max
 };