]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: use per-RTG bitmaps and summaries xfs-per-rtg-bitmap
authorChristoph Hellwig <hch@lst.de>
Wed, 31 Jul 2024 20:16:06 +0000 (13:16 -0700)
committerChristoph Hellwig <hch@lst.de>
Thu, 1 Aug 2024 01:25:46 +0000 (18:25 -0700)
Allow RT allocation to scale by making the bitmap and summary inodes
per-RTG.  The 64-bit wide xfs_rtxnum_t becomes relative to the RTG and
now is the main data type used in the allocator - xfs_rgbno is left for
use with the rmap and refcount trees and can remain 32-bits as it never
exists for a pre-RTG file systems.

sb_rbmblocks and m_rsumlevels become per-RTG and we always allocate them
for full RTG, even when the last one doesn't use all blocks.  That
simplifies growfs a lot.

This needs a careful audit (and sparse loopback based tests) to verify
there are no overflows when converting to the xfs_rtxnum_t for
legacy file systems.  I'm almost sure we have issues with that
somewhere at the moment.

Signed-off-by: Christoph Hellwig <hch@lst.de>
41 files changed:
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_metafile.c
fs/xfs/libxfs/xfs_rtbitmap.c
fs/xfs/libxfs/xfs_rtbitmap.h
fs/xfs/libxfs/xfs_rtgroup.c
fs/xfs/libxfs/xfs_rtgroup.h
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_trans_resv.c
fs/xfs/libxfs/xfs_types.c
fs/xfs/scrub/bmap.c
fs/xfs/scrub/bmap_repair.c
fs/xfs/scrub/common.c
fs/xfs/scrub/common.h
fs/xfs/scrub/cow_repair.c
fs/xfs/scrub/fscounters.c
fs/xfs/scrub/health.c
fs/xfs/scrub/inode_repair.c
fs/xfs/scrub/repair.c
fs/xfs/scrub/repair.h
fs/xfs/scrub/rtbitmap.c
fs/xfs/scrub/rtbitmap.h
fs/xfs/scrub/rtbitmap_repair.c
fs/xfs/scrub/rtrefcount_repair.c
fs/xfs/scrub/rtrmap_repair.c
fs/xfs/scrub/rtsummary.c
fs/xfs/scrub/rtsummary_repair.c
fs/xfs/scrub/scrub.c
fs/xfs/scrub/scrub.h
fs/xfs/scrub/stats.c
fs/xfs/scrub/trace.h
fs/xfs/xfs_discard.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_fsmap.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_reflink.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_super.c

index d60795dbe782c01f69512a0e524e4552af43b66b..ab296b81c342accbdc263d92982cd84fc435baf3 100644 (file)
@@ -3143,8 +3143,17 @@ xfs_bmap_adjacent_valid(
        struct xfs_mount        *mp = ap->ip->i_mount;
 
        if (XFS_IS_REALTIME_INODE(ap->ip) &&
-           (ap->datatype & XFS_ALLOC_USERDATA))
-               return x < mp->m_sb.sb_rblocks;
+           (ap->datatype & XFS_ALLOC_USERDATA)) {
+               if (x >= mp->m_sb.sb_rblocks)
+                       return false;
+               if (!xfs_has_rtgroups(mp))
+                       return true;
+
+               return xfs_rtb_to_rgno(mp, x) == xfs_rtb_to_rgno(mp, y) &&
+                       xfs_rtb_to_rgno(mp, x) < mp->m_sb.sb_rgcount &&
+                       xfs_rtb_to_rtx(mp, x) < mp->m_sb.sb_rgextents;
+
+       }
 
        return XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) &&
                XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount &&
