]> git.baikalelectronics.ru Git - kernel.git/commitdiff
btrfs: call __btrfs_remove_free_space_cache_locked on cache load failure
authorJosef Bacik <josef@toxicpanda.com>
Mon, 8 Aug 2022 20:10:26 +0000 (16:10 -0400)
committerDavid Sterba <dsterba@suse.com>
Mon, 26 Sep 2022 10:27:58 +0000 (12:27 +0200)
Now that lockdep is staying enabled through our entire CI runs I started
seeing the following stack in generic/475

------------[ cut here ]------------
WARNING: CPU: 1 PID: 2171864 at fs/btrfs/discard.c:604 btrfs_discard_update_discardable+0x98/0xb0
CPU: 1 PID: 2171864 Comm: kworker/u4:0 Not tainted 5.19.0-rc8+ #789
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-2.fc32 04/01/2014
Workqueue: btrfs-cache btrfs_work_helper
RIP: 0010:btrfs_discard_update_discardable+0x98/0xb0
RSP: 0018:ffffb857c2f7bad0 EFLAGS: 00010246
RAX: 0000000000000000 RBX: ffff8c85c605c200 RCX: 0000000000000001
RDX: 0000000000000000 RSI: ffffffff86807c5b RDI: ffffffff868a831e
RBP: ffff8c85c4c54000 R08: 0000000000000000 R09: 0000000000000000
R10: ffff8c85c66932f0 R11: 0000000000000001 R12: ffff8c85c3899010
R13: ffff8c85d5be4f40 R14: ffff8c85c4c54000 R15: ffff8c86114bfa80
FS:  0000000000000000(0000) GS:ffff8c863bd00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f2e7f168160 CR3: 000000010289a004 CR4: 0000000000370ee0
Call Trace:

 __btrfs_remove_free_space_cache+0x27/0x30
 load_free_space_cache+0xad2/0xaf0
 caching_thread+0x40b/0x650
 ? lock_release+0x137/0x2d0
 btrfs_work_helper+0xf2/0x3e0
 ? lock_is_held_type+0xe2/0x140
 process_one_work+0x271/0x590
 ? process_one_work+0x590/0x590
 worker_thread+0x52/0x3b0
 ? process_one_work+0x590/0x590
 kthread+0xf0/0x120
 ? kthread_complete_and_exit+0x20/0x20
 ret_from_fork+0x1f/0x30

This is the code

        ctl = block_group->free_space_ctl;
        discard_ctl = &block_group->fs_info->discard_ctl;

        lockdep_assert_held(&ctl->tree_lock);

We have a temporary free space ctl for loading the free space cache in
order to avoid having allocations happening while we're loading the
cache.  When we hit an error we free it all up, however this also calls
btrfs_discard_update_discardable, which requires
block_group->free_space_ctl->tree_lock to be held.  However this is our
temporary ctl so this lock isn't held.  Fix this by calling
__btrfs_remove_free_space_cache_locked instead so that we only clean up
the entries and do not mess with the discardable stats.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/free-space-cache.c

index 81d9fe33672ffa2f66d9843487006c37daae0aa4..f2a6dd0336231fd05c64225d35493d34539485ed 100644 (file)
@@ -48,6 +48,25 @@ static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
                              struct btrfs_free_space *info, u64 offset,
                              u64 bytes, bool update_stats);
 
+static void __btrfs_remove_free_space_cache_locked(
+                               struct btrfs_free_space_ctl *ctl)
+{
+       struct btrfs_free_space *info;
+       struct rb_node *node;
+
+       while ((node = rb_last(&ctl->free_space_offset)) != NULL) {
+               info = rb_entry(node, struct btrfs_free_space, offset_index);
+               if (!info->bitmap) {
+                       unlink_free_space(ctl, info, true);
+                       kmem_cache_free(btrfs_free_space_cachep, info);
+               } else {
+                       free_bitmap(ctl, info);
+               }
+
+               cond_resched_lock(&ctl->tree_lock);
+       }
+}
+
 static struct inode *__lookup_free_space_inode(struct btrfs_root *root,
                                               struct btrfs_path *path,
                                               u64 offset)
@@ -878,7 +897,14 @@ out:
        return ret;
 free_cache:
        io_ctl_drop_pages(&io_ctl);
-       __btrfs_remove_free_space_cache(ctl);
+
+       /*
+        * We need to call the _locked variant so we don't try to update the
+        * discard counters.
+        */
+       spin_lock(&ctl->tree_lock);
+       __btrfs_remove_free_space_cache_locked(ctl);
+       spin_unlock(&ctl->tree_lock);
        goto out;
 }
 
@@ -1014,7 +1040,13 @@ int load_free_space_cache(struct btrfs_block_group *block_group)
                if (ret == 0)
                        ret = 1;
        } else {
+               /*
+                * We need to call the _locked variant so we don't try to update
+                * the discard counters.
+                */
+               spin_lock(&tmp_ctl.tree_lock);
                __btrfs_remove_free_space_cache(&tmp_ctl);
+               spin_unlock(&tmp_ctl.tree_lock);
                btrfs_warn(fs_info,
                           "block group %llu has wrong amount of free space",
                           block_group->start);
@@ -2978,25 +3010,6 @@ static void __btrfs_return_cluster_to_free_space(
        btrfs_put_block_group(block_group);
 }
 
-static void __btrfs_remove_free_space_cache_locked(
-                               struct btrfs_free_space_ctl *ctl)
-{
-       struct btrfs_free_space *info;
-       struct rb_node *node;
-
-       while ((node = rb_last(&ctl->free_space_offset)) != NULL) {
-               info = rb_entry(node, struct btrfs_free_space, offset_index);
-               if (!info->bitmap) {
-                       unlink_free_space(ctl, info, true);
-                       kmem_cache_free(btrfs_free_space_cachep, info);
-               } else {
-                       free_bitmap(ctl, info);
-               }
-
-               cond_resched_lock(&ctl->tree_lock);
-       }
-}
-
 void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl)
 {
        spin_lock(&ctl->tree_lock);