ext4: add a new helper to check if es must be kept
authorBaokun Li <libaokun1@huawei.com>
Mon, 24 Apr 2023 03:38:36 +0000 (11:38 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 3 Dec 2023 06:32:10 +0000 (07:32 +0100)
[ Upstream commit 9649eb18c6288f514cacffdd699d5cd999c2f8f6 ]

In the extent status tree, we have extents which we can just drop without
issues and extents we must not drop - this depends on the extent's status
- currently ext4_es_is_delayed() extents must stay, others may be dropped.

A helper function is added to help determine if the current extent can
be dropped, although only ext4_es_is_delayed() extents cannot be dropped
currently.

Suggested-by: Jan Kara <jack@suse.cz>
Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20230424033846.4732-3-libaokun1@huawei.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Stable-dep-of: 8e387c89e96b ("ext4: make sure allocate pending entry not fail")
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/ext4/extents_status.c

index b57e497..c9ab439 100644 (file)
@@ -448,6 +448,19 @@ static void ext4_es_list_del(struct inode *inode)
        spin_unlock(&sbi->s_es_lock);
 }
 
+/*
+ * Returns true if we cannot fail to allocate memory for this extent_status
+ * entry and cannot reclaim it until its status changes.
+ */
+static inline bool ext4_es_must_keep(struct extent_status *es)
+{
+       /* fiemap, bigalloc, and seek_data/hole need to use it. */
+       if (ext4_es_is_delayed(es))
+               return true;
+
+       return false;
+}
+
 static struct extent_status *
 ext4_es_alloc_extent(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len,
                     ext4_fsblk_t pblk)
@@ -460,10 +473,8 @@ ext4_es_alloc_extent(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len,
        es->es_len = len;
        es->es_pblk = pblk;
 
-       /*
-        * We don't count delayed extent because we never try to reclaim them
-        */
-       if (!ext4_es_is_delayed(es)) {
+       /* We never try to reclaim a must kept extent, so we don't count it. */
+       if (!ext4_es_must_keep(es)) {
                if (!EXT4_I(inode)->i_es_shk_nr++)
                        ext4_es_list_add(inode);
                percpu_counter_inc(&EXT4_SB(inode->i_sb)->
@@ -481,8 +492,8 @@ static void ext4_es_free_extent(struct inode *inode, struct extent_status *es)
        EXT4_I(inode)->i_es_all_nr--;
        percpu_counter_dec(&EXT4_SB(inode->i_sb)->s_es_stats.es_stats_all_cnt);
 
-       /* Decrease the shrink counter when this es is not delayed */
-       if (!ext4_es_is_delayed(es)) {
+       /* Decrease the shrink counter when we can reclaim the extent. */
+       if (!ext4_es_must_keep(es)) {
                BUG_ON(EXT4_I(inode)->i_es_shk_nr == 0);
                if (!--EXT4_I(inode)->i_es_shk_nr)
                        ext4_es_list_del(inode);
@@ -853,7 +864,7 @@ retry:
        if (err == -ENOMEM && __es_shrink(EXT4_SB(inode->i_sb),
                                          128, EXT4_I(inode)))
                goto retry;
-       if (err == -ENOMEM && !ext4_es_is_delayed(&newes))
+       if (err == -ENOMEM && !ext4_es_must_keep(&newes))
                err = 0;
 
        if (sbi->s_cluster_ratio > 1 && test_opt(inode->i_sb, DELALLOC) &&
@@ -1704,11 +1715,8 @@ static int es_do_reclaim_extents(struct ext4_inode_info *ei, ext4_lblk_t end,
 
                (*nr_to_scan)--;
                node = rb_next(&es->rb_node);
-               /*
-                * We can't reclaim delayed extent from status tree because
-                * fiemap, bigallic, and seek_data/hole need to use it.
-                */
-               if (ext4_es_is_delayed(es))
+
+               if (ext4_es_must_keep(es))
                        goto next;
                if (ext4_es_is_referenced(es)) {
                        ext4_es_clear_referenced(es);
@@ -1772,7 +1780,7 @@ void ext4_clear_inode_es(struct inode *inode)
        while (node) {
                es = rb_entry(node, struct extent_status, rb_node);
                node = rb_next(node);
-               if (!ext4_es_is_delayed(es)) {
+               if (!ext4_es_must_keep(es)) {
                        rb_erase(&es->rb_node, &tree->root);
                        ext4_es_free_extent(inode, es);
                }