]> Git Repo - linux.git/commitdiff
ext4: fix FS_IOC_GETFSMAP handling
authorTheodore Ts'o <[email protected]>
Wed, 23 Oct 2024 04:25:37 +0000 (00:25 -0400)
committerTheodore Ts'o <[email protected]>
Wed, 13 Nov 2024 04:52:47 +0000 (23:52 -0500)
The original implementation ext4's FS_IOC_GETFSMAP handling only
worked when the range of queried blocks included at least one free
(unallocated) block range.  This is because how the metadata blocks
were emitted was as a side effect of ext4_mballoc_query_range()
calling ext4_getfsmap_datadev_helper(), and that function was only
called when a free block range was identified.  As a result, this
caused generic/365 to fail.

Fix this by creating a new function ext4_getfsmap_meta_helper() which
gets called so that blocks before the first free block range in a
block group can get properly reported.

Signed-off-by: Theodore Ts'o <[email protected]>
Cc: [email protected]
fs/ext4/fsmap.c
fs/ext4/mballoc.c
fs/ext4/mballoc.h

index df853c4d3a8c91b8ee8e7f07bb5853362067cb25..383c6edea6dd31d855ae9e65519580fbc63ba756 100644 (file)
@@ -185,6 +185,56 @@ static inline ext4_fsblk_t ext4_fsmap_next_pblk(struct ext4_fsmap *fmr)
        return fmr->fmr_physical + fmr->fmr_length;
 }
 
+static int ext4_getfsmap_meta_helper(struct super_block *sb,
+                                    ext4_group_t agno, ext4_grpblk_t start,
+                                    ext4_grpblk_t len, void *priv)
+{
+       struct ext4_getfsmap_info *info = priv;
+       struct ext4_fsmap *p;
+       struct ext4_fsmap *tmp;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       ext4_fsblk_t fsb, fs_start, fs_end;
+       int error;
+
+       fs_start = fsb = (EXT4_C2B(sbi, start) +
+                         ext4_group_first_block_no(sb, agno));
+       fs_end = fs_start + EXT4_C2B(sbi, len);
+
+       /* Return relevant extents from the meta_list */
+       list_for_each_entry_safe(p, tmp, &info->gfi_meta_list, fmr_list) {
+               if (p->fmr_physical < info->gfi_next_fsblk) {
+                       list_del(&p->fmr_list);
+                       kfree(p);
+                       continue;
+               }
+               if (p->fmr_physical <= fs_start ||
+                   p->fmr_physical + p->fmr_length <= fs_end) {
+                       /* Emit the retained free extent record if present */
+                       if (info->gfi_lastfree.fmr_owner) {
+                               error = ext4_getfsmap_helper(sb, info,
+                                                       &info->gfi_lastfree);
+                               if (error)
+                                       return error;
+                               info->gfi_lastfree.fmr_owner = 0;
+                       }
+                       error = ext4_getfsmap_helper(sb, info, p);
+                       if (error)
+                               return error;
+                       fsb = p->fmr_physical + p->fmr_length;
+                       if (info->gfi_next_fsblk < fsb)
+                               info->gfi_next_fsblk = fsb;
+                       list_del(&p->fmr_list);
+                       kfree(p);
+                       continue;
+               }
+       }
+       if (info->gfi_next_fsblk < fsb)
+               info->gfi_next_fsblk = fsb;
+
+       return 0;
+}
+
+
 /* Transform a blockgroup's free record into a fsmap */
 static int ext4_getfsmap_datadev_helper(struct super_block *sb,
                                        ext4_group_t agno, ext4_grpblk_t start,
@@ -539,6 +589,7 @@ static int ext4_getfsmap_datadev(struct super_block *sb,
                error = ext4_mballoc_query_range(sb, info->gfi_agno,
                                EXT4_B2C(sbi, info->gfi_low.fmr_physical),
                                EXT4_B2C(sbi, info->gfi_high.fmr_physical),
+                               ext4_getfsmap_meta_helper,
                                ext4_getfsmap_datadev_helper, info);
                if (error)
                        goto err;
@@ -560,7 +611,8 @@ static int ext4_getfsmap_datadev(struct super_block *sb,
 
        /* Report any gaps at the end of the bg */
        info->gfi_last = true;
-       error = ext4_getfsmap_datadev_helper(sb, end_ag, last_cluster, 0, info);
+       error = ext4_getfsmap_datadev_helper(sb, end_ag, last_cluster + 1,
+                                            0, info);
        if (error)
                goto err;
 
index d73e38323879ce217ba650e37197e7408666d877..92f49d7eb3c00157c3114bd475e8cc2a2cf0901e 100644 (file)
@@ -6999,13 +6999,14 @@ int
 ext4_mballoc_query_range(
        struct super_block              *sb,
        ext4_group_t                    group,
-       ext4_grpblk_t                   start,
+       ext4_grpblk_t                   first,
        ext4_grpblk_t                   end,
+       ext4_mballoc_query_range_fn     meta_formatter,
        ext4_mballoc_query_range_fn     formatter,
        void                            *priv)
 {
        void                            *bitmap;
-       ext4_grpblk_t                   next;
+       ext4_grpblk_t                   start, next;
        struct ext4_buddy               e4b;
        int                             error;
 
@@ -7016,10 +7017,19 @@ ext4_mballoc_query_range(
 
        ext4_lock_group(sb, group);
 
-       start = max(e4b.bd_info->bb_first_free, start);
+       start = max(e4b.bd_info->bb_first_free, first);
        if (end >= EXT4_CLUSTERS_PER_GROUP(sb))
                end = EXT4_CLUSTERS_PER_GROUP(sb) - 1;
-
+       if (meta_formatter && start != first) {
+               if (start > end)
+                       start = end;
+               ext4_unlock_group(sb, group);
+               error = meta_formatter(sb, group, first, start - first,
+                                      priv);
+               if (error)
+                       goto out_unload;
+               ext4_lock_group(sb, group);
+       }
        while (start <= end) {
                start = mb_find_next_zero_bit(bitmap, end + 1, start);
                if (start > end)
index d8553f1498d3cb7a49c6cce7c3321f8f76268b39..f8280de3e8820a639e775fafc40cde6030575814 100644 (file)
@@ -259,6 +259,7 @@ ext4_mballoc_query_range(
        ext4_group_t                    agno,
        ext4_grpblk_t                   start,
        ext4_grpblk_t                   end,
+       ext4_mballoc_query_range_fn     meta_formatter,
        ext4_mballoc_query_range_fn     formatter,
        void                            *priv);
 
This page took 0.068582 seconds and 4 git commands to generate.