• Zizhi Wo's avatar
    xfs: Fix missing interval for missing_owner in xfs fsmap · ca6448ae
    Zizhi Wo authored
    In the fsmap query of xfs, there is an interval missing problem:
    [root@fedora ~]# xfs_io -c 'fsmap -vvvv' /mnt
     EXT: DEV    BLOCK-RANGE           OWNER              FILE-OFFSET      AG AG-OFFSET             TOTAL
       0: 253:16 [0..7]:               static fs metadata                  0  (0..7)                    8
       1: 253:16 [8..23]:              per-AG metadata                     0  (8..23)                  16
       2: 253:16 [24..39]:             inode btree                         0  (24..39)                 16
       3: 253:16 [40..47]:             per-AG metadata                     0  (40..47)                  8
       4: 253:16 [48..55]:             refcount btree                      0  (48..55)                  8
       5: 253:16 [56..103]:            per-AG metadata                     0  (56..103)                48
       6: 253:16 [104..127]:           free space                          0  (104..127)               24
       ......
    
    BUG:
    [root@fedora ~]# xfs_io -c 'fsmap -vvvv -d 104 107' /mnt
    [root@fedora ~]#
    Normally, we should be able to get [104, 107), but we got nothing.
    
    The problem is caused by shifting. The query for the problem-triggered
    scenario is for the missing_owner interval (e.g. freespace in rmapbt/
    unknown space in bnobt), which is obtained by subtraction (gap). For this
    scenario, the interval is obtained by info->last. However, rec_daddr is
    calculated based on the start_block recorded in key[1], which is converted
    by calling XFS_BB_TO_FSBT. Then if rec_daddr does not exceed
    info->next_daddr, which means keys[1].fmr_physical >> (mp)->m_blkbb_log
    <= info->next_daddr, no records will be displayed. In the above example,
    104 >> (mp)->m_blkbb_log = 12 and 107 >> (mp)->m_blkbb_log = 12, so the two
    are reduced to 0 and the gap is ignored:
    
     before calculate ----------------> after shifting
     104(st)  107(ed)		      12(st/ed)
      |---------|				  |
      sector size			      block size
    
    Resolve this issue by introducing the "end_daddr" field in
    xfs_getfsmap_info. This records |key[1].fmr_physical + key[1].length| at
    the granularity of sector. If the current query is the last, the rec_daddr
    is end_daddr to prevent missing interval problems caused by shifting. We
    only need to focus on the last query, because xfs disks are internally
    aligned with disk blocksize that are powers of two and minimum 512, so
    there is no problem with shifting in previous queries.
    
    After applying this patch, the above problem have been solved:
    [root@fedora ~]# xfs_io -c 'fsmap -vvvv -d 104 107' /mnt
     EXT: DEV    BLOCK-RANGE      OWNER            FILE-OFFSET      AG AG-OFFSET        TOTAL
       0: 253:16 [104..106]:      free space                        0  (104..106)           3
    
    Fixes: e89c0413 ("xfs: implement the GETFSMAP ioctl")
    Signed-off-by: default avatarZizhi Wo <wozizhi@huawei.com>
    Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
    [djwong: limit the range of end_addr correctly]
    Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
    Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>
    ca6448ae
xfs_fsmap.c 27.8 KB