* [PATCH 1/7] btrfs: Use percpu refcounting for block groups
[not found] <20260112161549.2786827-1-martin@urbackup.org>
@ 2026-01-12 16:17 ` Martin Raiber
2026-01-12 22:32 ` Boris Burkov
2026-01-14 6:06 ` kernel test robot
0 siblings, 2 replies; 4+ messages in thread
From: Martin Raiber @ 2026-01-12 16:17 UTC (permalink / raw)
To: linux-btrfs; +Cc: Martin Raiber
Use a percpu counter to keep track of the block group refs.
This prevents CPU synchronization completely as long as the main reference
is not freed via btrfs_remove_block_group, improving performance of
btrfs_put_block_group, btrfs_get_block_group significantly.
Signed-off-by: Martin Raiber <martin@urbackup.org>
---
fs/btrfs/block-group.c | 111 +++++++++++++++++++++++------------------
fs/btrfs/block-group.h | 2 +-
2 files changed, 63 insertions(+), 50 deletions(-)
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index a1119f06b6d1..7569438ccbd5 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -153,37 +153,44 @@ u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags)
void btrfs_get_block_group(struct btrfs_block_group *cache)
{
- refcount_inc(&cache->refs);
+ percpu_ref_get(&cache->refs);
}
-void btrfs_put_block_group(struct btrfs_block_group *cache)
+static void btrfs_free_block_group(struct percpu_ref *ref)
{
- if (refcount_dec_and_test(&cache->refs)) {
- WARN_ON(cache->pinned > 0);
- /*
- * If there was a failure to cleanup a log tree, very likely due
- * to an IO failure on a writeback attempt of one or more of its
- * extent buffers, we could not do proper (and cheap) unaccounting
- * of their reserved space, so don't warn on reserved > 0 in that
- * case.
- */
- if (!(cache->flags & BTRFS_BLOCK_GROUP_METADATA) ||
- !BTRFS_FS_LOG_CLEANUP_ERROR(cache->fs_info))
- WARN_ON(cache->reserved > 0);
+ struct btrfs_block_group *cache =
+ container_of(ref, struct btrfs_block_group, refs);
- /*
- * A block_group shouldn't be on the discard_list anymore.
- * Remove the block_group from the discard_list to prevent us
- * from causing a panic due to NULL pointer dereference.
- */
- if (WARN_ON(!list_empty(&cache->discard_list)))
- btrfs_discard_cancel_work(&cache->fs_info->discard_ctl,
- cache);
+ WARN_ON(cache->pinned > 0);
+ /*
+ * If there was a failure to cleanup a log tree, very likely due
+ * to an IO failure on a writeback attempt of one or more of its
+ * extent buffers, we could not do proper (and cheap) unaccounting
+ * of their reserved space, so don't warn on reserved > 0 in that
+ * case.
+ */
+ if (!(cache->flags & BTRFS_BLOCK_GROUP_METADATA) ||
+ !BTRFS_FS_LOG_CLEANUP_ERROR(cache->fs_info))
+ WARN_ON(cache->reserved > 0);
- kfree(cache->free_space_ctl);
- btrfs_free_chunk_map(cache->physical_map);
- kfree(cache);
- }
+ /*
+ * A block_group shouldn't be on the discard_list anymore.
+ * Remove the block_group from the discard_list to prevent us
+ * from causing a panic due to NULL pointer dereference.
+ */
+ if (WARN_ON(!list_empty(&cache->discard_list)))
+ btrfs_discard_cancel_work(&cache->fs_info->discard_ctl,
+ cache);
+
+ percpu_ref_exit(&cache->refs);
+ kfree(cache->free_space_ctl);
+ btrfs_free_chunk_map(cache->physical_map);
+ kfree(cache);
+}
+
+void btrfs_put_block_group(struct btrfs_block_group *cache)
+{
+ percpu_ref_put(&cache->refs);
}
static int btrfs_bg_start_cmp(const struct rb_node *new,
@@ -406,8 +413,8 @@ void btrfs_wait_block_group_reservations(struct btrfs_block_group *bg)
* on the groups' semaphore is held and decremented after releasing
* the read access on that semaphore and creating the ordered extent.
*/
- down_write(&space_info->groups_sem);
- up_write(&space_info->groups_sem);
+ percpu_down_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
wait_var_event(&bg->reservations, !atomic_read(&bg->reservations));
}
@@ -1012,7 +1019,7 @@ static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)
struct btrfs_space_info *sinfo;
list_for_each_entry_rcu(sinfo, head, list) {
- down_read(&sinfo->groups_sem);
+ percpu_down_read(&sinfo->groups_sem);
if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID5]))
found_raid56 = true;
if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID6]))
@@ -1021,7 +1028,7 @@ static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)
found_raid1c34 = true;
if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID1C4]))
found_raid1c34 = true;
- up_read(&sinfo->groups_sem);
+ percpu_up_read(&sinfo->groups_sem);
}
if (!found_raid56)
btrfs_clear_fs_incompat(fs_info, RAID56);
@@ -1159,11 +1166,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
RB_CLEAR_NODE(&block_group->cache_node);
/* Once for the block groups rbtree */
- btrfs_put_block_group(block_group);
+ percpu_ref_kill(&block_group->refs);
write_unlock(&fs_info->block_group_cache_lock);
- down_write(&block_group->space_info->groups_sem);
+ percpu_down_write(&block_group->space_info->groups_sem);
/*
* we must use list_del_init so people can check to see if they
* are still on the list after taking the semaphore
@@ -1174,7 +1181,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
block_group->space_info->block_group_kobjs[index] = NULL;
clear_avail_alloc_bits(fs_info, block_group->flags);
}
- up_write(&block_group->space_info->groups_sem);
+ percpu_up_write(&block_group->space_info->groups_sem);
clear_incompat_bg_bits(fs_info, block_group->flags);
if (kobj) {
kobject_del(kobj);
@@ -1544,7 +1551,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
btrfs_discard_cancel_work(&fs_info->discard_ctl, block_group);
/* Don't want to race with allocators so take the groups_sem */
- down_write(&space_info->groups_sem);
+ percpu_down_write(&space_info->groups_sem);
/*
* Async discard moves the final block group discard to be prior
@@ -1554,7 +1561,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
if (btrfs_test_opt(fs_info, DISCARD_ASYNC) &&
!btrfs_is_free_space_trimmed(block_group)) {
trace_btrfs_skip_unused_block_group(block_group);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
/* Requeue if we failed because of async discard */
btrfs_discard_queue_work(&fs_info->discard_ctl,
block_group);
@@ -1581,7 +1588,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
trace_btrfs_skip_unused_block_group(block_group);
spin_unlock(&block_group->lock);
spin_unlock(&space_info->lock);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
goto next;
}
@@ -1618,7 +1625,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
trace_btrfs_skip_unused_block_group(block_group);
spin_unlock(&block_group->lock);
spin_unlock(&space_info->lock);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
goto next;
}
@@ -1627,7 +1634,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
/* We don't want to force the issue, only flip if it's ok. */
ret = inc_block_group_ro(block_group, 0);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
if (ret < 0) {
ret = 0;
goto next;
@@ -1882,7 +1889,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
spin_unlock(&fs_info->unused_bgs_lock);
/* Don't race with allocators so take the groups_sem */
- down_write(&space_info->groups_sem);
+ percpu_down_write(&space_info->groups_sem);
spin_lock(&space_info->lock);
spin_lock(&bg->lock);
@@ -1895,7 +1902,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
*/
spin_unlock(&bg->lock);
spin_unlock(&space_info->lock);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
goto next;
}
if (bg->used == 0) {
@@ -1914,7 +1921,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
btrfs_mark_bg_unused(bg);
spin_unlock(&bg->lock);
spin_unlock(&space_info->lock);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
goto next;
}
@@ -1931,7 +1938,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
if (!should_reclaim_block_group(bg, bg->length)) {
spin_unlock(&bg->lock);
spin_unlock(&space_info->lock);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
goto next;
}
@@ -1947,12 +1954,12 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
* never gets back to read-write to let us reclaim again.
*/
if (btrfs_need_cleaner_sleep(fs_info)) {
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
goto next;
}
ret = inc_block_group_ro(bg, 0);
- up_write(&space_info->groups_sem);
+ percpu_up_write(&space_info->groups_sem);
if (ret < 0)
goto next;
@@ -2288,7 +2295,12 @@ static struct btrfs_block_group *btrfs_create_block_group(
cache->discard_index = BTRFS_DISCARD_INDEX_UNUSED;
- refcount_set(&cache->refs, 1);
+ if (percpu_ref_init(&cache->refs, btrfs_free_block_group,
+ 0, GFP_NOFS)) {
+ kfree(cache->free_space_ctl);
+ kfree(cache);
+ return NULL;
+ }
spin_lock_init(&cache->lock);
init_rwsem(&cache->data_rwsem);
INIT_LIST_HEAD(&cache->list);
@@ -4550,9 +4562,9 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
RB_CLEAR_NODE(&block_group->cache_node);
write_unlock(&info->block_group_cache_lock);
- down_write(&block_group->space_info->groups_sem);
+ percpu_down_write(&block_group->space_info->groups_sem);
list_del(&block_group->list);
- up_write(&block_group->space_info->groups_sem);
+ percpu_up_write(&block_group->space_info->groups_sem);
/*
* We haven't cached this block group, which means we could
@@ -4567,9 +4579,10 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
ASSERT(list_empty(&block_group->dirty_list));
ASSERT(list_empty(&block_group->io_list));
ASSERT(list_empty(&block_group->bg_list));
- ASSERT(refcount_read(&block_group->refs) == 1);
+ ASSERT(!percpu_ref_is_zero(&block_group->refs));
ASSERT(block_group->swap_extents == 0);
- btrfs_put_block_group(block_group);
+ percpu_ref_kill(&block_group->refs);
+ ASSERT(percpu_ref_is_zero(&block_group->refs));
write_lock(&info->block_group_cache_lock);
}
diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
index 5f933455118c..d44675f9d601 100644
--- a/fs/btrfs/block-group.h
+++ b/fs/btrfs/block-group.h
@@ -178,7 +178,7 @@ struct btrfs_block_group {
/* For block groups in the same raid type */
struct list_head list;
- refcount_t refs;
+ struct percpu_ref refs;
/*
* List of struct btrfs_free_clusters for this block group.
--
2.39.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 1/7] btrfs: Use percpu refcounting for block groups
2026-01-12 16:17 ` Martin Raiber
@ 2026-01-12 22:32 ` Boris Burkov
2026-01-14 6:06 ` kernel test robot
1 sibling, 0 replies; 4+ messages in thread
From: Boris Burkov @ 2026-01-12 22:32 UTC (permalink / raw)
To: Martin Raiber; +Cc: linux-btrfs
On Mon, Jan 12, 2026 at 04:17:16PM +0000, Martin Raiber wrote:
> Use a percpu counter to keep track of the block group refs.
> This prevents CPU synchronization completely as long as the main reference
> is not freed via btrfs_remove_block_group, improving performance of
> btrfs_put_block_group, btrfs_get_block_group significantly.
Besides the potential mixup with patch 2, this looks like a nice
improvement to me, since we adhere to the pattern of having a "main"
refcount for the rb tree entry.
My only other complaint is that this seems to lose the helpful
refcount_t warning feature. But I think I can live with that.
>
> Signed-off-by: Martin Raiber <martin@urbackup.org>
> ---
> fs/btrfs/block-group.c | 111 +++++++++++++++++++++++------------------
> fs/btrfs/block-group.h | 2 +-
> 2 files changed, 63 insertions(+), 50 deletions(-)
>
> diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
> index a1119f06b6d1..7569438ccbd5 100644
> --- a/fs/btrfs/block-group.c
> +++ b/fs/btrfs/block-group.c
> @@ -153,37 +153,44 @@ u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags)
>
> void btrfs_get_block_group(struct btrfs_block_group *cache)
> {
> - refcount_inc(&cache->refs);
> + percpu_ref_get(&cache->refs);
> }
>
> -void btrfs_put_block_group(struct btrfs_block_group *cache)
> +static void btrfs_free_block_group(struct percpu_ref *ref)
> {
> - if (refcount_dec_and_test(&cache->refs)) {
> - WARN_ON(cache->pinned > 0);
> - /*
> - * If there was a failure to cleanup a log tree, very likely due
> - * to an IO failure on a writeback attempt of one or more of its
> - * extent buffers, we could not do proper (and cheap) unaccounting
> - * of their reserved space, so don't warn on reserved > 0 in that
> - * case.
> - */
> - if (!(cache->flags & BTRFS_BLOCK_GROUP_METADATA) ||
> - !BTRFS_FS_LOG_CLEANUP_ERROR(cache->fs_info))
> - WARN_ON(cache->reserved > 0);
> + struct btrfs_block_group *cache =
> + container_of(ref, struct btrfs_block_group, refs);
I think for most new code we call these 'block_group' rather than
'cache', so I think this is a good opportunity to update it.
>
> - /*
> - * A block_group shouldn't be on the discard_list anymore.
> - * Remove the block_group from the discard_list to prevent us
> - * from causing a panic due to NULL pointer dereference.
> - */
> - if (WARN_ON(!list_empty(&cache->discard_list)))
> - btrfs_discard_cancel_work(&cache->fs_info->discard_ctl,
> - cache);
> + WARN_ON(cache->pinned > 0);
> + /*
> + * If there was a failure to cleanup a log tree, very likely due
> + * to an IO failure on a writeback attempt of one or more of its
> + * extent buffers, we could not do proper (and cheap) unaccounting
> + * of their reserved space, so don't warn on reserved > 0 in that
> + * case.
> + */
> + if (!(cache->flags & BTRFS_BLOCK_GROUP_METADATA) ||
> + !BTRFS_FS_LOG_CLEANUP_ERROR(cache->fs_info))
> + WARN_ON(cache->reserved > 0);
>
> - kfree(cache->free_space_ctl);
> - btrfs_free_chunk_map(cache->physical_map);
> - kfree(cache);
> - }
> + /*
> + * A block_group shouldn't be on the discard_list anymore.
> + * Remove the block_group from the discard_list to prevent us
> + * from causing a panic due to NULL pointer dereference.
> + */
> + if (WARN_ON(!list_empty(&cache->discard_list)))
> + btrfs_discard_cancel_work(&cache->fs_info->discard_ctl,
> + cache);
> +
> + percpu_ref_exit(&cache->refs);
> + kfree(cache->free_space_ctl);
> + btrfs_free_chunk_map(cache->physical_map);
> + kfree(cache);
> +}
> +
> +void btrfs_put_block_group(struct btrfs_block_group *cache)
> +{
> + percpu_ref_put(&cache->refs);
> }
>
> static int btrfs_bg_start_cmp(const struct rb_node *new,
> @@ -406,8 +413,8 @@ void btrfs_wait_block_group_reservations(struct btrfs_block_group *bg)
> * on the groups' semaphore is held and decremented after releasing
> * the read access on that semaphore and creating the ordered extent.
> */
> - down_write(&space_info->groups_sem);
> - up_write(&space_info->groups_sem);
> + percpu_down_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
Did this sneak out of patch 2 into this patch? (several other instances
in this patch that I won't note)
>
> wait_var_event(&bg->reservations, !atomic_read(&bg->reservations));
> }
> @@ -1012,7 +1019,7 @@ static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)
> struct btrfs_space_info *sinfo;
>
> list_for_each_entry_rcu(sinfo, head, list) {
> - down_read(&sinfo->groups_sem);
> + percpu_down_read(&sinfo->groups_sem);
> if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID5]))
> found_raid56 = true;
> if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID6]))
> @@ -1021,7 +1028,7 @@ static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)
> found_raid1c34 = true;
> if (!list_empty(&sinfo->block_groups[BTRFS_RAID_RAID1C4]))
> found_raid1c34 = true;
> - up_read(&sinfo->groups_sem);
> + percpu_up_read(&sinfo->groups_sem);
> }
> if (!found_raid56)
> btrfs_clear_fs_incompat(fs_info, RAID56);
> @@ -1159,11 +1166,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
> RB_CLEAR_NODE(&block_group->cache_node);
>
> /* Once for the block groups rbtree */
> - btrfs_put_block_group(block_group);
> + percpu_ref_kill(&block_group->refs);
>
> write_unlock(&fs_info->block_group_cache_lock);
>
> - down_write(&block_group->space_info->groups_sem);
> + percpu_down_write(&block_group->space_info->groups_sem);
> /*
> * we must use list_del_init so people can check to see if they
> * are still on the list after taking the semaphore
> @@ -1174,7 +1181,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
> block_group->space_info->block_group_kobjs[index] = NULL;
> clear_avail_alloc_bits(fs_info, block_group->flags);
> }
> - up_write(&block_group->space_info->groups_sem);
> + percpu_up_write(&block_group->space_info->groups_sem);
> clear_incompat_bg_bits(fs_info, block_group->flags);
> if (kobj) {
> kobject_del(kobj);
> @@ -1544,7 +1551,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
> btrfs_discard_cancel_work(&fs_info->discard_ctl, block_group);
>
> /* Don't want to race with allocators so take the groups_sem */
> - down_write(&space_info->groups_sem);
> + percpu_down_write(&space_info->groups_sem);
>
> /*
> * Async discard moves the final block group discard to be prior
> @@ -1554,7 +1561,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
> if (btrfs_test_opt(fs_info, DISCARD_ASYNC) &&
> !btrfs_is_free_space_trimmed(block_group)) {
> trace_btrfs_skip_unused_block_group(block_group);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> /* Requeue if we failed because of async discard */
> btrfs_discard_queue_work(&fs_info->discard_ctl,
> block_group);
> @@ -1581,7 +1588,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
> trace_btrfs_skip_unused_block_group(block_group);
> spin_unlock(&block_group->lock);
> spin_unlock(&space_info->lock);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> goto next;
> }
>
> @@ -1618,7 +1625,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
> trace_btrfs_skip_unused_block_group(block_group);
> spin_unlock(&block_group->lock);
> spin_unlock(&space_info->lock);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> goto next;
> }
>
> @@ -1627,7 +1634,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
>
> /* We don't want to force the issue, only flip if it's ok. */
> ret = inc_block_group_ro(block_group, 0);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> if (ret < 0) {
> ret = 0;
> goto next;
> @@ -1882,7 +1889,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
> spin_unlock(&fs_info->unused_bgs_lock);
>
> /* Don't race with allocators so take the groups_sem */
> - down_write(&space_info->groups_sem);
> + percpu_down_write(&space_info->groups_sem);
>
> spin_lock(&space_info->lock);
> spin_lock(&bg->lock);
> @@ -1895,7 +1902,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
> */
> spin_unlock(&bg->lock);
> spin_unlock(&space_info->lock);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> goto next;
> }
> if (bg->used == 0) {
> @@ -1914,7 +1921,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
> btrfs_mark_bg_unused(bg);
> spin_unlock(&bg->lock);
> spin_unlock(&space_info->lock);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> goto next;
>
> }
> @@ -1931,7 +1938,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
> if (!should_reclaim_block_group(bg, bg->length)) {
> spin_unlock(&bg->lock);
> spin_unlock(&space_info->lock);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> goto next;
> }
>
> @@ -1947,12 +1954,12 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
> * never gets back to read-write to let us reclaim again.
> */
> if (btrfs_need_cleaner_sleep(fs_info)) {
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> goto next;
> }
>
> ret = inc_block_group_ro(bg, 0);
> - up_write(&space_info->groups_sem);
> + percpu_up_write(&space_info->groups_sem);
> if (ret < 0)
> goto next;
>
> @@ -2288,7 +2295,12 @@ static struct btrfs_block_group *btrfs_create_block_group(
>
> cache->discard_index = BTRFS_DISCARD_INDEX_UNUSED;
>
> - refcount_set(&cache->refs, 1);
> + if (percpu_ref_init(&cache->refs, btrfs_free_block_group,
> + 0, GFP_NOFS)) {
> + kfree(cache->free_space_ctl);
> + kfree(cache);
> + return NULL;
> + }
> spin_lock_init(&cache->lock);
> init_rwsem(&cache->data_rwsem);
> INIT_LIST_HEAD(&cache->list);
> @@ -4550,9 +4562,9 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
> RB_CLEAR_NODE(&block_group->cache_node);
> write_unlock(&info->block_group_cache_lock);
>
> - down_write(&block_group->space_info->groups_sem);
> + percpu_down_write(&block_group->space_info->groups_sem);
> list_del(&block_group->list);
> - up_write(&block_group->space_info->groups_sem);
> + percpu_up_write(&block_group->space_info->groups_sem);
>
> /*
> * We haven't cached this block group, which means we could
> @@ -4567,9 +4579,10 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
> ASSERT(list_empty(&block_group->dirty_list));
> ASSERT(list_empty(&block_group->io_list));
> ASSERT(list_empty(&block_group->bg_list));
> - ASSERT(refcount_read(&block_group->refs) == 1);
> + ASSERT(!percpu_ref_is_zero(&block_group->refs));
> ASSERT(block_group->swap_extents == 0);
> - btrfs_put_block_group(block_group);
> + percpu_ref_kill(&block_group->refs);
> + ASSERT(percpu_ref_is_zero(&block_group->refs));
>
> write_lock(&info->block_group_cache_lock);
> }
> diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
> index 5f933455118c..d44675f9d601 100644
> --- a/fs/btrfs/block-group.h
> +++ b/fs/btrfs/block-group.h
> @@ -178,7 +178,7 @@ struct btrfs_block_group {
> /* For block groups in the same raid type */
> struct list_head list;
>
> - refcount_t refs;
> + struct percpu_ref refs;
>
> /*
> * List of struct btrfs_free_clusters for this block group.
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/7] btrfs: Use percpu refcounting for block groups
@ 2026-01-13 10:32 kernel test robot
0 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-01-13 10:32 UTC (permalink / raw)
To: oe-kbuild
::::::
:::::: Manual check reason: "high confidence checkpatch report"
::::::
BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <0102019bb2ff56b7-9302e783-c17d-452d-b6a7-11f773776ae7-000000@eu-west-1.amazonses.com>
References: <0102019bb2ff56b7-9302e783-c17d-452d-b6a7-11f773776ae7-000000@eu-west-1.amazonses.com>
TO: Martin Raiber <martin@urbackup.org>
TO: linux-btrfs@vger.kernel.org
Hi Martin,
kernel test robot noticed the following build warnings:
[auto build test WARNING on kdave/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Martin-Raiber/btrfs-Use-percpu-semaphore-for-space-info-groups_sem/20260113-070107
base: https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
patch link: https://lore.kernel.org/r/0102019bb2ff56b7-9302e783-c17d-452d-b6a7-11f773776ae7-000000%40eu-west-1.amazonses.com
patch subject: [PATCH 1/7] btrfs: Use percpu refcounting for block groups
:::::: branch date: 12 hours ago
:::::: commit date: 12 hours ago
reproduce: (https://download.01.org/0day-ci/archive/20260113/202601131155.ulOGAl1n-lkp@intel.com/reproduce)
# many are suggestions rather than must-fix
WARNING:BLOCK_COMMENT_STYLE: Block comments should align the * on each line
#57: FILE: fs/btrfs/block-group.c:166:
+ /*
+ * If there was a failure to cleanup a log tree, very likely due
WARNING:BLOCK_COMMENT_STYLE: Block comments should align the * on each line
#72: FILE: fs/btrfs/block-group.c:177:
+ /*
+ * A block_group shouldn't be on the discard_list anymore.
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/7] btrfs: Use percpu refcounting for block groups
2026-01-12 16:17 ` Martin Raiber
2026-01-12 22:32 ` Boris Burkov
@ 2026-01-14 6:06 ` kernel test robot
1 sibling, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-01-14 6:06 UTC (permalink / raw)
To: Martin Raiber, linux-btrfs; +Cc: oe-kbuild-all, Martin Raiber
Hi Martin,
kernel test robot noticed the following build errors:
[auto build test ERROR on kdave/for-next]
[also build test ERROR on linus/master v6.19-rc5 next-20260113]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Martin-Raiber/btrfs-Use-percpu-semaphore-for-space-info-groups_sem/20260113-070107
base: https://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git for-next
patch link: https://lore.kernel.org/r/0102019bb2ff56b7-9302e783-c17d-452d-b6a7-11f773776ae7-000000%40eu-west-1.amazonses.com
patch subject: [PATCH 1/7] btrfs: Use percpu refcounting for block groups
config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20260114/202601141316.7JnRkX9k-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260114/202601141316.7JnRkX9k-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601141316.7JnRkX9k-lkp@intel.com/
All errors (new ones prefixed by >>):
fs/btrfs/block-group.c: In function 'btrfs_wait_block_group_reservations':
>> fs/btrfs/block-group.c:416:27: error: passing argument 1 of 'percpu_down_write' from incompatible pointer type [-Wincompatible-pointer-types]
416 | percpu_down_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
In file included from include/linux/fs/super_types.h:13,
from include/linux/fs/super.h:5,
from include/linux/fs.h:5,
from include/linux/huge_mm.h:7,
from include/linux/mm.h:1268,
from fs/btrfs/misc.h:10,
from fs/btrfs/block-group.c:5:
include/linux/percpu-rwsem.h:138:31: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
138 | extern void percpu_down_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> fs/btrfs/block-group.c:417:25: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
417 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c: In function 'clear_incompat_bg_bits':
>> fs/btrfs/block-group.c:1022:42: error: passing argument 1 of 'percpu_down_read' from incompatible pointer type [-Wincompatible-pointer-types]
1022 | percpu_down_read(&sinfo->groups_sem);
| ^~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:75:65: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
75 | static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
>> fs/btrfs/block-group.c:1031:40: error: passing argument 1 of 'percpu_up_read' from incompatible pointer type [-Wincompatible-pointer-types]
1031 | percpu_up_read(&sinfo->groups_sem);
| ^~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:110:63: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
110 | static inline void percpu_up_read(struct percpu_rw_semaphore *sem)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
fs/btrfs/block-group.c: In function 'btrfs_remove_block_group':
fs/btrfs/block-group.c:1173:27: error: passing argument 1 of 'percpu_down_write' from incompatible pointer type [-Wincompatible-pointer-types]
1173 | percpu_down_write(&block_group->space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:138:31: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
138 | extern void percpu_down_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1184:25: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1184 | percpu_up_write(&block_group->space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c: In function 'btrfs_delete_unused_bgs':
fs/btrfs/block-group.c:1554:35: error: passing argument 1 of 'percpu_down_write' from incompatible pointer type [-Wincompatible-pointer-types]
1554 | percpu_down_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:138:31: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
138 | extern void percpu_down_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1564:41: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1564 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1591:41: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1591 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1628:41: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1628 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1637:33: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1637 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c: In function 'btrfs_reclaim_bgs_work':
fs/btrfs/block-group.c:1892:35: error: passing argument 1 of 'percpu_down_write' from incompatible pointer type [-Wincompatible-pointer-types]
1892 | percpu_down_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:138:31: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
138 | extern void percpu_down_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1905:41: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1905 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1924:41: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1924 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1941:41: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1941 | percpu_up_write(&space_info->groups_sem);
| ^~~~~~~~~~~~~~~~~~~~~~~
| |
| struct rw_semaphore *
include/linux/percpu-rwsem.h:139:29: note: expected 'struct percpu_rw_semaphore *' but argument is of type 'struct rw_semaphore *'
139 | extern void percpu_up_write(struct percpu_rw_semaphore *);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/btrfs/block-group.c:1957:41: error: passing argument 1 of 'percpu_up_write' from incompatible pointer type [-Wincompatible-pointer-types]
1957 | percpu_up_write(&space_info->groups_sem);
vim +/percpu_down_write +416 fs/btrfs/block-group.c
396
397 void btrfs_wait_block_group_reservations(struct btrfs_block_group *bg)
398 {
399 struct btrfs_space_info *space_info = bg->space_info;
400
401 ASSERT(bg->ro);
402
403 if (!(bg->flags & BTRFS_BLOCK_GROUP_DATA))
404 return;
405
406 /*
407 * Our block group is read only but before we set it to read only,
408 * some task might have had allocated an extent from it already, but it
409 * has not yet created a respective ordered extent (and added it to a
410 * root's list of ordered extents).
411 * Therefore wait for any task currently allocating extents, since the
412 * block group's reservations counter is incremented while a read lock
413 * on the groups' semaphore is held and decremented after releasing
414 * the read access on that semaphore and creating the ordered extent.
415 */
> 416 percpu_down_write(&space_info->groups_sem);
> 417 percpu_up_write(&space_info->groups_sem);
418
419 wait_var_event(&bg->reservations, !atomic_read(&bg->reservations));
420 }
421
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-01-14 6:07 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-13 10:32 [PATCH 1/7] btrfs: Use percpu refcounting for block groups kernel test robot
[not found] <20260112161549.2786827-1-martin@urbackup.org>
2026-01-12 16:17 ` Martin Raiber
2026-01-12 22:32 ` Boris Burkov
2026-01-14 6:06 ` kernel test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.