]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
btrfs: add a global per cpu counter to track number of used extent maps
authorFilipe Manana <fdmanana@suse.com>
Fri, 22 Mar 2024 18:02:59 +0000 (18:02 +0000)
committerDavid Sterba <dsterba@suse.com>
Tue, 7 May 2024 19:31:06 +0000 (21:31 +0200)
Add a per cpu counter that tracks the total number of extent maps that are
in extent trees of inodes that belong to fs trees. This is going to be
used in an upcoming change that adds a shrinker for extent maps. Only
extent maps for fs trees are considered, because for special trees such as
the data relocation tree we don't want to evict their extent maps which
are critical for the relocation to work, and since those are limited, it's
not a concern to have them in memory during the relocation of a block
group. Another case are extent maps for free space cache inodes, which
must always remain in memory, but those are limited (there's only one per
free space cache inode, which means one per block group).

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/disk-io.c
fs/btrfs/extent_map.c
fs/btrfs/fs.h

index cee2e4f43dc6d7f553ae9fe46c88a523315f7c94..c2dc88f909b0c0e1e424fcf0d0c7d8a3cec8af8c 100644 (file)
@@ -1266,9 +1266,14 @@ static void free_global_roots(struct btrfs_fs_info *fs_info)
 
 void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
 {
+       struct percpu_counter *em_counter = &fs_info->evictable_extent_maps;
+
        percpu_counter_destroy(&fs_info->dirty_metadata_bytes);
        percpu_counter_destroy(&fs_info->delalloc_bytes);
        percpu_counter_destroy(&fs_info->ordered_bytes);
+       if (percpu_counter_initialized(em_counter))
+               ASSERT(percpu_counter_sum_positive(em_counter) == 0);
+       percpu_counter_destroy(em_counter);
        percpu_counter_destroy(&fs_info->dev_replace.bio_counter);
        btrfs_free_csum_hash(fs_info);
        btrfs_free_stripe_hash_table(fs_info);
@@ -2848,6 +2853,10 @@ static int init_mount_fs_info(struct btrfs_fs_info *fs_info, struct super_block
        if (ret)
                return ret;
 
+       ret = percpu_counter_init(&fs_info->evictable_extent_maps, 0, GFP_KERNEL);
+       if (ret)
+               return ret;
+
        ret = percpu_counter_init(&fs_info->dirty_metadata_bytes, 0, GFP_KERNEL);
        if (ret)
                return ret;
index fca08ac95a4a99a4caaefeac0fc796fdcb49d420..031c124c514ccd147f59d985d725e0d3941cf7c2 100644 (file)
@@ -76,6 +76,14 @@ static u64 range_end(u64 start, u64 len)
        return start + len;
 }
 
+static void dec_evictable_extent_maps(struct btrfs_inode *inode)
+{
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+
+       if (!btrfs_is_testing(fs_info) && is_fstree(btrfs_root_id(inode->root)))
+               percpu_counter_dec(&fs_info->evictable_extent_maps);
+}
+
 static int tree_insert(struct rb_root_cached *root, struct extent_map *em)
 {
        struct rb_node **p = &root->rb_root.rb_node;
@@ -259,6 +267,7 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
                        rb_erase_cached(&merge->rb_node, &tree->map);
                        RB_CLEAR_NODE(&merge->rb_node);
                        free_extent_map(merge);
+                       dec_evictable_extent_maps(inode);
                }
        }
 
@@ -273,6 +282,7 @@ static void try_merge_map(struct btrfs_inode *inode, struct extent_map *em)
                em->generation = max(em->generation, merge->generation);
                em->flags |= EXTENT_FLAG_MERGED;
                free_extent_map(merge);
+               dec_evictable_extent_maps(inode);
        }
 }
 
@@ -372,6 +382,8 @@ static int add_extent_mapping(struct btrfs_inode *inode,
                              struct extent_map *em, int modified)
 {
        struct extent_map_tree *tree = &inode->extent_tree;
+       struct btrfs_root *root = inode->root;
+       struct btrfs_fs_info *fs_info = root->fs_info;
        int ret;
 
        lockdep_assert_held_write(&tree->lock);
@@ -382,6 +394,9 @@ static int add_extent_mapping(struct btrfs_inode *inode,
 
        setup_extent_mapping(inode, em, modified);
 
+       if (!btrfs_is_testing(fs_info) && is_fstree(btrfs_root_id(root)))
+               percpu_counter_inc(&fs_info->evictable_extent_maps);
+
        return 0;
 }
 
@@ -467,6 +482,8 @@ void remove_extent_mapping(struct btrfs_inode *inode, struct extent_map *em)
        if (!(em->flags & EXTENT_FLAG_LOGGING))
                list_del_init(&em->list);
        RB_CLEAR_NODE(&em->rb_node);
+
+       dec_evictable_extent_maps(inode);
 }
 
 static void replace_extent_mapping(struct btrfs_inode *inode,
index 93f5c57ea4e3595a0715ec1b595d50016550a303..534d30dafe32f68704f3cfc9a1e4c1dd0b0ae1a6 100644 (file)
@@ -630,6 +630,8 @@ struct btrfs_fs_info {
        s32 dirty_metadata_batch;
        s32 delalloc_batch;
 
+       struct percpu_counter evictable_extent_maps;
+
        /* Protected by 'trans_lock'. */
        struct list_head dirty_cowonly_roots;