Thread (12 messages) 12 messages, 3 authors, 27d ago

Re: [PATCH v3 3/4] btrfs: make inode->outstanding_extents a u64

From: Filipe Manana <fdmanana@kernel.org>
Date: 2026-04-08 15:05:00

On Tue, Apr 7, 2026 at 8:31 PM Boris Burkov [off-list ref] wrote:
quoted hunk ↗ jump to hunk
The maximum file size is MAX_LFS_FILESIZE = (loff_t)LLONG_MAX

As a result, the max extent size computation in btrfs has always been
bounded above by LLONG_MAX / 128MiB, which is ~ 2^63 / 2^27. This has
never fit in a u32. With the recent changes to also divide by 128KiB in
compressed cases, that bound is even higher. Whether or not it is likely
to happen, I think it is nice to try to capture the intent in the types,
so change outstanding_extents to u64, and make mod_outstanding_extents
try to capture some expectations around the size of its inputs.

Signed-off-by: Boris Burkov <redacted>
---
 fs/btrfs/btrfs_inode.h       | 18 ++++++++++++++----
 fs/btrfs/delalloc-space.c    | 19 +++++++++----------
 fs/btrfs/inode.c             | 14 +++++++-------
 fs/btrfs/ordered-data.c      |  4 ++--
 fs/btrfs/tests/inode-tests.c | 18 +++++++++---------
 include/trace/events/btrfs.h |  8 ++++----
 6 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 5368ef87b41a..04825b28f384 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -180,7 +180,7 @@ struct btrfs_inode {
         * items we think we'll end up using, and reserved_extents is the number
         * of extent items we've reserved metadata for. Protected by 'lock'.
         */
-       unsigned outstanding_extents;
+       u64 outstanding_extents;

        /* used to order data wrt metadata */
        spinlock_t ordered_tree_lock;
@@ -429,14 +429,24 @@ static inline bool is_data_inode(const struct btrfs_inode *inode)
 }

 static inline void btrfs_mod_outstanding_extents(struct btrfs_inode *inode,
-                                                int mod)
+                                                int mod, u64 nr_extents)
 {
+       s64 delta = mod * (s64)nr_extents;
+
        lockdep_assert_held(&inode->lock);
-       inode->outstanding_extents += mod;
+       ASSERT(mod == 1 || mod == -1, "mod=%d", mod);
+       ASSERT(nr_extents <= S64_MAX, "nr_extents=%llu", nr_extents);
+       ASSERT(mod == -1 || inode->outstanding_extents <= U64_MAX - nr_extents,
+              "nr_extents=%llu, inode->outstanding_extents=%llu",
+              nr_extents, inode->outstanding_extents);
+       ASSERT(mod == 1 || inode->outstanding_extents >= nr_extents,
+              "mod=%d, nr_extents=%llu, inode->outstanding_extents=%llu",
I don't think there is a need to print mod here, if the assertion
failed, we know it must be -1.
In the previous assertion, we don't print mod, which makes sense since
it must be 1 if it fails.

With that change:

Reviewed-by: Filipe Manana <redacted>

Thanks.
quoted hunk ↗ jump to hunk
+              mod, nr_extents, inode->outstanding_extents);
+       inode->outstanding_extents += delta;
        if (btrfs_is_free_space_inode(inode))
                return;
        trace_btrfs_inode_mod_outstanding_extents(inode->root, btrfs_ino(inode),
-                                                 mod, inode->outstanding_extents);
+                                                 delta, inode->outstanding_extents);
 }

 /*
diff --git a/fs/btrfs/delalloc-space.c b/fs/btrfs/delalloc-space.c
index 9ff02a7da05b..d50081c8089a 100644
--- a/fs/btrfs/delalloc-space.c
+++ b/fs/btrfs/delalloc-space.c
@@ -289,7 +289,7 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
        struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
        u64 reserve_size = 0;
        u64 qgroup_rsv_size = 0;
-       unsigned outstanding_extents;
+       u64 outstanding_extents;

        lockdep_assert_held(&inode->lock);
        outstanding_extents = inode->outstanding_extents;
@@ -316,7 +316,7 @@ static void btrfs_calculate_inode_block_rsv_size(struct btrfs_fs_info *fs_info,
         *
         * This is overestimating in most cases.
         */
-       qgroup_rsv_size = (u64)outstanding_extents * fs_info->nodesize;
+       qgroup_rsv_size = outstanding_extents * fs_info->nodesize;

        spin_lock(&block_rsv->lock);
        block_rsv->size = reserve_size;
