ext4: move setting of trimmed bit into ext4_try_to_trim_range()
authorJan Kara <jack@suse.cz>
Wed, 13 Sep 2023 15:04:54 +0000 (17:04 +0200)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 14 Sep 2023 16:06:47 +0000 (12:06 -0400)
Currently we set the group's trimmed bit in ext4_trim_all_free() based
on return value of ext4_try_to_trim_range(). However when we will want
to abort trimming because of suspend attempt, we want to return success
from ext4_try_to_trim_range() but not set the trimmed bit. Instead
implementing awkward propagation of this information, just move setting
of trimmed bit into ext4_try_to_trim_range() when the whole group is
trimmed.

Cc: stable@kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20230913150504.9054-1-jack@suse.cz
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/mballoc.c

index c91db9f57524c4eef9c8c33bb195721784969e7b..09091adfde6497ff5b5bd8749c4b73d0a3b86d75 100644 (file)
@@ -6906,6 +6906,16 @@ __acquires(bitlock)
        return ret;
 }
 
+static ext4_grpblk_t ext4_last_grp_cluster(struct super_block *sb,
+                                          ext4_group_t grp)
+{
+       if (grp < ext4_get_groups_count(sb))
+               return EXT4_CLUSTERS_PER_GROUP(sb) - 1;
+       return (ext4_blocks_count(EXT4_SB(sb)->s_es) -
+               ext4_group_first_block_no(sb, grp) - 1) >>
+                                       EXT4_CLUSTER_BITS(sb);
+}
+
 static int ext4_try_to_trim_range(struct super_block *sb,
                struct ext4_buddy *e4b, ext4_grpblk_t start,
                ext4_grpblk_t max, ext4_grpblk_t minblocks)
@@ -6913,9 +6923,12 @@ __acquires(ext4_group_lock_ptr(sb, e4b->bd_group))
 __releases(ext4_group_lock_ptr(sb, e4b->bd_group))
 {
        ext4_grpblk_t next, count, free_count;
+       bool set_trimmed = false;
        void *bitmap;
 
        bitmap = e4b->bd_bitmap;
+       if (start == 0 && max >= ext4_last_grp_cluster(sb, e4b->bd_group))
+               set_trimmed = true;
        start = max(e4b->bd_info->bb_first_free, start);
        count = 0;
        free_count = 0;
@@ -6930,16 +6943,14 @@ __releases(ext4_group_lock_ptr(sb, e4b->bd_group))
                        int ret = ext4_trim_extent(sb, start, next - start, e4b);
 
                        if (ret && ret != -EOPNOTSUPP)
-                               break;
+                               return count;
                        count += next - start;
                }
                free_count += next - start;
                start = next + 1;
 
-               if (fatal_signal_pending(current)) {
-                       count = -ERESTARTSYS;
-                       break;
-               }
+               if (fatal_signal_pending(current))
+                       return -ERESTARTSYS;
 
                if (need_resched()) {
                        ext4_unlock_group(sb, e4b->bd_group);
@@ -6951,6 +6962,9 @@ __releases(ext4_group_lock_ptr(sb, e4b->bd_group))
                        break;
        }
 
+       if (set_trimmed)
+               EXT4_MB_GRP_SET_TRIMMED(e4b->bd_info);
+
        return count;
 }
 
@@ -6961,7 +6975,6 @@ __releases(ext4_group_lock_ptr(sb, e4b->bd_group))
  * @start:             first group block to examine
  * @max:               last group block to examine
  * @minblocks:         minimum extent block count
- * @set_trimmed:       set the trimmed flag if at least one block is trimmed
  *
  * ext4_trim_all_free walks through group's block bitmap searching for free
  * extents. When the free extent is found, mark it as used in group buddy
@@ -6971,7 +6984,7 @@ __releases(ext4_group_lock_ptr(sb, e4b->bd_group))
 static ext4_grpblk_t
 ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
                   ext4_grpblk_t start, ext4_grpblk_t max,
-                  ext4_grpblk_t minblocks, bool set_trimmed)
+                  ext4_grpblk_t minblocks)
 {
        struct ext4_buddy e4b;
        int ret;
@@ -6988,13 +7001,10 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
        ext4_lock_group(sb, group);
 
        if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) ||
-           minblocks < EXT4_SB(sb)->s_last_trim_minblks) {
+           minblocks < EXT4_SB(sb)->s_last_trim_minblks)
                ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks);
-               if (ret >= 0 && set_trimmed)
-                       EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
-       } else {
+       else
                ret = 0;
-       }
 
        ext4_unlock_group(sb, group);
        ext4_mb_unload_buddy(&e4b);
@@ -7027,7 +7037,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
        ext4_fsblk_t first_data_blk =
                        le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
        ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es);
-       bool whole_group, eof = false;
        int ret = 0;
 
        start = range->start >> sb->s_blocksize_bits;
@@ -7046,10 +7055,8 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
                if (minlen > EXT4_CLUSTERS_PER_GROUP(sb))
                        goto out;
        }
-       if (end >= max_blks - 1) {
+       if (end >= max_blks - 1)
                end = max_blks - 1;
-               eof = true;
-       }
        if (end <= first_data_blk)
                goto out;
        if (start < first_data_blk)
@@ -7063,7 +7070,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
 
        /* end now represents the last cluster to discard in this group */
        end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
-       whole_group = true;
 
        for (group = first_group; group <= last_group; group++) {
                grp = ext4_get_group_info(sb, group);
@@ -7082,13 +7088,11 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
                 * change it for the last group, note that last_cluster is
                 * already computed earlier by ext4_get_group_no_and_offset()
                 */
-               if (group == last_group) {
+               if (group == last_group)
                        end = last_cluster;
-                       whole_group = eof ? true : end == EXT4_CLUSTERS_PER_GROUP(sb) - 1;
-               }
                if (grp->bb_free >= minlen) {
                        cnt = ext4_trim_all_free(sb, group, first_cluster,
-                                                end, minlen, whole_group);
+                                                end, minlen);
                        if (cnt < 0) {
                                ret = cnt;
                                break;