Skip to content

Commit fc7cbcd

Browse files
committed
Revert "btrfs: turn fs_roots_radix in btrfs_fs_info into an XArray"
This reverts commit 48b36a6. Revert the xarray conversion, there's a problem with potential sleep-inside-spinlock [1] when calling xa_insert that triggers GFP_NOFS allocation. The radix tree used the preloading mechanism to avoid sleeping but this is not available in xarray. Conversion from spin lock to mutex is possible but at time of rc6 is riskier than a clean revert. [1] https://lore.kernel.org/linux-btrfs/cover.1657097693.git.fdmanana@suse.com/ Reported-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent b3a3b02 commit fc7cbcd

File tree

6 files changed

+171
-139
lines changed

6 files changed

+171
-139
lines changed

fs/btrfs/ctree.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -675,9 +675,8 @@ struct btrfs_fs_info {
675675
rwlock_t global_root_lock;
676676
struct rb_root global_root_tree;
677677

678-
/* The xarray that holds all the FS roots */
679-
spinlock_t fs_roots_lock;
680-
struct xarray fs_roots;
678+
spinlock_t fs_roots_radix_lock;
679+
struct radix_tree_root fs_roots_radix;
681680

682681
/* block group cache stuff */
683682
rwlock_t block_group_cache_lock;
@@ -1119,8 +1118,7 @@ enum {
11191118
*/
11201119
BTRFS_ROOT_SHAREABLE,
11211120
BTRFS_ROOT_TRACK_DIRTY,
1122-
/* The root is tracked in fs_info::fs_roots */
1123-
BTRFS_ROOT_REGISTERED,
1121+
BTRFS_ROOT_IN_RADIX,
11241122
BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
11251123
BTRFS_ROOT_DEFRAG_RUNNING,
11261124
BTRFS_ROOT_FORCE_COW,

fs/btrfs/disk-io.c

Lines changed: 97 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <linux/fs.h>
77
#include <linux/blkdev.h>
8+
#include <linux/radix-tree.h>
89
#include <linux/writeback.h>
910
#include <linux/workqueue.h>
1011
#include <linux/kthread.h>
@@ -1210,9 +1211,9 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
12101211
btrfs_qgroup_init_swapped_blocks(&root->swapped_blocks);
12111212
#ifdef CONFIG_BTRFS_DEBUG
12121213
INIT_LIST_HEAD(&root->leak_list);
1213-
spin_lock(&fs_info->fs_roots_lock);
1214+
spin_lock(&fs_info->fs_roots_radix_lock);
12141215
list_add_tail(&root->leak_list, &fs_info->allocated_roots);
1215-
spin_unlock(&fs_info->fs_roots_lock);
1216+
spin_unlock(&fs_info->fs_roots_radix_lock);
12161217
#endif
12171218
}
12181219

@@ -1659,11 +1660,12 @@ static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
16591660
{
16601661
struct btrfs_root *root;
16611662

1662-
spin_lock(&fs_info->fs_roots_lock);
1663-
root = xa_load(&fs_info->fs_roots, (unsigned long)root_id);
1663+
spin_lock(&fs_info->fs_roots_radix_lock);
1664+
root = radix_tree_lookup(&fs_info->fs_roots_radix,
1665+
(unsigned long)root_id);
16641666
if (root)
16651667
root = btrfs_grab_root(root);
1666-
spin_unlock(&fs_info->fs_roots_lock);
1668+
spin_unlock(&fs_info->fs_roots_radix_lock);
16671669
return root;
16681670
}
16691671

@@ -1705,14 +1707,20 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
17051707
{
17061708
int ret;
17071709

1708-
spin_lock(&fs_info->fs_roots_lock);
1709-
ret = xa_insert(&fs_info->fs_roots, (unsigned long)root->root_key.objectid,
1710-
root, GFP_NOFS);
1710+
ret = radix_tree_preload(GFP_NOFS);
1711+
if (ret)
1712+
return ret;
1713+
1714+
spin_lock(&fs_info->fs_roots_radix_lock);
1715+
ret = radix_tree_insert(&fs_info->fs_roots_radix,
1716+
(unsigned long)root->root_key.objectid,
1717+
root);
17111718
if (ret == 0) {
17121719
btrfs_grab_root(root);
1713-
set_bit(BTRFS_ROOT_REGISTERED, &root->state);
1720+
set_bit(BTRFS_ROOT_IN_RADIX, &root->state);
17141721
}
1715-
spin_unlock(&fs_info->fs_roots_lock);
1722+
spin_unlock(&fs_info->fs_roots_radix_lock);
1723+
radix_tree_preload_end();
17161724

17171725
return ret;
17181726
}
@@ -2342,31 +2350,38 @@ void btrfs_put_root(struct btrfs_root *root)
23422350
btrfs_drew_lock_destroy(&root->snapshot_lock);
23432351
free_root_extent_buffers(root);
23442352
#ifdef CONFIG_BTRFS_DEBUG
2345-
spin_lock(&root->fs_info->fs_roots_lock);
2353+
spin_lock(&root->fs_info->fs_roots_radix_lock);
23462354
list_del_init(&root->leak_list);
2347-
spin_unlock(&root->fs_info->fs_roots_lock);
2355+
spin_unlock(&root->fs_info->fs_roots_radix_lock);
23482356
#endif
23492357
kfree(root);
23502358
}
23512359
}
23522360

