btrfs: clear defragmented inodes using postorder in btrfs_cleanup_defrag_inodes()
authorDavid Sterba <dsterba@suse.com>
Tue, 27 Aug 2024 02:05:48 +0000 (04:05 +0200)
committerDavid Sterba <dsterba@suse.com>
Tue, 10 Sep 2024 14:51:19 +0000 (16:51 +0200)
btrfs_cleanup_defrag_inodes() is not called frequently, only in remount
or unmount, but the way it frees the inodes in fs_info->defrag_inodes
is inefficient. Each time it needs to locate first node, remove it,
potentially rebalance tree until it's done. This allows to do a
conditional reschedule.

For cleanups the rbtree_postorder_for_each_entry_safe() iterator is
convenient but we can't reschedule and restart iteration because some of
the tree nodes would be already freed.

The cleanup operation is kmem_cache_free() which will likely take the
fast path for most objects so rescheduling should not be necessary.

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

index 41d67065d02bd06415eb35101afdd5e0378117a3..89f51252d25cf6bfde402f6d6bc2987fd0843a55 100644 (file)
@@ -212,20 +212,14 @@ out:
 
 void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info)
 {
-       struct inode_defrag *defrag;
-       struct rb_node *node;
+       struct inode_defrag *defrag, *next;
 
        spin_lock(&fs_info->defrag_inodes_lock);
-       node = rb_first(&fs_info->defrag_inodes);
-       while (node) {
-               rb_erase(node, &fs_info->defrag_inodes);
-               defrag = rb_entry(node, struct inode_defrag, rb_node);
-               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
 
-               cond_resched_lock(&fs_info->defrag_inodes_lock);
+       rbtree_postorder_for_each_entry_safe(defrag, next,
+                                            &fs_info->defrag_inodes, rb_node)
+               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
 
-               node = rb_first(&fs_info->defrag_inodes);
-       }
        spin_unlock(&fs_info->defrag_inodes_lock);
 }