]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
xfs: fix off-by-one error when the last rt extent is in use
authorDarrick J. Wong <djwong@kernel.org>
Wed, 11 Aug 2021 00:00:31 +0000 (17:00 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 19 Aug 2021 01:46:00 +0000 (18:46 -0700)
The fsmap implementation for realtime devices uses the gap between
info->next_daddr and a free rtextent reported by xfs_rtalloc_query_range
to feed userspace fsmap records with an "unknown" owner.  We use this
trick to report to userspace when the last rtextent in the filesystem is
in use by synthesizing a null rmap record starting at the next block
after the query range.

Unfortunately, there's a minor accounting bug in the way that we
construct the null rmap record.  Originally, ahigh.ar_startext contains
the last rtextent for which the user wants records.  It's entirely
possible that number is beyond the end of the rt volume, so the location
synthesized rmap record /must/ be constrained to the minimum of the high
key and the number of extents in the rt volume.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Chandan Babu R <chandanrlinux@gmail.com>
fs/xfs/xfs_fsmap.c

index 7d0b09c1366ea5370994de952fc1fac0e9dbd68b..5f603ed3f6783405c303ebceb6750ee40c058477 100644 (file)
@@ -523,27 +523,37 @@ xfs_getfsmap_rtdev_rtbitmap_query(
 {
        struct xfs_rtalloc_rec          alow = { 0 };
        struct xfs_rtalloc_rec          ahigh = { 0 };
+       struct xfs_mount                *mp = tp->t_mountp;
        int                             error;
 
-       xfs_ilock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
+       xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED);
 
+       /*
+        * Set up query parameters to return free rtextents covering the range
+        * we want.
+        */
        alow.ar_startext = info->low.rm_startblock;
        ahigh.ar_startext = info->high.rm_startblock;
-       do_div(alow.ar_startext, tp->t_mountp->m_sb.sb_rextsize);
-       if (do_div(ahigh.ar_startext, tp->t_mountp->m_sb.sb_rextsize))
+       do_div(alow.ar_startext, mp->m_sb.sb_rextsize);
+       if (do_div(ahigh.ar_startext, mp->m_sb.sb_rextsize))
                ahigh.ar_startext++;
        error = xfs_rtalloc_query_range(tp, &alow, &ahigh,
                        xfs_getfsmap_rtdev_rtbitmap_helper, info);
        if (error)
                goto err;
 
-       /* Report any gaps at the end of the rtbitmap */
+       /*
+        * Report any gaps at the end of the rtbitmap by simulating a null
+        * rmap starting at the block after the end of the query range.
+        */
        info->last = true;
+       ahigh.ar_startext = min(mp->m_sb.sb_rextents, ahigh.ar_startext);
+
        error = xfs_getfsmap_rtdev_rtbitmap_helper(tp, &ahigh, info);
        if (error)
                goto err;
 err:
-       xfs_iunlock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
+       xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED);
        return error;
 }