23532361
void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
23542362
{
2355-
struct btrfs_root *root;
2356-
unsigned long index = 0;
2363+
int ret;
2364+
struct btrfs_root *gang[8];
2365+
int i;
23572366

23582367
while (!list_empty(&fs_info->dead_roots)) {
2359-
root = list_entry(fs_info->dead_roots.next,
2360-
struct btrfs_root, root_list);
2361-
list_del(&root->root_list);
2368+
gang[0] = list_entry(fs_info->dead_roots.next,
2369+
struct btrfs_root, root_list);
2370+
list_del(&gang[0]->root_list);
23622371

2363-
if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
2364-
btrfs_drop_and_free_fs_root(fs_info, root);
2365-
btrfs_put_root(root);
2372+
if (test_bit(BTRFS_ROOT_IN_RADIX, &gang[0]->state))
2373+
btrfs_drop_and_free_fs_root(fs_info, gang[0]);
2374+
btrfs_put_root(gang[0]);
23662375
}
23672376

2368-
xa_for_each(&fs_info->fs_roots, index, root) {
2369-
btrfs_drop_and_free_fs_root(fs_info, root);
2377+
while (1) {
2378+
ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
2379+
(void **)gang, 0,
2380+
ARRAY_SIZE(gang));
2381+
if (!ret)
2382+
break;
2383+
for (i = 0; i < ret; i++)
2384+
btrfs_drop_and_free_fs_root(fs_info, gang[i]);
23702385
}
23712386
}
23722387

@@ -3134,7 +3149,7 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
31343149