@@ -376,7 +376,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
        u64 meta_reserve, qgroup_reserve;
-       unsigned nr_extents;
+       u64 nr_extents;
        enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
        int ret = 0;
@@ -430,7 +430,7 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
         */
        nr_extents = btrfs_inode_max_extents(inode, num_bytes);
        spin_lock(&inode->lock);
-       btrfs_mod_outstanding_extents(inode, nr_extents);
+       btrfs_mod_outstanding_extents(inode, 1, nr_extents);
        if (!(inode->flags & BTRFS_INODE_NODATASUM))
                inode->csum_bytes += disk_num_bytes;
        btrfs_calculate_inode_block_rsv_size(fs_info, inode);
@@ -492,11 +492,11 @@ void btrfs_delalloc_release_metadata(struct btrfs_inode *inode, u64 num_bytes,
 void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
 {
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       unsigned num_extents;
+       u64 num_extents;

        spin_lock(&inode->lock);
        num_extents = btrfs_inode_max_extents(inode, num_bytes);
-       btrfs_mod_outstanding_extents(inode, -num_extents);
+       btrfs_mod_outstanding_extents(inode, -1, num_extents);
        btrfs_calculate_inode_block_rsv_size(fs_info, inode);
        spin_unlock(&inode->lock);
@@ -510,16 +510,15 @@ void btrfs_delalloc_release_extents(struct btrfs_inode *inode, u64 num_bytes)
 void btrfs_delalloc_shrink_extents(struct btrfs_inode *inode, u64 reserved_len, u64 new_len)
 {
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       const u32 reserved_num_extents = btrfs_inode_max_extents(inode, reserved_len);
-       const u32 new_num_extents = btrfs_inode_max_extents(inode, new_len);
-       const int diff_num_extents = new_num_extents - reserved_num_extents;
+       const u64 reserved_num_extents = btrfs_inode_max_extents(inode, reserved_len);
+       const u64 new_num_extents = btrfs_inode_max_extents(inode, new_len);

        ASSERT(new_len <= reserved_len);
        if (new_num_extents == reserved_num_extents)
                return;

        spin_lock(&inode->lock);
-       btrfs_mod_outstanding_extents(inode, diff_num_extents);
+       btrfs_mod_outstanding_extents(inode, -1, reserved_num_extents - new_num_extents);
        btrfs_calculate_inode_block_rsv_size(fs_info, inode);
        spin_unlock(&inode->lock);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 55255f3794c6..b45a92cfe94e 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2536,7 +2536,7 @@ void btrfs_split_delalloc_extent(struct btrfs_inode *inode,
        }

        spin_lock(&inode->lock);
-       btrfs_mod_outstanding_extents(inode, 1);
+       btrfs_mod_outstanding_extents(inode, 1, 1);
        spin_unlock(&inode->lock);
 }
@@ -2566,7 +2566,7 @@ void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state
        /* we're not bigger than the max, unreserve the space and go */
        if (new_size <= max_extent_size) {
                spin_lock(&inode->lock);
-               btrfs_mod_outstanding_extents(inode, -1);
+               btrfs_mod_outstanding_extents(inode, -1, 1);
                spin_unlock(&inode->lock);
                return;
        }
@@ -2597,7 +2597,7 @@ void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state
                return;

        spin_lock(&inode->lock);
-       btrfs_mod_outstanding_extents(inode, -1);
+       btrfs_mod_outstanding_extents(inode, -1, 1);
        spin_unlock(&inode->lock);
 }
@@ -2666,10 +2666,10 @@ void btrfs_set_delalloc_extent(struct btrfs_inode *inode, struct extent_state *s
        if (!(state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
                u64 len = state->end + 1 - state->start;
                u64 prev_delalloc_bytes;
-               u32 num_extents = btrfs_inode_max_extents(inode, len);
+               u64 num_extents = btrfs_inode_max_extents(inode, len);

                spin_lock(&inode->lock);
-               btrfs_mod_outstanding_extents(inode, num_extents);
+               btrfs_mod_outstanding_extents(inode, 1, num_extents);
                spin_unlock(&inode->lock);

                /* For sanity tests */
@@ -2712,7 +2712,7 @@ void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
 {
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
        u64 len = state->end + 1 - state->start;
-       u32 num_extents = btrfs_inode_max_extents(inode, len);
+       u64 num_extents = btrfs_inode_max_extents(inode, len);

        lockdep_assert_held(&inode->io_tree.lock);
@@ -2732,7 +2732,7 @@ void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
                u64 new_delalloc_bytes;

                spin_lock(&inode->lock);
-               btrfs_mod_outstanding_extents(inode, -num_extents);
+               btrfs_mod_outstanding_extents(inode, -1, num_extents);
                spin_unlock(&inode->lock);

                /*
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index e5a24b3ff95e..96ee8ebfdb92 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -223,7 +223,7 @@ static struct btrfs_ordered_extent *alloc_ordered_extent(
         * smallest the extent is going to get.
         */
        spin_lock(&inode->lock);
-       btrfs_mod_outstanding_extents(inode, 1);
+       btrfs_mod_outstanding_extents(inode, 1, 1);
        spin_unlock(&inode->lock);

 out:
@@ -655,7 +655,7 @@ void btrfs_remove_ordered_extent(struct btrfs_ordered_extent *entry)
        btrfs_lockdep_acquire(fs_info, btrfs_trans_pending_ordered);
        /* This is paired with alloc_ordered_extent(). */
        spin_lock(&btrfs_inode->lock);
-       btrfs_mod_outstanding_extents(btrfs_inode, -1);
+       btrfs_mod_outstanding_extents(btrfs_inode, -1, 1);
        spin_unlock(&btrfs_inode->lock);
        if (root != fs_info->tree_root) {
                u64 release;
diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c
index b04fbcaf0a1d..e63afbb9be2b 100644
--- a/fs/btrfs/tests/inode-tests.c
+++ b/fs/btrfs/tests/inode-tests.c
@@ -931,7 +931,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 1) {
                ret = -EINVAL;
-               test_err("miscount, wanted 1, got %u",
+               test_err("miscount, wanted 1, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -946,7 +946,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 2) {
                ret = -EINVAL;
-               test_err("miscount, wanted 2, got %u",
+               test_err("miscount, wanted 2, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -962,7 +962,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 2) {
                ret = -EINVAL;
-               test_err("miscount, wanted 2, got %u",
+               test_err("miscount, wanted 2, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -978,7 +978,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 2) {
                ret = -EINVAL;
-               test_err("miscount, wanted 2, got %u",
+               test_err("miscount, wanted 2, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -996,7 +996,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 4) {
                ret = -EINVAL;
-               test_err("miscount, wanted 4, got %u",
+               test_err("miscount, wanted 4, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -1013,7 +1013,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 3) {
                ret = -EINVAL;
-               test_err("miscount, wanted 3, got %u",
+               test_err("miscount, wanted 3, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -1029,7 +1029,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 4) {
                ret = -EINVAL;
-               test_err("miscount, wanted 4, got %u",
+               test_err("miscount, wanted 4, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -1047,7 +1047,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents != 3) {
                ret = -EINVAL;
-               test_err("miscount, wanted 3, got %u",
+               test_err("miscount, wanted 3, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
@@ -1061,7 +1061,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
        }
        if (BTRFS_I(inode)->outstanding_extents) {
                ret = -EINVAL;
-               test_err("miscount, wanted 0, got %u",
+               test_err("miscount, wanted 0, got %llu",
                         BTRFS_I(inode)->outstanding_extents);
                goto out;
        }
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h
index 8ad7a2d76c1d..caabdc8d9eed 100644
--- a/include/trace/events/btrfs.h
+++ b/include/trace/events/btrfs.h
@@ -2003,15 +2003,15 @@ DEFINE_EVENT(btrfs__prelim_ref, btrfs_prelim_ref_insert,
 );

 TRACE_EVENT(btrfs_inode_mod_outstanding_extents,
-       TP_PROTO(const struct btrfs_root *root, u64 ino, int mod, unsigned outstanding),
+       TP_PROTO(const struct btrfs_root *root, u64 ino, s64 mod, u64 outstanding),

        TP_ARGS(root, ino, mod, outstanding),

        TP_STRUCT__entry_btrfs(
                __field(        u64, root_objectid      )
                __field(        u64, ino                )
-               __field(        int, mod                )
-               __field(        unsigned, outstanding   )
+               __field(        s64, mod                )
+               __field(        u64, outstanding        )
        ),

        TP_fast_assign_btrfs(root->fs_info,
@@ -2021,7 +2021,7 @@ TRACE_EVENT(btrfs_inode_mod_outstanding_extents,
                __entry->outstanding    = outstanding;
        ),

-       TP_printk_btrfs("root=%llu(%s) ino=%llu mod=%d outstanding=%u",
+       TP_printk_btrfs("root=%llu(%s) ino=%llu mod=%lld outstanding=%llu",
                        show_root_type(__entry->root_objectid),
                        __entry->ino, __entry->mod, __entry->outstanding)
 );
--
2.53.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help