Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: e50ec7fac81aa2 ("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>

authored by

Darrick J. Wong and committed by
Carlos Maiolino
c6f1401b 1c406526

+33 -18
+33 -18
fs/xfs/xfs_fsmap.c
··· 876 876 const struct xfs_fsmap *keys, 877 877 struct xfs_getfsmap_info *info) 878 878 { 879 + struct xfs_fsmap key0 = *keys; /* struct copy */ 879 880 struct xfs_mount *mp = tp->t_mountp; 880 881 struct xfs_rtgroup *rtg = NULL; 881 882 struct xfs_btree_cur *bt_cur = NULL; ··· 888 887 int error = 0; 889 888 890 889 eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart + mp->m_sb.sb_rblocks); 891 - if (keys[0].fmr_physical >= eofs) 890 + if (key0.fmr_physical >= eofs) 892 891 return 0; 893 892 893 + /* 894 + * On zoned filesystems with an internal rt volume, the volume comes 895 + * immediately after the end of the data volume. However, the 896 + * xfs_rtblock_t address space is relative to the start of the data 897 + * device, which means that the first @rtstart fsblocks do not actually 898 + * point anywhere. If a fsmap query comes in with the low key starting 899 + * below @rtstart, report it as "owned by filesystem". 900 + */ 894 901 rtstart_daddr = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart); 895 - if (keys[0].fmr_physical < rtstart_daddr) { 902 + if (xfs_has_zoned(mp) && key0.fmr_physical < rtstart_daddr) { 896 903 struct xfs_fsmap_irec frec = { 897 904 .owner = XFS_RMAP_OWN_FS, 898 905 .len_daddr = rtstart_daddr, 899 906 }; 900 907 901 - /* Adjust the low key if we are continuing from where we left off. */ 902 - if (keys[0].fmr_length > 0) { 903 - info->low_daddr = keys[0].fmr_physical + keys[0].fmr_length; 904 - return 0; 908 + /* 909 + * Adjust the start of the query range if we're picking up from 910 + * a previous round, and only emit the record if we haven't 911 + * already gone past. 912 + */ 913 + key0.fmr_physical += key0.fmr_length; 914 + if (key0.fmr_physical < rtstart_daddr) { 915 + error = xfs_getfsmap_helper(tp, info, &frec); 916 + if (error) 917 + return error; 918 + 919 + key0.fmr_physical = rtstart_daddr; 905 920 } 906 921 907 - /* Fabricate an rmap entry for space occupied by the data dev */ 908 - error = xfs_getfsmap_helper(tp, info, &frec); 909 - if (error) 910 - return error; 922 + /* Zero the other fields to avoid further adjustments. */ 923 + key0.fmr_owner = 0; 924 + key0.fmr_offset = 0; 925 + key0.fmr_length = 0; 911 926 } 912 927 913 - start_rtb = xfs_daddr_to_rtb(mp, rtstart_daddr + keys[0].fmr_physical); 914 - end_rtb = xfs_daddr_to_rtb(mp, rtstart_daddr + 915 - min(eofs - 1, keys[1].fmr_physical)); 916 - 928 + start_rtb = xfs_daddr_to_rtb(mp, key0.fmr_physical); 929 + end_rtb = xfs_daddr_to_rtb(mp, min(eofs - 1, keys[1].fmr_physical)); 917 930 info->missing_owner = XFS_FMR_OWN_FREE; 918 931 919 932 /* ··· 935 920 * low to the fsmap low key and max out the high key to the end 936 921 * of the rtgroup. 937 922 */ 938 - info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset); 939 - error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]); 923 + info->low.rm_offset = XFS_BB_TO_FSBT(mp, key0.fmr_offset); 924 + error = xfs_fsmap_owner_to_rmap(&info->low, &key0); 940 925 if (error) 941 926 return error; 942 - info->low.rm_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fmr_length); 943 - xfs_getfsmap_set_irec_flags(&info->low, &keys[0]); 927 + info->low.rm_blockcount = XFS_BB_TO_FSBT(mp, key0.fmr_length); 928 + xfs_getfsmap_set_irec_flags(&info->low, &key0); 944 929 945 930 /* Adjust the low key if we are continuing from where we left off. */ 946 931 if (info->low.rm_blockcount == 0) {