31353150
void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
31363151
{
3137-
xa_init_flags(&fs_info->fs_roots, GFP_ATOMIC);
3152+
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
31383153
xa_init_flags(&fs_info->extent_buffers, GFP_ATOMIC);
31393154
INIT_LIST_HEAD(&fs_info->trans_list);
31403155
INIT_LIST_HEAD(&fs_info->dead_roots);
@@ -3143,7 +3158,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
31433158
INIT_LIST_HEAD(&fs_info->caching_block_groups);
31443159
spin_lock_init(&fs_info->delalloc_root_lock);
31453160
spin_lock_init(&fs_info->trans_lock);
3146-
spin_lock_init(&fs_info->fs_roots_lock);
3161+
spin_lock_init(&fs_info->fs_roots_radix_lock);
31473162
spin_lock_init(&fs_info->delayed_iput_lock);
31483163
spin_lock_init(&fs_info->defrag_inodes_lock);
31493164
spin_lock_init(&fs_info->super_lock);
@@ -3374,7 +3389,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
33743389
/*
33753390
* btrfs_find_orphan_roots() is responsible for finding all the dead
33763391
* roots (with 0 refs), flag them with BTRFS_ROOT_DEAD_TREE and load
3377-
* them into the fs_info->fs_roots. This must be done before
3392+
* them into the fs_info->fs_roots_radix tree. This must be done before
33783393
* calling btrfs_orphan_cleanup() on the tree root. If we don't do it
33793394
* first, then btrfs_orphan_cleanup() will delete a dead root's orphan
33803395
* item before the root's tree is deleted - this means that if we unmount
@@ -4498,11 +4513,12 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
44984513
{
44994514
bool drop_ref = false;
45004515

4501-
spin_lock(&fs_info->fs_roots_lock);
4502-
xa_erase(&fs_info->fs_roots, (unsigned long)root->root_key.objectid);
4503-
if (test_and_clear_bit(BTRFS_ROOT_REGISTERED, &root->state))
4516+
spin_lock(&fs_info->fs_roots_radix_lock);
4517+
radix_tree_delete(&fs_info->fs_roots_radix,
4518+
(unsigned long)root->root_key.objectid);
4519+
if (test_and_clear_bit(BTRFS_ROOT_IN_RADIX, &root->state))
45044520
drop_ref = true;
4505-
spin_unlock(&fs_info->fs_roots_lock);
4521+
spin_unlock(&fs_info->fs_roots_radix_lock);
45064522

45074523
if (BTRFS_FS_ERROR(fs_info)) {
45084524
ASSERT(root->log_root == NULL);
@@ -4518,48 +4534,50 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
45184534

45194535
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
45204536
{
4521-
struct btrfs_root *roots[8];
4522-
unsigned long index = 0;
4523-
int i;
4537+
u64 root_objectid = 0;
4538+
struct btrfs_root *gang[8];
4539+
int i = 0;
45244540
int err = 0;
4525-
int grabbed;
4541+
unsigned int ret = 0;
45264542

45274543
while (1) {
4528-
struct btrfs_root *root;
4529-
4530-
spin_lock(&fs_info->fs_roots_lock);
4531-
if (!xa_find(&fs_info->fs_roots, &index, ULONG_MAX, XA_PRESENT)) {
4532-
spin_unlock(&fs_info->fs_roots_lock);
4533-
return err;
4544+
spin_lock(&fs_info->fs_roots_radix_lock);
4545+
ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
4546+
(void **)gang, root_objectid,
4547+
ARRAY_SIZE(gang));
4548+
if (!ret) {
4549+
spin_unlock(&fs_info->fs_roots_radix_lock);
4550+
break;
45344551
}
4552+
root_objectid = gang[ret - 1]->root_key.objectid + 1;
45354553

4536-
grabbed = 0;
4537-
xa_for_each_start(&fs_info->fs_roots, index, root, index) {
4538-
/* Avoid grabbing roots in dead_roots */
4539-
if (btrfs_root_refs(&root->root_item) > 0)
4540-
roots[grabbed++] = btrfs_grab_root(root);
4541-
if (grabbed >= ARRAY_SIZE(roots))
4542-
break;
4554+
for (i = 0; i < ret; i++) {
4555+
/* Avoid to grab roots in dead_roots */
4556+
if (btrfs_root_refs(&gang[i]->root_item) == 0) {
4557+
gang[i] = NULL;
4558+
continue;
4559+
}
4560+
/* grab all the search result for later use */
4561+
gang[i] = btrfs_grab_root(gang[i]);
45434562
}
4544-
spin_unlock(&fs_info->fs_roots_lock);
4563+
spin_unlock(&fs_info->fs_roots_radix_lock);
45454564

4546-
for (i = 0; i < grabbed; i++) {
4547-
if (!roots[i])
4565+
for (i = 0; i < ret; i++) {
4566+
if (!gang[i])
45484567
continue;
4549-
index = roots[i]->root_key.objectid;
4550-
err = btrfs_orphan_cleanup(roots[i]);
4568+
root_objectid = gang[i]->root_key.objectid;
4569+
err = btrfs_orphan_cleanup(gang[i]);
45514570
if (err)
4552-
goto out;
4553-
btrfs_put_root(roots[i]);
4571+
break;
4572+
btrfs_put_root(gang[i]);
45544573
}
4555-
index++;
4574+
root_objectid++;
45564575
}
45574576

4558-
out:
4559-
/* Release the roots that remain uncleaned due to error */
4560-
for (; i < grabbed; i++) {
4561-
if (roots[i])
4562-
btrfs_put_root(roots[i]);
4577+
/* release the uncleaned roots due to error */
4578+
for (; i < ret; i++) {
4579+
if (gang[i])
4580+
btrfs_put_root(gang[i]);
45634581
}
45644582
return err;
45654583
}
@@ -4878,28 +4896,31 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
48784896

48794897
static void btrfs_drop_all_logs(struct btrfs_fs_info *fs_info)
48804898
{
4881-
unsigned long index = 0;
4882-
int grabbed = 0;
4883-
struct btrfs_root *roots[8];
4899+
struct btrfs_root *gang[8];
4900+
u64 root_objectid = 0;
4901+
int ret;
4902+
4903+
spin_lock(&fs_info->fs_roots_radix_lock);
4904+
while ((ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
4905+
(void **)gang, root_objectid,
4906+
ARRAY_SIZE(gang))) != 0) {
4907+
int i;
48844908

4885-
spin_lock(&fs_info->fs_roots_lock);
4886-
while ((grabbed = xa_extract(&fs_info->fs_roots, (void **)roots, index,
4887-
ULONG_MAX, 8, XA_PRESENT))) {
4888-
for (int i = 0; i < grabbed; i++)
4889-
roots[i] = btrfs_grab_root(roots[i]);
4890-
spin_unlock(&fs_info->fs_roots_lock);
4909+
for (i = 0; i < ret; i++)
4910+
gang[i] = btrfs_grab_root(gang[i]);
4911+
spin_unlock(&fs_info->fs_roots_radix_lock);
48914912

4892-
for (int i = 0; i < grabbed; i++) {
4893-
if (!roots[i])
4913+
for (i = 0; i < ret; i++) {
4914+
if (!gang[i])
48944915
continue;
4895-
index = roots[i]->root_key.objectid;
4896-
btrfs_free_log(NULL, roots[i]);
4897-
btrfs_put_root(roots[i]);
4916+
root_objectid = gang[i]->root_key.objectid;
4917+
btrfs_free_log(NULL, gang[i]);
4918+
btrfs_put_root(gang[i]);
48984919
}
4899-
index++;
4900-
spin_lock(&fs_info->fs_roots_lock);
4920+
root_objectid++;
4921+
spin_lock(&fs_info->fs_roots_radix_lock);
49014922
}
4902-
spin_unlock(&fs_info->fs_roots_lock);
4923+
spin_unlock(&fs_info->fs_roots_radix_lock);
49034924
btrfs_free_log_root_tree(NULL, fs_info);
49044925
}
49054926

fs/btrfs/extent-tree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5829,7 +5829,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
58295829
btrfs_qgroup_convert_reserved_meta(root, INT_MAX);
58305830
btrfs_qgroup_free_meta_all_pertrans(root);
58315831

5832-
if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
5832+
if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state))
58335833
btrfs_add_dropped_root(trans, root);
58345834
else
58355835
btrfs_put_root(root);

