Skip to content

Commit c6f1401

Browse files
Darrick J. Wongcmaiolino
authored andcommitted
xfs: fix fsmap for internal zoned devices
Filesystems with an internal zoned rt section use xfs_rtblock_t values that are relative to the start of the data device. When fsmap reports on internal rt sections, it reports the space used by the data section as "OWN_FS". Unfortunately, the logic for resuming a query isn't quite right, so xfs/273 fails because it stress-tests GETFSMAP with a single-record buffer. If we enter the "report fake space as OWN_FS" block with a nonzero key[0].fmr_length, we should add that to key[0].fmr_physical and recheck if we still need to emit the fake record. We should /not/ just return 0 from the whole function because that prevents all rmap record iteration. If we don't enter that block, the resumption is still wrong. keys[*].fmr_physical is a reflection of what we copied out to userspace on a previous query, which means that it already accounts for rgstart. It is not correct to add rtstart_daddr when computing start_rtb or end_rtb, so stop that. While we're at it, add a xfs_has_zoned to make it clear that this is a zoned filesystem thing. Fixes: e50ec7f ("xfs: enable fsmap reporting for internal RT devices") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Carlos Maiolino <cem@kernel.org>
1 parent 1c40652 commit c6f1401

File tree

1 file changed

+33
-18
lines changed

1 file changed

+33
-18
lines changed

fs/xfs/xfs_fsmap.c

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ xfs_getfsmap_rtdev_rmapbt(
876876
const struct xfs_fsmap *keys,
877877
struct xfs_getfsmap_info *info)
878878
{
879+
struct xfs_fsmap key0 = *keys; /* struct copy */
879880
struct xfs_mount *mp = tp->t_mountp;
880881
struct xfs_rtgroup *rtg = NULL;
881882
struct xfs_btree_cur *bt_cur = NULL;
@@ -887,45 +888,59 @@ xfs_getfsmap_rtdev_rmapbt(
887888
int error = 0;
888889

889890
eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart + mp->m_sb.sb_rblocks);
890-
if (keys[0].fmr_physical >= eofs)
891+
if (key0.fmr_physical >= eofs)
891892
return 0;
892893

894+
/*
895+
* On zoned filesystems with an internal rt volume, the volume comes
896+
* immediately after the end of the data volume. However, the
897+
* xfs_rtblock_t address space is relative to the start of the data
898+
* device, which means that the first @rtstart fsblocks do not actually
899+
* point anywhere. If a fsmap query comes in with the low key starting
900+
* below @rtstart, report it as "owned by filesystem".
901+
*/
893902
rtstart_daddr = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart);
894-
if (keys[0].fmr_physical < rtstart_daddr) {
903+
if (xfs_has_zoned(mp) && key0.fmr_physical < rtstart_daddr) {
895904
struct xfs_fsmap_irec frec = {
896905
.owner = XFS_RMAP_OWN_FS,
897906
.len_daddr = rtstart_daddr,
898907
};
899908

900-
/* Adjust the low key if we are continuing from where we left off. */
901-
if (keys[0].fmr_length > 0) {
902-
info->low_daddr = keys[0].fmr_physical + keys[0].fmr_length;
903-
return 0;
909+
/*
910+
* Adjust the start of the query range if we're picking up from
911+
* a previous round, and only emit the record if we haven't
912+
* already gone past.
913+
*/
914+
key0.fmr_physical += key0.fmr_length;
915+
if (key0.fmr_physical < rtstart_daddr) {
916+
error = xfs_getfsmap_helper(tp, info, &frec);
917+
if (error)
918+
return error;
919+
920+
key0.fmr_physical = rtstart_daddr;
904921
}
905922

906-
/* Fabricate an rmap entry for space occupied by the data dev */
907-
error = xfs_getfsmap_helper(tp, info, &frec);
908-
if (error)
909-
return error;
923+
/* Zero the other fields to avoid further adjustments. */
924+
key0.fmr_owner = 0;
925+
key0.fmr_offset = 0;
926+
key0.fmr_length = 0;
910927
}
911928

912-
start_rtb = xfs_daddr_to_rtb(mp, rtstart_daddr + keys[0].fmr_physical);
913-
end_rtb = xfs_daddr_to_rtb(mp, rtstart_daddr +
914-
min(eofs - 1, keys[1].fmr_physical));
915-
929+
start_rtb = xfs_daddr_to_rtb(mp, key0.fmr_physical);
930+
end_rtb = xfs_daddr_to_rtb(mp, min(eofs - 1, keys[1].fmr_physical));
916931
info->missing_owner = XFS_FMR_OWN_FREE;
917932

918933
/*
919934
* Convert the fsmap low/high keys to rtgroup based keys. Initialize
920935
* low to the fsmap low key and max out the high key to the end
921936
* of the rtgroup.
922937
*/
923-
info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
924-
error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
938+
info->low.rm_offset = XFS_BB_TO_FSBT(mp, key0.fmr_offset);
939+
error = xfs_fsmap_owner_to_rmap(&info->low, &key0);
925940
if (error)
926941
return error;
927-
info->low.rm_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fmr_length);
928-
xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
942+
info->low.rm_blockcount = XFS_BB_TO_FSBT(mp, key0.fmr_length);
943+
xfs_getfsmap_set_irec_flags(&info->low, &key0);
929944

930945
/* Adjust the low key if we are continuing from where we left off. */
931946
if (info->low.rm_blockcount == 0) {

0 commit comments

Comments
 (0)