@@ -4145,7 +4154,7 @@ retry:
 
        fdblocks = indlen;
        if (XFS_IS_REALTIME_INODE(ip)) {
-               error = xfs_dec_frextents(mp, xfs_rtb_to_rtx(mp, alen));
+               error = xfs_dec_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
                if (error)
                        goto out_unreserve_quota;
        } else {
@@ -4180,7 +4189,7 @@ retry:
 
 out_unreserve_frextents:
        if (XFS_IS_REALTIME_INODE(ip))
-               xfs_add_frextents(mp, xfs_rtb_to_rtx(mp, alen));
+               xfs_add_frextents(mp, xfs_blen_to_rtbxlen(mp, alen));
 out_unreserve_quota:
        if (XFS_IS_QUOTA_ON(mp))
                xfs_quota_unreserve_blkres(ip, alen);
@@ -5109,7 +5118,7 @@ xfs_bmap_del_extent_delay(
        fdblocks = da_diff;
 
        if (isrt)
-               xfs_add_frextents(mp, xfs_rtb_to_rtx(mp, del->br_blockcount));
+               xfs_add_frextents(mp, xfs_blen_to_rtbxlen(mp, del->br_blockcount));
        else
                fdblocks += del->br_blockcount;
 
@@ -5188,6 +5197,34 @@ xfs_bmap_del_extent_cow(
        ip->i_delayed_blks -= del->br_blockcount;
 }
 
+static int
+xfs_bmap_free_rtblocks(
+       struct xfs_trans        *tp,
+       struct xfs_bmbt_irec    *del)
+{
+       struct xfs_rtgroup      *rtg;
+       int                     error;
+
+       rtg = xfs_rtgroup_grab(tp->t_mountp, 0);
+       if (!rtg)
+               return -EIO;
+
+       /*
+        * Ensure the bitmap and summary inodes are locked and joined to the
+        * transaction before modifying them.
+        */
+       if (!(tp->t_flags & XFS_TRANS_RTBITMAP_LOCKED)) {
+               tp->t_flags |= XFS_TRANS_RTBITMAP_LOCKED;
+               xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP);
+               xfs_rtgroup_trans_join(tp, rtg, XFS_RTGLOCK_BITMAP);
+       }
+
+       error = xfs_rtfree_blocks(tp, rtg, del->br_startblock,
+                       del->br_blockcount);
+       xfs_rtgroup_rele(rtg);
+       return error;
+}
+
 /*
  * Called by xfs_bmapi to update file extent records and the btree
  * after removing space.
@@ -5405,17 +5442,7 @@ xfs_bmap_del_extent_real(
                if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) {
                        xfs_refcount_decrease_extent(tp, isrt, del);
                } else if (isrt && !xfs_has_rtgroups(mp)) {
-                       /*
-                        * Ensure the bitmap and summary inodes are locked
-                        * and joined to the transaction before modifying them.
-                        */
-                       if (!(tp->t_flags & XFS_TRANS_RTBITMAP_LOCKED)) {
-                               tp->t_flags |= XFS_TRANS_RTBITMAP_LOCKED;
-                               xfs_rtbitmap_lock(mp);
-                               xfs_rtbitmap_trans_join(tp);
-                       }
-                       error = xfs_rtfree_blocks(tp, del->br_startblock,
-                                       del->br_blockcount);
+                       error = xfs_bmap_free_rtblocks(tp, del);
                } else {
                        unsigned int    efi_flags = 0;
 
index b0394435265e8d8bb50a2aff1a58d565c2d0fd24..e6b83e2af8da7398a1afb88ffa2e05a8a6e801ae 100644 (file)
@@ -203,7 +203,11 @@ void
 xfs_metafile_resv_free(
        struct xfs_inode        *ip)
 {
-       if (!ip)
+       /*
+        * We can end up here for the rt bitmap/summary inodes that don't have
+        * reservations.  Just exist early in that case.
+        */
+       if (!ip || !ip->i_delayed_blks)
                return;
 
        ASSERT(xfs_is_metadir_inode(ip));
index a9aefffe33030d162492764c0cb3a2f914708551..6697887e76f8d01f1bfd0587f11e25857c581229 100644 (file)
@@ -7,6 +7,7 @@
 #include "xfs_fs.h"
 #include "xfs_shared.h"
 #include "xfs_format.h"
+#include "xfs_sb.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
@@ -163,12 +164,12 @@ xfs_rtbuf_get(
        if (issum) {
                cbpp = &args->sumbp;
                coffp = &args->sumoff;
-               ip = mp->m_rsumip;
+               ip = args->rtg->rtg_inodes[XFS_RTG_SUMMARY];
                type = XFS_BLFT_RTSUMMARY_BUF;
        } else {
                cbpp = &args->rbmbp;
                coffp = &args->rbmoff;
-               ip = mp->m_rbmip;
+               ip = args->rtg->rtg_inodes[XFS_RTG_BITMAP];
                type = XFS_BLFT_RTBITMAP_BUF;
        }
 
@@ -589,6 +590,7 @@ xfs_rtmodify_summary(
 {
        struct xfs_mount        *mp = args->mp;
        xfs_rtsumoff_t          so = xfs_rtsumoffs(mp, log, bbno);
+       uint8_t                 *rsum_cache = args->rtg->rtg_rsum_cache;
        unsigned int            infoword;
        xfs_suminfo_t           val;
        int                     error;
@@ -600,11 +602,11 @@ xfs_rtmodify_summary(
        infoword = xfs_rtsumoffs_to_infoword(mp, so);
        val = xfs_suminfo_add(args, infoword, delta);
 
-       if (mp->m_rsum_cache) {
-               if (val == 0 && log + 1 == mp->m_rsum_cache[bbno])
-                       mp->m_rsum_cache[bbno] = log;
-               if (val != 0 && log >= mp->m_rsum_cache[bbno])
-                       mp->m_rsum_cache[bbno] = log + 1;
+       if (rsum_cache) {
+               if (val == 0 && log + 1 == rsum_cache[bbno])
+                       rsum_cache[bbno] = log;
+               if (val != 0 && log >= rsum_cache[bbno])
+                       rsum_cache[bbno] = log + 1;
        }
 
        xfs_trans_log_rtsummary(args, infoword);
@@ -823,7 +825,7 @@ xfs_rtfree_range(
        /*
         * Find the next allocated block (end of allocated extent).
         */
-       error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
+       error = xfs_rtfind_forw(args, end, args->rtg->rtg_extents - 1,
                        &postblock);
        if (error)
                return error;
@@ -1047,19 +1049,22 @@ xfs_rtcheck_alloc_range(
 int
 xfs_rtfree_extent(
        struct xfs_trans        *tp,    /* transaction pointer */
+       struct xfs_rtgroup      *rtg,
        xfs_rtxnum_t            start,  /* starting rtext number to free */
        xfs_rtxlen_t            len)    /* length of extent freed */
 {
        struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_inode        *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
        struct xfs_rtalloc_args args = {
                .mp             = mp,
                .tp             = tp,
+               .rtg            = rtg,
        };
        int                     error;
        struct timespec64       atime;
 
-       ASSERT(mp->m_rbmip->i_itemp != NULL);
-       xfs_assert_ilocked(mp->m_rbmip, XFS_ILOCK_EXCL);
+       ASSERT(rbmip->i_itemp != NULL);
+       xfs_assert_ilocked(rbmip, XFS_ILOCK_EXCL);
 
        if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FREE_EXTENT))
                return -EIO;
@@ -1079,23 +1084,20 @@ xfs_rtfree_extent(
         * Mark more blocks free in the superblock.
         */
        xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len);
+
        /*
         * If we've now freed all the blocks, reset the file sequence
-        * number to 0.
+        * number to 0 for legacy file systems.
         */
-       if (tp->t_frextents_delta + mp->m_sb.sb_frextents ==
+       if (!xfs_has_rtgroups(mp) &&
+           tp->t_frextents_delta + mp->m_sb.sb_frextents ==
            mp->m_sb.sb_rextents) {
-               if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM))
-                       mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
-
-               if (xfs_has_rtgroups(mp)) {
-                       mp->m_rtgrotor = 0;
-               } else {
-                       atime = inode_get_atime(VFS_I(mp->m_rbmip));
-                       atime.tv_sec = 0;
-                       inode_set_atime_to_ts(VFS_I(mp->m_rbmip), atime);
-                       xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
-               }
+               rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
+
+               atime = inode_get_atime(VFS_I(rbmip));
+               atime.tv_sec = 0;
+               inode_set_atime_to_ts(VFS_I(rbmip), atime);
+               xfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE);
        }
        error = 0;
 out:
@@ -1111,6 +1113,7 @@ out:
 int
 xfs_rtfree_blocks(
        struct xfs_trans        *tp,
+       struct xfs_rtgroup      *rtg,
        xfs_fsblock_t           rtbno,
        xfs_filblks_t           rtlen)
 {
@@ -1131,21 +1134,23 @@ xfs_rtfree_blocks(
                return -EIO;
        }
 
-       return xfs_rtfree_extent(tp, xfs_rtb_to_rtx(mp, rtbno),
-                       xfs_rtb_to_rtx(mp, rtlen));
+       return xfs_rtfree_extent(tp, rtg, xfs_rtb_to_rtx(mp, rtbno),
+                       xfs_extlen_to_rtxlen(mp, rtlen));
 }
 
 /* Find all the free records within a given range. */
 int
 xfs_rtalloc_query_range(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        xfs_rtxnum_t                    start,
        xfs_rtxnum_t                    end,
        xfs_rtalloc_query_range_fn      fn,
        void                            *priv)
 {
+       struct xfs_mount                *mp = rtg->rtg_mount;
        struct xfs_rtalloc_args         args = {
+               .rtg                    = rtg,
                .mp                     = mp,
                .tp                     = tp,
        };
@@ -1153,10 +1158,10 @@ xfs_rtalloc_query_range(
 
        if (start > end)
                return -EINVAL;
-       if (start == end || start >= mp->m_sb.sb_rextents)
+       if (start == end || start >= rtg->rtg_extents)
                return 0;
 
-       end = min(end, mp->m_sb.sb_rextents - 1);
+       end = min(end, rtg->rtg_extents - 1);
 
        /* Iterate the bitmap, looking for discrepancies. */
        while (start <= end) {
@@ -1179,7 +1184,7 @@ xfs_rtalloc_query_range(
                        rec.ar_startext = start;
                        rec.ar_extcount = rtend - start + 1;
 
-                       error = fn(mp, tp, &rec, priv);
+                       error = fn(rtg, tp, &rec, priv);
                        if (error)
                                break;
                }
@@ -1194,26 +1199,27 @@ xfs_rtalloc_query_range(
 /* Find all the free records. */
 int
 xfs_rtalloc_query_all(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        xfs_rtalloc_query_range_fn      fn,
        void                            *priv)
 {
-       return xfs_rtalloc_query_range(mp, tp, 0, mp->m_sb.sb_rextents - 1, fn,
+       return xfs_rtalloc_query_range(rtg, tp, 0, rtg->rtg_extents - 1, fn,
                        priv);
 }
 
 /* Is the given extent all free? */
 int
 xfs_rtalloc_extent_is_free(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        xfs_rtxnum_t                    start,
        xfs_rtxlen_t                    len,
        bool                            *is_free)
 {
        struct xfs_rtalloc_args         args = {
-               .mp                     = mp,
+               .mp                     = rtg->rtg_mount,
+               .rtg                    = rtg,
                .tp                     = tp,
        };
        xfs_rtxnum_t                    end;
@@ -1242,16 +1248,25 @@ xfs_rtbitmap_rtx_per_rbmblock(
        return rbmblock_bytes * NBBY;
 }
 
+xfs_filblks_t
+__xfs_rtbitmap_blockcount(
+       struct xfs_mount        *mp,
+       xfs_rtbxlen_t           rtextents)
+{
+       return howmany_64(rtextents, xfs_rtbitmap_rtx_per_rbmblock(mp));
+}
+
 /*
  * Compute the number of rtbitmap blocks needed to track the given number of rt
  * extents.
  */
 xfs_filblks_t
 xfs_rtbitmap_blockcount(
-       struct xfs_mount        *mp,
-       xfs_rtbxlen_t           rtextents)
+       struct xfs_mount        *mp)
 {
-       return howmany_64(rtextents, xfs_rtbitmap_rtx_per_rbmblock(mp));
+       if (xfs_has_rtgroups(mp))
+               return __xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rgextents);
+       return __xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
 }
 
 /*
@@ -1260,13 +1275,9 @@ xfs_rtbitmap_blockcount(
  */
 unsigned long long
 xfs_rtbitmap_wordcount(
-       struct xfs_mount        *mp,
-       xfs_rtbxlen_t           rtextents)
+       struct xfs_mount        *mp)
 {
-       xfs_filblks_t           blocks;
-
-       blocks = xfs_rtbitmap_blockcount(mp, rtextents);
-       return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
+       return XFS_FSB_TO_B(mp, xfs_rtbitmap_blockcount(mp)) >> XFS_WORDLOG;
 }
 
 /* Compute the number of rtsummary blocks needed to track the given rt space. */
@@ -1302,63 +1313,14 @@ xfs_rtsummary_wordcount(
        return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
 }
 
-/* Lock both realtime free space metadata inodes for a freespace update. */
-void
-xfs_rtbitmap_lock(
-       struct xfs_mount        *mp)
-{
-       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
-}
-
-/*
- * Join both realtime free space metadata inodes to the transaction.  The
- * ILOCKs will be released on transaction commit.
- */
-void
-xfs_rtbitmap_trans_join(
-       struct xfs_trans        *tp)
-{
-       xfs_trans_ijoin(tp, tp->t_mountp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, tp->t_mountp->m_rsumip, XFS_ILOCK_EXCL);
-}
-
-/* Unlock both realtime free space metadata inodes after a freespace update. */
-void
-xfs_rtbitmap_unlock(
-       struct xfs_mount        *mp)
-{
-       xfs_iunlock(mp->m_rsumip, XFS_ILOCK_EXCL);
-       xfs_iunlock(mp->m_rbmip, XFS_ILOCK_EXCL);
-}
-
-/*
- * Lock the realtime free space metadata inodes for a freespace scan.  Callers
- * must walk metadata blocks in order of increasing file offset.
- */
-void
-xfs_rtbitmap_lock_shared(
-       struct xfs_mount        *mp,
-       unsigned int            rbmlock_flags)
-{
-       if (rbmlock_flags & XFS_RBMLOCK_BITMAP)
-               xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED);
-
-       if (rbmlock_flags & XFS_RBMLOCK_SUMMARY)
-               xfs_ilock(mp->m_rsumip, XFS_ILOCK_SHARED);
-}
-
-/* Unlock the realtime free space metadata inodes after a freespace scan. */
-void
-xfs_rtbitmap_unlock_shared(
+unsigned int
+xfs_compute_rsumlevels(
        struct xfs_mount        *mp,
-       unsigned int            rbmlock_flags)
+       uint64_t                rextents)
 {
-       if (rbmlock_flags & XFS_RBMLOCK_SUMMARY)
-               xfs_iunlock(mp->m_rsumip, XFS_ILOCK_SHARED);
-
-       if (rbmlock_flags & XFS_RBMLOCK_BITMAP)
-               xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED);
+       if (xfs_has_rtgroups(mp))
+               rextents = mp->m_sb.sb_rgextents;
+       return xfs_compute_rextslog(rextents) + 1;
 }
 
 static int
@@ -1401,11 +1363,13 @@ out_trans_cancel:
 /* Get a buffer for the block. */
 static int
 xfs_rtfile_initialize_block(
-       struct xfs_inode        *ip,
+       struct xfs_rtgroup      *rtg,
+       enum xfs_rtg_inodes     type,
        xfs_fsblock_t           fsbno,
        void                    *data)
 {
-       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       struct xfs_inode        *ip = rtg->rtg_inodes[type];
        struct xfs_trans        *tp;
        struct xfs_buf          *bp;
        void                    *bufdata;
@@ -1413,10 +1377,12 @@ xfs_rtfile_initialize_block(
        enum xfs_blft           buf_type;
        int                     error;
 
-       if (ip == mp->m_rsumip)
+       if (type == XFS_RTG_BITMAP)
+               buf_type = XFS_BLFT_RTBITMAP_BUF;
+       else if (type == XFS_RTG_SUMMARY)
                buf_type = XFS_BLFT_RTSUMMARY_BUF;
        else
-               buf_type = XFS_BLFT_RTBITMAP_BUF;
+               return -EINVAL;
 
        error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtzero, 0, 0, 0, &tp);
        if (error)
@@ -1433,12 +1399,12 @@ xfs_rtfile_initialize_block(
        bufdata = bp->b_addr;
 
        xfs_trans_buf_set_type(tp, bp, buf_type);
-       bp->b_ops = xfs_rtblock_ops(mp, buf_type == XFS_BLFT_RTSUMMARY_BUF);
+       bp->b_ops = xfs_rtblock_ops(mp, type == XFS_RTG_SUMMARY);
 
        if (xfs_has_rtgroups(mp)) {
                struct xfs_rtbuf_blkinfo        *hdr = bp->b_addr;
 
-               if (buf_type == XFS_BLFT_RTBITMAP_BUF)
+               if (type == XFS_RTG_BITMAP)
                        hdr->rt_magic = cpu_to_be32(XFS_RTBITMAP_MAGIC);
                else
                        hdr->rt_magic = cpu_to_be32(XFS_RTSUMMARY_MAGIC);
@@ -1464,12 +1430,13 @@ xfs_rtfile_initialize_block(
  */
 int
 xfs_rtfile_initialize_blocks(
-       struct xfs_inode        *ip,            /* inode (bitmap/summary) */
+       struct xfs_rtgroup      *rtg,
+       enum xfs_rtg_inodes     type,
        xfs_fileoff_t           offset_fsb,     /* offÑ•et to start from */
        xfs_fileoff_t           end_fsb,        /* offÑ•et to allocate to */
        void                    *data)          /* data to fill the blocks */
 {
-       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_mount        *mp = rtg->rtg_mount;
        const size_t            copylen = mp->m_blockwsize << XFS_WORDLOG;
 
        while (offset_fsb < end_fsb) {
@@ -1477,8 +1444,8 @@ xfs_rtfile_initialize_blocks(
                xfs_filblks_t           i;
                int                     error;
 
-               error = xfs_rtfile_alloc_blocks(ip, offset_fsb,
-                               end_fsb - offset_fsb, &map);
+               error = xfs_rtfile_alloc_blocks(rtg->rtg_inodes[type],
+                               offset_fsb, end_fsb - offset_fsb, &map);
                if (error)
                        return error;
 
@@ -1488,7 +1455,7 @@ xfs_rtfile_initialize_blocks(
                 * Do this one block per transaction, to keep it simple.
                 */
                for (i = 0; i < map.br_blockcount; i++) {
-                       error = xfs_rtfile_initialize_block(ip,
+                       error = xfs_rtfile_initialize_block(rtg, type,
                                        map.br_startblock + i, data);
                        if (error)
                                return error;
@@ -1501,3 +1468,33 @@ xfs_rtfile_initialize_blocks(
 
        return 0;
 }
+
+int
+xfs_rtbitmap_create(
+       struct xfs_rtgroup      *rtg,
+       struct xfs_inode        *ip,
+       struct xfs_trans        *tp,
+       bool                    init)
+{
+       struct xfs_mount        *mp = rtg->rtg_mount;
+
+       ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
+       if (init && !xfs_has_rtgroups(mp)) {
+               ip->i_diflags |= XFS_DIFLAG_NEWRTBM;
+               inode_set_atime(VFS_I(ip), 0, 0);
+       }
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       return 0;
+}
+
+int
+xfs_rtsummary_create(
+       struct xfs_rtgroup      *rtg,
+       struct xfs_inode        *ip,
+       struct xfs_trans        *tp,
+       bool                    init)
+{
+       ip->i_disk_size = rtg->rtg_mount->m_rsumsize;
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       return 0;
+}
index ccd28c1c9ce23e73511cec314d8a0e309ebee63e..57d33569b35aba1312fe432f3e71dcdf2b00ef49 100644 (file)
@@ -6,7 +6,10 @@
 #ifndef __XFS_RTBITMAP_H__
 #define        __XFS_RTBITMAP_H__
 
+#include "xfs_rtgroup.h"
+
 struct xfs_rtalloc_args {
+       struct xfs_rtgroup      *rtg;
        struct xfs_mount        *mp;
        struct xfs_trans        *tp;
 
@@ -17,15 +20,15 @@ struct xfs_rtalloc_args {
        xfs_fileoff_t           sumoff; /* summary block number */
 };
 
-static inline xfs_rtblock_t
-xfs_rtx_to_rtb(
+static inline uint64_t
+xfs_rtbxlen_to_blen(
        struct xfs_mount        *mp,
-       xfs_rtxnum_t            rtx)
+       xfs_rtbxlen_t           rtbxlen)
 {
        if (mp->m_rtxblklog >= 0)
-               return rtx << mp->m_rtxblklog;
+               return rtbxlen << mp->m_rtxblklog;
 
-       return rtx * mp->m_sb.sb_rextsize;
+       return rtbxlen * mp->m_sb.sb_rextsize;
 }
 
 static inline xfs_extlen_t
@@ -62,16 +65,16 @@ xfs_extlen_to_rtxlen(
        return len / mp->m_sb.sb_rextsize;
 }
 
-/* Convert an rt block number into an rt extent number. */
-static inline xfs_rtxnum_t
-xfs_rtb_to_rtx(
+/* Convert an rt block count into an rt extent count. */
+static inline xfs_rtbxlen_t
+xfs_blen_to_rtbxlen(
        struct xfs_mount        *mp,
-       xfs_rtblock_t           rtbno)
+       uint64_t                blen)
 {
        if (likely(mp->m_rtxblklog >= 0))
-               return rtbno >> mp->m_rtxblklog;
+               return blen >> mp->m_rtxblklog;
 
-       return div_u64(rtbno, mp->m_sb.sb_rextsize);
+       return div_u64(blen, mp->m_sb.sb_rextsize);
 }
 
 /* Return the offset of an rt block number within an rt extent. */
@@ -86,26 +89,6 @@ xfs_rtb_to_rtxoff(
        return do_div(rtbno, mp->m_sb.sb_rextsize);
 }
 
-/*
- * Convert an rt block number into an rt extent number, rounding up to the next
- * rt extent if the rt block is not aligned to an rt extent boundary.
- */
-static inline xfs_rtxnum_t
-xfs_rtb_to_rtxup(
-       struct xfs_mount        *mp,
-       xfs_rtblock_t           rtbno)
-{
-       if (likely(mp->m_rtxblklog >= 0)) {
-               if (rtbno & mp->m_rtxblkmask)
-                       return (rtbno >> mp->m_rtxblklog) + 1;
-               return rtbno >> mp->m_rtxblklog;
-       }
-
-       if (do_div(rtbno, mp->m_sb.sb_rextsize))
-               rtbno++;
-       return rtbno;
-}
-
 /* Round this rtblock up to the nearest rt extent size. */
 static inline xfs_rtblock_t
 xfs_rtb_roundup_rtx(
@@ -325,7 +308,7 @@ struct xfs_rtalloc_rec {
 };
 
 typedef int (*xfs_rtalloc_query_range_fn)(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        const struct xfs_rtalloc_rec    *rec,
        void                            *priv);
@@ -348,59 +331,50 @@ int xfs_rtmodify_summary(struct xfs_rtalloc_args *args, int log,
                xfs_fileoff_t bbno, int delta);
 int xfs_rtfree_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
                xfs_rtxlen_t len);
-int xfs_rtalloc_query_range(struct xfs_mount *mp, struct xfs_trans *tp,
+int xfs_rtalloc_query_range(struct xfs_rtgroup *rtg, struct xfs_trans *tp,
                xfs_rtxnum_t start, xfs_rtxnum_t end,
                xfs_rtalloc_query_range_fn fn, void *priv);
-int xfs_rtalloc_query_all(struct xfs_mount *mp, struct xfs_trans *tp,
+int xfs_rtalloc_query_all(struct xfs_rtgroup *rtg, struct xfs_trans *tp,
                          xfs_rtalloc_query_range_fn fn,
                          void *priv);
-int xfs_rtalloc_extent_is_free(struct xfs_mount *mp, struct xfs_trans *tp,
-                              xfs_rtxnum_t start, xfs_rtxlen_t len,
-                              bool *is_free);
-/*
- * Free an extent in the realtime subvolume.  Length is expressed in
- * realtime extents, as is the block number.
- */
-int                                    /* error */
-xfs_rtfree_extent(
-       struct xfs_trans        *tp,    /* transaction pointer */
-       xfs_rtxnum_t            start,  /* starting rtext number to free */
-       xfs_rtxlen_t            len);   /* length of extent freed */
-
+int xfs_rtalloc_extent_is_free(struct xfs_rtgroup *rtg, struct xfs_trans *tp,
+               xfs_rtxnum_t start, xfs_rtxlen_t len, bool *is_free);
+int xfs_rtfree_extent(struct xfs_trans *tp, struct xfs_rtgroup *rtg,
+               xfs_rtxnum_t start, xfs_rtxlen_t len);
 /* Same as above, but in units of rt blocks. */
-int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno,
-               xfs_filblks_t rtlen);
+int xfs_rtfree_blocks(struct xfs_trans *tp, struct xfs_rtgroup *rtg,
+               xfs_fsblock_t rtbno, xfs_filblks_t rtlen);
 
 xfs_rtxnum_t xfs_rtbitmap_rtx_per_rbmblock(struct xfs_mount *mp);
-xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t
-               rtextents);
-unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp,
+xfs_filblks_t __xfs_rtbitmap_blockcount(struct xfs_mount *mp,
                xfs_rtbxlen_t rtextents);
+xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp);
+unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp);
 
 xfs_filblks_t xfs_rtsummary_blockcount(struct xfs_mount *mp,
                unsigned int rsumlevels, xfs_extlen_t rbmblocks);
 unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp,
                unsigned int rsumlevels, xfs_extlen_t rbmblocks);
+unsigned int xfs_compute_rsumlevels(struct xfs_mount *mp, uint64_t rextents);
 
-int xfs_rtfile_initialize_blocks(struct xfs_inode *ip,
-               xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb, void *data);
+int xfs_rtfile_initialize_blocks(struct xfs_rtgroup *rtg,
+               enum xfs_rtg_inodes type, xfs_fileoff_t offset_fsb,
+               xfs_fileoff_t end_fsb, void *data);
+int xfs_rtbitmap_create(struct xfs_rtgroup *rtg, struct xfs_inode *ip,
+               struct xfs_trans *tp, bool init);
+int xfs_rtsummary_create(struct xfs_rtgroup *rtg, struct xfs_inode *ip,
+               struct xfs_trans *tp, bool init);
 
-void xfs_rtbitmap_lock(struct xfs_mount *mp);
-void xfs_rtbitmap_unlock(struct xfs_mount *mp);
-void xfs_rtbitmap_trans_join(struct xfs_trans *tp);
-
-/* Lock the rt bitmap inode in shared mode */
-#define XFS_RBMLOCK_BITMAP     (1U << 0)
-/* Lock the rt summary inode in shared mode */
-#define XFS_RBMLOCK_SUMMARY    (1U << 1)
-
-void xfs_rtbitmap_lock_shared(struct xfs_mount *mp,
-               unsigned int rbmlock_flags);
-void xfs_rtbitmap_unlock_shared(struct xfs_mount *mp,
-               unsigned int rbmlock_flags);
 #else /* CONFIG_XFS_RT */
 # define xfs_rtfree_extent(t,b,l)                      (-ENOSYS)
-# define xfs_rtfree_blocks(t,rb,rl)                    (-ENOSYS)
+
+static inline int xfs_rtfree_blocks(struct xfs_trans *tp,
+               struct xfs_rtgroup *rtg, xfs_fsblock_t rtbno,
+               xfs_filblks_t rtlen)
+{
+       return -ENOSYS;
+}
+
 # define xfs_rtalloc_query_range(m,t,l,h,f,p)          (-ENOSYS)
 # define xfs_rtalloc_query_all(m,t,f,p)                        (-ENOSYS)
 # define xfs_rtbitmap_read_buf(a,b)                    (-ENOSYS)
@@ -408,19 +382,14 @@ void xfs_rtbitmap_unlock_shared(struct xfs_mount *mp,
 # define xfs_rtbuf_cache_relse(a)                      (0)
 # define xfs_rtalloc_extent_is_free(m,t,s,l,i)         (-ENOSYS)
 static inline xfs_filblks_t
-xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
+__xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
 {
        /* shut up gcc */
        return 0;
 }
-# define xfs_rtbitmap_wordcount(mp, r)                 (0)
+# define xfs_rtbitmap_wordcount(mp)                    (0)
 # define xfs_rtsummary_blockcount(mp, l, b)            (0)
 # define xfs_rtsummary_wordcount(mp, l, b)             (0)
-# define xfs_rtbitmap_lock(mp)                 do { } while (0)
-# define xfs_rtbitmap_trans_join(tp)           do { } while (0)
-# define xfs_rtbitmap_unlock(mp)               do { } while (0)
-# define xfs_rtbitmap_lock_shared(mp, lf)      do { } while (0)
-# define xfs_rtbitmap_unlock_shared(mp, lf)    do { } while (0)
 #endif /* CONFIG_XFS_RT */
 
 #endif /* __XFS_RTBITMAP_H__ */
index b92a98a2413a6efcbddc0aac5c96230da871f9f1..f1520e05ceb97592ebde09b74938567c66b477df 100644 (file)
@@ -125,7 +125,7 @@ xfs_initialize_rtgroups(
        int                     error;
 
        if (!xfs_has_rtgroups(mp))
-               return 0;
+               rgcount = 1;
 
        /*
         * Walk the current rtgroup tree so we don't try to initialise rt
@@ -235,9 +235,6 @@ xfs_free_rtgroups(
        struct xfs_rtgroup      *rtg;
        xfs_rgnumber_t          rgno;
 
-       if (!xfs_has_rtgroups(mp))
-               return;
-
        for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
                spin_lock(&mp->m_rtgroup_lock);
                rtg = radix_tree_delete(&mp->m_rtgroup_tree, rgno);
@@ -256,30 +253,21 @@ xfs_free_rtgroups(
        }
 }
 
-/* Find the size of the rtgroup, in blocks. */
-static xfs_rgblock_t
-__xfs_rtgroup_block_count(
+/* Compute the number of rt extents in this realtime group. */
+xfs_rtxnum_t
+xfs_rtgroup_extents(
        struct xfs_mount        *mp,
-       xfs_rgnumber_t          rgno,
-       xfs_rgnumber_t          rgcount,
-       xfs_rfsblock_t          rblocks)
+       xfs_rgnumber_t          rgno)
 {
-       ASSERT(rgno < rgcount);
+       xfs_rgnumber_t          rgcount = mp->m_sb.sb_rgcount;
 
-       if (rgno < rgcount - 1)
-               return mp->m_rgblocks;
-       return xfs_rtb_rounddown_rtx(mp,
-                       rblocks - ((xfs_rtblock_t)rgno * mp->m_rgblocks));
-}
+       ASSERT(rgno < rgcount);
+       if (rgno == rgcount - 1)
+               return mp->m_sb.sb_rextents -
+                       ((xfs_rtxnum_t)rgno * mp->m_sb.sb_rgextents);
 
-/* Compute the number of blocks in this realtime group. */
-xfs_rgblock_t
-xfs_rtgroup_block_count(
-       struct xfs_mount        *mp,
-       xfs_rgnumber_t          rgno)
-{
-       return __xfs_rtgroup_block_count(mp, rgno, mp->m_sb.sb_rgcount,
-                       mp->m_sb.sb_rblocks);
+       ASSERT(xfs_has_rtgroups(mp));
+       return mp->m_sb.sb_rgextents;
 }
 
 /* Check superblock fields for a read or a write. */
@@ -433,10 +421,16 @@ xfs_rtgroup_lock(
        ASSERT(!(rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED) ||
               !(rtglock_flags & XFS_RTGLOCK_BITMAP));
 
-       if (rtglock_flags & XFS_RTGLOCK_BITMAP)
-               xfs_rtbitmap_lock(rtg->rtg_mount);
-       else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED)
-               xfs_rtbitmap_lock_shared(rtg->rtg_mount, XFS_RBMLOCK_BITMAP);
+       if (rtglock_flags & XFS_RTGLOCK_BITMAP) {
+               /*
+                * Lock both realtime free space metadata inodes for a freespace
+                * update.
+                */
+               xfs_ilock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_EXCL);
+               xfs_ilock(rtg->rtg_inodes[XFS_RTG_SUMMARY], XFS_ILOCK_EXCL);
+       } else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED) {
+               xfs_ilock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_SHARED);
+       }
 
        if ((rtglock_flags & XFS_RTGLOCK_RMAP) &&
            rtg->rtg_inodes[XFS_RTG_RMAP] != NULL)
@@ -464,10 +458,12 @@ xfs_rtgroup_unlock(
        if ((rtglock_flags & XFS_RTGLOCK_RMAP) && rtg->rtg_inodes[XFS_RTG_RMAP])
                xfs_iunlock(rtg->rtg_inodes[XFS_RTG_RMAP], XFS_ILOCK_EXCL);
 
-       if (rtglock_flags & XFS_RTGLOCK_BITMAP)
-               xfs_rtbitmap_unlock(rtg->rtg_mount);
-       else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED)
-               xfs_rtbitmap_unlock_shared(rtg->rtg_mount, XFS_RBMLOCK_BITMAP);
+       if (rtglock_flags & XFS_RTGLOCK_BITMAP) {
+               xfs_iunlock(rtg->rtg_inodes[XFS_RTG_SUMMARY], XFS_ILOCK_EXCL);
+               xfs_iunlock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_EXCL);
+       } else if (rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED) {
+               xfs_iunlock(rtg->rtg_inodes[XFS_RTG_BITMAP], XFS_ILOCK_SHARED);
+       }
 }
 
 /*
@@ -483,9 +479,12 @@ xfs_rtgroup_trans_join(
        ASSERT(!(rtglock_flags & ~XFS_RTGLOCK_ALL_FLAGS));
        ASSERT(!(rtglock_flags & XFS_RTGLOCK_BITMAP_SHARED));
 
-       if (rtglock_flags & XFS_RTGLOCK_BITMAP)
-               xfs_rtbitmap_trans_join(tp);
-
+       if (rtglock_flags & XFS_RTGLOCK_BITMAP) {
+               xfs_trans_ijoin(tp, rtg->rtg_inodes[XFS_RTG_BITMAP],
+                               XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, rtg->rtg_inodes[XFS_RTG_SUMMARY],
+                               XFS_ILOCK_EXCL);
+       }
        if ((rtglock_flags & XFS_RTGLOCK_RMAP) &&
            rtg->rtg_inodes[XFS_RTG_RMAP] != NULL)
                xfs_trans_ijoin(tp, rtg->rtg_inodes[XFS_RTG_RMAP],
@@ -506,7 +505,7 @@ xfs_rtgroup_get_geometry(
        /* Fill out form. */
        memset(rgeo, 0, sizeof(*rgeo));
        rgeo->rg_number = rtg->rtg_rgno;
-       rgeo->rg_length = rtg->rtg_blockcount;
+       rgeo->rg_length = rtg->rtg_extents * rtg->rtg_mount->m_sb.sb_rextsize;
        xfs_rtgroup_geom_health(rtg, rgeo);
        return 0;
 }
@@ -588,6 +587,16 @@ struct xfs_rtginode_ops {
 };
 
 static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTG_MAX] = {
+       [XFS_RTG_BITMAP] = {
+               .name           = "bitmap",
+               .sick           = XFS_SICK_RT_BITMAP,
+               .create         = xfs_rtbitmap_create,
+       },
+       [XFS_RTG_SUMMARY] = {
+               .name           = "summary",
+               .sick           = XFS_SICK_RT_SUMMARY,
+               .create         = xfs_rtsummary_create,
+       },
        [XFS_RTG_RMAP] = {
                .name           = "rmap",
                .format         = XFS_DINODE_FMT_RMAP,
@@ -620,6 +629,8 @@ xfs_rtginode_enabled(
 {
        const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[type];
 
+       if (!ops->enabled)
+               return true;
        return ops->enabled(rtg->rtg_mount);
 }
 
@@ -632,18 +643,36 @@ xfs_rtginode_load(
 {
        const struct xfs_rtginode_ops *ops = &xfs_rtginode_ops[type];
        struct xfs_mount        *mp = tp->t_mountp;
-       const char              *path;
        struct xfs_inode        *ip;
        int                     error;
 
        if (!xfs_rtginode_enabled(rtg, type))
                return 0;
 
-       path = xfs_rtginode_path(rtg->rtg_rgno, type);
-       if (!path)
-               return -ENOMEM;
-       error = xfs_metadir_load(tp, mp->m_rtdirip, path, S_IFREG, &ip);
-       kfree(path);
+       if (!xfs_has_rtgroups(mp)) {
+               xfs_ino_t       ino;
+
+               switch (type) {
+               case XFS_RTG_BITMAP:
+                       ino = mp->m_sb.sb_rbmino;
+                       break;
+               case XFS_RTG_SUMMARY:
+                       ino = mp->m_sb.sb_rsumino;
+                       break;
+               default:
+                       return 0;
+               }
+
+               error = xfs_metafile_iget(tp, ino, S_IFREG, &ip);
+       } else {
+               const char      *path;
+
+               path = xfs_rtginode_path(rtg->rtg_rgno, type);
+               if (!path)
+                       return -ENOMEM;
+               error = xfs_metadir_load(tp, mp->m_rtdirip, path, S_IFREG, &ip);
+               kfree(path);
+       }
 
        if (error) {
                if (xfs_metadata_is_sick(error))
@@ -651,7 +680,8 @@ xfs_rtginode_load(
                return error;
        }
 
-       if (XFS_IS_CORRUPT(mp, ip->i_df.if_format != ops->format)) {
+       if (ops->format &&
+           XFS_IS_CORRUPT(mp, ip->i_df.if_format != ops->format)) {
                xfs_irele(ip);
                xfs_rtgroup_mark_sick(rtg, ops->sick);
                return -EFSCORRUPTED;
@@ -750,6 +780,8 @@ xfs_rtginode_load_parent(
 {
        struct xfs_mount        *mp = tp->t_mountp;
 
+       if (!xfs_has_rtgroups(mp))
+               return 0;
        return xfs_metadir_load(tp, mp->m_metadirip, "rtgroups", S_IFDIR,
                        &mp->m_rtdirip);
 }
index cbd94fe3c8f348e7c81b10767690ac1c32c51bb1..27407ceccb94a01297997d1c3cc9df0bfd7b713e 100644 (file)
@@ -10,8 +10,11 @@ struct xfs_mount;
 struct xfs_trans;
 
 enum xfs_rtg_inodes {
+       XFS_RTG_BITMAP,         /* allocation bitmap */
+       XFS_RTG_SUMMARY,        /* allocation summary */
        XFS_RTG_RMAP,           /* rmap btree inode */
        XFS_RTG_REFCOUNT,       /* refcount btree inode */
+
        XFS_RTG_MAX,
 };
 
@@ -36,7 +39,7 @@ struct xfs_rtgroup {
        struct xfs_inode        *rtg_inodes[XFS_RTG_MAX];
 
        /* Number of blocks in this group */
-       xfs_rgblock_t           rtg_blockcount;
+       xfs_rtxnum_t            rtg_extents;
 
        /*
         * Bitsets of per-rtgroup metadata that have been checked and/or are
@@ -46,6 +49,14 @@ struct xfs_rtgroup {
        uint16_t                rtg_checked;
        uint16_t                rtg_sick;
 
+       /*
+        * Optional cache of rt summary level per bitmap block with the
+        * invariant that rtg_rsum_cache[bbno] > the maximum i for which
+        * rsum[i][bbno] != 0, or 0 if rsum[i][bbno] == 0 for all i.
+        * Reads and writes are serialized by the rsumip inode lock.
+        */
+       uint8_t                 *rtg_rsum_cache;
+
 #ifdef __KERNEL__
        /* -- kernel only structures below this line -- */
        spinlock_t              rtg_state_lock;
@@ -137,7 +148,7 @@ xfs_verify_rgbno(
 {
        struct xfs_mount        *mp = rtg->rtg_mount;
 
-       if (rgbno >= rtg->rtg_blockcount)
+       if (rgbno >= rtg->rtg_extents * mp->m_sb.sb_rextsize)
                return false;
        if (xfs_has_rtsb(mp) && rtg->rtg_rgno == 0 &&
            rgbno < mp->m_sb.sb_rextsize)
@@ -160,18 +171,23 @@ xfs_verify_rgbext(
        return xfs_verify_rgbno(rtg, rgbno + len - 1);
 }
 
+static inline xfs_rtblock_t
+xfs_rgno_start_rtb(
+       struct xfs_mount        *mp,
+       xfs_rgnumber_t          rgno)
+{
+       if (mp->m_rgblklog >= 0)
+               return ((xfs_rtblock_t)rgno << mp->m_rgblklog);
+       return ((xfs_rtblock_t)rgno * mp->m_rgblocks);
+}
+
 static inline xfs_rtblock_t
 xfs_rgbno_to_rtb(
        struct xfs_mount        *mp,
        xfs_rgnumber_t          rgno,
        xfs_rgblock_t           rgbno)
 {
-       ASSERT(xfs_has_rtgroups(mp));
-
-       if (mp->m_rgblklog >= 0)
-               return ((xfs_rtblock_t)rgno << mp->m_rgblklog) | rgbno;
-
-       return ((xfs_rtblock_t)rgno * mp->m_rgblocks) + rgbno;
+       return xfs_rgno_start_rtb(mp, rgno) + rgbno;
 }
 
 static inline xfs_rgnumber_t
@@ -179,8 +195,6 @@ xfs_rtb_to_rgno(
        struct xfs_mount        *mp,
        xfs_rtblock_t           rtbno)
 {
-       ASSERT(xfs_has_rtgroups(mp));
-
        if (mp->m_rgblklog >= 0)
                return rtbno >> mp->m_rgblklog;
 
@@ -195,8 +209,6 @@ xfs_rtb_to_rgbno(
 {
        uint32_t                rem;
 
-       ASSERT(xfs_has_rtgroups(mp));
-
        if (mp->m_rgblklog >= 0) {
                *rgno = rtbno >> mp->m_rgblklog;
                return rtbno & mp->m_rgblkmask;
@@ -206,6 +218,52 @@ xfs_rtb_to_rgbno(
        return rem;
 }
 
+static inline xfs_rtblock_t
+xfs_rtx_to_rtb(
+       struct xfs_rtgroup      *rtg,
+       xfs_rtxnum_t            rtx)
+{
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       xfs_rtblock_t           start = xfs_rgno_start_rtb(mp, rtg->rtg_rgno);
+
+       if (mp->m_rtxblklog >= 0)
+               return start + (rtx << mp->m_rtxblklog);
+       return start + (rtx * mp->m_sb.sb_rextsize);
+}
+
+/* Convert an rgbno into an rt extent number. */
+static inline xfs_rtxnum_t
+xfs_rgbno_to_rtx(
+       struct xfs_mount        *mp,
+       xfs_rgblock_t           rgbno)
+{
+       if (likely(mp->m_rtxblklog >= 0))
+               return rgbno >> mp->m_rtxblklog;
+       return rgbno / mp->m_sb.sb_rextsize;
+}
+
+/* Convert an rt block number into an rt extent number. */
+static inline xfs_rtxnum_t
+xfs_rtb_to_rtx(
+       struct xfs_mount        *mp,
+       xfs_rtblock_t           rtbno)
+{
+       uint64_t                rgbno;
+
+       if (mp->m_rgblklog >= 0) {
+               rgbno = rtbno & mp->m_rgblkmask;
+       } else {
+               uint32_t                rem;
+
+               div_u64_rem(rtbno, mp->m_rgblocks, &rem);
+               rgbno = rem;
+       }
+
+       if (likely(mp->m_rtxblklog >= 0))
+               return rgbno >> mp->m_rtxblklog;
+       return div_u64(rgbno, mp->m_sb.sb_rextsize);
+}
+
 static inline xfs_daddr_t
 xfs_rtb_to_daddr(
        struct xfs_mount        *mp,
@@ -223,8 +281,7 @@ xfs_daddr_to_rtb(
 }
 
 #ifdef CONFIG_XFS_RT
-xfs_rgblock_t xfs_rtgroup_block_count(struct xfs_mount *mp,
-               xfs_rgnumber_t rgno);
+xfs_rtxnum_t xfs_rtgroup_extents(struct xfs_mount *mp, xfs_rgnumber_t rgno);
 
 void xfs_rtgroup_update_super(struct xfs_buf *rtsb_bp,
                const struct xfs_buf *sb_bp);
@@ -272,7 +329,7 @@ static inline const char *xfs_rtginode_path(xfs_rgnumber_t rgno,
        return kasprintf(GFP_KERNEL, "%u.%s", rgno, xfs_rtginode_name(type));
 }
 #else
-# define xfs_rtgroup_block_count(mp, rgno)     (0)
+# define xfs_rtgroup_extents(mp, rgno)         (0)
 # define xfs_rtgroup_update_super(bp, sb_bp)   ((void)0)
 # define xfs_rtgroup_log_super(tp, sb_bp)      (NULL)
 # define xfs_rtgroup_lock(rtg, gf)             ((void)0)
index 252dbf300ce6575c7b0d6966c0f4b2b72663a56f..e14c9b36c3465f8038f6429d89f13a06d76adac8 100644 (file)
@@ -245,13 +245,11 @@ static uint64_t
 xfs_sb_calc_rbmblocks(
        struct xfs_sb           *sbp)
 {
-       unsigned int            rbmblock_bytes = sbp->sb_blocksize;
+       if (!xfs_sb_version_hasrtgroups(sbp))
+               return howmany_64(sbp->sb_rextents, NBBY * sbp->sb_blocksize);
 
-       if (xfs_sb_is_v5(sbp) &&
-           (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_RTGROUPS))
-               rbmblock_bytes -= sizeof(struct xfs_rtbuf_blkinfo);
-
-       return howmany_64(sbp->sb_rextents, NBBY * rbmblock_bytes);
+       return howmany_64(sbp->sb_rgextents,
+               NBBY * (sbp->sb_blocksize - sizeof(struct xfs_rtbuf_blkinfo)));
 }
 
 /* Validate the realtime geometry */
@@ -790,8 +788,8 @@ __xfs_sb_from_disk(
                to->sb_rgcount = be32_to_cpu(from->sb_rgcount);
                to->sb_rgextents = be32_to_cpu(from->sb_rgextents);
        } else {
-               to->sb_rgcount = 0;
-               to->sb_rgextents = 0;
+               to->sb_rgcount = 1;
+               to->sb_rgextents = UINT_MAX;
        }
 }
 
index 158a5635f6c8916cc0bb5ed2ef3b64bdfe0f009e..7019bd726da8ff428de0e7207bbe7ba585d5ae06 100644 (file)
@@ -235,7 +235,7 @@ xfs_rtalloc_block_count(
        unsigned int            t1, t2 = 0;
 
        rtxlen = xfs_extlen_to_rtxlen(mp, XFS_MAX_BMBT_EXTLEN);
-       rtbmp_blocks = xfs_rtbitmap_blockcount(mp, rtxlen);
+       rtbmp_blocks = __xfs_rtbitmap_blockcount(mp, rtxlen);
        t1 = (rtbmp_blocks + 1) * num_ops;
 
        if (xfs_has_rmapbt(mp))
index 6b09f8ef8e16b8eff42a45a81f9693b57288a776..664cd61763047c3f4ec4a4cd4bc22b019608103d 100644 (file)
@@ -136,26 +136,6 @@ xfs_verify_dir_ino(
        return xfs_verify_ino(mp, ino);
 }
 
-/*
- * Verify that an rtgroup block number pointer neither points outside the
- * rtgroup nor at static metadata.
- */
-static inline bool
-xfs_verify_rgno_rgbno(
-       struct xfs_mount        *mp,
-       xfs_rgnumber_t          rgno,
-       xfs_rgblock_t           rgbno)
-{
-       xfs_rgblock_t           eorg;
-
-       eorg = xfs_rtgroup_block_count(mp, rgno);
-       if (rgbno >= eorg)
-               return false;
-       if (xfs_has_rtsb(mp) && rgno == 0 && rgbno < mp->m_sb.sb_rextsize)
-               return false;
-       return true;
-}
-
 /*
  * Verify that a realtime block number pointer neither points outside the
  * allocatable areas of the rtgroup nor off the end of the realtime
@@ -166,20 +146,21 @@ xfs_verify_rtbno(
        struct xfs_mount        *mp,
        xfs_rtblock_t           rtbno)
 {
-       xfs_rgnumber_t          rgno;
-       xfs_rgblock_t           rgbno;
-
        if (rtbno >= mp->m_sb.sb_rblocks)
                return false;
 
-       if (!xfs_has_rtgroups(mp))
-               return true;
-
-       rgbno = xfs_rtb_to_rgbno(mp, rtbno, &rgno);
-       if (rgno >= mp->m_sb.sb_rgcount)
-               return false;
-
-       return xfs_verify_rgno_rgbno(mp, rgno, rgbno);
+       if (xfs_has_rtgroups(mp)) {
+               xfs_rgnumber_t  rgno = xfs_rtb_to_rgno(mp, rtbno);
+               xfs_rtxnum_t    rtx = xfs_rtb_to_rtx(mp, rtbno);
+
+               if (rgno >= mp->m_sb.sb_rgcount)
+                       return false;
+               if (rtx >= xfs_rtgroup_extents(mp, rgno))
+                       return false;
+               if (xfs_has_rtsb(mp) && rgno == 0 && rtx == 0)
+                       return false;
+       }
+       return true;
 }
 
 /*
index 297dfcf40d9051a1cea7ac73a244e44c55bb0324..cda257e77ba9c2693df3f9452179190794047dfa 100644 (file)
@@ -330,15 +330,6 @@ xchk_bmap_rt_iextent_xref(
        xfs_rgblock_t           rgbno;
        int                     error;
 
-       if (!xfs_has_rtrmapbt(mp)) {
-               xchk_rt_init(info->sc, &info->sc->sr,
-                               XCHK_RTLOCK_BITMAP_SHARED);
-               xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
-                               irec->br_blockcount);
-               xchk_rt_unlock(info->sc, &info->sc->sr);
-               return;
-       }
-
        rgbno = xfs_rtb_to_rgbno(mp, irec->br_startblock, &rgno);
        error = xchk_rtgroup_init(info->sc, rgno, &info->sc->sr,
                        XCHK_RTGLOCK_ALL);
@@ -348,6 +339,10 @@ xchk_bmap_rt_iextent_xref(
 
        xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
                        irec->br_blockcount);
+
+       if (!xfs_has_rtrmapbt(mp))
+               goto out_free;
+
        switch (info->whichfork) {
        case XFS_DATA_FORK:
                xchk_bmap_xref_rmap(info, irec, rgbno);
index b38c2012e3f4ce43c432ed81a26e915ceb28d31e..c447f6f526a7841887398615e9f493265a05831f 100644 (file)
@@ -380,8 +380,6 @@ xrep_bmap_check_rtfork_rmap(
        struct xfs_btree_cur            *cur,
        const struct xfs_rmap_irec      *rec)
 {
-       xfs_rtblock_t                   rtbno;
-
        /* xattr extents are never stored on realtime devices */
        if (rec->rm_flags & XFS_RMAP_ATTR_FORK)
                return -EFSCORRUPTED;
@@ -404,9 +402,8 @@ xrep_bmap_check_rtfork_rmap(
                return -EFSCORRUPTED;
 
        /* Make sure this isn't free space. */
-       rtbno = xfs_rgbno_to_rtb(sc->mp, cur->bc_ino.rtg->rtg_rgno,
-                       rec->rm_startblock);
-       return xrep_require_rtext_inuse(sc, rtbno, rec->rm_blockcount, false);
+       return xrep_require_rtext_inuse(sc, cur->bc_ino.rtg, rec->rm_startblock,
+                       rec->rm_blockcount, false);
 }
 
 /* Record realtime extents that belong to this inode's fork. */
@@ -461,7 +458,7 @@ xrep_bmap_scan_rtgroup(
        struct xfs_scrub        *sc = rb->sc;
        int                     error;
 
-       if (xrep_is_rtmeta_ino(sc, rtg, sc->ip->i_ino))
+       if (xrep_is_rtmeta_ino(rtg, sc->ip->i_ino))
                return 0;
 
        error = xrep_rtgroup_init(sc, rtg, &sc->sr,
@@ -539,11 +536,13 @@ xrep_bmap_find_mappings(
        int                     error = 0;
 
        /* Iterate the rtrmaps for extents. */
-       for_each_rtgroup(sc->mp, rgno, rtg) {
-               error = xrep_bmap_scan_rtgroup(rb, rtg);
-               if (error) {
-                       xfs_rtgroup_rele(rtg);
-                       return error;
+       if (xfs_has_rtgroups(sc->mp)) {
+               for_each_rtgroup(sc->mp, rgno, rtg) {
+                       error = xrep_bmap_scan_rtgroup(rb, rtg);
+                       if (error) {
+                               xfs_rtgroup_rele(rtg);
+                               return error;
+                       }
                }
        }
 
index 38efe41cfe45697a0cf2fe0c103d7d48dd4fe496..84b9abf4856963a94224adfff218e8afb55de08f 100644 (file)
@@ -710,78 +710,6 @@ xchk_ag_init(
        return 0;
 }
 
-/*
- * For scrubbing a realtime file, grab all the in-core resources we'll need to
- * check the realtime metadata, which means taking the ILOCK of the realtime
- * metadata inodes.  Callers must not join these inodes to the transaction
- * with non-zero lockflags or concurrency problems will result.  The
- * @rtlock_flags argument takes XCHK_RTLOCK_* flags because scrub has somewhat
- * unusual locking requirements.
- */
-void
-xchk_rt_init(
-       struct xfs_scrub        *sc,
-       struct xchk_rt          *sr,
-       unsigned int            rtlock_flags)
-{
-       ASSERT(!(rtlock_flags & ~XCHK_RTLOCK_ALL));
-       ASSERT(hweight32(rtlock_flags & (XCHK_RTLOCK_BITMAP |
-                                        XCHK_RTLOCK_BITMAP_SHARED)) < 2);
-       ASSERT(hweight32(rtlock_flags & (XCHK_RTLOCK_SUMMARY |
-                                        XCHK_RTLOCK_SUMMARY_SHARED)) < 2);
-       ASSERT(sr->rtg == NULL);
-
-       if (rtlock_flags & XCHK_RTLOCK_BITMAP)
-               xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_EXCL);
-       else if (rtlock_flags & XCHK_RTLOCK_BITMAP_SHARED)
-               xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED);
-
-       if (rtlock_flags & XCHK_RTLOCK_SUMMARY)
-               xfs_ilock(sc->mp->m_rsumip, XFS_ILOCK_EXCL);
-       else if (rtlock_flags & XCHK_RTLOCK_SUMMARY_SHARED)
-               xfs_ilock(sc->mp->m_rsumip, XFS_ILOCK_SHARED);
-
-       sr->rtlock_flags = rtlock_flags;
-}
-
-/*
- * Unlock the realtime metadata inodes.  This must be done /after/ committing
- * (or cancelling) the scrub transaction.
- */
-void
-xchk_rt_unlock(
-       struct xfs_scrub        *sc,
-       struct xchk_rt          *sr)
-{
-       ASSERT(sr->rtg == NULL);
-
-       if (!sr->rtlock_flags)
-               return;
-
-       if (sr->rtlock_flags & XCHK_RTLOCK_SUMMARY)
-               xfs_iunlock(sc->mp->m_rsumip, XFS_ILOCK_EXCL);
-       else if (sr->rtlock_flags & XCHK_RTLOCK_SUMMARY_SHARED)
-               xfs_iunlock(sc->mp->m_rsumip, XFS_ILOCK_SHARED);
-
-       if (sr->rtlock_flags & XCHK_RTLOCK_BITMAP)
-               xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_EXCL);
-       else if (sr->rtlock_flags & XCHK_RTLOCK_BITMAP_SHARED)
-               xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED);
-
-       sr->rtlock_flags = 0;
-}
-
-/* Drop only the shared rt bitmap lock. */
-void
-xchk_rt_unlock_rtbitmap(
-       struct xfs_scrub        *sc)
-{
-       ASSERT(sc->sr.rtlock_flags & XCHK_RTLOCK_BITMAP_SHARED);
-
-       xfs_iunlock(sc->mp->m_rbmip, XFS_ILOCK_SHARED);
-       sc->sr.rtlock_flags &= ~XCHK_RTLOCK_BITMAP_SHARED;
-}
-
 #ifdef CONFIG_XFS_RT
 /* Lock all the rt group metadata inode ILOCKs and wait for intents. */
 int
index fc498a0ce2802625f58c81c82a0408df999268ee..e7c4299c2adb10260f16cd42001e0988a1ac919b 100644 (file)
@@ -80,14 +80,12 @@ int xchk_setup_parent(struct xfs_scrub *sc);
 int xchk_setup_dirtree(struct xfs_scrub *sc);
 int xchk_setup_metapath(struct xfs_scrub *sc);
 #ifdef CONFIG_XFS_RT
-int xchk_setup_rtbitmap(struct xfs_scrub *sc);
 int xchk_setup_rtsummary(struct xfs_scrub *sc);
 int xchk_setup_rgsuperblock(struct xfs_scrub *sc);
 int xchk_setup_rgbitmap(struct xfs_scrub *sc);
 int xchk_setup_rtrmapbt(struct xfs_scrub *sc);
 int xchk_setup_rtrefcountbt(struct xfs_scrub *sc);
 #else
-# define xchk_setup_rtbitmap           xchk_setup_nothing
 # define xchk_setup_rtsummary          xchk_setup_nothing
 # define xchk_setup_rgsuperblock       xchk_setup_nothing
 # define xchk_setup_rgbitmap           xchk_setup_nothing
@@ -131,25 +129,6 @@ xchk_ag_init_existing(
        return error == -ENOENT ? -EFSCORRUPTED : error;
 }
 
-/* Lock the rt bitmap in exclusive mode */
-#define XCHK_RTLOCK_BITMAP             (1U << 31)
-/* Lock the rt bitmap in shared mode */
-#define XCHK_RTLOCK_BITMAP_SHARED      (1U << 30)
-/* Lock the rt summary in exclusive mode */
-#define XCHK_RTLOCK_SUMMARY            (1U << 29)
-/* Lock the rt summary in shared mode */
-#define XCHK_RTLOCK_SUMMARY_SHARED     (1U << 28)
-
-#define XCHK_RTLOCK_ALL                (XCHK_RTLOCK_BITMAP | \
-                                XCHK_RTLOCK_BITMAP_SHARED | \
-                                XCHK_RTLOCK_SUMMARY | \
-                                XCHK_RTLOCK_SUMMARY_SHARED)
-
-void xchk_rt_init(struct xfs_scrub *sc, struct xchk_rt *sr,
-               unsigned int xchk_rtlock_flags);
-void xchk_rt_unlock(struct xfs_scrub *sc, struct xchk_rt *sr);
-void xchk_rt_unlock_rtbitmap(struct xfs_scrub *sc);
-
 #ifdef CONFIG_XFS_RT
 
 /* All the locks we need to check an rtgroup. */
index db612609d420f8b9c47553e0a62ac8b6aa3c26a8..cd09fa15abb67270ed4d6f198c0b21ff8859c59d 100644 (file)
@@ -356,7 +356,7 @@ xrep_cow_find_bad_rt(
        if (!rtg)
                return -EFSCORRUPTED;
 
-       if (xrep_is_rtmeta_ino(sc, rtg, sc->ip->i_ino))
+       if (xrep_is_rtmeta_ino(rtg, sc->ip->i_ino))
                goto out_rtg;
 
        error = xrep_rtgroup_init(sc, rtg, &sc->sr,
@@ -473,30 +473,18 @@ xrep_cow_alloc_rt(
        xfs_extlen_t            maxlen,
        struct xrep_cow_extent  *repl)
 {
-       xfs_rtxnum_t            rtx = 0;
-       xfs_rtxlen_t            maxrtx;
-       xfs_rtxlen_t            rtxlen = 0;
-       xfs_rtblock_t           rtbno;
-       xfs_extlen_t            len;
+       xfs_rtxlen_t            maxrtx = xfs_extlen_to_rtxlen(sc->mp, maxlen);
        int                     error;
 
-       maxrtx = xfs_rtb_to_rtx(sc->mp, maxlen);
        error = xfs_trans_reserve_more(sc->tp, 0, maxrtx);
        if (error)
                return error;
 
-       xfs_rtbitmap_lock(sc->mp);
-       xfs_rtbitmap_trans_join(sc->tp);
-       error = xfs_rtallocate_extent(sc->tp, 0, maxlen, &rtxlen, &rtx);
+       error = xfs_rtallocate_rtgs(sc->tp, 0, 1, maxrtx, 1, false, false,
+                       &repl->fsbno, &repl->len);
        if (error)
                return error;
-
-       rtbno = xfs_rtx_to_rtb(sc->mp, rtx);
-       len = xfs_rtxlen_to_extlen(sc->mp, rtxlen);
-       xfs_refcount_alloc_cow_extent(sc->tp, true, rtbno, len);
-
-       repl->fsbno = rtbno;
-       repl->len = len;
+       xfs_refcount_alloc_cow_extent(sc->tp, true, repl->fsbno, repl->len);
        return 0;
 }
 
index 1d3e98346933e1100d951af3ce77618b1d00aa0f..5f6449fc85dc0eda4b5148cb0dd43dbfcd80978d 100644 (file)
@@ -19,6 +19,7 @@
 #include "xfs_rtbitmap.h"
 #include "xfs_inode.h"
 #include "xfs_icache.h"
+#include "xfs_rtgroup.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
@@ -388,7 +389,7 @@ retry:
 #ifdef CONFIG_XFS_RT
 STATIC int
 xchk_fscount_add_frextent(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        const struct xfs_rtalloc_rec    *rec,
        void                            *priv)
@@ -409,6 +410,8 @@ xchk_fscount_count_frextents(
        struct xchk_fscounters  *fsc)
 {
        struct xfs_mount        *mp = sc->mp;
+       struct xfs_rtgroup      *rtg;
+       xfs_rgnumber_t          rgno;
        int                     error;
 
        fsc->frextents = 0;
@@ -416,19 +419,20 @@ xchk_fscount_count_frextents(
        if (!xfs_has_realtime(mp))
                return 0;
 
-       xfs_rtbitmap_lock_shared(sc->mp, XFS_RBMLOCK_BITMAP);
-       error = xfs_rtalloc_query_all(sc->mp, sc->tp,
-                       xchk_fscount_add_frextent, fsc);
-       if (error) {
-               xchk_set_incomplete(sc);
-               goto out_unlock;
+       for_each_rtgroup(mp, rgno, rtg) {
+               xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+               error = xfs_rtalloc_query_all(rtg, sc->tp,
+                               xchk_fscount_add_frextent, fsc);
+               xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+               if (error) {
+                       xchk_set_incomplete(sc);
+                       xfs_rtgroup_rele(rtg);
+                       return error;
+               }
        }
 
        fsc->frextents_delayed = percpu_counter_sum(&mp->m_delalloc_rtextents);
-
-out_unlock:
-       xfs_rtbitmap_unlock_shared(sc->mp, XFS_RBMLOCK_BITMAP);
-       return error;
+       return 0;
 }
 #else
 STATIC int
index 67131f00aa9f3c002889cb1649580cac9fa545ef..bff1f6cd81b2227e8396e186c5ea4f0fbfc17482 100644 (file)
@@ -102,8 +102,8 @@ static const struct xchk_health_map type_to_health_flag[XFS_SCRUB_TYPE_NR] = {
        [XFS_SCRUB_TYPE_XATTR]          = { XHG_INO, XFS_SICK_INO_XATTR },
        [XFS_SCRUB_TYPE_SYMLINK]        = { XHG_INO, XFS_SICK_INO_SYMLINK },
        [XFS_SCRUB_TYPE_PARENT]         = { XHG_INO, XFS_SICK_INO_PARENT },
-       [XFS_SCRUB_TYPE_RTBITMAP]       = { XHG_RT,  XFS_SICK_RT_BITMAP },
-       [XFS_SCRUB_TYPE_RTSUM]          = { XHG_RT XFS_SICK_RT_SUMMARY },
+       [XFS_SCRUB_TYPE_RGBITMAP]       = { XHG_RTGROUP, XFS_SICK_RG_BITMAP },
+       [XFS_SCRUB_TYPE_RTSUM]          = { XHG_RTGROUP, XFS_SICK_RT_SUMMARY },
        [XFS_SCRUB_TYPE_UQUOTA]         = { XHG_FS,  XFS_SICK_FS_UQUOTA },
        [XFS_SCRUB_TYPE_GQUOTA]         = { XHG_FS,  XFS_SICK_FS_GQUOTA },
        [XFS_SCRUB_TYPE_PQUOTA]         = { XHG_FS,  XFS_SICK_FS_PQUOTA },
@@ -113,7 +113,6 @@ static const struct xchk_health_map type_to_health_flag[XFS_SCRUB_TYPE_NR] = {
        [XFS_SCRUB_TYPE_DIRTREE]        = { XHG_INO, XFS_SICK_INO_DIRTREE },
        [XFS_SCRUB_TYPE_METAPATH]       = { XHG_FS,  XFS_SICK_FS_METAPATH },
        [XFS_SCRUB_TYPE_RGSUPER]        = { XHG_RTGROUP, XFS_SICK_RG_SUPER },
-       [XFS_SCRUB_TYPE_RGBITMAP]       = { XHG_RTGROUP, XFS_SICK_RG_BITMAP },
        [XFS_SCRUB_TYPE_RTRMAPBT]       = { XHG_RTGROUP, XFS_SICK_RG_RMAPBT },
        [XFS_SCRUB_TYPE_RTREFCBT]       = { XHG_RTGROUP, XFS_SICK_RG_REFCNTBT },
 };
index a5cfe3214519a22d4c1960cff4aac6d37e23e72b..4a2e818835f5997d8dac64402a5e9a3a395a87dd 100644 (file)
@@ -802,7 +802,7 @@ xrep_dinode_count_rtgroup_rmaps(
        int                     error;
 
        if (!xfs_has_realtime(sc->mp) ||
-           xrep_is_rtmeta_ino(sc, rtg, sc->sm->sm_ino))
+           xrep_is_rtmeta_ino(rtg, sc->sm->sm_ino))
                return 0;
 
        error = xrep_rtgroup_init(sc, rtg, &sc->sr, XFS_RTGLOCK_RMAP);
@@ -830,11 +830,13 @@ xrep_dinode_count_rmaps(
        if (!xfs_has_rmapbt(ri->sc->mp))
                return -EOPNOTSUPP;
 
-       for_each_rtgroup(ri->sc->mp, rgno, rtg) {
-               error = xrep_dinode_count_rtgroup_rmaps(ri, rtg);
-               if (error) {
-                       xfs_rtgroup_rele(rtg);
-                       return error;
+       if (xfs_has_rtgroups(ri->sc->mp)) {
+               for_each_rtgroup(ri->sc->mp, rgno, rtg) {
+                       error = xrep_dinode_count_rtgroup_rmaps(ri, rtg);
+                       if (error) {
+                               xfs_rtgroup_rele(rtg);
+                               return error;
+                       }
                }
        }
 
index 220107e994bf5da5e3ed0de2561cf4a1d019917b..29f7557cae7ed6cb5ae74b27638c871c660eaeaa 100644 (file)
@@ -405,7 +405,7 @@ xrep_calc_rtgroup_resblks(
                return 0;
 
        rtg = xfs_rtgroup_get(mp, sm->sm_agno);
-       usedlen = rtg->rtg_blockcount;
+       usedlen = rtg->rtg_extents * mp->m_sb.sb_rextsize;
        xfs_rtgroup_put(rtg);
 
        if (xfs_has_rmapbt(mp))
@@ -1047,7 +1047,8 @@ xrep_rtgroup_init(
 int
 xrep_require_rtext_inuse(
        struct xfs_scrub        *sc,
-       xfs_rtblock_t           rtbno,
+       struct xfs_rtgroup      *rtg,
+       xfs_rgblock_t           rgbno,
        xfs_filblks_t           len,
        bool                    must_align)
 {
@@ -1058,17 +1059,17 @@ xrep_require_rtext_inuse(
        bool                    is_free = false;
        int                     error;
 
-       mod = xfs_rtb_to_rtxoff(mp, rtbno);
+       mod = xfs_rtb_to_rtxoff(mp, rgbno);
        if (must_align && mod != 0)
                return -EFSCORRUPTED;
-       startrtx = xfs_rtb_to_rtx(mp, rtbno);
+       startrtx = xfs_rgbno_to_rtx(mp, rgbno);
 
-       mod = xfs_rtb_to_rtxoff(mp, rtbno + len - 1);
+       mod = xfs_rtb_to_rtxoff(mp, rgbno + len - 1);
        if (must_align && mod != mp->m_sb.sb_rextsize - 1)
                return -EFSCORRUPTED;
-       endrtx = xfs_rtb_to_rtx(mp, rtbno + len - 1);
+       endrtx = xfs_rgbno_to_rtx(mp, rgbno + len - 1);
 
-       error = xfs_rtalloc_extent_is_free(mp, sc->tp, startrtx,
+       error = xfs_rtalloc_extent_is_free(rtg, sc->tp, startrtx,
                        endrtx - startrtx + 1, &is_free);
        if (error)
                return error;
@@ -1344,22 +1345,11 @@ xrep_buf_verify_struct(
 /* Are we looking at a realtime metadata inode? */
 bool
 xrep_is_rtmeta_ino(
-       struct xfs_scrub        *sc,
        struct xfs_rtgroup      *rtg,
        xfs_ino_t               ino)
 {
        unsigned int            i;
 
-       /*
-        * All filesystems have rt bitmap and summary inodes, even if they
-        * don't have an rt section.
-        */
-       if (ino == sc->mp->m_rbmip->i_ino)
-               return true;
-       if (ino == sc->mp->m_rsumip->i_ino)
-               return true;
-
-       /* Newer rtgroup metadata files are not guaranteed to exist */
        for (i = 0; i < XFS_RTG_MAX; i++) {
                if (rtg->rtg_inodes[i] && ino == rtg->rtg_inodes[i]->i_ino)
                        return true;
index e9f58e22c67d92970dd0c04ce7ce2f966de8f9ab..4f40d928d579e856dda02f55bb911212e7991399 100644 (file)
@@ -114,16 +114,15 @@ int xrep_ag_init(struct xfs_scrub *sc, struct xfs_perag *pag,
 int xrep_rtgroup_init(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
                struct xchk_rt *sr, unsigned int rtglock_flags);
 void xrep_rtgroup_btcur_init(struct xfs_scrub *sc, struct xchk_rt *sr);
-int xrep_require_rtext_inuse(struct xfs_scrub *sc, xfs_rtblock_t rtbno,
-               xfs_filblks_t len, bool must_align);
+int xrep_require_rtext_inuse(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
+               xfs_rgblock_t rgbno, xfs_filblks_t len, bool must_align);
 xfs_extlen_t xrep_calc_rtgroup_resblks(struct xfs_scrub *sc);
 #else
 # define xrep_rtgroup_init(sc, rtg, sr, lockflags)     (-ENOSYS)
 # define xrep_calc_rtgroup_resblks(sc)                 (0)
 #endif /* CONFIG_XFS_RT */
 
-bool xrep_is_rtmeta_ino(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,
-               xfs_ino_t ino);
+bool xrep_is_rtmeta_ino(struct xfs_rtgroup *rtg, xfs_ino_t ino);
 int xrep_check_ino_btree_mapping(struct xfs_scrub *sc,
                const struct xfs_rmap_irec *rec);
 
@@ -157,14 +156,12 @@ int xrep_dirtree(struct xfs_scrub *sc);
 int xrep_metapath(struct xfs_scrub *sc);
 
 #ifdef CONFIG_XFS_RT
-int xrep_rtbitmap(struct xfs_scrub *sc);
 int xrep_rtsummary(struct xfs_scrub *sc);
 int xrep_rgsuperblock(struct xfs_scrub *sc);
 int xrep_rgbitmap(struct xfs_scrub *sc);
 int xrep_rtrmapbt(struct xfs_scrub *sc);
 int xrep_rtrefcountbt(struct xfs_scrub *sc);
 #else
-# define xrep_rtbitmap                 xrep_notsupported
 # define xrep_rtsummary                        xrep_notsupported
 # define xrep_rgsuperblock             xrep_notsupported
 # define xrep_rgbitmap                 xrep_notsupported
@@ -268,7 +265,6 @@ static inline int xrep_setup_symlink(struct xfs_scrub *sc, unsigned int *x)
 #define xrep_bmap_data                 xrep_notsupported
 #define xrep_bmap_attr                 xrep_notsupported
 #define xrep_bmap_cow                  xrep_notsupported
-#define xrep_rtbitmap                  xrep_notsupported
 #define xrep_quota                     xrep_notsupported
 #define xrep_quotacheck                        xrep_notsupported
 #define xrep_nlinks                    xrep_notsupported
index d0bcca2054fb4296586be92dbdcd3aae917bb4b6..930b98c9df99dd1c55390bd4677f2ff27e1824d6 100644 (file)
 #include "scrub/rtbitmap.h"
 #include "scrub/btree.h"
 
-static inline void
-xchk_rtbitmap_compute_geometry(
-       struct xfs_mount        *mp,
-       struct xchk_rtbitmap    *rtb)
-{
-       if (mp->m_sb.sb_rblocks == 0)
-               return;
-
-       rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
-       rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
-       rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
-}
-
 /* Set us up with the realtime group metadata locked. */
 int
 xchk_setup_rgbitmap(
@@ -48,6 +35,7 @@ xchk_setup_rgbitmap(
 {
        struct xfs_mount        *mp = sc->mp;
        struct xchk_rgbitmap    *rgb;
+       struct xfs_rtgroup      *rtg;
        unsigned int            wordcnt = xchk_rgbitmap_wordcnt(sc);
        int                     error;
 
@@ -61,82 +49,44 @@ xchk_setup_rgbitmap(
        sc->buf = rgb;
        rgb->rtglock_flags = XCHK_RTGLOCK_ALL;
 
+       rtg = xfs_rtgroup_get(mp, sc->sm->sm_agno);
+       if (!rtg)
+               return -ENOENT;
+
        if (xchk_could_repair(sc)) {
                error = xrep_setup_rgbitmap(sc, rgb);
                if (error)
-                       return error;
+                       goto out_rtg;
        }
 
-       error = xchk_trans_alloc(sc, rgb->rtb.resblks);
+       error = xchk_trans_alloc(sc, rgb->resblks);
        if (error)
-               return error;
+               goto out_rtg;
 
-       error = xchk_install_live_inode(sc, mp->m_rbmip);
+       error = xchk_install_live_inode(sc, rtg->rtg_inodes[XFS_RTG_BITMAP]);
        if (error)
-               return error;
+               goto out_rtg;
 
        error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr,
                        rgb->rtglock_flags);
        if (error)
-               return error;
+               goto out_rtg;
 
        /*
         * Now that we've locked the rtbitmap, we can't race with growfsrt
         * trying to expand the bitmap or change the size of the rt volume.
         * Hence it is safe to compute and check the geometry values.
         */
-       xchk_rtbitmap_compute_geometry(mp, &rgb->rtb);
-       return 0;
-}
-
-/* Set us up with the realtime metadata locked. */
-int
-xchk_setup_rtbitmap(
-       struct xfs_scrub        *sc)
-{
-       struct xfs_mount        *mp = sc->mp;
-       struct xchk_rtbitmap    *rtb;
-       int                     error;
-
-       if (xchk_need_intent_drain(sc))
-               xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
-
-       rtb = kzalloc(sizeof(struct xchk_rtbitmap), XCHK_GFP_FLAGS);
-       if (!rtb)
-               return -ENOMEM;
-       sc->buf = rtb;
-
-       if (xchk_could_repair(sc)) {
-               error = xrep_setup_rtbitmap(sc, rtb);
-               if (error)
-                       return error;
+       if (mp->m_sb.sb_rblocks) {
+               rgb->rextents = xfs_blen_to_rtbxlen(mp, mp->m_sb.sb_rblocks);
+               rgb->rextslog = xfs_compute_rextslog(rgb->rextents);
+               rgb->rbmblocks = xfs_rtbitmap_blockcount(mp);
        }
-
-       error = xchk_trans_alloc(sc, rtb->resblks);
-       if (error)
-               return error;
-
-       error = xchk_install_live_inode(sc, sc->mp->m_rbmip);
-       if (error)
-               return error;
-
-       error = xchk_ino_dqattach(sc);
-       if (error)
-               return error;
-
-       xchk_rt_init(sc, &sc->sr, XCHK_RTLOCK_BITMAP);
-
-       /*
-        * Now that we've locked the rtbitmap, we can't race with growfsrt
-        * trying to expand the bitmap or change the size of the rt volume.
-        * Hence it is safe to compute and check the geometry values.
-        */
-       xchk_rtbitmap_compute_geometry(mp, rtb);
-       return 0;
+out_rtg:
+       xfs_rtgroup_put(rtg);
+       return error;
 }
 
-/* Per-rtgroup bitmap contents. */
-
 /* Cross-reference rtbitmap entries with other metadata. */
 STATIC void
 xchk_rgbitmap_xref(
@@ -167,7 +117,7 @@ xchk_rgbitmap_xref(
 /* Scrub a free extent record from the realtime bitmap. */
 STATIC int
 xchk_rgbitmap_rec(
-       struct xfs_mount        *mp,
+       struct xfs_rtgroup      *rtg,
        struct xfs_trans        *tp,
        const struct xfs_rtalloc_rec *rec,
        void                    *priv)
@@ -177,10 +127,10 @@ xchk_rgbitmap_rec(
        xfs_rtblock_t           startblock;
        xfs_filblks_t           blockcount;
 
-       startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
-       blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+       startblock = xfs_rtx_to_rtb(rtg, rec->ar_startext);
+       blockcount = xfs_rtxlen_to_extlen(rtg->rtg_mount, rec->ar_extcount);
 
-       if (!xfs_verify_rtbext(mp, startblock, blockcount))
+       if (!xfs_verify_rtbext(rtg->rtg_mount, startblock, blockcount))
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
 
        xchk_rgbitmap_xref(rgb, startblock, blockcount);
@@ -191,71 +141,6 @@ xchk_rgbitmap_rec(
        return 0;
 }
 
-/* Scrub this group's realtime bitmap. */
-int
-xchk_rgbitmap(
-       struct xfs_scrub        *sc)
-{
-       struct xfs_mount        *mp = sc->mp;
-       struct xfs_rtgroup      *rtg = sc->sr.rtg;
-       struct xchk_rgbitmap    *rgb = sc->buf;
-       xfs_rtblock_t           start, last;
-       xfs_rgblock_t           last_rgbno = rtg->rtg_blockcount - 1;
-       int                     error;
-
-       /* Sanity check the realtime bitmap size. */
-       if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rtb.rbmblocks)) {
-               xchk_ino_set_corrupt(sc, sc->ip->i_ino);
-               return 0;
-       }
-
-       /*
-        * Check only the portion of the rtbitmap that corresponds to this
-        * realtime group.
-        */
-       rgb->next_free_rgbno = 0;
-       start = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, 0);
-       last = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, last_rgbno);
-
-       error = xfs_rtalloc_query_range(mp, sc->tp, xfs_rtb_to_rtx(mp, start),
-                       xfs_rtb_to_rtx(mp, last), xchk_rgbitmap_rec, rgb);
-       if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
-               return error;
-
-       /*
-        * Check that the are rmappings for all rt extents between the end of
-        * the last free extent we saw and the last possible extent in the rt
-        * group.
-        */
-       if (rgb->next_free_rgbno < last_rgbno)
-               xchk_xref_has_rt_owner(sc, rgb->next_free_rgbno,
-                               last_rgbno - rgb->next_free_rgbno);
-
-       return 0;
-}
-
-/* Realtime bitmap. */
-
-/* Scrub a free extent record from the realtime bitmap. */
-STATIC int
-xchk_rtbitmap_rec(
-       struct xfs_mount        *mp,
-       struct xfs_trans        *tp,
-       const struct xfs_rtalloc_rec *rec,
-       void                    *priv)
-{
-       struct xfs_scrub        *sc = priv;
-       xfs_rtblock_t           startblock;
-       xfs_filblks_t           blockcount;
-
-       startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
-       blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
-
-       if (!xfs_verify_rt_freesp(mp, startblock, blockcount))
-               xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
-       return 0;
-}
-
 /* Make sure the entire rtbitmap file is mapped with written extents. */
 STATIC int
 xchk_rtbitmap_check_extents(
@@ -300,24 +185,28 @@ xchk_rtbitmap_check_extents(
        return error;
 }
 
-/* Scrub the realtime bitmap. */
+/* Scrub this group's realtime bitmap. */
 int
-xchk_rtbitmap(
+xchk_rgbitmap(
        struct xfs_scrub        *sc)
 {
        struct xfs_mount        *mp = sc->mp;
-       struct xchk_rtbitmap    *rtb = sc->buf;
+       struct xfs_rtgroup      *rtg = sc->sr.rtg;
+       struct xfs_inode        *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+       struct xchk_rgbitmap    *rgb = sc->buf;
+       xfs_rgblock_t           last_rgbno =
+               (rtg->rtg_extents * mp->m_sb.sb_rextsize) - 1;
        int                     error;
 
        /* Is sb_rextents correct? */
-       if (mp->m_sb.sb_rextents != rtb->rextents) {
-               xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+       if (mp->m_sb.sb_rextents != rgb->rextents) {
+               xchk_ino_set_corrupt(sc, rbmip->i_ino);
                return 0;
        }
 
        /* Is sb_rextslog correct? */
-       if (mp->m_sb.sb_rextslog != rtb->rextslog) {
-               xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+       if (mp->m_sb.sb_rextslog != rgb->rextslog) {
+               xchk_ino_set_corrupt(sc, rbmip->i_ino);
                return 0;
        }
 
@@ -325,18 +214,18 @@ xchk_rtbitmap(
         * Is sb_rbmblocks large enough to handle the current rt volume?  In no
         * case can we exceed 4bn bitmap blocks since the super field is a u32.
         */
-       if (rtb->rbmblocks > U32_MAX) {
-               xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+       if (rgb->rbmblocks > U32_MAX) {
+               xchk_ino_set_corrupt(sc, rbmip->i_ino);
                return 0;
        }
-       if (mp->m_sb.sb_rbmblocks != rtb->rbmblocks) {
-               xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+       if (mp->m_sb.sb_rbmblocks != rgb->rbmblocks) {
+               xchk_ino_set_corrupt(sc, rbmip->i_ino);
                return 0;
        }
 
        /* The bitmap file length must be aligned to an fsblock. */
-       if (mp->m_rbmip->i_disk_size & mp->m_blockmask) {
-               xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+       if (rbmip->i_disk_size & mp->m_blockmask) {
+               xchk_ino_set_corrupt(sc, rbmip->i_ino);
                return 0;
        }
 
@@ -345,8 +234,8 @@ xchk_rtbitmap(
         * growfsrt expands the bitmap file before updating sb_rextents, so the
         * file can be larger than sb_rbmblocks.
         */
-       if (mp->m_rbmip->i_disk_size < XFS_FSB_TO_B(mp, rtb->rbmblocks)) {
-               xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
+       if (rbmip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rbmblocks)) {
+               xchk_ino_set_corrupt(sc, rbmip->i_ino);
                return 0;
        }
 
@@ -359,17 +248,19 @@ xchk_rtbitmap(
        if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
                return error;
 
-       /*
-        * Each rtgroup checks its portion of the rt bitmap, so if we don't
-        * have that feature, we have to check the bitmap contents now.
-        */
-       if (xfs_has_rtgroups(mp))
-               return 0;
-
-       error = xfs_rtalloc_query_all(mp, sc->tp, xchk_rtbitmap_rec, sc);
+       rgb->next_free_rgbno = 0;
+       error = xfs_rtalloc_query_all(rtg, sc->tp, xchk_rgbitmap_rec, rgb);
        if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
                return error;
 
+       /*
+        * Check that the are rmappings for all rt extents between the end of
+        * the last free extent we saw and the last possible extent in the rt
+        * group.
+        */
+       if (rgb->next_free_rgbno < last_rgbno)
+               xchk_xref_has_rt_owner(sc, rgb->next_free_rgbno,
+                               last_rgbno - rgb->next_free_rgbno);
        return 0;
 }
 
@@ -380,6 +271,7 @@ xchk_xref_is_used_rt_space(
        xfs_rtblock_t           rtbno,
        xfs_extlen_t            len)
 {
+       struct xfs_rtgroup      *rtg = sc->sr.rtg;
        xfs_rtxnum_t            startext;
        xfs_rtxnum_t            endext;
        bool                    is_free;
@@ -390,10 +282,11 @@ xchk_xref_is_used_rt_space(
 
        startext = xfs_rtb_to_rtx(sc->mp, rtbno);
        endext = xfs_rtb_to_rtx(sc->mp, rtbno + len - 1);
-       error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext,
+       error = xfs_rtalloc_extent_is_free(rtg, sc->tp, startext,
                        endext - startext + 1, &is_free);
        if (!xchk_should_check_xref(sc, &error, NULL))
                return;
        if (is_free)
-               xchk_ino_xref_set_corrupt(sc, sc->mp->m_rbmip->i_ino);
+               xchk_ino_xref_set_corrupt(sc,
+                       rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
 }
index f1c8e7b1e07d81d600fdd8d9e6d5fcf2a5c81355..33f907ea401bd1339a63d5c391ebe2c9dc4debd5 100644 (file)
@@ -6,13 +6,6 @@
 #ifndef __XFS_SCRUB_RTBITMAP_H__
 #define __XFS_SCRUB_RTBITMAP_H__
 
-struct xchk_rtbitmap {
-       uint64_t                rextents;
-       uint64_t                rbmblocks;
-       unsigned int            rextslog;
-       unsigned int            resblks;
-};
-
 /*
  * We use an xfile to construct new bitmap blocks for the portion of the
  * rtbitmap file that we're replacing.  Whereas the ondisk bitmap must be
@@ -29,7 +22,11 @@ typedef unsigned int xrep_wordcnt_t;
 struct xchk_rgbitmap {
        struct xfs_scrub        *sc;
 
-       struct xchk_rtbitmap    rtb;
+       uint64_t                rblocks;
+       uint64_t                rextents;
+       unsigned int            rextslog;
+       uint64_t                rbmblocks;
+       unsigned int            resblks;
 
        /* The next free rt group block number that we expect to see. */
        xfs_rgblock_t           next_free_rgbno;
@@ -40,12 +37,6 @@ struct xchk_rgbitmap {
        struct xrep_tempexch    tempexch;
 #endif
 
-       /* file offset inside the rtbitmap where we start swapping */
-       xfs_fileoff_t           group_rbmoff;
-
-       /* number of rtbitmap blocks for this group */
-       xfs_filblks_t           group_rbmlen;
-
        /* The next rtgroup block we expect to see during our rtrmapbt walk. */
        xfs_rgblock_t           next_rgbno;
 
@@ -60,7 +51,6 @@ struct xchk_rgbitmap {
 };
 
 #ifdef CONFIG_XFS_ONLINE_REPAIR
-int xrep_setup_rtbitmap(struct xfs_scrub *sc, struct xchk_rtbitmap *rtb);
 int xrep_setup_rgbitmap(struct xfs_scrub *sc, struct xchk_rgbitmap *rgb);
 
 /*
@@ -80,7 +70,6 @@ xchk_rgbitmap_wordcnt(
        return 0;
 }
 #else
-# define xrep_setup_rtbitmap(sc, rtb)  (0)
 # define xrep_setup_rgbitmap(sc, rgb)  (0)
 # define xchk_rgbitmap_wordcnt(sc)     (0)
 #endif /* CONFIG_XFS_ONLINE_REPAIR */
index 1ffe4577385cd2c96d262ec426f6ca069dc4a1ce..2f2a0219cf9cb433ac05dc069904e68c7889a4b7 100644 (file)
@@ -52,7 +52,7 @@ xrep_setup_rgbitmap(
                return error;
 
        /* Create an xfile to hold our reconstructed bitmap. */
-       rtbmp_words = xfs_rtbitmap_wordcount(mp, mp->m_sb.sb_rextents);
+       rtbmp_words = xfs_rtbitmap_wordcount(mp);
        descr = xchk_xfile_rtgroup_descr(sc, "bitmap file");
        error = xfile_create(descr, rtbmp_words << XFS_WORDLOG, &sc->xfile);
        kfree(descr);
@@ -76,8 +76,7 @@ xrep_setup_rgbitmap(
        blocks += xfs_bmbt_calc_size(mp, blocks) * 2;
        if (blocks > UINT_MAX)
                return -EOPNOTSUPP;
-
-       rgb->rtb.resblks += blocks;
+       rgb->resblks += blocks;
 
        /*
         * We must hold rbmip with ILOCK_EXCL to use the file mapping exchange
@@ -165,224 +164,6 @@ xfbmp_copyout(
                        wordoff << XFS_WORDLOG);
 }
 
-/*
- * Preserve the portions of the rtbitmap block for the start of this rtgroup
- * that map to the previous rtgroup.
- */
-STATIC int
-xrep_rgbitmap_load_before(
-       struct xchk_rgbitmap    *rgb)
-{
-       struct xfs_scrub        *sc = rgb->sc;
-       struct xfs_mount        *mp = sc->mp;
-       struct xfs_rtgroup      *rtg = sc->sr.rtg;
-       xrep_wordoff_t          wordoff;
-       xfs_rtblock_t           group_rtbno;
-       xfs_rtxnum_t            group_rtx, rbmoff_rtx;
-       xfs_rtword_t            ondisk_word;
-       xfs_rtword_t            xfile_word;
-       xfs_rtword_t            mask;
-       xrep_wordcnt_t          wordcnt;
-       int                     bit;
-       int                     error;
-
-       /*
-        * Compute the file offset within the rtbitmap block that corresponds
-        * to the start of this group, and decide if we need to read blocks
-        * from the group before this one.
-        */
-       group_rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, 0);
-       group_rtx = xfs_rtb_to_rtx(mp, group_rtbno);
-
-       rgb->group_rbmoff = xfs_rtx_to_rbmblock(mp, group_rtx);
-       rbmoff_rtx = xfs_rbmblock_to_rtx(mp, rgb->group_rbmoff);
-       rgb->prep_wordoff = rtx_to_wordoff(mp, rbmoff_rtx);
-
-       trace_xrep_rgbitmap_load(rtg, rgb->group_rbmoff, rbmoff_rtx,
-                       group_rtx - 1);
-
-       if (rbmoff_rtx == group_rtx)
-               return 0;
-
-       rgb->args.mp = sc->mp;
-       rgb->args.tp = sc->tp;
-       error = xfs_rtbitmap_read_buf(&rgb->args, rgb->group_rbmoff);
-       if (error) {
-               /*
-                * Reading the existing rbmblock failed, and we must deal with
-                * the part of the rtbitmap block that corresponds to the
-                * previous group.  The most conservative option is to fill
-                * that part of the bitmap with zeroes so that it won't get
-                * allocated.  The xfile contains zeroes already, so we can
-                * return.
-                */
-               return 0;
-       }
-
-       /*
-        * Copy full rtbitmap words into memory from the beginning of the
-        * ondisk block until we get to the word that corresponds to the start
-        * of this group.
-        */
-       wordoff = rtx_to_wordoff(mp, rbmoff_rtx);
-       wordcnt = rtxlen_to_wordcnt(group_rtx - rbmoff_rtx);
-       if (wordcnt > 0) {
-               union xfs_rtword_raw    *p;
-
-               p = xfs_rbmblock_wordptr(&rgb->args, 0);
-               error = xfbmp_copyin(rgb, wordoff, p, wordcnt);
-               if (error)
-                       goto out_rele;
-
-               trace_xrep_rgbitmap_load_words(mp, rgb->group_rbmoff, wordoff,
-                               wordcnt);
-               wordoff += wordcnt;
-       }
-
-       /*
-        * Compute the bit position of the first rtextent of this group.  If
-        * the bit position is zero, we don't have to RMW a partial word and
-        * move to the next step.
-        */
-       bit = group_rtx & XREP_RTBMP_WORDMASK;
-       if (bit == 0)
-               goto out_rele;
-
-       /*
-        * Create a mask of the bits that we want to load from disk.  These
-        * bits track space in a different rtgroup, which is why we must
-        * preserve them even as we replace parts of the bitmap.
-        */
-       mask = ~((((xfs_rtword_t)1 << (XFS_NBWORD - bit)) - 1) << bit);
-
-       error = xfbmp_load(rgb, wordoff, &xfile_word);
-       if (error)
-               goto out_rele;
-       ondisk_word = xfs_rtbitmap_getword(&rgb->args, wordcnt);
-
-       trace_xrep_rgbitmap_load_word(mp, wordoff, bit, ondisk_word,
-                       xfile_word, mask);
-
-       xfile_word &= ~mask;
-       xfile_word |= (ondisk_word & mask);
-
-       error = xfbmp_store(rgb, wordoff, xfile_word);
-       if (error)
-               goto out_rele;
-
-out_rele:
-       xfs_rtbuf_cache_relse(&rgb->args);
-       return error;
-}
-
-/*
- * Preserve the portions of the rtbitmap block for the end of this rtgroup
- * that map to the next rtgroup.
- */
-STATIC int
-xrep_rgbitmap_load_after(
-       struct xchk_rgbitmap    *rgb)
-{
-       struct xfs_scrub        *sc = rgb->sc;
-       struct xfs_mount        *mp = rgb->sc->mp;
-       struct xfs_rtgroup      *rtg = rgb->sc->sr.rtg;
-       xrep_wordoff_t          wordoff;
-       xfs_rtblock_t           last_rtbno;
-       xfs_rtxnum_t            last_group_rtx, last_rbmblock_rtx;
-       xfs_fileoff_t           last_group_rbmoff;
-       xfs_rtword_t            ondisk_word;
-       xfs_rtword_t            xfile_word;
-       xfs_rtword_t            mask;
-       xrep_wordcnt_t          wordcnt;
-       unsigned int            last_group_word;
-       int                     bit;
-       int                     error;
-
-       last_rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno,
-                                       rtg->rtg_blockcount - 1);
-       last_group_rtx = xfs_rtb_to_rtx(mp, last_rtbno);
-
-       last_group_rbmoff = xfs_rtx_to_rbmblock(mp, last_group_rtx);
-       rgb->group_rbmlen = last_group_rbmoff - rgb->group_rbmoff + 1;
-       last_rbmblock_rtx = xfs_rbmblock_to_rtx(mp, last_group_rbmoff + 1) - 1;
-
-       trace_xrep_rgbitmap_load(rtg, last_group_rbmoff, last_group_rtx + 1,
-                       last_rbmblock_rtx);
-
-       if (last_rbmblock_rtx == last_group_rtx ||
-           rtg->rtg_rgno == mp->m_sb.sb_rgcount - 1)
-               return 0;
-
-       rgb->args.mp = sc->mp;
-       rgb->args.tp = sc->tp;
-       error = xfs_rtbitmap_read_buf(&rgb->args, last_group_rbmoff);
-       if (error) {
-               /*
-                * Reading the existing rbmblock failed, and we must deal with
-                * the part of the rtbitmap block that corresponds to the
-                * previous group.  The most conservative option is to fill
-                * that part of the bitmap with zeroes so that it won't get
-                * allocated.  The xfile contains zeroes already, so we can
-                * return.
-                */
-               return 0;
-       }
-
-       /*
-        * Compute the bit position of the first rtextent of the next group.
-        * If the bit position is zero, we don't have to RMW a partial word
-        * and move to the next step.
-        */
-       wordoff = rtx_to_wordoff(mp, last_group_rtx);
-       bit = (last_group_rtx + 1) & XREP_RTBMP_WORDMASK;
-       if (bit == 0)
-               goto copy_words;
-
-       /*
-        * Create a mask of the bits that we want to load from disk.  These
-        * bits track space in a different rtgroup, which is why we must
-        * preserve them even as we replace parts of the bitmap.
-        */
-       mask = (((xfs_rtword_t)1 << (XFS_NBWORD - bit)) - 1) << bit;
-
-       error = xfbmp_load(rgb, wordoff, &xfile_word);
-       if (error)
-               goto out_rele;
-       last_group_word = xfs_rtx_to_rbmword(mp, last_group_rtx);
-       ondisk_word = xfs_rtbitmap_getword(&rgb->args, last_group_word);
-
-       trace_xrep_rgbitmap_load_word(mp, wordoff, bit, ondisk_word,
-                       xfile_word, mask);
-
-       xfile_word &= ~mask;
-       xfile_word |= (ondisk_word & mask);
-
-       error = xfbmp_store(rgb, wordoff, xfile_word);
-       if (error)
-               goto out_rele;
-
-copy_words:
-       /* Copy as many full words as we can. */
-       wordoff++;
-       wordcnt = rtxlen_to_wordcnt(last_rbmblock_rtx - last_group_rtx);
-       if (wordcnt > 0) {
-               union xfs_rtword_raw    *p;
-
-               p = xfs_rbmblock_wordptr(&rgb->args,
-                               mp->m_blockwsize - wordcnt);
-               error = xfbmp_copyin(rgb, wordoff, p, wordcnt);
-               if (error)
-                       goto out_rele;
-
-               trace_xrep_rgbitmap_load_words(mp, last_group_rbmoff, wordoff,
-                               wordcnt);
-       }
-
-out_rele:
-       xfs_rtbuf_cache_relse(&rgb->args);
-       return error;
-}
-
 /* Perform a logical OR operation on an rtword in the incore bitmap. */
 static int
 xrep_rgbitmap_or(
@@ -414,7 +195,6 @@ xrep_rgbitmap_mark_free(
        struct xfs_mount        *mp = rgb->sc->mp;
        struct xchk_rt          *sr =  &rgb->sc->sr;
        struct xfs_rtgroup      *rtg = sr->rtg;
-       xfs_rtblock_t           rtbno;
        xfs_rtxnum_t            startrtx;
        xfs_rtxnum_t            nextrtx;
        xrep_wordoff_t          wordoff, nextwordoff;
@@ -432,17 +212,15 @@ xrep_rgbitmap_mark_free(
         * Convert rt blocks to rt extents  The block range we find must be
         * aligned to an rtextent boundary on both ends.
         */
-       rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, rgb->next_rgbno);
-       mod = xfs_rtb_to_rtxoff(mp, rtbno);
+       startrtx = xfs_rgbno_to_rtx(mp, rgb->next_rgbno);
+       mod = xfs_rtb_to_rtxoff(mp, rgb->next_rgbno);
        if (mod)
                return -EFSCORRUPTED;
-       startrtx = xfs_rtb_to_rtx(mp, rtbno);
 
-       rtbno = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, rgbno - 1);
-       mod = xfs_rtb_to_rtxoff(mp, rtbno);
+       nextrtx = xfs_rgbno_to_rtx(mp, rgbno - 1) + 1;
+       mod = xfs_rtb_to_rtxoff(mp, rgbno - 1);
        if (mod != mp->m_sb.sb_rextsize - 1)
                return -EFSCORRUPTED;
-       nextrtx = xfs_rtb_to_rtx(mp, rtbno) + 1;
 
        /* Must not be shared or CoW staging. */
        if (sr->refc_cur) {
@@ -561,6 +339,7 @@ xrep_rgbitmap_find_freespace(
        struct xfs_scrub        *sc = rgb->sc;
        struct xfs_mount        *mp = sc->mp;
        struct xfs_rtgroup      *rtg = sc->sr.rtg;
+       u64                     blockcount;
        int                     error;
 
        /* Prepare a buffer of ones so that we can accelerate bulk setting. */
@@ -576,8 +355,9 @@ xrep_rgbitmap_find_freespace(
         * Mark as free every possible rt extent from the last one we saw to
         * the end of the rt group.
         */
-       if (rgb->next_rgbno < rtg->rtg_blockcount) {
-               error = xrep_rgbitmap_mark_free(rgb, rtg->rtg_blockcount);
+       blockcount = rtg->rtg_extents * mp->m_sb.sb_rextsize;
+       if (rgb->next_rgbno < blockcount) {
+               error = xrep_rgbitmap_mark_free(rgb, blockcount);
                if (error)
                        goto out;
        }
@@ -627,117 +407,6 @@ xrep_rgbitmap_prep_buf(
        return 0;
 }
 
-/* Repair the realtime bitmap for this rt group. */
-int
-xrep_rgbitmap(
-       struct xfs_scrub        *sc)
-{
-       struct xchk_rgbitmap    *rgb = sc->buf;
-       int                     error;
-
-       /* We require the realtime rmapbt to rebuild anything. */
-       if (!xfs_has_rtrmapbt(sc->mp))
-               return -EOPNOTSUPP;
-       /* We require atomic file exchange range to rebuild anything. */
-       if (!xfs_has_exchange_range(sc->mp))
-               return -EOPNOTSUPP;
-
-       /*
-        * If the start or end of this rt group happens to be in the middle of
-        * an rtbitmap block, try to read in the parts of the bitmap that are
-        * from some other group.
-        */
-       error = xrep_rgbitmap_load_before(rgb);
-       if (error)
-               return error;
-       error = xrep_rgbitmap_load_after(rgb);
-       if (error)
-               return error;
-
-       /*
-        * Generate the new rtbitmap data.  We don't need the rtbmp information
-        * once this call is finished.
-        */
-       error = xrep_rgbitmap_find_freespace(rgb);
-       if (error)
-               return error;
-
-       /*
-        * Try to take ILOCK_EXCL of the temporary file.  We had better be the
-        * only ones holding onto this inode, but we can't block while holding
-        * the rtbitmap file's ILOCK_EXCL.
-        */
-       while (!xrep_tempfile_ilock_nowait(sc)) {
-               if (xchk_should_terminate(sc, &error))
-                       return error;
-               delay(1);
-       }
-
-       /*
-        * Make sure we have space allocated for the part of the bitmap
-        * file that corresponds to this group.
-        */
-       xfs_trans_ijoin(sc->tp, sc->ip, 0);
-       xfs_trans_ijoin(sc->tp, sc->tempip, 0);
-       error = xrep_tempfile_prealloc(sc, rgb->group_rbmoff, rgb->group_rbmlen);
-       if (error)
-               return error;
-
-       /* Last chance to abort before we start committing fixes. */
-       if (xchk_should_terminate(sc, &error))
-               return error;
-
-       /* Copy the bitmap file that we generated. */
-       error = xrep_tempfile_copyin(sc, rgb->group_rbmoff, rgb->group_rbmlen,
-                       xrep_rgbitmap_prep_buf, rgb);
-       if (error)
-               return error;
-       error = xrep_tempfile_set_isize(sc,
-                       XFS_FSB_TO_B(sc->mp, sc->mp->m_sb.sb_rbmblocks));
-       if (error)
-               return error;
-
-       /*
-        * Now exchange the data fork contents.  We're done with the temporary
-        * buffer, so we can reuse it for the tempfile exchmaps information.
-        */
-       error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK,
-                       rgb->group_rbmoff, rgb->group_rbmlen, &rgb->tempexch);
-       if (error)
-               return error;
-
-       error = xrep_tempexch_contents(sc, &rgb->tempexch);
-       if (error)
-               return error;
-
-       /* Free the old bitmap blocks if they are free. */
-       return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);
-}
-
-/* rt bitmap file repairs */
-
-/* Set up to repair the realtime bitmap file metadata. */
-int
-xrep_setup_rtbitmap(
-       struct xfs_scrub        *sc,
-       struct xchk_rtbitmap    *rtb)
-{
-       struct xfs_mount        *mp = sc->mp;
-       unsigned long long      blocks = 0;
-
-       /*
-        * Reserve enough blocks to write out a completely new bmbt for a
-        * maximally fragmented bitmap file.  We do not hold the rtbitmap
-        * ILOCK yet, so this is entirely speculative.
-        */
-       blocks = xfs_bmbt_calc_size(mp, mp->m_sb.sb_rbmblocks);
-       if (blocks > UINT_MAX)
-               return -EOPNOTSUPP;
-
-       rtb->resblks += blocks;
-       return 0;
-}
-
 /*
  * Make sure that the given range of the data fork of the realtime file is
  * mapped to written blocks.  The caller must ensure that the inode is joined
@@ -817,47 +486,53 @@ xrep_rtbitmap_data_mappings(
 STATIC int
 xrep_rtbitmap_geometry(
        struct xfs_scrub        *sc,
-       struct xchk_rtbitmap    *rtb)
+       struct xchk_rgbitmap    *rgb)
 {
        struct xfs_mount        *mp = sc->mp;
        struct xfs_trans        *tp = sc->tp;
 
        /* Superblock fields */
-       if (mp->m_sb.sb_rextents != rtb->rextents)
+       if (mp->m_sb.sb_rextents != rgb->rextents)
                xfs_trans_mod_sb(sc->tp, XFS_TRANS_SB_REXTENTS,
-                               rtb->rextents - mp->m_sb.sb_rextents);
+                               rgb->rextents - mp->m_sb.sb_rextents);
 
-       if (mp->m_sb.sb_rbmblocks != rtb->rbmblocks)
+       if (mp->m_sb.sb_rbmblocks != rgb->rbmblocks)
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS,
-                               rtb->rbmblocks - mp->m_sb.sb_rbmblocks);
-
-       if (mp->m_sb.sb_rextslog != rtb->rextslog)
+                               rgb->rbmblocks - mp->m_sb.sb_rbmblocks);
+       if (mp->m_sb.sb_rextslog != rgb->rextslog)
                xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG,
-                               rtb->rextslog - mp->m_sb.sb_rextslog);
+                               rgb->rextslog - mp->m_sb.sb_rextslog);
 
        /* Fix broken isize */
        sc->ip->i_disk_size = roundup_64(sc->ip->i_disk_size,
                                         mp->m_sb.sb_blocksize);
 
-       if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rtb->rbmblocks))
-               sc->ip->i_disk_size = XFS_FSB_TO_B(mp, rtb->rbmblocks);
+       if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rbmblocks))
+               sc->ip->i_disk_size = XFS_FSB_TO_B(mp, rgb->rbmblocks);
 
        xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
        return xrep_roll_trans(sc);
 }
 
-/* Repair the realtime bitmap file metadata. */
+/* Repair the realtime bitmap for this rt group. */
 int
-xrep_rtbitmap(
+xrep_rgbitmap(
        struct xfs_scrub        *sc)
 {
-       struct xchk_rtbitmap    *rtb = sc->buf;
+       struct xchk_rgbitmap    *rgb = sc->buf;
        struct xfs_mount        *mp = sc->mp;
        unsigned long long      blocks = 0;
        int                     error;
 
+       /* We require the realtime rmapbt to rebuild anything. */
+       if (!xfs_has_rtrmapbt(sc->mp))
+               return -EOPNOTSUPP;
+       /* We require atomic file exchange range to rebuild anything. */
+       if (!xfs_has_exchange_range(sc->mp))
+               return -EOPNOTSUPP;
+
        /* Impossibly large rtbitmap means we can't touch the filesystem. */
-       if (rtb->rbmblocks > U32_MAX)
+       if (rgb->rbmblocks > U32_MAX)
                return 0;
 
        /*
@@ -865,15 +540,15 @@ xrep_rtbitmap(
         * figure out if we need to adjust the block reservation in the
         * transaction.
         */
-       blocks = xfs_bmbt_calc_size(mp, rtb->rbmblocks);
+       blocks = xfs_bmbt_calc_size(mp, rgb->rbmblocks);
        if (blocks > UINT_MAX)
                return -EOPNOTSUPP;
-       if (blocks > rtb->resblks) {
+       if (blocks > rgb->resblks) {
                error = xfs_trans_reserve_more(sc->tp, blocks, 0);
                if (error)
                        return error;
 
-               rtb->resblks += blocks;
+               rgb->resblks += blocks;
        }
 
        /* Fix inode core and forks. */
@@ -884,10 +559,71 @@ xrep_rtbitmap(
        xfs_trans_ijoin(sc->tp, sc->ip, 0);
 
        /* Ensure no unwritten extents. */
-       error = xrep_rtbitmap_data_mappings(sc, rtb->rbmblocks);
+       error = xrep_rtbitmap_data_mappings(sc, rgb->rbmblocks);
        if (error)
                return error;
 
        /* Fix inconsistent bitmap geometry */
-       return xrep_rtbitmap_geometry(sc, rtb);
+       error = xrep_rtbitmap_geometry(sc, rgb);
+       if (error)
+               return error;
+
+       /*
+        * Generate the new rtbitmap data.  We don't need the rtbmp information
+        * once this call is finished.
+        */
+       error = xrep_rgbitmap_find_freespace(rgb);
+       if (error)
+               return error;
+
+       /*
+        * Try to take ILOCK_EXCL of the temporary file.  We had better be the
+        * only ones holding onto this inode, but we can't block while holding
+        * the rtbitmap file's ILOCK_EXCL.
+        */
+       while (!xrep_tempfile_ilock_nowait(sc)) {
+               if (xchk_should_terminate(sc, &error))
+                       return error;
+               delay(1);
+       }
+
+       /*
+        * Make sure we have space allocated for the part of the bitmap
+        * file that corresponds to this group.
+        */
+       xfs_trans_ijoin(sc->tp, sc->ip, 0);
+       xfs_trans_ijoin(sc->tp, sc->tempip, 0);
+       error = xrep_tempfile_prealloc(sc, 0, rgb->rbmblocks);
+       if (error)
+               return error;
+
+       /* Last chance to abort before we start committing fixes. */
+       if (xchk_should_terminate(sc, &error))
+               return error;
+
+       /* Copy the bitmap file that we generated. */
+       error = xrep_tempfile_copyin(sc, 0, rgb->rbmblocks,
+                       xrep_rgbitmap_prep_buf, rgb);
+       if (error)
+               return error;
+       error = xrep_tempfile_set_isize(sc,
+                       XFS_FSB_TO_B(sc->mp, sc->mp->m_sb.sb_rbmblocks));
+       if (error)
+               return error;
+
+       /*
+        * Now exchange the data fork contents.  We're done with the temporary
+        * buffer, so we can reuse it for the tempfile exchmaps information.
+        */
+       error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK, 0,
+                       rgb->rbmblocks, &rgb->tempexch);
+       if (error)
+               return error;
+
+       error = xrep_tempexch_contents(sc, &rgb->tempexch);
+       if (error)
+               return error;
+
+       /* Free the old bitmap blocks if they are free. */
+       return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);
 }
index 962d08c3514b24e4b3169e5481a2e65ed783a654..6b9d9b97f833b38f1be03d3670aca7df5a378e86 100644 (file)
@@ -142,15 +142,12 @@ xrep_rtrefc_check_ext(
        struct xfs_scrub                *sc,
        const struct xfs_refcount_irec  *rec)
 {
-       xfs_rtblock_t                   rtbno;
-
        if (xfs_rtrefcount_check_irec(sc->sr.rtg, rec) != NULL)
                return -EFSCORRUPTED;
 
        /* Make sure this isn't free space or misaligned. */
-       rtbno = xfs_rgbno_to_rtb(sc->mp, sc->sr.rtg->rtg_rgno,
-                       rec->rc_startblock);
-       return xrep_require_rtext_inuse(sc, rtbno, rec->rc_blockcount, true);
+       return xrep_require_rtext_inuse(sc, sc->sr.rtg, rec->rc_startblock,
+                       rec->rc_blockcount, true);
 }
 
 /* Record a reference count extent. */
index deb491852104ae261f70b665161e2c59ab444a48..841b213750cceff3bdf998e3a0f79802cea7c6cd 100644 (file)
@@ -129,15 +129,12 @@ xrep_rtrmap_check_mapping(
        struct xfs_scrub        *sc,
        const struct xfs_rmap_irec *rec)
 {
-       xfs_rtblock_t           rtbno;
-
        if (xfs_rtrmap_check_irec(sc->sr.rtg, rec) != NULL)
                return -EFSCORRUPTED;
 
        /* Make sure this isn't free space. */
-       rtbno = xfs_rgbno_to_rtb(sc->mp, sc->sr.rtg->rtg_rgno,
-                       rec->rm_startblock);
-       return xrep_require_rtext_inuse(sc, rtbno, rec->rm_blockcount, false);
+       return xrep_require_rtext_inuse(sc, sc->sr.rtg, rec->rm_startblock,
+                       rec->rm_blockcount, false);
 }
 
 /* Store a reverse-mapping record. */
index c7f5659ab32ccf82924698f18831da33c31af1f8..2bc6caba07b3e8ae6cc2f94a3600dbd1cbebe08f 100644 (file)
@@ -18,6 +18,7 @@
 #include "xfs_bmap.h"
 #include "xfs_sb.h"
 #include "xfs_exchmaps.h"
+#include "xfs_rtgroup.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
@@ -42,20 +43,28 @@ xchk_setup_rtsummary(
        struct xfs_scrub        *sc)
 {
        struct xfs_mount        *mp = sc->mp;
+       struct xfs_rtgroup      *rtg;
        char                    *descr;
        struct xchk_rtsummary   *rts;
        int                     error;
 
+       if (xchk_need_intent_drain(sc))
+               xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
+
        rts = kvzalloc(struct_size(rts, words, mp->m_blockwsize),
                        XCHK_GFP_FLAGS);
        if (!rts)
                return -ENOMEM;
        sc->buf = rts;
 
+       rtg = xfs_rtgroup_get(mp, sc->sm->sm_agno);
+       if (!rtg)
+               return -ENOENT;
+
        if (xchk_could_repair(sc)) {
                error = xrep_setup_rtsummary(sc, rts);
                if (error)
-                       return error;
+                       goto out_rtg;
        }
 
        /*
@@ -66,41 +75,48 @@ xchk_setup_rtsummary(
        error = xfile_create(descr, mp->m_rsumsize, &sc->xfile);
        kfree(descr);
        if (error)
-               return error;
+               goto out_rtg;
 
        error = xchk_trans_alloc(sc, rts->resblks);
        if (error)
-               return error;
+               goto out_rtg;
 
-       error = xchk_install_live_inode(sc, mp->m_rsumip);
+       error = xchk_install_live_inode(sc, rtg->rtg_inodes[XFS_RTG_SUMMARY]);
        if (error)
-               return error;
+               goto out_rtg;
 
        error = xchk_ino_dqattach(sc);
        if (error)
                return error;
 
-       xchk_rt_init(sc, &sc->sr,
-                       XCHK_RTLOCK_SUMMARY | XCHK_RTLOCK_BITMAP_SHARED);
+       /*
+        * There is no strict requirement for an exclusive lock on the summary
+        * here, but to keep the locking APIs simple we lock both inodes
+        * exclusively here.  If we ever start caring about running concurrent
+        * fsmap with scrub this could be changed.
+        */
+       error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr,
+                       XFS_RTGLOCK_BITMAP);
+       if (error)
+               goto out_rtg;
 
        /*
         * Now that we've locked the rtbitmap and rtsummary, we can't race with
         * growfsrt trying to expand the summary or change the size of the rt
         * volume.  Hence it is safe to compute and check the geometry values.
         */
-       if (mp->m_sb.sb_rblocks) {
-               xfs_filblks_t   rsumblocks;
-               int             rextslog;
-
-               rts->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
-               rextslog = xfs_compute_rextslog(rts->rextents);
-               rts->rsumlevels = rextslog + 1;
-               rts->rbmblocks = xfs_rtbitmap_blockcount(mp, rts->rextents);
-               rsumblocks = xfs_rtsummary_blockcount(mp, rts->rsumlevels,
-                               rts->rbmblocks);
-               rts->rsumsize = XFS_FSB_TO_B(mp, rsumblocks);
-       }
-       return 0;
+       if (!mp->m_sb.sb_rblocks)
+               goto out_rtg;
+
+       rts->rextents = xfs_blen_to_rtbxlen(mp, mp->m_sb.sb_rblocks);
+       rts->rbmblocks = xfs_rtbitmap_blockcount(mp);
+       rts->rsumlevels = xfs_compute_rsumlevels(mp, rts->rextents);
+       rts->rsumsize = XFS_FSB_TO_B(mp,
+               xfs_rtsummary_blockcount(mp, rts->rsumlevels, rts->rbmblocks));
+
+out_rtg:
+       xfs_rtgroup_put(rtg);
+       return error;
 }
 
 /* Helper functions to record suminfo words in an xfile. */
@@ -155,11 +171,12 @@ xchk_rtsum_inc(
 /* Update the summary file to reflect the free extent that we've accumulated. */
 STATIC int
 xchk_rtsum_record_free(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        const struct xfs_rtalloc_rec    *rec,
        void                            *priv)
 {
+       struct xfs_mount                *mp = rtg->rtg_mount;
        struct xfs_scrub                *sc = priv;
        xfs_fileoff_t                   rbmoff;
        xfs_rtblock_t                   rtbno;
@@ -178,11 +195,12 @@ xchk_rtsum_record_free(
        lenlog = xfs_highbit64(rec->ar_extcount);
        offs = xfs_rtsumoffs(mp, lenlog, rbmoff);
 
-       rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
-       rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+       rtbno = xfs_rtx_to_rtb(rtg, rec->ar_startext);
+       rtlen = xfs_rtxlen_to_extlen(mp, rec->ar_extcount);
 
        if (!xfs_verify_rt_freesp(mp, rtbno, rtlen)) {
-               xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
+               xchk_ino_xref_set_corrupt(sc,
+                               rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
                return -EFSCORRUPTED;
        }
 
@@ -204,15 +222,14 @@ xchk_rtsum_compute(
        struct xfs_scrub        *sc)
 {
        struct xfs_mount        *mp = sc->mp;
-       unsigned long long      rtbmp_blocks;
+       struct xfs_rtgroup      *rtg = sc->sr.rtg;
 
        /* If the bitmap size doesn't match the computed size, bail. */
-       rtbmp_blocks = xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
-       if (XFS_FSB_TO_B(mp, rtbmp_blocks) != mp->m_rbmip->i_disk_size)
+       if (XFS_FSB_TO_B(mp, xfs_rtbitmap_blockcount(mp)) !=
+           rtg->rtg_inodes[XFS_RTG_BITMAP]->i_disk_size)
                return -EFSCORRUPTED;
 
-       return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
-                       sc);
+       return xfs_rtalloc_query_all(rtg, sc->tp, xchk_rtsum_record_free, sc);
 }
 
 /* Compare the rtsummary file against the one we computed. */
@@ -231,8 +248,9 @@ xchk_rtsum_compare(
        xfs_rtsumoff_t          sumoff = 0;
        int                     error = 0;
 
-       rts->args.mp = sc->mp;
+       rts->args.mp = mp;
        rts->args.tp = sc->tp;
+       rts->args.rtg = sc->sr.rtg;
 
        /* Mappings may not cross or lie beyond EOF. */
        endoff = XFS_B_TO_FSB(mp, ip->i_disk_size);
@@ -299,31 +317,34 @@ xchk_rtsummary(
        struct xfs_scrub        *sc)
 {
        struct xfs_mount        *mp = sc->mp;
+       struct xfs_rtgroup      *rtg = sc->sr.rtg;
+       struct xfs_inode        *rsumip = rtg->rtg_inodes[XFS_RTG_SUMMARY];
        struct xchk_rtsummary   *rts = sc->buf;
-       int                     error = 0;
+       int                     error;
 
        /* Is sb_rextents correct? */
        if (mp->m_sb.sb_rextents != rts->rextents) {
-               xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino);
-               goto out_rbm;
+               xchk_ino_set_corrupt(sc,
+                       rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
+               return 0;
        }
 
        /* Is m_rsumlevels correct? */
        if (mp->m_rsumlevels != rts->rsumlevels) {
-               xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
-               goto out_rbm;
+               xchk_ino_set_corrupt(sc, rsumip->i_ino);
+               return 0;
        }
 
        /* Is m_rsumsize correct? */
        if (mp->m_rsumsize != rts->rsumsize) {
-               xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
-               goto out_rbm;
+               xchk_ino_set_corrupt(sc, rsumip->i_ino);
+               return 0;
        }
 
        /* The summary file length must be aligned to an fsblock. */
-       if (mp->m_rsumip->i_disk_size & mp->m_blockmask) {
-               xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
-               goto out_rbm;
+       if (rsumip->i_disk_size & mp->m_blockmask) {
+               xchk_ino_set_corrupt(sc, rsumip->i_ino);
+               return 0;
        }
 
        /*
@@ -331,15 +352,15 @@ xchk_rtsummary(
         * growfsrt expands the summary file before updating sb_rextents, so
         * the file can be larger than rsumsize.
         */
-       if (mp->m_rsumip->i_disk_size < rts->rsumsize) {
-               xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
-               goto out_rbm;
+       if (rsumip->i_disk_size < rts->rsumsize) {
+               xchk_ino_set_corrupt(sc, rsumip->i_ino);
+               return 0;
        }
 
        /* Invoke the fork scrubber. */
        error = xchk_metadata_inode_forks(sc);
        if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
-               goto out_rbm;
+               return error;
 
        /* Construct the new summary file from the rtbitmap. */
        error = xchk_rtsum_compute(sc);
@@ -348,23 +369,12 @@ xchk_rtsummary(
                 * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref
                 * error since we're checking the summary file.
                 */
-               xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
-               error = 0;
-               goto out_rbm;
+               xchk_ino_xref_set_corrupt(sc,
+                       rtg->rtg_inodes[XFS_RTG_BITMAP]->i_ino);
+               return error;
        }
        if (error)
-               goto out_rbm;
-
+               return error;
        /* Does the computed summary file match the actual rtsummary file? */
-       error = xchk_rtsum_compare(sc);
-
-out_rbm:
-       /*
-        * Unlock the rtbitmap since we're done with it.  All other writers of
-        * the rt free space metadata grab the bitmap and summary ILOCKs in
-        * that order, so we're still protected against allocation activities
-        * even if we continue on to the repair function.
-        */
-       xchk_rt_unlock_rtbitmap(sc);
-       return error;
+       return xchk_rtsum_compare(sc);
 }
index 6813cc58b64f42dd6b78362537b8b95793499978..232805743abea6d7753d94ffc949addddf0142b1 100644 (file)
@@ -76,8 +76,9 @@ xrep_rtsummary_prep_buf(
        union xfs_suminfo_raw   *ondisk;
        int                     error;
 
-       rts->args.mp = sc->mp;
+       rts->args.mp = mp;
        rts->args.tp = sc->tp;
+       rts->args.rtg = sc->sr.rtg;
        rts->args.sumbp = bp;
        ondisk = xfs_rsumblock_infoptr(&rts->args, 0);
        rts->args.sumbp = NULL;
@@ -176,8 +177,8 @@ xrep_rtsummary(
                return error;
 
        /* Reset incore state and blow out the summary cache. */
-       if (mp->m_rsum_cache)
-               memset(mp->m_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);
+       if (sc->sr.rtg->rtg_rsum_cache)
+               memset(sc->sr.rtg->rtg_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);
 
        mp->m_rsumlevels = rts->rsumlevels;
        mp->m_rsumsize = rts->rsumsize;
index d0413d351e1acdd14c0634ab0d17348e6d0bf8f3..1e89075e1bab02b25cab2fca0e1ec676f62557cf 100644 (file)
@@ -227,10 +227,10 @@ xchk_teardown(
                        xfs_trans_cancel(sc->tp);
                sc->tp = NULL;
        }
+
        if (sc->sr.rtg)
                xchk_rtgroup_free(sc, &sc->sr);
-       else
-               xchk_rt_unlock(sc, &sc->sr);
+
        if (sc->ip) {
                if (sc->ilock_flags)
                        xchk_iunlock(sc, sc->ilock_flags);
@@ -387,12 +387,6 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
                .scrub  = xchk_parent,
                .repair = xrep_parent,
        },
-       [XFS_SCRUB_TYPE_RTBITMAP] = {   /* realtime bitmap */
-               .type   = ST_FS,
-               .setup  = xchk_setup_rtbitmap,
-               .scrub  = xchk_rtbitmap,
-               .repair = xrep_rtbitmap,
-       },
        [XFS_SCRUB_TYPE_RTSUM] = {      /* realtime summary */
                .type   = ST_FS,
                .setup  = xchk_setup_rtsummary,
index c64775912db8c0a4d6ee0ef6147a4b122e628d81..aa41a35e33147e1f7d35b5d99f61387b9c1ddcf7 100644 (file)
@@ -124,10 +124,7 @@ struct xchk_rt {
        /* incore rtgroup, if applicable */
        struct xfs_rtgroup      *rtg;
 
-       /*
-        * XCHK_RTLOCK_* lock state if rtg == NULL, or XFS_RTGLOCK_* lock state
-        * if rtg != NULL.
-        */
+       /* XFS_RTGLOCK_* */
        unsigned int            rtlock_flags;
 
        /* rtgroup btrees */
@@ -278,14 +275,12 @@ int xchk_parent(struct xfs_scrub *sc);
 int xchk_dirtree(struct xfs_scrub *sc);
 int xchk_metapath(struct xfs_scrub *sc);
 #ifdef CONFIG_XFS_RT
-int xchk_rtbitmap(struct xfs_scrub *sc);
 int xchk_rtsummary(struct xfs_scrub *sc);
 int xchk_rgsuperblock(struct xfs_scrub *sc);
 int xchk_rgbitmap(struct xfs_scrub *sc);
 int xchk_rtrmapbt(struct xfs_scrub *sc);
 int xchk_rtrefcountbt(struct xfs_scrub *sc);
 #else
-# define xchk_rtbitmap         xchk_nothing
 # define xchk_rtsummary                xchk_nothing
 # define xchk_rgsuperblock     xchk_nothing
 # define xchk_rgbitmap         xchk_nothing
index 0475d76a8f4647ad6fe70251c44c95c9721bd60b..709f7fe25894fade66d0604edc07b113547773ea 100644 (file)
@@ -71,7 +71,6 @@ static const char *name_map[XFS_SCRUB_TYPE_NR] = {
        [XFS_SCRUB_TYPE_XATTR]          = "xattr",
        [XFS_SCRUB_TYPE_SYMLINK]        = "symlink",
        [XFS_SCRUB_TYPE_PARENT]         = "parent",
-       [XFS_SCRUB_TYPE_RTBITMAP]       = "rtbitmap",
        [XFS_SCRUB_TYPE_RTSUM]          = "rtsummary",
        [XFS_SCRUB_TYPE_UQUOTA]         = "usrquota",
        [XFS_SCRUB_TYPE_GQUOTA]         = "grpquota",
index 7a1e4f2f0420605cbc3697b63936c6a9c93b910d..4ae9eedb63cd816c1fe6619319e5b393e8043273 100644 (file)
@@ -59,7 +59,6 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_DIR);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_XATTR);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_SYMLINK);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_PARENT);
-TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RTBITMAP);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RTSUM);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_UQUOTA);
 TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_GQUOTA);
@@ -96,7 +95,6 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RTREFCBT);
        { XFS_SCRUB_TYPE_XATTR,         "xattr" }, \
        { XFS_SCRUB_TYPE_SYMLINK,       "symlink" }, \
        { XFS_SCRUB_TYPE_PARENT,        "parent" }, \
-       { XFS_SCRUB_TYPE_RTBITMAP,      "rtbitmap" }, \
        { XFS_SCRUB_TYPE_RTSUM,         "rtsummary" }, \
        { XFS_SCRUB_TYPE_UQUOTA,        "usrquota" }, \
        { XFS_SCRUB_TYPE_GQUOTA,        "grpquota" }, \
index 48aefc300624dcb85717b01c9badc2bb338f7b2d..12a47e0ca6bfb6da7eb78ee10ee974b1316013af 100644 (file)
@@ -21,6 +21,7 @@
 #include "xfs_ag.h"
 #include "xfs_health.h"
 #include "xfs_rtbitmap.h"
+#include "xfs_rtgroup.h"
 
 /*
  * Notes on an efficient, low latency fstrim algorithm
@@ -515,7 +516,7 @@ xfs_discard_rtdev_extents(
 
 static int
 xfs_trim_gather_rtextent(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        const struct xfs_rtalloc_rec    *rec,
        void                            *priv)
@@ -534,12 +535,12 @@ xfs_trim_gather_rtextent(
                return -ECANCELED;
        }
 
-       rbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
-       rlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+       rbno = xfs_rtx_to_rtb(rtg, rec->ar_startext);
+       rlen = xfs_rtxlen_to_extlen(rtg->rtg_mount, rec->ar_extcount);
 
        /* Ignore too small. */
        if (rlen < tr->minlen_fsb) {
-               trace_xfs_discard_rttoosmall(mp, rbno, rlen);
+               trace_xfs_discard_rttoosmall(rtg->rtg_mount, rbno, rlen);
                return 0;
        }
 
@@ -558,71 +559,50 @@ xfs_trim_gather_rtextent(
 }
 
 static int
-xfs_trim_rtdev_extents(
-       struct xfs_mount        *mp,
-       xfs_daddr_t             start,
-       xfs_daddr_t             end,
+xfs_trim_rtg_extents(
+       struct xfs_rtgroup      *rtg,
+       xfs_rtxnum_t            low,
+       xfs_rtxnum_t            high,
        xfs_daddr_t             minlen,
        uint64_t                *blocks_trimmed)
 {
+       struct xfs_mount        *mp = rtg->rtg_mount;
        struct xfs_trim_rtdev   tr = {
                .blocks_trimmed = blocks_trimmed,
                .minlen_fsb     = XFS_BB_TO_FSB(mp, minlen),
+               .extent_list    = LIST_HEAD_INIT(tr.extent_list),
        };
-       xfs_rtxnum_t            low, high;
        struct xfs_trans        *tp;
-       xfs_daddr_t             rtdev_daddr;
        int                     error;
 
-       INIT_LIST_HEAD(&tr.extent_list);
-
-       /* Shift the start and end downwards to match the rt device. */
-       rtdev_daddr = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
-       if (start > rtdev_daddr)
-               start -= rtdev_daddr;
-       else
-               start = 0;
-
-       if (end <= rtdev_daddr)
-               return 0;
-       end -= rtdev_daddr;
-
        error = xfs_trans_alloc_empty(mp, &tp);
        if (error)
                return error;
 
-       end = min_t(xfs_daddr_t, end,
-                       XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks) - 1);
-
-       /* Convert the rt blocks to rt extents */
-       low = xfs_rtb_to_rtxup(mp, XFS_BB_TO_FSB(mp, start));
-       high = xfs_rtb_to_rtx(mp, XFS_BB_TO_FSBT(mp, end));
-
        /*
         * Walk the free ranges between low and high.  The query_range function
         * trims the extents returned.
         */
        do {
                tr.stop_rtx = low + xfs_rtbitmap_rtx_per_rbmblock(mp);
-               xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
-               error = xfs_rtalloc_query_range(mp, tp, low, high,
+               xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+               error = xfs_rtalloc_query_range(rtg, tp, low, high,
                                xfs_trim_gather_rtextent, &tr);
-
                if (error == -ECANCELED)
                        error = 0;
                if (error) {
-                       xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
+                       xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
                        xfs_discard_free_rtdev_extents(&tr);
                        break;
                }
 
                if (list_empty(&tr.extent_list)) {
-                       xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
+                       xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
                        break;
                }
 
                error = xfs_discard_rtdev_extents(mp, &tr);
-               xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
+               xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
                if (error)
                        break;
 
@@ -632,6 +612,57 @@ xfs_trim_rtdev_extents(
        xfs_trans_cancel(tp);
        return error;
 }
+
+static int
+xfs_trim_rtdev_extents(
+       struct xfs_mount        *mp,
+       xfs_daddr_t             start,
+       xfs_daddr_t             end,
+       xfs_daddr_t             minlen,
+       uint64_t                *blocks_trimmed)
+{
+       xfs_rtblock_t           start_rtbno, end_rtbno;
+       xfs_rtxnum_t            start_rtx, end_rtx;
+       xfs_rgnumber_t          rgno, end_rgno;
+       int                     last_error = 0, error;
+       struct xfs_rtgroup      *rtg;
+
+       /* Shift the start and end downwards to match the rt device. */
+       start_rtbno = xfs_daddr_to_rtb(mp, start);
+       if (start_rtbno > mp->m_sb.sb_dblocks)
+               start_rtbno -= mp->m_sb.sb_dblocks;
+       else
+               start_rtbno = 0;
+       start_rtx = xfs_rtb_to_rtx(mp, start_rtbno);
+       rgno = xfs_rtb_to_rgno(mp, start_rtbno);
+
+       end_rtbno = xfs_daddr_to_rtb(mp, end);
+       if (end_rtbno <= mp->m_sb.sb_dblocks)
+               return 0;
+       end_rtbno -= mp->m_sb.sb_dblocks;
+       end_rtx = xfs_rtb_to_rtx(mp, end_rtbno + mp->m_sb.sb_rextsize - 1);
+       end_rgno = xfs_rtb_to_rgno(mp, end_rtbno);
+       
+       for_each_rtgroup_range(mp, rgno, end_rgno, rtg) {
+               xfs_rtxnum_t    rtg_end = rtg->rtg_extents;
+
+               if (rgno == end_rgno)
+                       rtg_end = min(rtg_end, end_rtx);
+               
+               error = xfs_trim_rtg_extents(rtg, start_rtx, rtg_end, minlen,
+                               blocks_trimmed);
+               if (error)
+                       last_error = error;
+
+               if (xfs_trim_should_stop()) {
+                       xfs_rtgroup_rele(rtg);
+                       break;
+               }
+               start_rtx = 0;
+       }
+
+       return last_error;
+}
 #else
 # define xfs_trim_rtdev_extents(m,s,e,n,b)     (-EOPNOTSUPP)
 #endif /* CONFIG_XFS_RT */
index 94d08c05e43c422da8a742d127c89dc9d543ee64..149388b4fd048174e5083a954801169adebb2894 100644 (file)
@@ -787,23 +787,21 @@ xfs_rtextent_free_finish_item(
        struct xfs_mount                *mp = tp->t_mountp;
        struct xfs_extent_free_item     *xefi = xefi_entry(item);
        struct xfs_efd_log_item         *efdp = EFD_ITEM(done);
+       struct xfs_rtgroup              **rtgp = (struct xfs_rtgroup **)state;
        int                             error = 0;
 
-       /*
-        * Lock the rt bitmap if we've any realtime extents to free and we
-        * haven't locked the rt inodes yet.
-        */
-       if (*state == NULL) {
-               xfs_rtbitmap_lock(mp);
-               xfs_rtbitmap_trans_join(tp);
-               *state = (struct xfs_btree_cur *)1;
-       }
-
        trace_xfs_extent_free_deferred(mp, xefi);
 
-       if (!(xefi->xefi_flags & XFS_EFI_CANCELLED))
-               error = xfs_rtfree_blocks(tp, xefi->xefi_startblock,
-                                       xefi->xefi_blockcount);
+       if (!(xefi->xefi_flags & XFS_EFI_CANCELLED)) {
+               if (*rtgp != xefi->xefi_rtg) {
+                       xfs_rtgroup_lock(xefi->xefi_rtg, XFS_RTGLOCK_BITMAP);
+                       xfs_rtgroup_trans_join(tp, xefi->xefi_rtg,
+                                       XFS_RTGLOCK_BITMAP);
+                       *rtgp = xefi->xefi_rtg;
+               }
+               error = xfs_rtfree_blocks(tp, xefi->xefi_rtg,
+                               xefi->xefi_startblock, xefi->xefi_blockcount);
+       }
        if (error == -EAGAIN) {
                xfs_efd_from_efi(efdp);
                return error;
index 7ec96380f765107f993391a9f01adb299d4ff5c7..510cd4b8dc6d1a40ee203294419e882284ebb81b 100644 (file)
@@ -709,29 +709,22 @@ xfs_getfsmap_logdev(
 /* Transform a rtbitmap "record" into a fsmap */
 STATIC int
 xfs_getfsmap_rtdev_rtbitmap_helper(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        const struct xfs_rtalloc_rec    *rec,
        void                            *priv)
 {
+       struct xfs_mount                *mp = rtg->rtg_mount;
        struct xfs_getfsmap_info        *info = priv;
-       struct xfs_rmap_irec            irec;
-       xfs_rtblock_t                   rtbno;
-       xfs_daddr_t                     rec_daddr, len_daddr;
-
-       rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
-       rec_daddr = XFS_FSB_TO_BB(mp, rtbno);
-       irec.rm_startblock = rtbno;
-
-       rtbno = xfs_rtx_to_rtb(mp, rec->ar_extcount);
-       len_daddr = XFS_FSB_TO_BB(mp, rtbno);
-       irec.rm_blockcount = rtbno;
-
-       irec.rm_owner = XFS_RMAP_OWN_NULL;      /* "free" */
-       irec.rm_offset = 0;
-       irec.rm_flags = 0;
-
-       return xfs_getfsmap_helper(tp, info, &irec, rec_daddr, len_daddr);
+       struct xfs_rmap_irec            irec = {
+               .rm_startblock  = xfs_rtx_to_rtb(rtg, rec->ar_startext),
+               .rm_blockcount  = xfs_rtxlen_to_extlen(mp, rec->ar_extcount),
+               .rm_owner       = XFS_RMAP_OWN_NULL, /* "free" */
+       };
+
+       return xfs_getfsmap_helper(tp, info, &irec,
+                       XFS_FSB_TO_BB(mp, irec.rm_startblock),
+                       XFS_FSB_TO_BB(mp, irec.rm_blockcount));
 }
 
 /* Execute a getfsmap query against the realtime device rtbitmap. */
@@ -741,59 +734,69 @@ xfs_getfsmap_rtdev_rtbitmap(
        const struct xfs_fsmap          *keys,
        struct xfs_getfsmap_info        *info)
 {
-
-       struct xfs_rtalloc_rec          ahigh = { 0 };
        struct xfs_mount                *mp = tp->t_mountp;
-       xfs_rtblock_t                   start_rtb;
-       xfs_rtblock_t                   end_rtb;
-       xfs_rtxnum_t                    high;
+       xfs_rtblock_t                   start_rtbno, end_rtbno;
+       xfs_rtxnum_t                    start_rtx, end_rtx;
+       xfs_rgnumber_t                  rgno, end_rgno;
+       struct xfs_rtgroup              *rtg;
        uint64_t                        eofs;
        int                             error;
 
-       eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
+       eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
        if (keys[0].fmr_physical >= eofs)
                return 0;
-       start_rtb = XFS_BB_TO_FSBT(mp,
-                               keys[0].fmr_physical + keys[0].fmr_length);
-       end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
 
        info->missing_owner = XFS_FMR_OWN_UNKNOWN;
 
        /* Adjust the low key if we are continuing from where we left off. */
+       start_rtbno =
+               XFS_BB_TO_FSBT(mp, keys[0].fmr_physical + keys[0].fmr_length);
        if (keys[0].fmr_length > 0) {
-               info->low_daddr = XFS_FSB_TO_BB(mp, start_rtb);
+               info->low_daddr = XFS_FSB_TO_BB(mp, start_rtbno);
                if (info->low_daddr >= eofs)
                        return 0;
        }
+       start_rtx = xfs_rtb_to_rtx(mp, start_rtbno);
+       rgno = xfs_rtb_to_rgno(mp, start_rtbno);
+       trace_xfs_fsmap_low_key_linear(mp, info->dev, start_rtbno);
+
+       end_rtbno = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
+       end_rtx = xfs_rtb_to_rtx(mp, end_rtbno + mp->m_sb.sb_rextsize - 1);
+       end_rgno = xfs_rtb_to_rgno(mp, end_rtbno);
+       trace_xfs_fsmap_high_key_linear(mp, info->dev, end_rtbno);
+
+       for_each_rtgroup_range(mp, rgno, end_rgno, rtg) {
+               xfs_rtxnum_t            rtg_end = rtg->rtg_extents;
+
+               if (rgno == end_rgno)
+                       rtg_end = end_rtx;
+
+               xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+               error = xfs_rtalloc_query_range(rtg, tp, start_rtx, rtg_end,
+                               xfs_getfsmap_rtdev_rtbitmap_helper, info);
+               if (!error) {
+                       struct xfs_rtalloc_rec  ahigh = {
+                               .ar_startext    = rtg_end,
+                       };
+
+                       /*
+                        * 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;
+                       error = xfs_getfsmap_rtdev_rtbitmap_helper(rtg, tp,
+                                       &ahigh, info);
+               }
+               xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+               if (error) {
+                       xfs_rtgroup_rele(rtg);
+                       return error;
+               }
+               start_rtx = 0;
+       }
 
-       trace_xfs_fsmap_low_key_linear(mp, info->dev, start_rtb);
-       trace_xfs_fsmap_high_key_linear(mp, info->dev, end_rtb);
-
-       xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
-
-       /*
-        * Set up query parameters to return free rtextents covering the range
-        * we want.
-        */
-       high = xfs_rtb_to_rtxup(mp, end_rtb);
-       error = xfs_rtalloc_query_range(mp, tp, xfs_rtb_to_rtx(mp, start_rtb),
-                       high, xfs_getfsmap_rtdev_rtbitmap_helper, info);
-       if (error)
-               goto err;
-
-       /*
-        * 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, high);
-
-       error = xfs_getfsmap_rtdev_rtbitmap_helper(mp, tp, &ahigh, info);
-       if (error)
-               goto err;
-err:
-       xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
-       return error;
+       return 0;
 }
 
 /* Transform a realtime rmapbt record into a fsmap */
@@ -853,7 +856,7 @@ xfs_getfsmap_rtdev_rmapbt(
        uint64_t                        eofs;
        int                             error = 0;
 
-       eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
+       eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
        if (keys[0].fmr_physical >= eofs)
                return 0;
        start_rtb = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
index edb3bdecbed895aaa96e335687fe1cf0246ef416..607d360c4a911ea40b0a3b565b72b18a3dadf6d9 100644 (file)
@@ -117,7 +117,6 @@ xfs_bmbt_to_iomap(
                iomap->type = IOMAP_DELALLOC;
        } else {
                xfs_daddr_t     bno = xfs_fsb_to_db(ip, imap->br_startblock);
-               xfs_rgnumber_t  dummy;
 
                iomap->addr = BBTOB(bno);
                if (mapping_flags & IOMAP_DAX)
@@ -134,7 +133,8 @@ xfs_bmbt_to_iomap(
                 * single RTG.
                 */
                if (XFS_IS_REALTIME_INODE(ip) && xfs_has_rtgroups(mp) &&
-                   xfs_rtb_to_rgbno(mp, bno, &dummy) == 0)
+                   xfs_rtb_to_rtx(mp, bno) == 0 &&
+                   xfs_rtb_to_rtxoff(mp, bno) == 0)
                        iomap->flags |= IOMAP_F_BOUNDARY;
        }
        iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff);
@@ -513,8 +513,8 @@ xfs_iomap_prealloc_size(
                                       alloc_blocks);
 
        if (unlikely(XFS_IS_REALTIME_INODE(ip)))
-               freesp = xfs_rtx_to_rtb(mp,
-                       xfs_iomap_freesp(&mp->m_frextents,
+               freesp = xfs_rtbxlen_to_blen(mp,
+                               xfs_iomap_freesp(&mp->m_frextents,
                                        mp->m_low_rtexts, &shift));
        else
                freesp = xfs_iomap_freesp(&mp->m_fdblocks, mp->m_low_space,
index 051340cf00157e77b92dccab2827f0fcb8e50a21..233b73012b2494fc998f644da08fe6e9cb4d76e9 100644 (file)
@@ -1496,7 +1496,7 @@ xfs_mod_delalloc(
 
        if (XFS_IS_REALTIME_INODE(ip)) {
                percpu_counter_add_batch(&mp->m_delalloc_rtextents,
-                               xfs_rtb_to_rtx(mp, data_delta),
+                               xfs_blen_to_rtbxlen(mp, data_delta),
                                XFS_DELALLOC_BATCH);
                if (!ind_delta)
                        return;
index fcddb4be3c9b72be4cc011ce4dbf2b994fb45f2b..90b7f3efa37877be8f4782ad6ba48dd68520cb9b 100644 (file)
@@ -92,8 +92,6 @@ typedef struct xfs_mount {
        struct xfs_da_geometry  *m_dir_geo;     /* directory block geometry */
        struct xfs_da_geometry  *m_attr_geo;    /* attribute block geometry */
        struct xlog             *m_log;         /* log specific stuff */
-       struct xfs_inode        *m_rbmip;       /* pointer to bitmap inode */
-       struct xfs_inode        *m_rsumip;      /* pointer to summary inode */
        struct xfs_inode        *m_rootip;      /* pointer to root directory */
        struct xfs_inode        *m_metadirip;   /* ptr to metadata directory */
        struct xfs_inode        *m_rtdirip;     /* ptr to realtime metadir */
@@ -102,14 +100,6 @@ typedef struct xfs_mount {
        struct xfs_buftarg      *m_logdev_targp;/* log device */
        struct xfs_buftarg      *m_rtdev_targp; /* rt device */
        void __percpu           *m_inodegc;     /* percpu inodegc structures */
-
-       /*
-        * Optional cache of rt summary level per bitmap block with the
-        * invariant that m_rsum_cache[bbno] > the maximum i for which
-        * rsum[i][bbno] != 0, or 0 if rsum[i][bbno] == 0 for all i.
-        * Reads and writes are serialized by the rsumip inode lock.
-        */
-       uint8_t                 *m_rsum_cache;
        struct xfs_mru_cache    *m_filestream;  /* per-mount filestream data */
        struct workqueue_struct *m_buf_workqueue;
        struct workqueue_struct *m_unwritten_workqueue;
@@ -240,9 +230,9 @@ typedef struct xfs_mount {
 #ifdef CONFIG_XFS_ONLINE_SCRUB_STATS
        struct xchk_stats       *m_scrub_stats;
 #endif
-       xfs_rgnumber_t          m_rtgrotor;     /* last rtgroup rtpicked */
        xfs_agnumber_t          m_agfrotor;     /* last ag where space found */
        atomic_t                m_agirotor;     /* last ag dir inode alloced */
+       atomic_t                m_rtgrotor;     /* last rtgroup rtpicked */
 
        /* Memory shrinker to throttle and reprioritize inodegc */
        struct shrinker         *m_inodegc_shrinker;
index a6a52bfe3cde983957b378107248436c50ce252c..e2bc44ab8b23fb3affd893565b0b32bb64203380 100644 (file)
@@ -29,6 +29,7 @@
 #include "xfs_health.h"
 #include "xfs_da_format.h"
 #include "xfs_metafile.h"
+#include "xfs_rtgroup.h"
 
 /*
  * The global quota manager. There is only one of these for the entire
@@ -210,6 +211,21 @@ xfs_qm_unmount(
        }
 }
 
+static void
+xfs_qm_unmount_rt(
+       struct xfs_mount        *mp)
+{
+       struct xfs_rtgroup      *rtg = xfs_rtgroup_grab(mp, 0);
+
+       if (!rtg)
+               return;
+       if (rtg->rtg_inodes[XFS_RTG_BITMAP])
+               xfs_qm_dqdetach(rtg->rtg_inodes[XFS_RTG_BITMAP]);
+       if (rtg->rtg_inodes[XFS_RTG_SUMMARY])
+               xfs_qm_dqdetach(rtg->rtg_inodes[XFS_RTG_SUMMARY]);
+       xfs_rtgroup_rele(rtg);
+}
+
 /*
  * Called from the vfsops layer.
  */
@@ -223,10 +239,13 @@ xfs_qm_unmount_quotas(
         */
        ASSERT(mp->m_rootip);
        xfs_qm_dqdetach(mp->m_rootip);
-       if (mp->m_rbmip)
-               xfs_qm_dqdetach(mp->m_rbmip);
-       if (mp->m_rsumip)
-               xfs_qm_dqdetach(mp->m_rsumip);
+
+       /*
+        * For pre-RTG file systems, the RT inodes have quotas attached,
+        * detach them now.
+        */
+       if (!xfs_has_rtgroups(mp))
+               xfs_qm_unmount_rt(mp);
 
        /*
         * Release the quota inodes.
index aa26a80ce3db921e679ac1b1b5744bda6fe29a3b..2cb3f8493e30566d3eb88391c90bab1734ca009d 100644 (file)
@@ -1000,6 +1000,9 @@ xfs_reflink_recover_cow(
                }
        }
 
+       if (!xfs_has_rtgroups(mp))
+               return 0;
+
        for_each_rtgroup(mp, rgno, rtg) {
                error = xfs_refcount_recover_rtcow_leftovers(mp, rtg);
                if (error) {
index 82d583251ba94d2ffb120c2858a66b8c53616e54..1c5d4da79518f08150aa6fe4efd2b143557f2390 100644 (file)
 #include "xfs_trace.h"
 #include "xfs_rtrefcount_btree.h"
 
-/*
- * Realtime metadata files are not quite regular files because userspace can't
- * access the realtime bitmap directly, and because we take the ILOCK of the rt
- * bitmap file (and then the rt summary file) while holding the ILOCK of a
- * regular realtime file.  This double locking confuses lockdep, so create
- * different lockdep classes here to help it keep things straight.
- */
-static struct lock_class_key xfs_rtbitmap_key;
-static struct lock_class_key xfs_rtsummary_key;
-
 /*
  * Return whether there are any free extents in the size range given
  * by low and high, for the bitmap block bbno.
@@ -57,14 +47,14 @@ xfs_rtany_summary(
        xfs_fileoff_t           bbno,   /* bitmap block number */
        int                     *maxlog) /* out: max log2 extent size free */
 {
-       struct xfs_mount        *mp = args->mp;
+       uint8_t                 *rsum_cache = args->rtg->rtg_rsum_cache;
        int                     error;
        int                     log;    /* loop counter, log2 of ext. size */
        xfs_suminfo_t           sum;    /* summary data */
 
-       /* There are no extents at levels >= m_rsum_cache[bbno]. */
-       if (mp->m_rsum_cache) {
-               high = min(high, mp->m_rsum_cache[bbno] - 1);
+       /* There are no extents at levels >= rsum_cache[bbno]. */
+       if (rsum_cache) {
+               high = min(high, rsum_cache[bbno] - 1);
                if (low > high) {
                        *maxlog = -1;
                        return 0;
@@ -96,12 +86,11 @@ xfs_rtany_summary(
        *maxlog = -1;
 out:
        /* There were no extents at levels > log. */
-       if (mp->m_rsum_cache && log + 1 < mp->m_rsum_cache[bbno])
-               mp->m_rsum_cache[bbno] = log + 1;
+       if (rsum_cache && log + 1 < rsum_cache[bbno])
+               rsum_cache[bbno] = log + 1;
        return 0;
 }
 
-
 /*
  * Copy and transform the summary file, given the old and new
  * parameters in the mount structures.
@@ -139,6 +128,7 @@ out:
        xfs_rtbuf_cache_relse(oargs);
        return 0;
 }
+
 /*
  * Mark an extent specified by start and len allocated.
  * Updates all the summary information as well as the bitmap.
@@ -150,12 +140,11 @@ xfs_rtallocate_range(
        xfs_rtxlen_t            len)    /* in/out: summary block number */
 {
        struct xfs_mount        *mp = args->mp;
-       xfs_rtxnum_t            end;    /* end of the allocated rtext */
+       xfs_rtxnum_t            end = start + len - 1;
        int                     error;
        xfs_rtxnum_t            postblock = 0; /* first rtext allocated > end */
        xfs_rtxnum_t            preblock = 0; /* first rtext allocated < start */
 
-       end = start + len - 1;
        /*
         * Assume we're allocating out of the middle of a free extent.
         * We need to find the beginning and end of the extent so we can
@@ -168,7 +157,7 @@ xfs_rtallocate_range(
        /*
         * Find the next allocated block (end of free extent).
         */
-       error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
+       error = xfs_rtfind_forw(args, end, args->rtg->rtg_extents - 1,
                        &postblock);
        if (error)
                return error;
@@ -230,40 +219,17 @@ xfs_rtalloc_align_len(
  */
 static inline xfs_rtxlen_t
 xfs_rtallocate_clamp_len(
-       struct xfs_mount        *mp,
+       struct xfs_rtgroup      *rtg,
        xfs_rtxnum_t            startrtx,
        xfs_rtxlen_t            rtxlen,
        xfs_rtxlen_t            prod)
 {
        xfs_rtxlen_t            ret;
 
-       ret = min(mp->m_sb.sb_rextents, startrtx + rtxlen) - startrtx;
+       ret = min(rtg->rtg_extents, startrtx + rtxlen) - startrtx;
        return xfs_rtalloc_align_len(ret, prod);
 }
 
-/*
- * Given a candidate range of freespace that might be allocated, clamp the end
- * of the range to the end of the rtgroup to avoid crossing rtgroup boundaries.
- * Caller needs to round down the return value to prod if needed.
- */
-static inline xfs_rtxlen_t
-xfs_rtalloc_clamp_rtgroup(
-       struct xfs_mount        *mp,
-       xfs_rtxnum_t            startrtx,
-       xfs_rtxlen_t            rtxlen)
-{
-       xfs_rtxnum_t            next_rtx;
-       xfs_rtblock_t           rtb, next_rtb;
-       xfs_rgnumber_t          rgno;
-
-       rtb = xfs_rtx_to_rtb(mp, startrtx);
-       rgno = xfs_rtb_to_rgno(mp, rtb);
-       next_rtb = xfs_rgbno_to_rtb(mp, rgno + 1, 0);
-       next_rtx = xfs_rtb_to_rtx(mp, next_rtb);
-
-       return min(next_rtx, startrtx + rtxlen) - startrtx;
-}
-
 /*
  * Attempt to allocate an extent minlen<=len<=maxlen starting from
  * bitmap block bbno.  If we don't get maxlen then use prod to trim
@@ -288,7 +254,6 @@ xfs_rtallocate_extent_block(
        xfs_rtxnum_t            next;   /* next rtext to try */
        xfs_rtxlen_t            scanlen; /* number of free rtx to look for */
        xfs_rtxlen_t            bestlen = 0; /* best length found so far */
-       xfs_rtxlen_t            thislen; /* candidate length */
        int                     stat;   /* status from internal calls */
        int                     error;
 
@@ -296,10 +261,11 @@ xfs_rtallocate_extent_block(
         * Loop over all the extents starting in this bitmap block up to the
         * end of the rt volume, looking for one that's long enough.
         */
-       end = min(mp->m_sb.sb_rextents, xfs_rbmblock_to_rtx(mp, bbno + 1)) - 1;
+       end = min(args->rtg->rtg_extents, xfs_rbmblock_to_rtx(mp, bbno + 1)) -
+               1;
        for (i = xfs_rbmblock_to_rtx(mp, bbno); i <= end; i++) {
                /* Make sure we don't scan off the end of the rt volume. */
-               scanlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
+               scanlen = xfs_rtallocate_clamp_len(args->rtg, i, maxlen, prod);
                if (scanlen < minlen)
                        break;
 
@@ -310,19 +276,6 @@ xfs_rtallocate_extent_block(
                error = xfs_rtcheck_range(args, i, scanlen, 1, &next, &stat);
                if (error)
                        return error;
-               if (stat && xfs_has_rtgroups(mp)) {
-                       /*
-                        * i to scanlen is all free, but we can't return space
-                        * that would cross an rtgroup boundary.  If it does
-                        * cross the boundary, treat this like a short
-                        * allocation.
-                        */
-                       thislen = xfs_rtalloc_clamp_rtgroup(mp, i, scanlen);
-                       if (thislen != scanlen) {
-                               next = i + thislen;
-                               stat = 0;
-                       }
-               }
                if (stat) {
                        /*
                         * i to scanlen is all free, allocate and return that.
@@ -339,11 +292,8 @@ xfs_rtallocate_extent_block(
                 * so far, remember it.
                 */
                if (minlen < maxlen) {
-                       if (xfs_has_rtgroups(mp))
-                               thislen = xfs_rtalloc_clamp_rtgroup(mp, i,
-                                               next - i);
-                       else
-                               thislen = next - i;
+                       xfs_rtxlen_t thislen = next - i;
+       
                        if (thislen >= minlen && thislen > bestlen) {
                                besti = i;
                                bestlen = thislen;
@@ -399,7 +349,6 @@ xfs_rtallocate_extent_exact(
        xfs_rtxlen_t            prod,   /* extent product factor */
        xfs_rtxnum_t            *rtx)   /* out: start rtext allocated */
 {
-       struct xfs_mount        *mp = args->mp;
        xfs_rtxnum_t            next;   /* next rtext to try (dummy) */
        xfs_rtxlen_t            alloclen; /* candidate length */
        xfs_rtxlen_t            scanlen; /* number of free rtx to look for */
@@ -410,7 +359,7 @@ xfs_rtallocate_extent_exact(
        ASSERT(maxlen % prod == 0);
 
        /* Make sure we don't run off the end of the rt volume. */
-       scanlen = xfs_rtallocate_clamp_len(mp, start, maxlen, prod);
+       scanlen = xfs_rtallocate_clamp_len(args->rtg, start, maxlen, prod);
        if (scanlen < minlen)
                return -ENOSPC;
 
@@ -419,29 +368,12 @@ xfs_rtallocate_extent_exact(
        if (error)
                return error;
 
-       if (isfree && xfs_has_rtgroups(mp)) {
-               /*
-                * start to scanlen is all free, but we can't return space that
-                * would cross an rtgroup boundary.  If it does, treat this
-                * like a short allocation.
-                */
-               alloclen = xfs_rtalloc_clamp_rtgroup(mp, start, scanlen);
-               if (alloclen < scanlen) {
-                       next = start + alloclen;
-                       isfree = 0;
-               }
-       }
-
        if (isfree) {
                /* start to scanlen is all free; allocate it. */
                alloclen = scanlen;
        } else {
                /* If not, allocate what there is, if it's at least minlen. */
-               if (xfs_has_rtgroups(mp))
-                       alloclen = xfs_rtalloc_clamp_rtgroup(mp, start,
-                                       next - start);
-               else
-                       alloclen = next - start;
+               alloclen = next - start;
                if (alloclen < minlen)
                        return -ENOSPC;
 
@@ -484,11 +416,10 @@ xfs_rtallocate_extent_near(
        ASSERT(maxlen % prod == 0);
 
        /*
-        * If the block number given is off the end, silently set it to
-        * the last block.
+        * If the block number given is off the end, silently set it to the last
+        * block.
         */
-       if (start >= mp->m_sb.sb_rextents)
-               start = mp->m_sb.sb_rextents - 1;
+       start = min(start, args->rtg->rtg_extents);
 
        /*
         * Try the exact allocation first.
@@ -722,17 +653,17 @@ xfs_rtallocate_extent_size(
 
 static int
 xfs_alloc_rsum_cache(
-       struct xfs_mount        *mp,
+       struct xfs_rtgroup      *rtg,
        xfs_extlen_t            rbmblocks)
 {
        /*
         * The rsum cache is initialized to the maximum value, which is
         * trivially an upper bound on the maximum level with any free extents.
         */
-       mp->m_rsum_cache = kvmalloc(rbmblocks, GFP_KERNEL);
-       if (!mp->m_rsum_cache)
+       rtg->rtg_rsum_cache = kvmalloc(rbmblocks, GFP_KERNEL);
+       if (!rtg->rtg_rsum_cache)
                return -ENOMEM;
-       memset(mp->m_rsum_cache, -1, rbmblocks);
+       memset(rtg->rtg_rsum_cache, -1, rbmblocks);
        return 0;
 }
 
@@ -759,100 +690,28 @@ xfs_rtginode_ensure(
        return xfs_rtginode_create(rtg, type, true);
 }
 
-/* Add rtgroups as needed to deal with this phase of rt expansion. */
-STATIC int
-xfs_growfsrt_alloc_rtgroups(
-       struct xfs_mount        *mp,
-       xfs_rgnumber_t          last_rgno,
-       struct xfs_mount        *nmp)
-{
-       struct xfs_sb           *nsbp = &nmp->m_sb;
-       struct xfs_rtgroup      *rtg;
-       struct xfs_trans        *tp;
-       int                     error;
-
-       /* Make sure the /rtgroups dir has been created */
-       if (!mp->m_rtdirip) {
-               error = xfs_trans_alloc_empty(mp, &tp);
-               if (error)
-                       return error;
-
-               error = xfs_rtginode_load_parent(tp);
-               xfs_trans_cancel(tp);
-               switch (error) {
-               case 0:
-                       break;
-               case -ENOENT:
-                       error = xfs_rtginode_mkdir_parent(mp);
-                       if (error)
-                               return error;
-                       break;
-               default:
-                       return error;
-               }
-       }
-
-       nsbp->sb_rgcount = howmany_64(nsbp->sb_rextents, nsbp->sb_rgextents);
-       error = xfs_initialize_rtgroups(mp, nsbp->sb_rgcount);
-       if (error)
-               return error;
-
-       for_each_rtgroup_range(mp, last_rgno, nsbp->sb_rgcount, rtg) {
-               error = xfs_rtginode_ensure(rtg, XFS_RTG_RMAP);
-               if (error) {
-                       xfs_rtgroup_rele(rtg);
-                       return error;
-               }
-
-               error = xfs_rtginode_ensure(rtg, XFS_RTG_REFCOUNT);
-               if (error) {
-                       xfs_rtgroup_rele(rtg);
-                       return error;
-               }
-       }
-
-       return 0;
-}
-
-/* Remove excess rtgroups after a grow failed. */
-STATIC void
-xfs_growfsrt_free_rtgroups(
-       struct xfs_mount        *mp,
-       struct xfs_mount        *nmp)
-{
-       struct xfs_rtgroup      *rtg;
-       xfs_rgnumber_t          rgno = mp->m_sb.sb_rgcount + 1;
-       unsigned int            i;
-
-       for_each_rtgroup_range(mp, rgno, nmp->m_sb.sb_rgcount, rtg) {
-               for (i = 0; i < XFS_RTG_MAX; i++)
-                       xfs_rtginode_irele(&rtg->rtg_inodes[i]);
-       }
-
-       xfs_free_unused_rtgroup_range(mp, mp->m_sb.sb_rgcount + 1,
-                       nmp->m_sb.sb_rgcount);
-}
-
 /* Free all the new space and return the number of extents actually freed. */
 static int
 xfs_growfs_rt_free_new(
-       struct xfs_mount        *mp,
+       struct xfs_rtgroup      *rtg,
        struct xfs_rtalloc_args *nargs,
        xfs_rtbxlen_t           *freed_rtx)
 {
-       struct xfs_mount        *nmp = nargs->mp;
-       struct xfs_sb           *sbp = &mp->m_sb;
-       struct xfs_sb           *nsbp = &nmp->m_sb;
-       xfs_rtxnum_t            start_rtx = sbp->sb_rextents;
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       xfs_rgnumber_t          rgno = rtg->rtg_rgno;
+       xfs_rtxnum_t            start_rtx = 0, end_rtx;
+
+       if (rgno < mp->m_sb.sb_rgcount)
+               start_rtx = xfs_rtgroup_extents(mp, rgno);
+       end_rtx = xfs_rtgroup_extents(nargs->mp, rgno);
 
        /*
         * Compute the first new extent that we want to free, being careful to
         * skip past a realtime superblock at the start of the realtime volume.
         */
-       if (xfs_has_rtsb(mp) && start_rtx == 0)
+       if (xfs_has_rtsb(mp) && rgno == 0 && start_rtx == 0)
                start_rtx++;
-
-       *freed_rtx = nsbp->sb_rextents - start_rtx;
+       *freed_rtx = end_rtx - start_rtx;
        return xfs_rtfree_range(nargs, start_rtx, *freed_rtx);
 }
 
@@ -867,11 +726,12 @@ xfs_rt_compute_geometry(
        mp->m_sb.sb_rblocks = rblocks;
        mp->m_sb.sb_rextsize = rextsize;
        mp->m_sb.sb_rextents = div_u64(rblocks, rextsize);
-       mp->m_sb.sb_rbmblocks =
-               xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
+       mp->m_sb.sb_rbmblocks = xfs_rtbitmap_blockcount(mp);
        mp->m_sb.sb_rextslog = xfs_compute_rextslog(mp->m_sb.sb_rextents);
+       mp->m_sb.sb_rgcount =
+               howmany_64(mp->m_sb.sb_rextents, mp->m_sb.sb_rgextents);
 
-       mp->m_rsumlevels =  mp->m_sb.sb_rextslog + 1;
+       mp->m_rsumlevels = xfs_compute_rsumlevels(mp, mp->m_sb.sb_rextents);
        mp->m_rsumsize = XFS_FSB_TO_B(mp,
                xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
                                mp->m_sb.sb_rbmblocks));
@@ -879,53 +739,52 @@ xfs_rt_compute_geometry(
 
 static int
 xfs_growfs_rt_bmblock(
-       struct xfs_mount        *mp,
+       struct xfs_rtgroup      *rtg,
        xfs_rfsblock_t          nrblocks,
        xfs_agblock_t           rextsize,
        xfs_fileoff_t           bmbno)
 {
-       struct xfs_inode        *rbmip = mp->m_rbmip;
-       struct xfs_inode        *rsumip = mp->m_rsumip;
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       struct xfs_inode        *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+       struct xfs_inode        *rsumip = rtg->rtg_inodes[XFS_RTG_SUMMARY];
        struct xfs_rtalloc_args args = {
                .mp             = mp,
+               .rtg            = rtg,
        };
        struct xfs_rtalloc_args nargs = {
+               .rtg            = rtg,
        };
        struct xfs_mount        *nmp;
-       struct xfs_rtgroup      *rtg;
+       xfs_rtbxlen_t           freed_rtx = 0;
        xfs_rfsblock_t          nrblocks_step;
-       xfs_rtbxlen_t           freed_rtx;
-       xfs_rgnumber_t          last_rgno = mp->m_sb.sb_rgcount - 1;
        int                     error;
 
-       nrblocks_step = (bmbno + 1) * mp->m_rtx_per_rbmblock * rextsize;
+       nrblocks_step = rtg->rtg_rgno * mp->m_rgblocks +
+               min(mp->m_rgblocks,
+                   (bmbno + 1) * mp->m_rtx_per_rbmblock * rextsize);
 
        nmp = nargs.mp = kmemdup(mp, sizeof(*mp), GFP_KERNEL);
        if (!nmp)
                return -ENOMEM;
 
        /*
-        * Calculate new sb and mount fields for this round.
+        * Calculate new sb and mount fields for this round.  Also ensure the
+        * rtg_extents value is uptodate as the rtbitmap code relies on it.
         */
        xfs_rt_compute_geometry(nmp, min(nrblocks, nrblocks_step), rextsize);
+       rtg->rtg_extents = xfs_rtgroup_extents(nmp, rtg->rtg_rgno);
 
        /* recompute growfsrt reservation from new rsumsize */
        xfs_trans_resv_calc(nmp, &nmp->m_resv);
 
-       if (xfs_has_rtgroups(mp)) {
-               error = xfs_growfsrt_alloc_rtgroups(mp, last_rgno, nmp);
-               if (error)
-                       goto out_free;
-       }
-
        error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtfree, 0, 0, 0,
                        &args.tp);
        if (error)
                goto out_free;
        nargs.tp = args.tp;
 
-       xfs_rtbitmap_lock(mp);
-       xfs_rtbitmap_trans_join(args.tp);
+       xfs_rtgroup_lock(args.rtg, XFS_RTGLOCK_BITMAP);
+       xfs_rtgroup_trans_join(args.tp, args.rtg, XFS_RTGLOCK_BITMAP);
 
        /*
         * Update the bitmap inode's size ondisk and incore.  We need to update
@@ -981,8 +840,7 @@ xfs_growfs_rt_bmblock(
        /*
         * Free the new extent.
         */
-       freed_rtx = nmp->m_sb.sb_rextents - mp->m_sb.sb_rextents;
-       error = xfs_growfs_rt_free_new(mp, &nargs, &freed_rtx);
+       error = xfs_growfs_rt_free_new(rtg, &nargs, &freed_rtx);
        xfs_rtbuf_cache_relse(&nargs);
        if (error)
                goto out_cancel;
@@ -1007,10 +865,6 @@ xfs_growfs_rt_bmblock(
        if (error)
                goto out_free;
 
-       for_each_rtgroup_from(mp, last_rgno, rtg)
-               rtg->rtg_blockcount =
-                               xfs_rtgroup_block_count(mp, rtg->rtg_rgno);
-
        /*
         * Ensure the mount RT feature flag is now set, and compute new
         * maxlevels for rt btrees.
@@ -1025,8 +879,6 @@ xfs_growfs_rt_bmblock(
 out_cancel:
        xfs_trans_cancel(args.tp);
 out_free:
-       if (xfs_has_rtgroups(mp))
-               xfs_growfsrt_free_rtgroups(mp, nmp);
        kfree(nmp);
        return error;
 }
@@ -1038,13 +890,22 @@ out_free:
  */
 static xfs_fileoff_t
 xfs_last_rt_bmblock(
-       struct xfs_mount        *mp)
+       struct xfs_rtgroup      *rtg)
 {
-       xfs_fileoff_t           bmbno = mp->m_sb.sb_rbmblocks;
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       xfs_rgnumber_t          rgno = rtg->rtg_rgno;
+       xfs_fileoff_t           bmbno = 0;
+
+       ASSERT(rgno >= mp->m_sb.sb_rgcount - 1);
+       if (rgno == mp->m_sb.sb_rgcount - 1) {
+               xfs_rtxnum_t    nrext = xfs_rtgroup_extents(mp, rgno);
+
+               /* Skip the current block if it is exactly full. */
+               bmbno = __xfs_rtbitmap_blockcount(mp, nrext);
+               if (xfs_rtx_to_rbmword(mp, nrext) != 0)
+                       bmbno--;
+       }
 
-       /* Skip the current block if it is exactly full. */
-       if (xfs_rtx_to_rbmword(mp, mp->m_sb.sb_rextents) != 0)
-               bmbno--;
        return bmbno;
 }
 
@@ -1070,6 +931,102 @@ xfs_growfs_rt_init_super(
        return error;
 }
 
+/*
+ * Allocate space to the bitmap and summary files, as necessary.
+ */
+static int
+xfs_growfs_rt_alloc_blocks(
+       struct xfs_rtgroup      *rtg,
+       xfs_rfsblock_t          nrblocks,
+       xfs_agblock_t           rextsize,
+       xfs_extlen_t            *nrbmblocks)
+{
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       struct xfs_inode        *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+       struct xfs_inode        *rsumip = rtg->rtg_inodes[XFS_RTG_SUMMARY];
+       xfs_rtxnum_t            nrextents = div_u64(nrblocks, rextsize);
+       xfs_extlen_t            orbmblocks;
+       xfs_extlen_t            orsumblocks;
+       xfs_extlen_t            nrsumblocks;
+       int                     error;
+
+       if (xfs_has_rtgroups(mp)) {
+               /*
+                * For file systems with the rtgroups feature, the RT bitmap and
+                * summary are always fully allocated, which means that we never
+                * need to grow the existing files.
+                */
+               *nrbmblocks = mp->m_sb.sb_rbmblocks;
+               if (rtg->rtg_rgno <= mp->m_sb.sb_rgcount - 1)
+                       return 0;
+               orbmblocks = 0;
+               orsumblocks = 0;
+               nrsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumsize);
+       } else {
+               /*
+                * Get the old block counts for bitmap and summary inodes.
+                * These can't change since other growfs callers are locked out.
+                */
+               orbmblocks = XFS_B_TO_FSB(mp, rbmip->i_disk_size);
+               orsumblocks = XFS_B_TO_FSB(mp, rsumip->i_disk_size);
+
+               *nrbmblocks = __xfs_rtbitmap_blockcount(mp, nrextents);
+               nrsumblocks = xfs_rtsummary_blockcount(mp,
+                       xfs_compute_rsumlevels(mp, nrextents), *nrbmblocks);
+       }
+
+       error = xfs_rtfile_initialize_blocks(rtg, XFS_RTG_BITMAP, orbmblocks,
+                       *nrbmblocks, NULL);
+       if (error)
+               return error;
+       return xfs_rtfile_initialize_blocks(rtg, XFS_RTG_SUMMARY, orsumblocks,
+                       nrsumblocks, NULL);
+}
+
+static int
+xfs_growfs_rtg(
+       struct xfs_rtgroup      *rtg,
+       xfs_rfsblock_t          nrblocks,
+       xfs_agblock_t           rextsize)
+{
+       uint8_t                 *old_rsum_cache = NULL;
+       xfs_extlen_t            bmblocks;
+       xfs_fileoff_t           bmbno;
+       int                     error;
+
+       error = xfs_growfs_rt_alloc_blocks(rtg, nrblocks, rextsize, &bmblocks);
+       if (error)
+               return error;
+
+       if (bmblocks != rtg->rtg_mount->m_sb.sb_rbmblocks) {
+               old_rsum_cache = rtg->rtg_rsum_cache;
+               error = xfs_alloc_rsum_cache(rtg, bmblocks);
+               if (error)
+                       return error;
+       }
+
+       for (bmbno = xfs_last_rt_bmblock(rtg); bmbno < bmblocks; bmbno++) {
+               error = xfs_growfs_rt_bmblock(rtg, nrblocks, rextsize, bmbno);
+               if (error)
+                       goto out_error;
+       }
+
+       if (old_rsum_cache)
+               kvfree(old_rsum_cache);
+       return 0;
+
+out_error:
+       /*
+        * Reset rtg_extents to the old value if adding more blocks failed.
+        */
+       rtg->rtg_extents = xfs_rtgroup_extents(rtg->rtg_mount, rtg->rtg_rgno);
+       if (old_rsum_cache) {
+               kvfree(rtg->rtg_rsum_cache);
+               rtg->rtg_rsum_cache = old_rsum_cache;
+       }
+       return error;
+}
+
 /*
  * Check that changes to the realtime geometry won't affect the minimum
  * log size, which would cause the fs to become unusable.
@@ -1124,18 +1081,17 @@ xfs_growfs_check_rtgeom(
  */
 int
 xfs_growfs_rt(
-       xfs_mount_t     *mp,            /* mount point for filesystem */
-       xfs_growfs_rt_t *in)            /* growfs rt input struct */
+       struct xfs_mount        *mp,
+       struct xfs_growfs_rt    *in)
 {
-       xfs_fileoff_t   bmbno;          /* bitmap block number */
-       struct xfs_buf  *bp;            /* temporary buffer */
-       int             error;          /* error return value */
-       xfs_extlen_t    nrbmblocks;     /* new number of rt bitmap blocks */
-       xfs_rtxnum_t    nrextents;      /* new number of realtime extents */
-       xfs_extlen_t    nrsumblocks;    /* new number of summary blocks */
-       xfs_extlen_t    rbmblocks;      /* current number of rt bitmap blocks */
-       xfs_extlen_t    rsumblocks;     /* current number of rt summary blks */
-       uint8_t         *rsum_cache;    /* old summary cache */
+       xfs_rgnumber_t          last_rgno = mp->m_sb.sb_rgcount - 1;
+       unsigned int            new_rgcount = 1;
+       xfs_rtxnum_t            nrextents;
+       struct xfs_rtgroup      *rtg;
+       xfs_rgnumber_t          rgno;
+       struct xfs_buf          *bp;
+       int                     error;  
+       unsigned int            i;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1143,12 +1099,6 @@ xfs_growfs_rt(
        /* Needs to have been mounted with an rt device. */
        if (!XFS_IS_REALTIME_MOUNT(mp))
                return -EINVAL;
-       /*
-        * Mount should fail if the rt bitmap/summary files don't load, but
-        * we'll check anyway.
-        */
-       if (!mp->m_rbmip || !mp->m_rsumip)
-               return -EINVAL;
 
        /* Shrink not supported. */
        if (in->newblocks <= mp->m_sb.sb_rblocks)
@@ -1190,9 +1140,6 @@ xfs_growfs_rt(
        nrextents = div_u64(in->newblocks, in->extsize);
        if (nrextents == 0)
                return -EINVAL;
-       nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents);
-       nrsumblocks = xfs_rtsummary_blockcount(mp,
-                       xfs_compute_rextslog(nrextents) + 1, nrbmblocks);
 
        /* Make sure the new fs size won't cause problems with the log. */
        error = xfs_growfs_check_rtgeom(mp, mp->m_sb.sb_dblocks, in->newblocks,
@@ -1206,51 +1153,63 @@ xfs_growfs_rt(
         * because the userspace ABI doesn't support it.
         */
        if (xfs_has_rtgroups(mp)) {
-               uint64_t        new_rgcount;
-
                new_rgcount = howmany_64(nrextents, mp->m_sb.sb_rgextents);
                if (new_rgcount > XFS_MAX_RGNUMBER)
                        return -EINVAL;
-       }
 
-       /* Set up the realtime superblock if we're adding a new rt section. */
-       if (xfs_has_rtsb(mp) && mp->m_sb.sb_rblocks == 0) {
-               error = xfs_growfs_rt_init_super(mp);
-               if (error)
-                       return error;
+               /*
+                * Set up the realtime superblock if we're adding a new rt
+                * section.
+                */
+               if (xfs_has_rtsb(mp) && mp->m_sb.sb_rblocks == 0) {
+                       error = xfs_growfs_rt_init_super(mp);
+                       if (error)
+                               return error;
+               }
+
+               /* Make sure the /rtgroups dir has been created */
+               if (!mp->m_rtdirip) {
+                       struct xfs_trans        *tp;
+
+                       error = xfs_trans_alloc_empty(mp, &tp);
+                       if (error)
+                               return error;
+                       error = xfs_rtginode_load_parent(tp);
+                       xfs_trans_cancel(tp);
+
+                       if (error == -ENOENT)
+                               error = xfs_rtginode_mkdir_parent(mp);
+                       if (error)
+                               return error;
+               }
        }
 
-       /*
-        * Get the old block counts for bitmap and summary inodes.
-        * These can't change since other growfs callers are locked out.
-        */
-       rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_disk_size);
-       rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_disk_size);
-       /*
-        * Allocate space to the bitmap and summary files, as necessary.
-        */
-       error = xfs_rtfile_initialize_blocks(mp->m_rbmip, rbmblocks,
-                       nrbmblocks, NULL);
-       if (error)
-               return error;
-       error = xfs_rtfile_initialize_blocks(mp->m_rsumip, rsumblocks,
-                       nrsumblocks, NULL);
+       error = xfs_initialize_rtgroups(mp, new_rgcount);
        if (error)
                return error;
 
-       rsum_cache = mp->m_rsum_cache;
-       if (nrbmblocks != mp->m_sb.sb_rbmblocks) {
-               error = xfs_alloc_rsum_cache(mp, nrbmblocks);
-               if (error)
-                       return error;
-       }
+       /*
+        * If the last RT group is completely full we can skip it.
+        */
+       if (xfs_rtgroup_extents(mp, last_rgno) == mp->m_sb.sb_rgextents)
+               last_rgno++;
 
-       /* Initialize the free space bitmap one bitmap block at a time. */
-       for (bmbno = xfs_last_rt_bmblock(mp); bmbno < nrbmblocks; bmbno++) {
-               error = xfs_growfs_rt_bmblock(mp, in->newblocks, in->extsize,
-                               bmbno);
-               if (error)
+       for_each_rtgroup_range(mp, last_rgno, new_rgcount - 1, rtg) {
+               unsigned int    i;
+
+               for (i = 0; i < XFS_RTG_MAX; i++) {
+                       error = xfs_rtginode_ensure(rtg, i);
+                       if (error) {
+                               xfs_rtgroup_rele(rtg);
+                               goto out_free;
+                       }
+               }
+
+               error = xfs_growfs_rtg(rtg, in->newblocks, in->extsize);
+               if (error) {
+                       xfs_rtgroup_rele(rtg);
                        goto out_free;
+               }
        }
 
        /* Update secondary superblocks now the physical grow has completed */
@@ -1263,22 +1222,20 @@ xfs_growfs_rt(
        error = xfs_rt_resv_init(mp);
        if (error == -ENOSPC)
                error = 0;
+       if (error)
+               goto out_free;
+
+       return 0;
 
 out_free:
-       /*
-        * If we had to allocate a new rsum_cache, we either need to free the
-        * old one (if we succeeded) or free the new one and restore the old one
-        * (if there was an error).
-        */
-       if (rsum_cache != mp->m_rsum_cache) {
-               if (error) {
-                       kvfree(mp->m_rsum_cache);
-                       mp->m_rsum_cache = rsum_cache;
-               } else {
-                       kvfree(rsum_cache);
-               }
+       rgno = mp->m_sb.sb_rgcount + 1;
+       for_each_rtgroup_range(mp, rgno, new_rgcount - 1, rtg) {
+               for (i = 0; i < XFS_RTG_MAX; i++)
+                       xfs_rtginode_irele(&rtg->rtg_inodes[i]);
        }
 
+       xfs_free_unused_rtgroup_range(mp, mp->m_sb.sb_rgcount + 1,
+                       new_rgcount - 1);
        return error;
 }
 
@@ -1353,11 +1310,11 @@ xfs_rtmount_init(
        "Filesystem has a realtime volume, use rtdev=device option");
                return -ENODEV;
        }
-       mp->m_rsumlevels = sbp->sb_rextslog + 1;
+       mp->m_rsumlevels = xfs_compute_rsumlevels(mp, sbp->sb_rextents);
        rsumblocks = xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
                        mp->m_sb.sb_rbmblocks);
        mp->m_rsumsize = XFS_FSB_TO_B(mp, rsumblocks);
-       mp->m_rbmip = mp->m_rsumip = NULL;
+
        /*
         * Check that the realtime section is an ok size.
         */
@@ -1381,7 +1338,7 @@ xfs_rtmount_init(
 
 static int
 xfs_rtalloc_count_frextent(
-       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg,
        struct xfs_trans                *tp,
        const struct xfs_rtalloc_rec    *rec,
        void                            *priv)
@@ -1403,12 +1360,17 @@ xfs_rtalloc_reinit_frextents(
        uint64_t                val = 0;
        int                     error;
 
-       xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
-       error = xfs_rtalloc_query_all(mp, NULL, xfs_rtalloc_count_frextent,
-                       &val);
-       xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
-       if (error)
-               return error;
+       struct xfs_rtgroup      *rtg;
+       xfs_rgnumber_t          rgno;
+
+       for_each_rtgroup(mp, rgno, rtg) {
+               xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+               error = xfs_rtalloc_query_all(rtg, NULL, xfs_rtalloc_count_frextent,
+                               &val);
+               xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED);
+               if (error)
+                       return error;
+       }
 
        spin_lock(&mp->m_sb_lock);
        mp->m_sb.sb_frextents = val;
@@ -1466,7 +1428,7 @@ xfs_rt_resv_init(
  * at runtime.  This enables the use of shared ILOCKs for rtbitmap scans.  Use
  * an empty transaction to avoid deadlocking on loops in the bmbt.
  */
-static inline int
+static int
 xfs_rtmount_iread_extents(
        struct xfs_trans        *tp,
        struct xfs_inode        *ip)
@@ -1475,9 +1437,13 @@ xfs_rtmount_iread_extents(
 
        xfs_ilock(ip, XFS_ILOCK_EXCL);
 
-       error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
-       if (error)
-               goto out_unlock;
+       /* No need to read the data for btree inodes */
+       if (ip->i_df.if_format != XFS_DINODE_FMT_RMAP &&
+           ip->i_df.if_format != XFS_DINODE_FMT_REFCOUNT) {
+               error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
+               if (error)
+                       goto out_unlock;
+       }
 
        if (xfs_inode_has_attr_fork(ip)) {
                error = xfs_iread_extents(tp, ip, XFS_ATTR_FORK);
@@ -1490,18 +1456,31 @@ out_unlock:
        return error;
 }
 
-static void
-xfs_rtgroup_unmount_inodes(
-       struct xfs_mount        *mp)
+static int
+xfs_rtmount_rtg(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_rtgroup      *rtg)
 {
-       struct xfs_rtgroup      *rtg;
-       xfs_rgnumber_t          rgno;
-       unsigned int            i;
+       int                     error, i;
 
-       for_each_rtgroup(mp, rgno, rtg) {
-               for (i = 0; i < XFS_RTG_MAX; i++)
-                       xfs_rtginode_irele(&rtg->rtg_inodes[i]);
+       rtg->rtg_extents = xfs_rtgroup_extents(mp, rtg->rtg_rgno);
+
+       for (i = 0; i < XFS_RTG_MAX; i++) {
+               error = xfs_rtginode_load(rtg, i, tp);
+               if (error)
+                       return error;
+
+               if (rtg->rtg_inodes[i]) {
+                       error = xfs_rtmount_iread_extents(tp,
+                                       rtg->rtg_inodes[i]);
+                       if (error)
+                               return error;
+               }
        }
+
+       xfs_alloc_rsum_cache(rtg, mp->m_sb.sb_rbmblocks);
+       return 0;
 }
 
 /*
@@ -1513,76 +1492,30 @@ xfs_rtmount_inodes(
        struct xfs_mount        *mp)
 {
        struct xfs_trans        *tp;
-       struct xfs_sb           *sbp = &mp->m_sb;
        struct xfs_rtgroup      *rtg;
        xfs_rgnumber_t          rgno;
-       unsigned int            i;
        int                     error;
 
        error = xfs_trans_alloc_empty(mp, &tp);
        if (error)
                return error;
 
-       error = xfs_metafile_iget(tp, mp->m_sb.sb_rbmino, S_IFREG, &mp->m_rbmip);
-       if (xfs_metadata_is_sick(error))
-               xfs_rt_mark_sick(mp, XFS_SICK_RT_BITMAP);
-       if (error)
-               goto out_trans;
-       ASSERT(mp->m_rbmip != NULL);
-
-       lockdep_set_class(&mp->m_rbmip->i_lock, &xfs_rtbitmap_key);
-
-       error = xfs_rtmount_iread_extents(tp, mp->m_rbmip);
-       if (error)
-               goto out_rele_bitmap;
-
-       error = xfs_metafile_iget(tp, mp->m_sb.sb_rsumino, S_IFREG, &mp->m_rsumip);
-       if (xfs_metadata_is_sick(error))
-               xfs_rt_mark_sick(mp, XFS_SICK_RT_SUMMARY);
-       if (error)
-               goto out_rele_bitmap;
-       ASSERT(mp->m_rsumip != NULL);
-
-       lockdep_set_class(&mp->m_rsumip->i_lock, &xfs_rtsummary_key);
-
-       error = xfs_rtmount_iread_extents(tp, mp->m_rsumip);
-       if (error)
-               goto out_rele_summary;
-
        if (xfs_has_rtgroups(mp) && mp->m_sb.sb_rgcount > 0) {
                error = xfs_rtginode_load_parent(tp);
                if (error)
-                       goto out_rele_rtdir;
+                       goto out_cancel;
        }
 
        for_each_rtgroup(mp, rgno, rtg) {
-               rtg->rtg_blockcount = xfs_rtgroup_block_count(mp,
-                                                             rtg->rtg_rgno);
-
-               for (i = 0; i < XFS_RTG_MAX; i++) {
-                       error = xfs_rtginode_load(rtg, i, tp);
-                       if (error) {
-                               xfs_rtgroup_rele(rtg);
-                               goto out_rele_inodes;
-                       }
+               error = xfs_rtmount_rtg(mp, tp, rtg);
+               if (error) {
+                       xfs_rtgroup_rele(rtg);
+                       xfs_rtunmount_inodes(mp);
+                       break;
                }
        }
 
-       error = xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
-       if (error)
-               goto out_rele_summary;
-       xfs_trans_cancel(tp);
-       return 0;
-
-out_rele_inodes:
-       xfs_rtgroup_unmount_inodes(mp);
-out_rele_rtdir:
-       xfs_rtginode_irele(&mp->m_rtdirip);
-out_rele_summary:
-       xfs_irele(mp->m_rsumip);
-out_rele_bitmap:
-       xfs_irele(mp->m_rbmip);
-out_trans:
+out_cancel:
        xfs_trans_cancel(tp);
        return error;
 }
@@ -1591,14 +1524,17 @@ void
 xfs_rtunmount_inodes(
        struct xfs_mount        *mp)
 {
-       kvfree(mp->m_rsum_cache);
+       struct xfs_rtgroup      *rtg;
+       xfs_rgnumber_t          rgno;
+       int                     i;
+
+       for_each_rtgroup(mp, rgno, rtg) {
+               for (i = 0; i < XFS_RTG_MAX; i++)
+                       xfs_rtginode_irele(&rtg->rtg_inodes[i]);
+               kvfree(rtg->rtg_rsum_cache);
+       }
 
-       xfs_rtgroup_unmount_inodes(mp);
        xfs_rtginode_irele(&mp->m_rtdirip);
-       if (mp->m_rbmip)
-               xfs_irele(mp->m_rbmip);
-       if (mp->m_rsumip)
-               xfs_irele(mp->m_rsumip);
 }
 
 /*
@@ -1610,37 +1546,29 @@ xfs_rtunmount_inodes(
  */
 static xfs_rtxnum_t
 xfs_rtpick_extent(
-       xfs_mount_t             *mp,            /* file system mount point */
-       xfs_trans_t             *tp,            /* transaction pointer */
+       struct xfs_trans        *tp,
+       struct xfs_rtgroup      *rtg,
        xfs_rtxlen_t            len)            /* allocation length (rtextents) */
 {
-       xfs_rtxnum_t            b;              /* result rtext */
+       struct xfs_mount        *mp = rtg->rtg_mount;
+       struct xfs_inode        *rbmip = rtg->rtg_inodes[XFS_RTG_BITMAP];
+       xfs_rtxnum_t            b = 0;          /* result rtext */
        int                     log2;           /* log of sequence number */
        uint64_t                resid;          /* residual after log removed */
        uint64_t                seq;            /* sequence number of file creation */
        struct timespec64       ts;             /* timespec in inode */
 
-       xfs_assert_ilocked(mp->m_rbmip, XFS_ILOCK_EXCL);
-
-       if (xfs_has_rtgroups(mp)) {
-               xfs_rtblock_t   rtbno;
-
-               /* Pick the first usable rtx of the group. */
-               rtbno = xfs_rgbno_to_rtb(mp, mp->m_rtgrotor, 0);
-               mp->m_rtgrotor = (mp->m_rtgrotor + 1) % mp->m_sb.sb_rgcount;
-               return xfs_rtb_to_rtx(mp, rtbno) + 1;
-       }
+       xfs_assert_ilocked(rbmip, XFS_ILOCK_EXCL);
 
-       ts = inode_get_atime(VFS_I(mp->m_rbmip));
-       if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) {
-               mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
+       ts = inode_get_atime(VFS_I(rbmip));
+       if (!(rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) {
+               rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
                seq = 0;
        } else {
                seq = ts.tv_sec;
        }
-       if ((log2 = xfs_highbit64(seq)) == -1)
-               b = 0;
-       else {
+       log2 = xfs_highbit64(seq);
+       if (log2 != -1) {
                resid = seq - (1ULL << log2);
                b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >>
                    (log2 + 1);
@@ -1650,8 +1578,8 @@ xfs_rtpick_extent(
                        b = mp->m_sb.sb_rextents - len;
        }
        ts.tv_sec = seq + 1;
-       inode_set_atime_to_ts(VFS_I(mp->m_rbmip), ts);
-       xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
+       inode_set_atime_to_ts(VFS_I(rbmip), ts);
+       xfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE);
        return b;
 }
 
@@ -1685,9 +1613,10 @@ xfs_rtalloc_align_minmax(
 }
 
 static int
-xfs_rtallocate(
+xfs_rtallocate_rtg(
        struct xfs_trans        *tp,
-       xfs_rtxnum_t            start,
+       xfs_rgnumber_t          rgno,
+       xfs_fsblock_t           bno_hint,
        xfs_rtxlen_t            minlen,
        xfs_rtxlen_t            maxlen,
        xfs_rtxlen_t            prod,
@@ -1701,16 +1630,38 @@ xfs_rtallocate(
                .mp             = tp->t_mountp,
                .tp             = tp,
        };
+       xfs_rtxnum_t            start = 0;
        xfs_rtxnum_t            rtx;
        xfs_rtxlen_t            len = 0;
        int                     error = 0;
 
+       args.rtg = xfs_rtgroup_grab(args.mp, rgno);
+       if (!args.rtg)
+               return -ENOSPC;
+
        /*
-        * Lock out modifications to both the RT bitmap and summary inodes.
+        * We need to lock out modifications to both the RT bitmap and summary
+        * inodes for finding free space in xfs_rtallocate_extent_{near,size}
+        * and join the bitmap and summary inodes for the actual allocation
+        * down in xfs_rtallocate_range.
+        *
+        * For RTG-enabled file system we don't want to join the inodes to the
+        * transaction until we are committed to allocate to allocate from this
+        * RTG so that only one inode of each type is locked at a time.
+        *
+        * But for pre-RTG file systems we need to already to join the bitmap
+        * inode to the transaction for xfs_rtpick_extent, which bumps the
+        * sequence number in it, so we'll have to join the inode to the
+        * transaction early here.
+        *
+        * This is all a bit messy, but at least the mess is contained in
+        * this function.
         */
        if (!*rtlocked) {
-               xfs_rtbitmap_lock(args.mp);
-               xfs_rtbitmap_trans_join(tp);
+               xfs_rtgroup_lock(args.rtg, XFS_RTGLOCK_BITMAP);
+               if (!xfs_has_rtgroups(args.mp))
+                       xfs_rtgroup_trans_join(tp, args.rtg,
+                                       XFS_RTGLOCK_BITMAP);
                *rtlocked = true;
        }
 
@@ -1718,8 +1669,10 @@ xfs_rtallocate(
         * For an allocation to an empty file at offset 0, pick an extent that
         * will space things out in the rt area.
         */
-       if (!start && initial_user_data)
-               start = xfs_rtpick_extent(args.mp, tp, maxlen);
+       if (bno_hint)
+               start = xfs_rtb_to_rtx(args.mp, bno_hint);
+       else if (!xfs_has_rtgroups(args.mp) && initial_user_data)
+               start = xfs_rtpick_extent(tp, args.rtg, maxlen);
 
        if (start) {
                error = xfs_rtallocate_extent_near(&args, start, minlen, maxlen,
@@ -1739,8 +1692,16 @@ xfs_rtallocate(
                                prod, &rtx);
        }
 
-       if (error)
+       if (error) {
+               if (xfs_has_rtgroups(args.mp)) {
+                       xfs_rtgroup_unlock(args.rtg, XFS_RTGLOCK_BITMAP);
+                       *rtlocked = false;
+               }
                goto out_release;
+       }
+
+       if (xfs_has_rtgroups(args.mp))
+               xfs_rtgroup_trans_join(tp, args.rtg, XFS_RTGLOCK_BITMAP);
 
        error = xfs_rtallocate_range(&args, rtx, len);
        if (error)
@@ -1749,14 +1710,62 @@ xfs_rtallocate(
        xfs_trans_mod_sb(tp, wasdel ?
                        XFS_TRANS_SB_RES_FREXTENTS : XFS_TRANS_SB_FREXTENTS,
                        -(long)len);
-       *bno = xfs_rtx_to_rtb(args.mp, rtx);
+       *bno = xfs_rtx_to_rtb(args.rtg, rtx);
        *blen = xfs_rtxlen_to_extlen(args.mp, len);
 
 out_release:
+       xfs_rtgroup_rele(args.rtg);
        xfs_rtbuf_cache_relse(&args);
        return error;
 }
 
+int
+xfs_rtallocate_rtgs(
+       struct xfs_trans        *tp,
+       xfs_fsblock_t           bno_hint,
+       xfs_rtxlen_t            minlen,
+       xfs_rtxlen_t            maxlen,
+       xfs_rtxlen_t            prod,
+       bool                    wasdel,
+       bool                    initial_user_data,
+       xfs_rtblock_t           *bno,
+       xfs_extlen_t            *blen)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       xfs_rgnumber_t          start_rgno, rgno;
+       int                     error;
+
+       /*
+        * For now this just blindly iterates over the RTGs for an initial
+        * allocation.  We could try to keep an in-memory rtg_longest member
+        * to avoid the locking when just looking for big enough free space,
+        * but for now this keep things simple.
+        */
+       if (bno_hint != NULLFSBLOCK)
+               start_rgno = xfs_rtb_to_rgno(mp, bno_hint);
+       else
+               start_rgno = (atomic_inc_return(&mp->m_rtgrotor) - 1) %
+                               mp->m_sb.sb_rgcount;
+
+       rgno = start_rgno;
+       do {
+               bool            rtlocked = false;
+
+               error = xfs_rtallocate_rtg(tp, rgno, bno_hint, minlen, maxlen,
+                               prod, wasdel, initial_user_data, &rtlocked,
+                               bno, blen);
+               if (error != -ENOSPC)
+                       return error;
+               ASSERT(!rtlocked);
+
+               if (++rgno == mp->m_sb.sb_rgcount)
+                       rgno = 0;
+               bno_hint = NULLFSBLOCK;
+       } while (rgno != start_rgno);
+
+       return -ENOSPC;
+}
+
 static int
 xfs_rtallocate_align(
        struct xfs_bmalloca     *ap,
@@ -1836,13 +1845,15 @@ xfs_bmap_rtalloc(
 {
        struct xfs_mount        *mp = ap->ip->i_mount;
        xfs_fileoff_t           orig_offset = ap->offset;
-       xfs_rtxnum_t            start = 0; /* allocation hint rtextent no */
        xfs_rtxlen_t            prod = 0;  /* product factor for allocators */
        xfs_rtxlen_t            ralen = 0; /* realtime allocation length */
+       xfs_fsblock_t           bno_hint = NULLFSBLOCK;
        xfs_extlen_t            orig_length = ap->length;
        xfs_rtxlen_t            raminlen;
        bool                    rtlocked = false;
        bool                    noalign = false;
+       bool                    initial_user_data =
+               ap->datatype & XFS_ALLOC_INITIAL_USER_DATA;
        int                     error;
 
 retry:
@@ -1851,11 +1862,18 @@ retry:
                return error;
 
        if (xfs_bmap_adjacent(ap))
-               start = xfs_rtb_to_rtx(mp, ap->blkno);
+               bno_hint = ap->blkno;
+
+       if (xfs_has_rtgroups(mp)) {
+               error = xfs_rtallocate_rtgs(ap->tp, bno_hint, raminlen, ralen,
+                               prod, ap->wasdel, initial_user_data,
+                               &ap->blkno, &ap->length);
+       } else {
+               error = xfs_rtallocate_rtg(ap->tp, 0, bno_hint, raminlen, ralen,
+                               prod, ap->wasdel, initial_user_data,
+                               &rtlocked, &ap->blkno, &ap->length);
+       }
 
-       error = xfs_rtallocate(ap->tp, start, raminlen, ralen, prod, ap->wasdel,
-                       ap->datatype & XFS_ALLOC_INITIAL_USER_DATA, &rtlocked,
-                       &ap->blkno, &ap->length);
        if (error == -ENOSPC) {
                if (!noalign) {
                        /*
@@ -1881,52 +1899,3 @@ retry:
        xfs_bmap_alloc_account(ap);
        return 0;
 }
-
-/*
- * Allocate an extent in the realtime subvolume.
- *
- * If @start is nonzero, try to allocate near that exact rtx.  @maxlen should
- * be the maximum length to allocate; the allocated space can be as short as a
- * single rtx.  If no free space was allocated, returns -ENOSPC without
- * touching @len or @rtx.
- */
-int
-xfs_rtallocate_extent(
-       struct xfs_trans        *tp,
-       xfs_rtxnum_t            start,  /* starting rtext number to allocate */
-       xfs_rtxlen_t            maxlen, /* maximum length to allocate */
-       xfs_rtxlen_t            *len,   /* out: actual length allocated */
-       xfs_rtxnum_t            *rtx)   /* out: start rtext allocated */
-{
-       struct xfs_rtalloc_args args = {
-               .mp             = tp->t_mountp,
-               .tp             = tp,
-       };
-       xfs_rtxnum_t            r;
-       xfs_rtxlen_t            l;
-       int                     error;
-
-       xfs_assert_ilocked(args.mp->m_rbmip, XFS_ILOCK_EXCL);
-
-       if (start == 0) {
-               error = xfs_rtallocate_extent_size(&args, 1, maxlen, &l, 1, &r);
-       } else {
-               error = xfs_rtallocate_extent_near(&args, start, 1, maxlen,
-                               &l, 1, &r);
-       }
-       if (error)
-               goto out_release;
-
-       ASSERT(l <= maxlen);
-       error = xfs_rtallocate_range(&args, r, l);
-       if (error)
-               goto out_release;
-
-       xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -(int64_t)l);
-       *rtx = r;
-       *len = l;
-
-out_release:
-       xfs_rtbuf_cache_relse(&args);
-       return error;
-}
index 318c7dbfc51a34f532fe1252275562c227c3d6f7..e899f707899cc6a781a97076aa6bdca441ce5509 100644 (file)
@@ -48,8 +48,10 @@ xfs_growfs_rt(
 int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
 int xfs_growfs_check_rtgeom(const struct xfs_mount *mp, xfs_rfsblock_t dblocks,
                xfs_rfsblock_t rblocks, xfs_agblock_t rextsize);
-int xfs_rtallocate_extent(struct xfs_trans *tp, xfs_rtxnum_t start,
-               xfs_rtxlen_t maxlen, xfs_rtxlen_t *len, xfs_rtxnum_t *rtx);
+int xfs_rtallocate_rtgs(struct xfs_trans *tp, xfs_fsblock_t bno_hint,
+               xfs_rtxlen_t minlen, xfs_rtxlen_t maxlen, xfs_rtxlen_t prod,
+               bool wasdel, bool initial_user_data, xfs_rtblock_t *bno,
+               xfs_extlen_t *blen);
 #else
 # define xfs_growfs_rt(mp,in)                          (-ENOSYS)
 # define xfs_rtalloc_reinit_frextents(m)               (0)
@@ -69,7 +71,15 @@ xfs_rtmount_init(
 # define xfs_rtunmount_inodes(m)
 # define xfs_rt_resv_free(mp)                          ((void)0)
 # define xfs_rt_resv_init(mp)                          (0)
-# define xfs_rtallocate_extent(...)                    (-ENOSYS)
+
+static inline int
+xfs_rtallocate_rtgs(struct xfs_trans *tp, xfs_fsblock_t bno_hint,
+               xfs_rtxlen_t minlen, xfs_rtxlen_t maxlen, xfs_rtxlen_t prod,
+               bool wasdel, bool initial_user_data, xfs_rtblock_t *bno,
+               xfs_extlen_t *blen)
+{
+       return -EINVAL;
+}
 
 static inline int
 xfs_growfs_check_rtgeom(const struct xfs_mount *mp,
index 73a496b3cf63c01c4c25e7aa5286ffb980995ceb..02e16cb5242967082c737fa205ec63f1b96e9fc0 100644 (file)
@@ -886,7 +886,8 @@ xfs_fs_statfs(
 
                statp->f_blocks = sbp->sb_rblocks;
                freertx = percpu_counter_sum_positive(&mp->m_frextents);
-               statp->f_bavail = statp->f_bfree = xfs_rtx_to_rtb(mp, freertx);
+               statp->f_bavail = statp->f_bfree =
+                       xfs_rtbxlen_to_blen(mp, freertx);
        }
 
        return 0;