fs/btrfs/inode.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3578,7 +3578,6 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
35783578
u64 last_objectid = 0;
35793579
int ret = 0, nr_unlink = 0;
35803580

3581-
/* Bail out if the cleanup is already running. */
35823581
if (test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &root->state))
35833582
return 0;
35843583

@@ -3661,17 +3660,17 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
36613660
*
36623661
* btrfs_find_orphan_roots() ran before us, which has
36633662
* found all deleted roots and loaded them into
3664-
* fs_info->fs_roots. So here we can find if an
3663+
* fs_info->fs_roots_radix. So here we can find if an
36653664
* orphan item corresponds to a deleted root by looking
3666-
* up the root from that xarray.
3665+
* up the root from that radix tree.
36673666
*/
36683667

3669-
spin_lock(&fs_info->fs_roots_lock);
3670-
dead_root = xa_load(&fs_info->fs_roots,
3671-
(unsigned long)found_key.objectid);
3668+
spin_lock(&fs_info->fs_roots_radix_lock);
3669+
dead_root = radix_tree_lookup(&fs_info->fs_roots_radix,
3670+
(unsigned long)found_key.objectid);
36723671
if (dead_root && btrfs_root_refs(&dead_root->root_item) == 0)
36733672
is_dead_root = 1;
3674-
spin_unlock(&fs_info->fs_roots_lock);
3673+
spin_unlock(&fs_info->fs_roots_radix_lock);
36753674

36763675
if (is_dead_root) {
36773676
/* prevent this orphan from being found again */

fs/btrfs/tests/btrfs-tests.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ void btrfs_free_dummy_root(struct btrfs_root *root)
186186
if (!root)
187187
return;
188188
/* Will be freed by btrfs_free_fs_roots */
189-
if (WARN_ON(test_bit(BTRFS_ROOT_REGISTERED, &root->state)))
189+
if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
190190
return;
191191
btrfs_global_root_delete(root);
192192
btrfs_put_root(root);

0 commit comments

Comments
 (0)