Merge tag 'xfs-6.7-merge-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 Nov 2023 21:22:16 +0000 (13:22 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 Nov 2023 21:22:16 +0000 (13:22 -0800)
Pull xfs updates from Chandan Babu:

 - Realtime device subsystem:
    - Cleanup usage of xfs_rtblock_t and xfs_fsblock_t data types
    - Replace open coded conversions between rt blocks and rt extents
      with calls to static inline helpers
    - Replace open coded realtime geometry compuation and macros with
      helper functions
    - CPU usage optimizations for realtime allocator
    - Misc bug fixes associated with Realtime device

 - Allow read operations to execute while an FICLONE ioctl is being
   serviced

 - Misc bug fixes:
    - Alert user when xfs_droplink() encounters an inode with a link
      count of zero
    - Handle the case where the allocator could return zero extents when
      servicing an fallocate request

* tag 'xfs-6.7-merge-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (40 commits)
  xfs: allow read IO and FICLONE to run concurrently
  xfs: handle nimaps=0 from xfs_bmapi_write in xfs_alloc_file_space
  xfs: introduce protection for drop nlink
  xfs: don't look for end of extent further than necessary in xfs_rtallocate_extent_near()
  xfs: don't try redundant allocations in xfs_rtallocate_extent_near()
  xfs: limit maxlen based on available space in xfs_rtallocate_extent_near()
  xfs: return maximum free size from xfs_rtany_summary()
  xfs: invert the realtime summary cache
  xfs: simplify rt bitmap/summary block accessor functions
  xfs: simplify xfs_rtbuf_get calling conventions
  xfs: cache last bitmap block in realtime allocator
  xfs: use accessor functions for summary info words
  xfs: consolidate realtime allocation arguments
  xfs: create helpers for rtsummary block/wordcount computations
  xfs: use accessor functions for bitmap words
  xfs: create helpers for rtbitmap block/wordcount computations
  xfs: create a helper to handle logging parts of rt bitmap/summary blocks
  xfs: convert rt summary macros to helpers
  xfs: convert open-coded xfs_rtword_t pointer accesses to helper
  xfs: remove XFS_BLOCKWSIZE and XFS_BLOCKWMASK macros
  ...

31 files changed:
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_format.h
fs/xfs/libxfs/xfs_rtbitmap.c
fs/xfs/libxfs/xfs_rtbitmap.h [new file with mode: 0644]
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_sb.h
fs/xfs/libxfs/xfs_trans_resv.c
fs/xfs/libxfs/xfs_types.c
fs/xfs/libxfs/xfs_types.h
fs/xfs/scrub/bmap.c
fs/xfs/scrub/fscounters.c
fs/xfs/scrub/inode.c
fs/xfs/scrub/rtbitmap.c
fs/xfs/scrub/rtsummary.c
fs/xfs/scrub/trace.c
fs/xfs/scrub/trace.h
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_file.c
fs/xfs/xfs_fsmap.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_linux.h
fs/xfs/xfs_mount.h
fs/xfs/xfs_ondisk.h
fs/xfs/xfs_reflink.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_super.c
fs/xfs/xfs_trans.c

index 30c931b38853c9a50d44465e78b41b7bdd993a41..be62acffad6ccdfb31748987cc507e03f08afb81 100644 (file)
@@ -21,7 +21,7 @@
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_rtalloc.h"
+#include "xfs_rtbitmap.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_quota.h"
@@ -2989,7 +2989,7 @@ xfs_bmap_extsize_align(
         * If realtime, and the result isn't a multiple of the realtime
         * extent size we need to remove blocks until it is.
         */
-       if (rt && (temp = (align_alen % mp->m_sb.sb_rextsize))) {
+       if (rt && (temp = xfs_extlen_to_rtxmod(mp, align_alen))) {
                /*
                 * We're not covering the original request, or
                 * we won't be able to once we fix the length.
@@ -3016,7 +3016,7 @@ xfs_bmap_extsize_align(
                else {
                        align_alen -= orig_off - align_off;
                        align_off = orig_off;
-                       align_alen -= align_alen % mp->m_sb.sb_rextsize;
+                       align_alen -= xfs_extlen_to_rtxmod(mp, align_alen);
                }
                /*
                 * Result doesn't cover the request, fail it.
@@ -4826,12 +4826,8 @@ xfs_bmap_del_extent_delay(
        ASSERT(got->br_startoff <= del->br_startoff);
        ASSERT(got_endoff >= del_endoff);
 
-       if (isrt) {
-               uint64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount);
-
-               do_div(rtexts, mp->m_sb.sb_rextsize);
-               xfs_mod_frextents(mp, rtexts);
-       }
+       if (isrt)
+               xfs_mod_frextents(mp, xfs_rtb_to_rtx(mp, del->br_blockcount));
 
        /*
         * Update the inode delalloc counter now and wait to update the
@@ -5057,33 +5053,20 @@ xfs_bmap_del_extent_real(
 
        flags = XFS_ILOG_CORE;
        if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) {
-               xfs_filblks_t   len;
-               xfs_extlen_t    mod;
-
-               len = div_u64_rem(del->br_blockcount, mp->m_sb.sb_rextsize,
-                                 &mod);
-               ASSERT(mod == 0);
-
                if (!(bflags & XFS_BMAPI_REMAP)) {
-                       xfs_fsblock_t   bno;
-
-                       bno = div_u64_rem(del->br_startblock,
-                                       mp->m_sb.sb_rextsize, &mod);
-                       ASSERT(mod == 0);
-
-                       error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len);
+                       error = xfs_rtfree_blocks(tp, del->br_startblock,
+                                       del->br_blockcount);
                        if (error)
                                goto done;
                }
 
                do_fx = 0;
-               nblks = len * mp->m_sb.sb_rextsize;
                qfield = XFS_TRANS_DQ_RTBCOUNT;
        } else {
                do_fx = 1;
-               nblks = del->br_blockcount;
                qfield = XFS_TRANS_DQ_BCOUNT;
        }
+       nblks = del->br_blockcount;
 
        del_endblock = del->br_startblock + del->br_blockcount;
        if (cur) {
@@ -5289,7 +5272,6 @@ __xfs_bunmapi(
        int                     tmp_logflags;   /* partial logging flags */
        int                     wasdel;         /* was a delayed alloc extent */
        int                     whichfork;      /* data or attribute fork */
-       xfs_fsblock_t           sum;
        xfs_filblks_t           len = *rlen;    /* length to unmap in file */
        xfs_fileoff_t           end;
        struct xfs_iext_cursor  icur;
@@ -5384,8 +5366,8 @@ __xfs_bunmapi(
                if (!isrt)
                        goto delete;
 
-               sum = del.br_startblock + del.br_blockcount;
-               div_u64_rem(sum, mp->m_sb.sb_rextsize, &mod);
+               mod = xfs_rtb_to_rtxoff(mp,
+                               del.br_startblock + del.br_blockcount);
                if (mod) {
                        /*
                         * Realtime extent not lined up at the end.
@@ -5432,7 +5414,8 @@ __xfs_bunmapi(
                                goto error0;
                        goto nodelete;
                }
-               div_u64_rem(del.br_startblock, mp->m_sb.sb_rextsize, &mod);
+
+               mod = xfs_rtb_to_rtxoff(mp, del.br_startblock);
                if (mod) {
                        xfs_extlen_t off = mp->m_sb.sb_rextsize - mod;
 
@@ -6209,8 +6192,8 @@ xfs_bmap_validate_extent(
                return __this_address;
 
        if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) {
-               if (!xfs_verify_rtext(mp, irec->br_startblock,
-                                         irec->br_blockcount))
+               if (!xfs_verify_rtbext(mp, irec->br_startblock,
+                                          irec->br_blockcount))
                        return __this_address;
        } else {
                if (!xfs_verify_fsbext(mp, irec->br_startblock,
index 371dc07233e059a95545629107d409f21653dbe4..9a88aba1589f87b45c470c8a8ec9a3a559a4c86d 100644 (file)
@@ -98,7 +98,7 @@ typedef struct xfs_sb {
        uint32_t        sb_blocksize;   /* logical block size, bytes */
        xfs_rfsblock_t  sb_dblocks;     /* number of data blocks */
        xfs_rfsblock_t  sb_rblocks;     /* number of realtime blocks */
-       xfs_rtblock_t   sb_rextents;    /* number of realtime extents */
+       xfs_rtbxlen_t   sb_rextents;    /* number of realtime extents */
        uuid_t          sb_uuid;        /* user-visible file system unique id */
        xfs_fsblock_t   sb_logstart;    /* starting block of log if internal */
        xfs_ino_t       sb_rootino;     /* root inode number */
@@ -690,6 +690,22 @@ struct xfs_agfl {
            ASSERT(xfs_daddr_to_agno(mp, d) == \
                   xfs_daddr_to_agno(mp, (d) + (len) - 1)))
 
+/*
+ * Realtime bitmap information is accessed by the word, which is currently
+ * stored in host-endian format.
+ */
+union xfs_rtword_raw {
+       __u32           old;
+};
+
+/*
+ * Realtime summary counts are accessed by the word, which is currently
+ * stored in host-endian format.
+ */
+union xfs_suminfo_raw {
+       __u32           old;
+};
+
 /*
  * XFS Timestamps
  * ==============
@@ -1142,24 +1158,10 @@ static inline bool xfs_dinode_has_large_extent_counts(
 
 #define        XFS_BLOCKSIZE(mp)       ((mp)->m_sb.sb_blocksize)
 #define        XFS_BLOCKMASK(mp)       ((mp)->m_blockmask)
-#define        XFS_BLOCKWSIZE(mp)      ((mp)->m_blockwsize)
-#define        XFS_BLOCKWMASK(mp)      ((mp)->m_blockwmask)
 
 /*
- * RT Summary and bit manipulation macros.
+ * RT bit manipulation macros.
  */
-#define        XFS_SUMOFFS(mp,ls,bb)   ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb)))
-#define        XFS_SUMOFFSTOBLOCK(mp,s)        \
-       (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog)
-#define        XFS_SUMPTR(mp,bp,so)    \
-       ((xfs_suminfo_t *)((bp)->b_addr + \
-               (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp))))
-
-#define        XFS_BITTOBLOCK(mp,bi)   ((bi) >> (mp)->m_blkbit_log)
-#define        XFS_BLOCKTOBIT(mp,bb)   ((bb) << (mp)->m_blkbit_log)
-#define        XFS_BITTOWORD(mp,bi)    \
-       ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp)))
-
 #define        XFS_RTMIN(a,b)  ((a) < (b) ? (a) : (b))
 #define        XFS_RTMAX(a,b)  ((a) > (b) ? (a) : (b))
 
index 396648acb5be169dc54f98c657780a34d164f1f3..c269d704314d7d5afc0497985f46c936ea275f27 100644 (file)
@@ -16,6 +16,7 @@
 #include "xfs_trans.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
+#include "xfs_rtbitmap.h"
 
 /*
  * Realtime allocator bitmap functions shared with userspace.
@@ -46,25 +47,69 @@ const struct xfs_buf_ops xfs_rtbuf_ops = {
        .verify_write = xfs_rtbuf_verify_write,
 };
 
+/* Release cached rt bitmap and summary buffers. */
+void
+xfs_rtbuf_cache_relse(
+       struct xfs_rtalloc_args *args)
+{
+       if (args->rbmbp) {
+               xfs_trans_brelse(args->tp, args->rbmbp);
+               args->rbmbp = NULL;
+               args->rbmoff = NULLFILEOFF;
+       }
+       if (args->sumbp) {
+               xfs_trans_brelse(args->tp, args->sumbp);
+               args->sumbp = NULL;
+               args->sumoff = NULLFILEOFF;
+       }
+}
+
 /*
  * Get a buffer for the bitmap or summary file block specified.
  * The buffer is returned read and locked.
  */
 int
 xfs_rtbuf_get(
-       xfs_mount_t     *mp,            /* file system mount structure */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   block,          /* block number in bitmap or summary */
-       int             issum,          /* is summary not bitmap */
-       struct xfs_buf  **bpp)          /* output: buffer for the block */
+       struct xfs_rtalloc_args *args,
+       xfs_fileoff_t           block,  /* block number in bitmap or summary */
+       int                     issum)  /* is summary not bitmap */
 {
-       struct xfs_buf  *bp;            /* block buffer, result */
-       xfs_inode_t     *ip;            /* bitmap or summary inode */
-       xfs_bmbt_irec_t map;
-       int             nmap = 1;
-       int             error;          /* error value */
+       struct xfs_mount        *mp = args->mp;
+       struct xfs_buf          **cbpp; /* cached block buffer */
+       xfs_fileoff_t           *coffp; /* cached block number */
+       struct xfs_buf          *bp;    /* block buffer, result */
+       struct xfs_inode        *ip;    /* bitmap or summary inode */
+       struct xfs_bmbt_irec    map;
+       enum xfs_blft           type;
+       int                     nmap = 1;
+       int                     error;
 
-       ip = issum ? mp->m_rsumip : mp->m_rbmip;
+       if (issum) {
+               cbpp = &args->sumbp;
+               coffp = &args->sumoff;
+               ip = mp->m_rsumip;
+               type = XFS_BLFT_RTSUMMARY_BUF;
+       } else {
+               cbpp = &args->rbmbp;
+               coffp = &args->rbmoff;
+               ip = mp->m_rbmip;
+               type = XFS_BLFT_RTBITMAP_BUF;
+       }
+
+       /*
+        * If we have a cached buffer, and the block number matches, use that.
+        */
+       if (*cbpp && *coffp == block)
+               return 0;
+
+       /*
+        * Otherwise we have to have to get the buffer.  If there was an old
+        * one, get rid of it first.
+        */
+       if (*cbpp) {
+               xfs_trans_brelse(args->tp, *cbpp);
+               *cbpp = NULL;
+       }
 
        error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0);
        if (error)
@@ -74,15 +119,15 @@ xfs_rtbuf_get(
                return -EFSCORRUPTED;
 
        ASSERT(map.br_startblock != NULLFSBLOCK);
-       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
+       error = xfs_trans_read_buf(mp, args->tp, mp->m_ddev_targp,
                                   XFS_FSB_TO_DADDR(mp, map.br_startblock),
                                   mp->m_bsize, 0, &bp, &xfs_rtbuf_ops);
        if (error)
                return error;
 
-       xfs_trans_buf_set_type(tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF
-                                            : XFS_BLFT_RTBITMAP_BUF);
-       *bpp = bp;
+       xfs_trans_buf_set_type(args->tp, bp, type);
+       *cbpp = bp;
+       *coffp = block;
        return 0;
 }
 
@@ -92,47 +137,44 @@ xfs_rtbuf_get(
  */
 int
 xfs_rtfind_back(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   start,          /* starting block to look at */
-       xfs_rtblock_t   limit,          /* last block to look at */
-       xfs_rtblock_t   *rtblock)       /* out: start block found */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext to look at */
+       xfs_rtxnum_t            limit,  /* last rtext to look at */
+       xfs_rtxnum_t            *rtx)   /* out: start rtext found */
 {
-       xfs_rtword_t    *b;             /* current word in buffer */
-       int             bit;            /* bit number in the word */
-       xfs_rtblock_t   block;          /* bitmap block number */
-       struct xfs_buf  *bp;            /* buf for the block */
-       xfs_rtword_t    *bufp;          /* starting word in buffer */
-       int             error;          /* error value */
-       xfs_rtblock_t   firstbit;       /* first useful bit in the word */
-       xfs_rtblock_t   i;              /* current bit number rel. to start */
-       xfs_rtblock_t   len;            /* length of inspected area */
-       xfs_rtword_t    mask;           /* mask of relevant bits for value */
-       xfs_rtword_t    want;           /* mask for "good" values */
-       xfs_rtword_t    wdiff;          /* difference from wanted value */
-       int             word;           /* word number in the buffer */
+       struct xfs_mount        *mp = args->mp;
+       int                     bit;    /* bit number in the word */
+       xfs_fileoff_t           block;  /* bitmap block number */
+       int                     error;  /* error value */
+       xfs_rtxnum_t            firstbit; /* first useful bit in the word */
+       xfs_rtxnum_t            i;      /* current bit number rel. to start */
+       xfs_rtxnum_t            len;    /* length of inspected area */
+       xfs_rtword_t            mask;   /* mask of relevant bits for value */
+       xfs_rtword_t            want;   /* mask for "good" values */
+       xfs_rtword_t            wdiff;  /* difference from wanted value */
+       xfs_rtword_t            incore;
+       unsigned int            word;   /* word number in the buffer */
 
        /*
         * Compute and read in starting bitmap block for starting block.
         */
-       block = XFS_BITTOBLOCK(mp, start);
-       error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
-       if (error) {
+       block = xfs_rtx_to_rbmblock(mp, start);
+       error = xfs_rtbitmap_read_buf(args, block);
+       if (error)
                return error;
-       }
-       bufp = bp->b_addr;
+
        /*
         * Get the first word's index & point to it.
         */
-       word = XFS_BITTOWORD(mp, start);
-       b = &bufp[word];
+       word = xfs_rtx_to_rbmword(mp, start);
        bit = (int)(start & (XFS_NBWORD - 1));
        len = start - limit + 1;
        /*
         * Compute match value, based on the bit at start: if 1 (free)
         * then all-ones, else all-zeroes.
         */
-       want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
+       incore = xfs_rtbitmap_getword(args, word);
+       want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
        /*
         * If the starting position is not word-aligned, deal with the
         * partial word.
@@ -149,13 +191,12 @@ xfs_rtfind_back(
                 * Calculate the difference between the value there
                 * and what we're looking for.
                 */
-               if ((wdiff = (*b ^ want) & mask)) {
+               if ((wdiff = (incore ^ want) & mask)) {
                        /*
                         * Different.  Mark where we are and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i = bit - XFS_RTHIBIT(wdiff);
-                       *rtblock = start - i + 1;
+                       *rtx = start - i + 1;
                        return 0;
                }
                i = bit - firstbit + 1;
@@ -167,19 +208,11 @@ xfs_rtfind_back(
                        /*
                         * If done with this block, get the previous one.
                         */
-                       xfs_trans_brelse(tp, bp);
-                       error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
-                       if (error) {
+                       error = xfs_rtbitmap_read_buf(args, --block);
+                       if (error)
                                return error;
-                       }
-                       bufp = bp->b_addr;
-                       word = XFS_BLOCKWMASK(mp);
-                       b = &bufp[word];
-               } else {
-                       /*
-                        * Go on to the previous word in the buffer.
-                        */
-                       b--;
+
+                       word = mp->m_blockwsize - 1;
                }
        } else {
                /*
@@ -195,13 +228,13 @@ xfs_rtfind_back(
                /*
                 * Compute difference between actual and desired value.
                 */
-               if ((wdiff = *b ^ want)) {
+               incore = xfs_rtbitmap_getword(args, word);
+               if ((wdiff = incore ^ want)) {
                        /*
                         * Different, mark where we are and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
-                       *rtblock = start - i + 1;
+                       *rtx = start - i + 1;
                        return 0;
                }
                i += XFS_NBWORD;
@@ -213,19 +246,11 @@ xfs_rtfind_back(
                        /*
                         * If done with this block, get the previous one.
                         */
-                       xfs_trans_brelse(tp, bp);
-                       error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
-                       if (error) {
+                       error = xfs_rtbitmap_read_buf(args, --block);
+                       if (error)
                                return error;
-                       }
-                       bufp = bp->b_addr;
-                       word = XFS_BLOCKWMASK(mp);
-                       b = &bufp[word];
-               } else {
-                       /*
-                        * Go on to the previous word in the buffer.
-                        */
-                       b--;
+
+                       word = mp->m_blockwsize - 1;
                }
        }
        /*
@@ -242,13 +267,13 @@ xfs_rtfind_back(
                /*
                 * Compute difference between actual and desired value.
                 */
-               if ((wdiff = (*b ^ want) & mask)) {
+               incore = xfs_rtbitmap_getword(args, word);
+               if ((wdiff = (incore ^ want) & mask)) {
                        /*
                         * Different, mark where we are and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
-                       *rtblock = start - i + 1;
+                       *rtx = start - i + 1;
                        return 0;
                } else
                        i = len;
@@ -256,8 +281,7 @@ xfs_rtfind_back(
        /*
         * No match, return that we scanned the whole area.
         */
-       xfs_trans_brelse(tp, bp);
-       *rtblock = start - i + 1;
+       *rtx = start - i + 1;
        return 0;
 }
 
@@ -267,47 +291,44 @@ xfs_rtfind_back(
  */
 int
 xfs_rtfind_forw(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   start,          /* starting block to look at */
-       xfs_rtblock_t   limit,          /* last block to look at */
-       xfs_rtblock_t   *rtblock)       /* out: start block found */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext to look at */
+       xfs_rtxnum_t            limit,  /* last rtext to look at */
+       xfs_rtxnum_t            *rtx)   /* out: start rtext found */
 {
-       xfs_rtword_t    *b;             /* current word in buffer */
-       int             bit;            /* bit number in the word */
-       xfs_rtblock_t   block;          /* bitmap block number */
-       struct xfs_buf  *bp;            /* buf for the block */
-       xfs_rtword_t    *bufp;          /* starting word in buffer */
-       int             error;          /* error value */
-       xfs_rtblock_t   i;              /* current bit number rel. to start */
-       xfs_rtblock_t   lastbit;        /* last useful bit in the word */
-       xfs_rtblock_t   len;            /* length of inspected area */
-       xfs_rtword_t    mask;           /* mask of relevant bits for value */
-       xfs_rtword_t    want;           /* mask for "good" values */
-       xfs_rtword_t    wdiff;          /* difference from wanted value */
-       int             word;           /* word number in the buffer */
+       struct xfs_mount        *mp = args->mp;
+       int                     bit;    /* bit number in the word */
+       xfs_fileoff_t           block;  /* bitmap block number */
+       int                     error;
+       xfs_rtxnum_t            i;      /* current bit number rel. to start */
+       xfs_rtxnum_t            lastbit;/* last useful bit in the word */
+       xfs_rtxnum_t            len;    /* length of inspected area */
+       xfs_rtword_t            mask;   /* mask of relevant bits for value */
+       xfs_rtword_t            want;   /* mask for "good" values */
+       xfs_rtword_t            wdiff;  /* difference from wanted value */
+       xfs_rtword_t            incore;
+       unsigned int            word;   /* word number in the buffer */
 
        /*
         * Compute and read in starting bitmap block for starting block.
         */
-       block = XFS_BITTOBLOCK(mp, start);
-       error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
-       if (error) {
+       block = xfs_rtx_to_rbmblock(mp, start);
+       error = xfs_rtbitmap_read_buf(args, block);
+       if (error)
                return error;
-       }
-       bufp = bp->b_addr;
+
        /*
         * Get the first word's index & point to it.
         */
-       word = XFS_BITTOWORD(mp, start);
-       b = &bufp[word];
+       word = xfs_rtx_to_rbmword(mp, start);
        bit = (int)(start & (XFS_NBWORD - 1));
        len = limit - start + 1;
        /*
         * Compute match value, based on the bit at start: if 1 (free)
         * then all-ones, else all-zeroes.
         */
-       want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
+       incore = xfs_rtbitmap_getword(args, word);
+       want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
        /*
         * If the starting position is not word-aligned, deal with the
         * partial word.
@@ -323,13 +344,12 @@ xfs_rtfind_forw(
                 * Calculate the difference between the value there
                 * and what we're looking for.
                 */
-               if ((wdiff = (*b ^ want) & mask)) {
+               if ((wdiff = (incore ^ want) & mask)) {
                        /*
                         * Different.  Mark where we are and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i = XFS_RTLOBIT(wdiff) - bit;
-                       *rtblock = start + i - 1;
+                       *rtx = start + i - 1;
                        return 0;
                }
                i = lastbit - bit;
@@ -337,22 +357,15 @@ xfs_rtfind_forw(
                 * Go on to next block if that's where the next word is
                 * and we need the next word.
                 */
-               if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
+               if (++word == mp->m_blockwsize && i < len) {
                        /*
                         * If done with this block, get the previous one.
                         */
-                       xfs_trans_brelse(tp, bp);
-                       error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
-                       if (error) {
+                       error = xfs_rtbitmap_read_buf(args, ++block);
+                       if (error)
                                return error;
-                       }
-                       b = bufp = bp->b_addr;
+
                        word = 0;
-               } else {
-                       /*
-                        * Go on to the previous word in the buffer.
-                        */
-                       b++;
                }
        } else {
                /*
@@ -368,13 +381,13 @@ xfs_rtfind_forw(
                /*
                 * Compute difference between actual and desired value.
                 */
-               if ((wdiff = *b ^ want)) {
+               incore = xfs_rtbitmap_getword(args, word);
+               if ((wdiff = incore ^ want)) {
                        /*
                         * Different, mark where we are and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i += XFS_RTLOBIT(wdiff);
-                       *rtblock = start + i - 1;
+                       *rtx = start + i - 1;
                        return 0;
                }
                i += XFS_NBWORD;
@@ -382,22 +395,15 @@ xfs_rtfind_forw(
                 * Go on to next block if that's where the next word is
                 * and we need the next word.
                 */
-               if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
+               if (++word == mp->m_blockwsize && i < len) {
                        /*
                         * If done with this block, get the next one.
                         */
-                       xfs_trans_brelse(tp, bp);
-                       error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
-                       if (error) {
+                       error = xfs_rtbitmap_read_buf(args, ++block);
+                       if (error)
                                return error;
-                       }
-                       b = bufp = bp->b_addr;
+
                        word = 0;
-               } else {
-                       /*
-                        * Go on to the next word in the buffer.
-                        */
-                       b++;
                }
        }
        /*
@@ -412,13 +418,13 @@ xfs_rtfind_forw(
                /*
                 * Compute difference between actual and desired value.
                 */
-               if ((wdiff = (*b ^ want) & mask)) {
+               incore = xfs_rtbitmap_getword(args, word);
+               if ((wdiff = (incore ^ want) & mask)) {
                        /*
                         * Different, mark where we are and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i += XFS_RTLOBIT(wdiff);
-                       *rtblock = start + i - 1;
+                       *rtx = start + i - 1;
                        return 0;
                } else
                        i = len;
@@ -426,11 +432,25 @@ xfs_rtfind_forw(
        /*
         * No match, return that we scanned the whole area.
         */
-       xfs_trans_brelse(tp, bp);
-       *rtblock = start + i - 1;
+       *rtx = start + i - 1;
        return 0;
 }
 
+/* Log rtsummary counter at @infoword. */
+static inline void
+xfs_trans_log_rtsummary(
+       struct xfs_rtalloc_args *args,
+       unsigned int            infoword)
+{
+       struct xfs_buf          *bp = args->sumbp;
+       size_t                  first, last;
+
+       first = (void *)xfs_rsumblock_infoptr(args, infoword) - bp->b_addr;
+       last = first + sizeof(xfs_suminfo_t) - 1;
+
+       xfs_trans_log_buf(args->tp, bp, first, last);
+}
+
 /*
  * Read and/or modify the summary information for a given extent size,
  * bitmap block combination.
@@ -442,86 +462,77 @@ xfs_rtfind_forw(
  */
 int
 xfs_rtmodify_summary_int(
-       xfs_mount_t     *mp,            /* file system mount structure */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       int             log,            /* log2 of extent size */
-       xfs_rtblock_t   bbno,           /* bitmap block number */
-       int             delta,          /* change to make to summary info */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
-       xfs_suminfo_t   *sum)           /* out: summary info for this block */
+       struct xfs_rtalloc_args *args,
+       int                     log,    /* log2 of extent size */
+       xfs_fileoff_t           bbno,   /* bitmap block number */
+       int                     delta,  /* change to make to summary info */
+       xfs_suminfo_t           *sum)   /* out: summary info for this block */
 {
-       struct xfs_buf  *bp;            /* buffer for the summary block */
-       int             error;          /* error value */
-       xfs_fsblock_t   sb;             /* summary fsblock */
-       int             so;             /* index into the summary file */
-       xfs_suminfo_t   *sp;            /* pointer to returned data */
+       struct xfs_mount        *mp = args->mp;
+       int                     error;
+       xfs_fileoff_t           sb;     /* summary fsblock */
+       xfs_rtsumoff_t          so;     /* index into the summary file */
+       unsigned int            infoword;
 
        /*
         * Compute entry number in the summary file.
         */
-       so = XFS_SUMOFFS(mp, log, bbno);
+       so = xfs_rtsumoffs(mp, log, bbno);
        /*
         * Compute the block number in the summary file.
         */
-       sb = XFS_SUMOFFSTOBLOCK(mp, so);
-       /*
-        * If we have an old buffer, and the block number matches, use that.
-        */
-       if (*rbpp && *rsb == sb)
-               bp = *rbpp;
-       /*
-        * Otherwise we have to get the buffer.
-        */
-       else {
-               /*
-                * If there was an old one, get rid of it first.
-                */
-               if (*rbpp)
-                       xfs_trans_brelse(tp, *rbpp);
-               error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
-               if (error) {
-                       return error;
-               }
-               /*
-                * Remember this buffer and block for the next call.
-                */
-               *rbpp = bp;
-               *rsb = sb;
-       }
+       sb = xfs_rtsumoffs_to_block(mp, so);
+
+       error = xfs_rtsummary_read_buf(args, sb);
+       if (error)
+               return error;
+
        /*
         * Point to the summary information, modify/log it, and/or copy it out.
         */
-       sp = XFS_SUMPTR(mp, bp, so);
+       infoword = xfs_rtsumoffs_to_infoword(mp, so);
        if (delta) {
-               uint first = (uint)((char *)sp - (char *)bp->b_addr);
+               xfs_suminfo_t   val = xfs_suminfo_add(args, infoword, delta);
 
-               *sp += delta;
                if (mp->m_rsum_cache) {
-                       if (*sp == 0 && log == mp->m_rsum_cache[bbno])
-                               mp->m_rsum_cache[bbno]++;
-                       if (*sp != 0 && log < mp->m_rsum_cache[bbno])
+                       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;
                }
-               xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
+               xfs_trans_log_rtsummary(args, infoword);
+               if (sum)
+                       *sum = val;
+       } else if (sum) {
+               *sum = xfs_suminfo_get(args, infoword);
        }
-       if (sum)
-               *sum = *sp;
        return 0;
 }
 
 int
 xfs_rtmodify_summary(
-       xfs_mount_t     *mp,            /* file system mount structure */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       int             log,            /* log2 of extent size */
-       xfs_rtblock_t   bbno,           /* bitmap block number */
-       int             delta,          /* change to make to summary info */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb)           /* in/out: summary block number */
+       struct xfs_rtalloc_args *args,
+       int                     log,    /* log2 of extent size */
+       xfs_fileoff_t           bbno,   /* bitmap block number */
+       int                     delta)  /* in/out: summary block number */
+{
+       return xfs_rtmodify_summary_int(args, log, bbno, delta, NULL);
+}
+
+/* Log rtbitmap block from the word @from to the byte before @next. */
+static inline void
+xfs_trans_log_rtbitmap(
+       struct xfs_rtalloc_args *args,
+       unsigned int            from,
+       unsigned int            next)
 {
-       return xfs_rtmodify_summary_int(mp, tp, log, bbno,
-                                       delta, rbpp, rsb, NULL);
+       struct xfs_buf          *bp = args->rbmbp;
+       size_t                  first, last;
+
+       first = (void *)xfs_rbmblock_wordptr(args, from) - bp->b_addr;
+       last = ((void *)xfs_rbmblock_wordptr(args, next) - 1) - bp->b_addr;
+
+       xfs_trans_log_buf(args->tp, bp, first, last);
 }
 
 /*
@@ -530,41 +541,37 @@ xfs_rtmodify_summary(
  */
 int
 xfs_rtmodify_range(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   start,          /* starting block to modify */
-       xfs_extlen_t    len,            /* length of extent to modify */
-       int             val)            /* 1 for free, 0 for allocated */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext to modify */
+       xfs_rtxlen_t            len,    /* length of extent to modify */
+       int                     val)    /* 1 for free, 0 for allocated */
 {
-       xfs_rtword_t    *b;             /* current word in buffer */
-       int             bit;            /* bit number in the word */
-       xfs_rtblock_t   block;          /* bitmap block number */
-       struct xfs_buf  *bp;            /* buf for the block */
-       xfs_rtword_t    *bufp;          /* starting word in buffer */
-       int             error;          /* error value */
-       xfs_rtword_t    *first;         /* first used word in the buffer */
-       int             i;              /* current bit number rel. to start */
-       int             lastbit;        /* last useful bit in word */
-       xfs_rtword_t    mask;           /* mask o frelevant bits for value */
-       int             word;           /* word number in the buffer */
+       struct xfs_mount        *mp = args->mp;
+       int                     bit;    /* bit number in the word */
+       xfs_fileoff_t           block;  /* bitmap block number */
+       int                     error;
+       int                     i;      /* current bit number rel. to start */
+       int                     lastbit; /* last useful bit in word */
+       xfs_rtword_t            mask;    /* mask of relevant bits for value */
+       xfs_rtword_t            incore;
+       unsigned int            firstword; /* first word used in the buffer */
+       unsigned int            word;   /* word number in the buffer */
 
        /*
         * Compute starting bitmap block number.
         */
-       block = XFS_BITTOBLOCK(mp, start);
+       block = xfs_rtx_to_rbmblock(mp, start);
        /*
         * Read the bitmap block, and point to its data.
         */
-       error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
-       if (error) {
+       error = xfs_rtbitmap_read_buf(args, block);
+       if (error)
                return error;
-       }
-       bufp = bp->b_addr;
+
        /*
         * Compute the starting word's address, and starting bit.
         */
-       word = XFS_BITTOWORD(mp, start);
-       first = b = &bufp[word];
+       firstword = word = xfs_rtx_to_rbmword(mp, start);
        bit = (int)(start & (XFS_NBWORD - 1));
        /*
         * 0 (allocated) => all zeroes; 1 (free) => all ones.
@@ -583,34 +590,28 @@ xfs_rtmodify_range(
                /*
                 * Set/clear the active bits.
                 */
+               incore = xfs_rtbitmap_getword(args, word);
                if (val)
-                       *b |= mask;
+                       incore |= mask;
                else
-                       *b &= ~mask;
+                       incore &= ~mask;
+               xfs_rtbitmap_setword(args, word, incore);
                i = lastbit - bit;
                /*
                 * Go on to the next block if that's where the next word is
                 * and we need the next word.
                 */
-               if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
+               if (++word == mp->m_blockwsize && i < len) {
                        /*
                         * Log the changed part of this block.
                         * Get the next one.
                         */
-                       xfs_trans_log_buf(tp, bp,
-                               (uint)((char *)first - (char *)bufp),
-                               (uint)((char *)b - (char *)bufp));
-                       error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
-                       if (error) {
+                       xfs_trans_log_rtbitmap(args, firstword, word);
+                       error = xfs_rtbitmap_read_buf(args, ++block);
+                       if (error)
                                return error;
-                       }
-                       first = b = bufp = bp->b_addr;
-                       word = 0;
-               } else {
-                       /*
-                        * Go on to the next word in the buffer
-                        */
-                       b++;
+
+                       firstword = word = 0;
                }
        } else {
                /*
@@ -626,31 +627,23 @@ xfs_rtmodify_range(
                /*
                 * Set the word value correctly.
                 */
-               *b = val;
+               xfs_rtbitmap_setword(args, word, val);
                i += XFS_NBWORD;
                /*
                 * Go on to the next block if that's where the next word is
                 * and we need the next word.
                 */
-               if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
+               if (++word == mp->m_blockwsize && i < len) {
                        /*
                         * Log the changed part of this block.
                         * Get the next one.
                         */
-                       xfs_trans_log_buf(tp, bp,
-                               (uint)((char *)first - (char *)bufp),
-                               (uint)((char *)b - (char *)bufp));
-                       error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
-                       if (error) {
+                       xfs_trans_log_rtbitmap(args, firstword, word);
+                       error = xfs_rtbitmap_read_buf(args, ++block);
+                       if (error)
                                return error;
-                       }
-                       first = b = bufp = bp->b_addr;
-                       word = 0;
-               } else {
-                       /*
-                        * Go on to the next word in the buffer
-                        */
-                       b++;
+
+                       firstword = word = 0;
                }
        }
        /*
@@ -665,18 +658,19 @@ xfs_rtmodify_range(
                /*
                 * Set/clear the active bits.
                 */
+               incore = xfs_rtbitmap_getword(args, word);
                if (val)
-                       *b |= mask;
+                       incore |= mask;
                else
-                       *b &= ~mask;
-               b++;
+                       incore &= ~mask;
+               xfs_rtbitmap_setword(args, word, incore);
+               word++;
        }
        /*
         * Log any remaining changed bytes.
         */
-       if (b > first)
-               xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp),
-                       (uint)((char *)b - (char *)bufp - 1));
+       if (word > firstword)
+               xfs_trans_log_rtbitmap(args, firstword, word);
        return 0;
 }
 
@@ -686,23 +680,21 @@ xfs_rtmodify_range(
  */
 int
 xfs_rtfree_range(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   start,          /* starting block to free */
-       xfs_extlen_t    len,            /* length to free */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb)           /* in/out: summary block number */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext to free */
+       xfs_rtxlen_t            len)    /* in/out: summary block number */
 {
-       xfs_rtblock_t   end;            /* end of the freed extent */
-       int             error;          /* error value */
-       xfs_rtblock_t   postblock;      /* first block freed > end */
-       xfs_rtblock_t   preblock;       /* first block freed < start */
+       struct xfs_mount        *mp = args->mp;
+       xfs_rtxnum_t            end;    /* end of the freed extent */
+       int                     error;  /* error value */
+       xfs_rtxnum_t            postblock; /* first rtext freed > end */
+       xfs_rtxnum_t            preblock;  /* first rtext freed < start */
 
        end = start + len - 1;
        /*
         * Modify the bitmap to mark this extent freed.
         */
-       error = xfs_rtmodify_range(mp, tp, start, len, 1);
+       error = xfs_rtmodify_range(args, start, len, 1);
        if (error) {
                return error;
        }
@@ -711,15 +703,15 @@ xfs_rtfree_range(
         * We need to find the beginning and end of the extent so we can
         * properly update the summary.
         */
-       error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
+       error = xfs_rtfind_back(args, start, 0, &preblock);
        if (error) {
                return error;
        }
        /*
         * Find the next allocated block (end of allocated extent).
         */
-       error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
-               &postblock);
+       error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
+                       &postblock);
        if (error)
                return error;
        /*
@@ -727,9 +719,9 @@ xfs_rtfree_range(
         * old extent, add summary data for them to be allocated.
         */
        if (preblock < start) {
-               error = xfs_rtmodify_summary(mp, tp,
-                       XFS_RTBLOCKLOG(start - preblock),
-                       XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
+               error = xfs_rtmodify_summary(args,
+                               XFS_RTBLOCKLOG(start - preblock),
+                               xfs_rtx_to_rbmblock(mp, preblock), -1);
                if (error) {
                        return error;
                }
@@ -739,9 +731,9 @@ xfs_rtfree_range(
         * old extent, add summary data for them to be allocated.
         */
        if (postblock > end) {
-               error = xfs_rtmodify_summary(mp, tp,
-                       XFS_RTBLOCKLOG(postblock - end),
-                       XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb);
+               error = xfs_rtmodify_summary(args,
+                               XFS_RTBLOCKLOG(postblock - end),
+                               xfs_rtx_to_rbmblock(mp, end + 1), -1);
                if (error) {
                        return error;
                }
@@ -750,10 +742,9 @@ xfs_rtfree_range(
         * Increment the summary information corresponding to the entire
         * (new) free extent.
         */
-       error = xfs_rtmodify_summary(mp, tp,
-               XFS_RTBLOCKLOG(postblock + 1 - preblock),
-               XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
-       return error;
+       return xfs_rtmodify_summary(args,
+                       XFS_RTBLOCKLOG(postblock + 1 - preblock),
+                       xfs_rtx_to_rbmblock(mp, preblock), 1);
 }
 
 /*
@@ -762,43 +753,39 @@ xfs_rtfree_range(
  */
 int
 xfs_rtcheck_range(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   start,          /* starting block number of extent */
-       xfs_extlen_t    len,            /* length of extent */
-       int             val,            /* 1 for free, 0 for allocated */
-       xfs_rtblock_t   *new,           /* out: first block not matching */
-       int             *stat)          /* out: 1 for matches, 0 for not */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext number of extent */
+       xfs_rtxlen_t            len,    /* length of extent */
+       int                     val,    /* 1 for free, 0 for allocated */
+       xfs_rtxnum_t            *new,   /* out: first rtext not matching */
+       int                     *stat)  /* out: 1 for matches, 0 for not */
 {
-       xfs_rtword_t    *b;             /* current word in buffer */
-       int             bit;            /* bit number in the word */
-       xfs_rtblock_t   block;          /* bitmap block number */
-       struct xfs_buf  *bp;            /* buf for the block */
-       xfs_rtword_t    *bufp;          /* starting word in buffer */
-       int             error;          /* error value */
-       xfs_rtblock_t   i;              /* current bit number rel. to start */
-       xfs_rtblock_t   lastbit;        /* last useful bit in word */
-       xfs_rtword_t    mask;           /* mask of relevant bits for value */
-       xfs_rtword_t    wdiff;          /* difference from wanted value */
-       int             word;           /* word number in the buffer */
+       struct xfs_mount        *mp = args->mp;
+       int                     bit;    /* bit number in the word */
+       xfs_fileoff_t           block;  /* bitmap block number */
+       int                     error;
+       xfs_rtxnum_t            i;      /* current bit number rel. to start */
+       xfs_rtxnum_t            lastbit; /* last useful bit in word */
+       xfs_rtword_t            mask;   /* mask of relevant bits for value */
+       xfs_rtword_t            wdiff;  /* difference from wanted value */
+       xfs_rtword_t            incore;
+       unsigned int            word;   /* word number in the buffer */
 
        /*
         * Compute starting bitmap block number
         */
-       block = XFS_BITTOBLOCK(mp, start);
+       block = xfs_rtx_to_rbmblock(mp, start);
        /*
         * Read the bitmap block.
         */
-       error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
-       if (error) {
+       error = xfs_rtbitmap_read_buf(args, block);
+       if (error)
                return error;
-       }
-       bufp = bp->b_addr;
+
        /*
         * Compute the starting word's address, and starting bit.
         */
-       word = XFS_BITTOWORD(mp, start);
-       b = &bufp[word];
+       word = xfs_rtx_to_rbmword(mp, start);
        bit = (int)(start & (XFS_NBWORD - 1));
        /*
         * 0 (allocated) => all zero's; 1 (free) => all one's.
@@ -820,11 +807,11 @@ xfs_rtcheck_range(
                /*
                 * Compute difference between actual and desired value.
                 */
-               if ((wdiff = (*b ^ val) & mask)) {
+               incore = xfs_rtbitmap_getword(args, word);
+               if ((wdiff = (incore ^ val) & mask)) {
                        /*
                         * Different, compute first wrong bit and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i = XFS_RTLOBIT(wdiff) - bit;
                        *new = start + i;
                        *stat = 0;
@@ -835,22 +822,15 @@ xfs_rtcheck_range(
                 * Go on to next block if that's where the next word is
                 * and we need the next word.
                 */
-               if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
+               if (++word == mp->m_blockwsize && i < len) {
                        /*
                         * If done with this block, get the next one.
                         */
-                       xfs_trans_brelse(tp, bp);
-                       error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
-                       if (error) {
+                       error = xfs_rtbitmap_read_buf(args, ++block);
+                       if (error)
                                return error;
-                       }
-                       b = bufp = bp->b_addr;
+
                        word = 0;
-               } else {
-                       /*
-                        * Go on to the next word in the buffer.
-                        */
-                       b++;
                }
        } else {
                /*
@@ -866,11 +846,11 @@ xfs_rtcheck_range(
                /*
                 * Compute difference between actual and desired value.
                 */
-               if ((wdiff = *b ^ val)) {
+               incore = xfs_rtbitmap_getword(args, word);
+               if ((wdiff = incore ^ val)) {
                        /*
                         * Different, compute first wrong bit and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i += XFS_RTLOBIT(wdiff);
                        *new = start + i;
                        *stat = 0;
@@ -881,22 +861,15 @@ xfs_rtcheck_range(
                 * Go on to next block if that's where the next word is
                 * and we need the next word.
                 */
-               if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
+               if (++word == mp->m_blockwsize && i < len) {
                        /*
                         * If done with this block, get the next one.
                         */
-                       xfs_trans_brelse(tp, bp);
-                       error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
-                       if (error) {
+                       error = xfs_rtbitmap_read_buf(args, ++block);
+                       if (error)
                                return error;
-                       }
-                       b = bufp = bp->b_addr;
+
                        word = 0;
-               } else {
-                       /*
-                        * Go on to the next word in the buffer.
-                        */
-                       b++;
                }
        }
        /*
@@ -911,11 +884,11 @@ xfs_rtcheck_range(
                /*
                 * Compute difference between actual and desired value.
                 */
-               if ((wdiff = (*b ^ val) & mask)) {
+               incore = xfs_rtbitmap_getword(args, word);
+               if ((wdiff = (incore ^ val) & mask)) {
                        /*
                         * Different, compute first wrong bit and return.
                         */
-                       xfs_trans_brelse(tp, bp);
                        i += XFS_RTLOBIT(wdiff);
                        *new = start + i;
                        *stat = 0;
@@ -926,7 +899,6 @@ xfs_rtcheck_range(
        /*
         * Successful, return.
         */
-       xfs_trans_brelse(tp, bp);
        *new = start + i;
        *stat = 1;
        return 0;
@@ -936,58 +908,57 @@ xfs_rtcheck_range(
 /*
  * Check that the given extent (block range) is allocated already.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtcheck_alloc_range(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   bno,            /* starting block number of extent */
-       xfs_extlen_t    len)            /* length of extent */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext number of extent */
+       xfs_rtxlen_t            len)    /* length of extent */
 {
-       xfs_rtblock_t   new;            /* dummy for xfs_rtcheck_range */
-       int             stat;
-       int             error;
+       xfs_rtxnum_t            new;    /* dummy for xfs_rtcheck_range */
+       int                     stat;
+       int                     error;
 
-       error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat);
+       error = xfs_rtcheck_range(args, start, len, 0, &new, &stat);
        if (error)
                return error;
        ASSERT(stat);
        return 0;
 }
 #else
-#define xfs_rtcheck_alloc_range(m,t,b,l)       (0)
+#define xfs_rtcheck_alloc_range(a,b,l) (0)
 #endif
 /*
  * Free an extent in the realtime subvolume.  Length is expressed in
  * realtime extents, as is the block number.
  */
-int                                    /* error */
+int
 xfs_rtfree_extent(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   bno,            /* starting block number to free */
-       xfs_extlen_t    len)            /* length of extent freed */
+       struct xfs_trans        *tp,    /* transaction pointer */
+       xfs_rtxnum_t            start,  /* starting rtext number to free */
+       xfs_rtxlen_t            len)    /* length of extent freed */
 {
-       int             error;          /* error value */
-       xfs_mount_t     *mp;            /* file system mount structure */
-       xfs_fsblock_t   sb;             /* summary file block number */
-       struct xfs_buf  *sumbp = NULL;  /* summary file block buffer */
-       struct timespec64 atime;
-
-       mp = tp->t_mountp;
+       struct xfs_mount        *mp = tp->t_mountp;
+       struct xfs_rtalloc_args args = {
+               .mp             = mp,
+               .tp             = tp,
+       };
+       int                     error;
+       struct timespec64       atime;
 
        ASSERT(mp->m_rbmip->i_itemp != NULL);
        ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
 
-       error = xfs_rtcheck_alloc_range(mp, tp, bno, len);
+       error = xfs_rtcheck_alloc_range(&args, start, len);
        if (error)
                return error;
 
        /*
         * Free the range of realtime blocks.
         */
-       error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb);
-       if (error) {
-               return error;
-       }
+       error = xfs_rtfree_range(&args, start, len);
+       if (error)
+               goto out;
+
        /*
         * Mark more blocks free in the superblock.
         */
@@ -1002,11 +973,47 @@ xfs_rtfree_extent(
                        mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
 
                atime = inode_get_atime(VFS_I(mp->m_rbmip));
-               *((uint64_t *)&atime) = 0;
+               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);
        }
-       return 0;
+       error = 0;
+out:
+       xfs_rtbuf_cache_relse(&args);
+       return error;
+}
+
+/*
+ * Free some blocks in the realtime subvolume.  rtbno and rtlen are in units of
+ * rt blocks, not rt extents; must be aligned to the rt extent size; and rtlen
+ * cannot exceed XFS_MAX_BMBT_EXTLEN.
+ */
+int
+xfs_rtfree_blocks(
+       struct xfs_trans        *tp,
+       xfs_fsblock_t           rtbno,
+       xfs_filblks_t           rtlen)
+{
+       struct xfs_mount        *mp = tp->t_mountp;
+       xfs_rtxnum_t            start;
+       xfs_filblks_t           len;
+       xfs_extlen_t            mod;
+
+       ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN);
+
+       len = xfs_rtb_to_rtxrem(mp, rtlen, &mod);
+       if (mod) {
+               ASSERT(mod == 0);
+               return -EIO;
+       }
+
+       start = xfs_rtb_to_rtxrem(mp, rtbno, &mod);
+       if (mod) {
+               ASSERT(mod == 0);
+               return -EIO;
+       }
+
+       return xfs_rtfree_extent(tp, start, len);
 }
 
 /* Find all the free records within a given range. */
@@ -1019,10 +1026,14 @@ xfs_rtalloc_query_range(
        xfs_rtalloc_query_range_fn      fn,
        void                            *priv)
 {
+       struct xfs_rtalloc_args         args = {
+               .mp                     = mp,
+               .tp                     = tp,
+       };
        struct xfs_rtalloc_rec          rec;
-       xfs_rtblock_t                   rtstart;
-       xfs_rtblock_t                   rtend;
-       xfs_rtblock_t                   high_key;
+       xfs_rtxnum_t                    rtstart;
+       xfs_rtxnum_t                    rtend;
+       xfs_rtxnum_t                    high_key;
        int                             is_free;
        int                             error = 0;
 
@@ -1038,13 +1049,13 @@ xfs_rtalloc_query_range(
        rtstart = low_rec->ar_startext;
        while (rtstart <= high_key) {
                /* Is the first block free? */
-               error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtend,
+               error = xfs_rtcheck_range(&args, rtstart, 1, 1, &rtend,
                                &is_free);
                if (error)
                        break;
 
                /* How long does the extent go for? */
-               error = xfs_rtfind_forw(mp, tp, rtstart, high_key, &rtend);
+               error = xfs_rtfind_forw(&args, rtstart, high_key, &rtend);
                if (error)
                        break;
 
@@ -1060,6 +1071,7 @@ xfs_rtalloc_query_range(
                rtstart = rtend + 1;
        }
 
+       xfs_rtbuf_cache_relse(&args);
        return error;
 }
 
@@ -1085,18 +1097,79 @@ int
 xfs_rtalloc_extent_is_free(
        struct xfs_mount                *mp,
        struct xfs_trans                *tp,
-       xfs_rtblock_t                   start,
-       xfs_extlen_t                    len,
+       xfs_rtxnum_t                    start,
+       xfs_rtxlen_t                    len,
        bool                            *is_free)
 {
-       xfs_rtblock_t                   end;
+       struct xfs_rtalloc_args         args = {
+               .mp                     = mp,
+               .tp                     = tp,
+       };
+       xfs_rtxnum_t                    end;
        int                             matches;
        int                             error;
 
-       error = xfs_rtcheck_range(mp, tp, start, len, 1, &end, &matches);
+       error = xfs_rtcheck_range(&args, start, len, 1, &end, &matches);
+       xfs_rtbuf_cache_relse(&args);
        if (error)
                return error;
 
        *is_free = matches;
        return 0;
 }
+
+/*
+ * 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)
+{
+       return howmany_64(rtextents, NBBY * mp->m_sb.sb_blocksize);
+}
+
+/*
+ * Compute the number of rtbitmap words needed to populate every block of a
+ * bitmap that is large enough to track the given number of rt extents.
+ */
+unsigned long long
+xfs_rtbitmap_wordcount(
+       struct xfs_mount        *mp,
+       xfs_rtbxlen_t           rtextents)
+{
+       xfs_filblks_t           blocks;
+
+       blocks = xfs_rtbitmap_blockcount(mp, rtextents);
+       return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
+}
+
+/* Compute the number of rtsummary blocks needed to track the given rt space. */
+xfs_filblks_t
+xfs_rtsummary_blockcount(
+       struct xfs_mount        *mp,
+       unsigned int            rsumlevels,
+       xfs_extlen_t            rbmblocks)
+{
+       unsigned long long      rsumwords;
+
+       rsumwords = (unsigned long long)rsumlevels * rbmblocks;
+       return XFS_B_TO_FSB(mp, rsumwords << XFS_WORDLOG);
+}
+
+/*
+ * Compute the number of rtsummary info words needed to populate every block of
+ * a summary file that is large enough to track the given rt space.
+ */
+unsigned long long
+xfs_rtsummary_wordcount(
+       struct xfs_mount        *mp,
+       unsigned int            rsumlevels,
+       xfs_extlen_t            rbmblocks)
+{
+       xfs_filblks_t           blocks;
+
+       blocks = xfs_rtsummary_blockcount(mp, rsumlevels, rbmblocks);
+       return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
+}
diff --git a/fs/xfs/libxfs/xfs_rtbitmap.h b/fs/xfs/libxfs/xfs_rtbitmap.h
new file mode 100644 (file)
index 0000000..c063705
--- /dev/null
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ */
+#ifndef __XFS_RTBITMAP_H__
+#define        __XFS_RTBITMAP_H__
+
+struct xfs_rtalloc_args {
+       struct xfs_mount        *mp;
+       struct xfs_trans        *tp;
+
+       struct xfs_buf          *rbmbp; /* bitmap block buffer */
+       struct xfs_buf          *sumbp; /* summary block buffer */
+
+       xfs_fileoff_t           rbmoff; /* bitmap block number */
+       xfs_fileoff_t           sumoff; /* summary block number */
+};
+
+static inline xfs_rtblock_t
+xfs_rtx_to_rtb(
+       struct xfs_mount        *mp,
+       xfs_rtxnum_t            rtx)
+{
+       if (mp->m_rtxblklog >= 0)
+               return rtx << mp->m_rtxblklog;
+
+       return rtx * mp->m_sb.sb_rextsize;
+}
+
+static inline xfs_extlen_t
+xfs_rtxlen_to_extlen(
+       struct xfs_mount        *mp,
+       xfs_rtxlen_t            rtxlen)
+{
+       if (mp->m_rtxblklog >= 0)
+               return rtxlen << mp->m_rtxblklog;
+
+       return rtxlen * mp->m_sb.sb_rextsize;
+}
+
+/* Compute the misalignment between an extent length and a realtime extent .*/
+static inline unsigned int
+xfs_extlen_to_rtxmod(
+       struct xfs_mount        *mp,
+       xfs_extlen_t            len)
+{
+       if (mp->m_rtxblklog >= 0)
+               return len & mp->m_rtxblkmask;
+
+       return len % mp->m_sb.sb_rextsize;
+}
+
+static inline xfs_rtxlen_t
+xfs_extlen_to_rtxlen(
+       struct xfs_mount        *mp,
+       xfs_extlen_t            len)
+{
+       if (mp->m_rtxblklog >= 0)
+               return len >> mp->m_rtxblklog;
+
+       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(
+       struct xfs_mount        *mp,
+       xfs_rtblock_t           rtbno)
+{
+       if (likely(mp->m_rtxblklog >= 0))
+               return rtbno >> mp->m_rtxblklog;
+
+       return div_u64(rtbno, mp->m_sb.sb_rextsize);
+}
+
+/* Return the offset of an rt block number within an rt extent. */
+static inline xfs_extlen_t
+xfs_rtb_to_rtxoff(
+       struct xfs_mount        *mp,
+       xfs_rtblock_t           rtbno)
+{
+       if (likely(mp->m_rtxblklog >= 0))
+               return rtbno & mp->m_rtxblkmask;
+
+       return do_div(rtbno, mp->m_sb.sb_rextsize);
+}
+
+/*
+ * Crack an rt block number into an rt extent number and an offset within that
+ * rt extent.  Returns the rt extent number directly and the offset in @off.
+ */
+static inline xfs_rtxnum_t
+xfs_rtb_to_rtxrem(
+       struct xfs_mount        *mp,
+       xfs_rtblock_t           rtbno,
+       xfs_extlen_t            *off)
+{
+       if (likely(mp->m_rtxblklog >= 0)) {
+               *off = rtbno & mp->m_rtxblkmask;
+               return rtbno >> mp->m_rtxblklog;
+       }
+
+       return div_u64_rem(rtbno, mp->m_sb.sb_rextsize, off);
+}
+
+/*
+ * 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(
+       struct xfs_mount        *mp,
+       xfs_rtblock_t           rtbno)
+{
+       return roundup_64(rtbno, mp->m_sb.sb_rextsize);
+}
+
+/* Round this rtblock down to the nearest rt extent size. */
+static inline xfs_rtblock_t
+xfs_rtb_rounddown_rtx(
+       struct xfs_mount        *mp,
+       xfs_rtblock_t           rtbno)
+{
+       return rounddown_64(rtbno, mp->m_sb.sb_rextsize);
+}
+
+/* Convert an rt extent number to a file block offset in the rt bitmap file. */
+static inline xfs_fileoff_t
+xfs_rtx_to_rbmblock(
+       struct xfs_mount        *mp,
+       xfs_rtxnum_t            rtx)
+{
+       return rtx >> mp->m_blkbit_log;
+}
+
+/* Convert an rt extent number to a word offset within an rt bitmap block. */
+static inline unsigned int
+xfs_rtx_to_rbmword(
+       struct xfs_mount        *mp,
+       xfs_rtxnum_t            rtx)
+{
+       return (rtx >> XFS_NBWORDLOG) & (mp->m_blockwsize - 1);
+}
+
+/* Convert a file block offset in the rt bitmap file to an rt extent number. */
+static inline xfs_rtxnum_t
+xfs_rbmblock_to_rtx(
+       struct xfs_mount        *mp,
+       xfs_fileoff_t           rbmoff)
+{
+       return rbmoff << mp->m_blkbit_log;
+}
+
+/* Return a pointer to a bitmap word within a rt bitmap block. */
+static inline union xfs_rtword_raw *
+xfs_rbmblock_wordptr(
+       struct xfs_rtalloc_args *args,
+       unsigned int            index)
+{
+       union xfs_rtword_raw    *words = args->rbmbp->b_addr;
+
+       return words + index;
+}
+
+/* Convert an ondisk bitmap word to its incore representation. */
+static inline xfs_rtword_t
+xfs_rtbitmap_getword(
+       struct xfs_rtalloc_args *args,
+       unsigned int            index)
+{
+       union xfs_rtword_raw    *word = xfs_rbmblock_wordptr(args, index);
+
+       return word->old;
+}
+
+/* Set an ondisk bitmap word from an incore representation. */
+static inline void
+xfs_rtbitmap_setword(
+       struct xfs_rtalloc_args *args,
+       unsigned int            index,
+       xfs_rtword_t            value)
+{
+       union xfs_rtword_raw    *word = xfs_rbmblock_wordptr(args, index);
+
+       word->old = value;
+}
+
+/*
+ * Convert a rt extent length and rt bitmap block number to a xfs_suminfo_t
+ * offset within the rt summary file.
+ */
+static inline xfs_rtsumoff_t
+xfs_rtsumoffs(
+       struct xfs_mount        *mp,
+       int                     log2_len,
+       xfs_fileoff_t           rbmoff)
+{
+       return log2_len * mp->m_sb.sb_rbmblocks + rbmoff;
+}
+
+/*
+ * Convert an xfs_suminfo_t offset to a file block offset within the rt summary
+ * file.
+ */
+static inline xfs_fileoff_t
+xfs_rtsumoffs_to_block(
+       struct xfs_mount        *mp,
+       xfs_rtsumoff_t          rsumoff)
+{
+       return XFS_B_TO_FSBT(mp, rsumoff * sizeof(xfs_suminfo_t));
+}
+
+/*
+ * Convert an xfs_suminfo_t offset to an info word offset within an rt summary
+ * block.
+ */
+static inline unsigned int
+xfs_rtsumoffs_to_infoword(
+       struct xfs_mount        *mp,
+       xfs_rtsumoff_t          rsumoff)
+{
+       unsigned int            mask = mp->m_blockmask >> XFS_SUMINFOLOG;
+
+       return rsumoff & mask;
+}
+
+/* Return a pointer to a summary info word within a rt summary block. */
+static inline union xfs_suminfo_raw *
+xfs_rsumblock_infoptr(
+       struct xfs_rtalloc_args *args,
+       unsigned int            index)
+{
+       union xfs_suminfo_raw   *info = args->sumbp->b_addr;
+
+       return info + index;
+}
+
+/* Get the current value of a summary counter. */
+static inline xfs_suminfo_t
+xfs_suminfo_get(
+       struct xfs_rtalloc_args *args,
+       unsigned int            index)
+{
+       union xfs_suminfo_raw   *info = xfs_rsumblock_infoptr(args, index);
+
+       return info->old;
+}
+
+/* Add to the current value of a summary counter and return the new value. */
+static inline xfs_suminfo_t
+xfs_suminfo_add(
+       struct xfs_rtalloc_args *args,
+       unsigned int            index,
+       int                     delta)
+{
+       union xfs_suminfo_raw   *info = xfs_rsumblock_infoptr(args, index);
+
+       info->old += delta;
+       return info->old;
+}
+
+/*
+ * Functions for walking free space rtextents in the realtime bitmap.
+ */
+struct xfs_rtalloc_rec {
+       xfs_rtxnum_t            ar_startext;
+       xfs_rtbxlen_t           ar_extcount;
+};
+
+typedef int (*xfs_rtalloc_query_range_fn)(
+       struct xfs_mount                *mp,
+       struct xfs_trans                *tp,
+       const struct xfs_rtalloc_rec    *rec,
+       void                            *priv);
+
+#ifdef CONFIG_XFS_RT
+void xfs_rtbuf_cache_relse(struct xfs_rtalloc_args *args);
+
+int xfs_rtbuf_get(struct xfs_rtalloc_args *args, xfs_fileoff_t block,
+               int issum);
+
+static inline int
+xfs_rtbitmap_read_buf(
+       struct xfs_rtalloc_args         *args,
+       xfs_fileoff_t                   block)
+{
+       return xfs_rtbuf_get(args, block, 0);
+}
+
+static inline int
+xfs_rtsummary_read_buf(
+       struct xfs_rtalloc_args         *args,
+       xfs_fileoff_t                   block)
+{
+       return xfs_rtbuf_get(args, block, 1);
+}
+
+int xfs_rtcheck_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
+               xfs_rtxlen_t len, int val, xfs_rtxnum_t *new, int *stat);
+int xfs_rtfind_back(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
+               xfs_rtxnum_t limit, xfs_rtxnum_t *rtblock);
+int xfs_rtfind_forw(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
+               xfs_rtxnum_t limit, xfs_rtxnum_t *rtblock);
+int xfs_rtmodify_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
+               xfs_rtxlen_t len, int val);
+int xfs_rtmodify_summary_int(struct xfs_rtalloc_args *args, int log,
+               xfs_fileoff_t bbno, int delta, xfs_suminfo_t *sum);
+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,
+               const struct xfs_rtalloc_rec *low_rec,
+               const struct xfs_rtalloc_rec *high_rec,
+               xfs_rtalloc_query_range_fn fn, void *priv);
+int xfs_rtalloc_query_all(struct xfs_mount *mp, 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 */
+
+/* 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);
+
+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_rtbxlen_t rtextents);
+
+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);
+#else /* CONFIG_XFS_RT */
+# define xfs_rtfree_extent(t,b,l)                      (-ENOSYS)
+# define xfs_rtfree_blocks(t,rb,rl)                    (-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)
+# define xfs_rtsummary_read_buf(a,b)                   (-ENOSYS)
+# 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)
+{
+       /* shut up gcc */
+       return 0;
+}
+# define xfs_rtbitmap_wordcount(mp, r)                 (0)
+# define xfs_rtsummary_blockcount(mp, l, b)            (0)
+# define xfs_rtsummary_wordcount(mp, l, b)             (0)
+#endif /* CONFIG_XFS_RT */
+
+#endif /* __XFS_RTBITMAP_H__ */
index 6264daaab37b06151bd12abc2ef9f41f61fcc675..1f74d0cd161841b410311e2490e7759e194fdfab 100644 (file)
@@ -975,6 +975,8 @@ xfs_sb_mount_common(
        mp->m_blockmask = sbp->sb_blocksize - 1;
        mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
        mp->m_blockwmask = mp->m_blockwsize - 1;
+       mp->m_rtxblklog = log2_if_power2(sbp->sb_rextsize);
+       mp->m_rtxblkmask = mask64_if_power2(sbp->sb_rextsize);
 
        mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
        mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
index a5e14740ec9ac3935d5fe9e254d41292174df0a5..19134b23c10be3824de6a7949d6ccf9ebdfa8de0 100644 (file)
@@ -25,7 +25,7 @@ extern uint64_t       xfs_sb_version_to_features(struct xfs_sb *sbp);
 
 extern int     xfs_update_secondary_sbs(struct xfs_mount *mp);
 
-#define XFS_FS_GEOM_MAX_STRUCT_VER     (4)
+#define XFS_FS_GEOM_MAX_STRUCT_VER     (5)
 extern void    xfs_fs_geometry(struct xfs_mount *mp, struct xfs_fsop_geom *geo,
                                int struct_version);
 extern int     xfs_sb_read_secondary(struct xfs_mount *mp,
index 5b2f27cbdb8089d9386cf144288d960777f9d7de..6cd45e8c118daf63b60542b2c1934faff4de3813 100644 (file)
@@ -19,6 +19,7 @@
 #include "xfs_trans.h"
 #include "xfs_qm.h"
 #include "xfs_trans_space.h"
+#include "xfs_rtbitmap.h"
 
 #define _ALLOC true
 #define _FREE  false
@@ -217,11 +218,12 @@ xfs_rtalloc_block_count(
        struct xfs_mount        *mp,
        unsigned int            num_ops)
 {
-       unsigned int            blksz = XFS_FSB_TO_B(mp, 1);
-       unsigned int            rtbmp_bytes;
+       unsigned int            rtbmp_blocks;
+       xfs_rtxlen_t            rtxlen;
 
-       rtbmp_bytes = (XFS_MAX_BMBT_EXTLEN / mp->m_sb.sb_rextsize) / NBBY;
-       return (howmany(rtbmp_bytes, blksz) + 1) * num_ops;
+       rtxlen = xfs_extlen_to_rtxlen(mp, XFS_MAX_BMBT_EXTLEN);
+       rtbmp_blocks = xfs_rtbitmap_blockcount(mp, rtxlen);
+       return (rtbmp_blocks + 1) * num_ops;
 }
 
 /*
index 5c27659347329bc4b6fea4c88b9bc642cbe929cc..c299b16c9365fab61b98e13bebc38607d9768f87 100644 (file)
@@ -148,10 +148,10 @@ xfs_verify_rtbno(
 
 /* Verify that a realtime device extent is fully contained inside the volume. */
 bool
-xfs_verify_rtext(
+xfs_verify_rtbext(
        struct xfs_mount        *mp,
        xfs_rtblock_t           rtbno,
-       xfs_rtblock_t           len)
+       xfs_filblks_t           len)
 {
        if (rtbno + len <= rtbno)
                return false;
index 851220021484177e969ec4b08ae96582d708abcc..533200c4ccc25aa876ae30cd852066f143a2d1a1 100644 (file)
@@ -11,6 +11,7 @@ typedef uint32_t      prid_t;         /* project ID */
 typedef uint32_t       xfs_agblock_t;  /* blockno in alloc. group */
 typedef uint32_t       xfs_agino_t;    /* inode # within allocation grp */
 typedef uint32_t       xfs_extlen_t;   /* extent length in blocks */
+typedef uint32_t       xfs_rtxlen_t;   /* file extent length in rtextents */
 typedef uint32_t       xfs_agnumber_t; /* allocation group number */
 typedef uint64_t       xfs_extnum_t;   /* # of extents in a file */
 typedef uint32_t       xfs_aextnum_t;  /* # extents in an attribute fork */
@@ -18,6 +19,7 @@ typedef int64_t               xfs_fsize_t;    /* bytes in a file */
 typedef uint64_t       xfs_ufsize_t;   /* unsigned bytes in a file */
 
 typedef int32_t                xfs_suminfo_t;  /* type of bitmap summary info */
+typedef uint32_t       xfs_rtsumoff_t; /* offset of an rtsummary info word */
 typedef uint32_t       xfs_rtword_t;   /* word type for bitmap manipulations */
 
 typedef int64_t                xfs_lsn_t;      /* log sequence number */
@@ -31,6 +33,8 @@ typedef uint64_t      xfs_rfsblock_t; /* blockno in filesystem (raw) */
 typedef uint64_t       xfs_rtblock_t;  /* extent (block) in realtime area */
 typedef uint64_t       xfs_fileoff_t;  /* block number in a file */
 typedef uint64_t       xfs_filblks_t;  /* number of blocks in a file */
+typedef uint64_t       xfs_rtxnum_t;   /* rtextent number */
+typedef uint64_t       xfs_rtbxlen_t;  /* rtbitmap extent length in rtextents */
 
 typedef int64_t                xfs_srtblock_t; /* signed version of xfs_rtblock_t */
 
@@ -47,6 +51,7 @@ typedef void *                xfs_failaddr_t;
 #define        NULLRFSBLOCK    ((xfs_rfsblock_t)-1)
 #define        NULLRTBLOCK     ((xfs_rtblock_t)-1)
 #define        NULLFILEOFF     ((xfs_fileoff_t)-1)
+#define        NULLRTEXTNO     ((xfs_rtxnum_t)-1)
 
 #define        NULLAGBLOCK     ((xfs_agblock_t)-1)
 #define        NULLAGNUMBER    ((xfs_agnumber_t)-1)
@@ -145,6 +150,7 @@ typedef uint32_t    xfs_dqid_t;
  */
 #define        XFS_NBBYLOG     3               /* log2(NBBY) */
 #define        XFS_WORDLOG     2               /* log2(sizeof(xfs_rtword_t)) */
+#define        XFS_SUMINFOLOG  2               /* log2(sizeof(xfs_suminfo_t)) */
 #define        XFS_NBWORDLOG   (XFS_NBBYLOG + XFS_WORDLOG)
 #define        XFS_NBWORD      (1 << XFS_NBWORDLOG)
 #define        XFS_WORDMASK    ((1 << XFS_WORDLOG) - 1)
@@ -229,8 +235,8 @@ bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino);
 bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);
 bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino);
 bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno);
-bool xfs_verify_rtext(struct xfs_mount *mp, xfs_rtblock_t rtbno,
-               xfs_rtblock_t len);
+bool xfs_verify_rtbext(struct xfs_mount *mp, xfs_rtblock_t rtbno,
+               xfs_filblks_t len);
 bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount);
 bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off);
 void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min,
index 75588915572e92c3b99c0d89b033ae590086fc18..06d8c1996a3389e4396b3c354a3f88ab76c94d81 100644 (file)
@@ -410,7 +410,7 @@ xchk_bmap_iextent(
 
        /* Make sure the extent points to a valid place. */
        if (info->is_rt &&
-           !xfs_verify_rtext(mp, irec->br_startblock, irec->br_blockcount))
+           !xfs_verify_rtbext(mp, irec->br_startblock, irec->br_blockcount))
                xchk_fblock_set_corrupt(info->sc, info->whichfork,
                                irec->br_startoff);
        if (!info->is_rt &&
index 05be757668bb25ca0bef1d7db4fb0ea5bd996738..5799e9a94f1f665dba31af5b5908248311aa1fb1 100644 (file)
@@ -16,7 +16,7 @@
 #include "xfs_health.h"
 #include "xfs_btree.h"
 #include "xfs_ag.h"
-#include "xfs_rtalloc.h"
+#include "xfs_rtbitmap.h"
 #include "xfs_inode.h"
 #include "xfs_icache.h"
 #include "scrub/scrub.h"
index 59d7912fb75f1eae7ad88fe4acac9ae95553f135..889f556bc98f60cde87832cd0d1612cf49d7c919 100644 (file)
@@ -20,6 +20,7 @@
 #include "xfs_reflink.h"
 #include "xfs_rmap.h"
 #include "xfs_bmap_util.h"
+#include "xfs_rtbitmap.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
@@ -225,7 +226,7 @@ xchk_inode_extsize(
         */
        if ((flags & XFS_DIFLAG_RTINHERIT) &&
            (flags & XFS_DIFLAG_EXTSZINHERIT) &&
-           value % sc->mp->m_sb.sb_rextsize > 0)
+           xfs_extlen_to_rtxmod(sc->mp, value) > 0)
                xchk_ino_set_warning(sc, ino);
 }
 
index 008ddb599e13244b9fcbb57e99191e59035e08dd..41a1d89ae8e6cdce6e465ea68d7fc77a02c189ba 100644 (file)
@@ -11,7 +11,7 @@
 #include "xfs_mount.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_rtalloc.h"
+#include "xfs_rtbitmap.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "scrub/scrub.h"
@@ -48,12 +48,12 @@ xchk_rtbitmap_rec(
 {
        struct xfs_scrub        *sc = priv;
        xfs_rtblock_t           startblock;
-       xfs_rtblock_t           blockcount;
+       xfs_filblks_t           blockcount;
 
-       startblock = rec->ar_startext * mp->m_sb.sb_rextsize;
-       blockcount = rec->ar_extcount * mp->m_sb.sb_rextsize;
+       startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
+       blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
 
-       if (!xfs_verify_rtext(mp, startblock, blockcount))
+       if (!xfs_verify_rtbext(mp, startblock, blockcount))
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
        return 0;
 }
@@ -128,26 +128,22 @@ out:
 void
 xchk_xref_is_used_rt_space(
        struct xfs_scrub        *sc,
-       xfs_rtblock_t           fsbno,
+       xfs_rtblock_t           rtbno,
        xfs_extlen_t            len)
 {
-       xfs_rtblock_t           startext;
-       xfs_rtblock_t           endext;
-       xfs_rtblock_t           extcount;
+       xfs_rtxnum_t            startext;
+       xfs_rtxnum_t            endext;
        bool                    is_free;
        int                     error;
 
        if (xchk_skip_xref(sc->sm))
                return;
 
-       startext = fsbno;
-       endext = fsbno + len - 1;
-       do_div(startext, sc->mp->m_sb.sb_rextsize);
-       do_div(endext, sc->mp->m_sb.sb_rextsize);
-       extcount = endext - startext + 1;
+       startext = xfs_rtb_to_rtx(sc->mp, rtbno);
+       endext = xfs_rtb_to_rtx(sc->mp, rtbno + len - 1);
        xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
-       error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext, extcount,
-                       &is_free);
+       error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext,
+                       endext - startext + 1, &is_free);
        if (!xchk_should_check_xref(sc, &error, NULL))
                goto out_unlock;
        if (is_free)
index 437ed9acbb27383e7a389ff2526f9ba4e1cdd04d..8b15c47408d0310db7889864b9b0b10a3a7a60f7 100644 (file)
@@ -13,7 +13,7 @@
 #include "xfs_inode.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_rtalloc.h"
+#include "xfs_rtbitmap.h"
 #include "xfs_bit.h"
 #include "xfs_bmap.h"
 #include "scrub/scrub.h"
@@ -81,34 +81,45 @@ typedef unsigned int xchk_rtsumoff_t;
 static inline int
 xfsum_load(
        struct xfs_scrub        *sc,
-       xchk_rtsumoff_t         sumoff,
-       xfs_suminfo_t           *info)
+       xfs_rtsumoff_t          sumoff,
+       union xfs_suminfo_raw   *rawinfo)
 {
-       return xfile_obj_load(sc->xfile, info, sizeof(xfs_suminfo_t),
+       return xfile_obj_load(sc->xfile, rawinfo,
+                       sizeof(union xfs_suminfo_raw),
                        sumoff << XFS_WORDLOG);
 }
 
 static inline int
 xfsum_store(
        struct xfs_scrub        *sc,
-       xchk_rtsumoff_t         sumoff,
-       const xfs_suminfo_t     info)
+       xfs_rtsumoff_t          sumoff,
+       const union xfs_suminfo_raw rawinfo)
 {
-       return xfile_obj_store(sc->xfile, &info, sizeof(xfs_suminfo_t),
+       return xfile_obj_store(sc->xfile, &rawinfo,
+                       sizeof(union xfs_suminfo_raw),
                        sumoff << XFS_WORDLOG);
 }
 
 static inline int
 xfsum_copyout(
        struct xfs_scrub        *sc,
-       xchk_rtsumoff_t         sumoff,
-       xfs_suminfo_t           *info,
+       xfs_rtsumoff_t          sumoff,
+       union xfs_suminfo_raw   *rawinfo,
        unsigned int            nr_words)
 {
-       return xfile_obj_load(sc->xfile, info, nr_words << XFS_WORDLOG,
+       return xfile_obj_load(sc->xfile, rawinfo, nr_words << XFS_WORDLOG,
                        sumoff << XFS_WORDLOG);
 }
 
+static inline xfs_suminfo_t
+xchk_rtsum_inc(
+       struct xfs_mount        *mp,
+       union xfs_suminfo_raw   *v)
+{
+       v->old += 1;
+       return v->old;
+}
+
 /* Update the summary file to reflect the free extent that we've accumulated. */
 STATIC int
 xchk_rtsum_record_free(
@@ -121,23 +132,24 @@ xchk_rtsum_record_free(
        xfs_fileoff_t                   rbmoff;
        xfs_rtblock_t                   rtbno;
        xfs_filblks_t                   rtlen;
-       xchk_rtsumoff_t                 offs;
+       xfs_rtsumoff_t                  offs;
        unsigned int                    lenlog;
-       xfs_suminfo_t                   v = 0;
+       union xfs_suminfo_raw           v;
+       xfs_suminfo_t                   value;
        int                             error = 0;
 
        if (xchk_should_terminate(sc, &error))
                return error;
 
        /* Compute the relevant location in the rtsum file. */
-       rbmoff = XFS_BITTOBLOCK(mp, rec->ar_startext);
+       rbmoff = xfs_rtx_to_rbmblock(mp, rec->ar_startext);
        lenlog = XFS_RTBLOCKLOG(rec->ar_extcount);
-       offs = XFS_SUMOFFS(mp, lenlog, rbmoff);
+       offs = xfs_rtsumoffs(mp, lenlog, rbmoff);
 
-       rtbno = rec->ar_startext * mp->m_sb.sb_rextsize;
-       rtlen = rec->ar_extcount * mp->m_sb.sb_rextsize;
+       rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
+       rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
 
-       if (!xfs_verify_rtext(mp, rtbno, rtlen)) {
+       if (!xfs_verify_rtbext(mp, rtbno, rtlen)) {
                xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
                return -EFSCORRUPTED;
        }
@@ -147,9 +159,9 @@ xchk_rtsum_record_free(
        if (error)
                return error;
 
-       v++;
+       value = xchk_rtsum_inc(sc->mp, &v);
        trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount,
-                       lenlog, offs, v);
+                       lenlog, offs, value);
 
        return xfsum_store(sc, offs, v);
 }
@@ -160,12 +172,11 @@ xchk_rtsum_compute(
        struct xfs_scrub        *sc)
 {
        struct xfs_mount        *mp = sc->mp;
-       unsigned long long      rtbmp_bytes;
+       unsigned long long      rtbmp_blocks;
 
        /* If the bitmap size doesn't match the computed size, bail. */
-       rtbmp_bytes = howmany_64(mp->m_sb.sb_rextents, NBBY);
-       if (roundup_64(rtbmp_bytes, mp->m_sb.sb_blocksize) !=
-                       mp->m_rbmip->i_disk_size)
+       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)
                return -EFSCORRUPTED;
 
        return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
@@ -177,14 +188,18 @@ STATIC int
 xchk_rtsum_compare(
        struct xfs_scrub        *sc)
 {
+       struct xfs_rtalloc_args args = {
+               .mp             = sc->mp,
+               .tp             = sc->tp,
+       };
        struct xfs_mount        *mp = sc->mp;
-       struct xfs_buf          *bp;
        struct xfs_bmbt_irec    map;
        xfs_fileoff_t           off;
        xchk_rtsumoff_t         sumoff = 0;
        int                     nmap;
 
        for (off = 0; off < XFS_B_TO_FSB(mp, mp->m_rsumsize); off++) {
+               union xfs_suminfo_raw *ondisk_info;
                int             error = 0;
 
                if (xchk_should_terminate(sc, &error))
@@ -205,22 +220,23 @@ xchk_rtsum_compare(
                }
 
                /* Read a block's worth of ondisk rtsummary file. */
-               error = xfs_rtbuf_get(mp, sc->tp, off, 1, &bp);
+               error = xfs_rtsummary_read_buf(&args, off);
                if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
                        return error;
 
                /* Read a block's worth of computed rtsummary file. */
                error = xfsum_copyout(sc, sumoff, sc->buf, mp->m_blockwsize);
                if (error) {
-                       xfs_trans_brelse(sc->tp, bp);
+                       xfs_rtbuf_cache_relse(&args);
                        return error;
                }
 
-               if (memcmp(bp->b_addr, sc->buf,
+               ondisk_info = xfs_rsumblock_infoptr(&args, 0);
+               if (memcmp(ondisk_info, sc->buf,
                                        mp->m_blockwsize << XFS_WORDLOG) != 0)
                        xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
 
-               xfs_trans_brelse(sc->tp, bp);
+               xfs_rtbuf_cache_relse(&args);
                sumoff += mp->m_blockwsize;
        }
 
index 46249e7b17e09f66b6266758b159a537ab5f66d5..29afa48512355e08be55b2e13392ab1522ebf796 100644 (file)
@@ -13,6 +13,7 @@
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "xfs_ag.h"
+#include "xfs_rtbitmap.h"
 #include "scrub/scrub.h"
 #include "scrub/xfile.h"
 #include "scrub/xfarray.h"
index cbd4d01e253c068e6a47f9366a582d2e1d9e42bd..4a8bc6f3c8f2eaf6f270ce56b7a8dec5fd3a46c1 100644 (file)
@@ -1036,17 +1036,18 @@ TRACE_EVENT(xfarray_sort_stats,
 
 #ifdef CONFIG_XFS_RT
 TRACE_EVENT(xchk_rtsum_record_free,
-       TP_PROTO(struct xfs_mount *mp, xfs_rtblock_t start,
-                uint64_t len, unsigned int log, loff_t pos, xfs_suminfo_t v),
-       TP_ARGS(mp, start, len, log, pos, v),
+       TP_PROTO(struct xfs_mount *mp, xfs_rtxnum_t start,
+                xfs_rtbxlen_t len, unsigned int log, loff_t pos,
+                xfs_suminfo_t value),
+       TP_ARGS(mp, start, len, log, pos, value),
        TP_STRUCT__entry(
                __field(dev_t, dev)
                __field(dev_t, rtdev)
-               __field(xfs_rtblock_t, start)
+               __field(xfs_rtxnum_t, start)
                __field(unsigned long long, len)
                __field(unsigned int, log)
                __field(loff_t, pos)
-               __field(xfs_suminfo_t, v)
+               __field(xfs_suminfo_t, value)
        ),
        TP_fast_assign(
                __entry->dev = mp->m_super->s_dev;
@@ -1055,7 +1056,7 @@ TRACE_EVENT(xchk_rtsum_record_free,
                __entry->len = len;
                __entry->log = log;
                __entry->pos = pos;
-               __entry->v = v;
+               __entry->value = value;
        ),
        TP_printk("dev %d:%d rtdev %d:%d rtx 0x%llx rtxcount 0x%llx log %u rsumpos 0x%llx sumcount %u",
                  MAJOR(__entry->dev), MINOR(__entry->dev),
@@ -1064,7 +1065,7 @@ TRACE_EVENT(xchk_rtsum_record_free,
                  __entry->len,
                  __entry->log,
                  __entry->pos,
-                 __entry->v)
+                 __entry->value)
 );
 #endif /* CONFIG_XFS_RT */
 
index 40e0a1f1f7530cba2193655b0be5ff661bfb107e..731260a5af6db43d06849d32a7384a90188f4031 100644 (file)
@@ -28,6 +28,7 @@
 #include "xfs_icache.h"
 #include "xfs_iomap.h"
 #include "xfs_reflink.h"
+#include "xfs_rtbitmap.h"
 
 /* Kernel only BMAP related definitions and functions */
 
@@ -75,28 +76,28 @@ xfs_bmap_rtalloc(
 {
        struct xfs_mount        *mp = ap->ip->i_mount;
        xfs_fileoff_t           orig_offset = ap->offset;
-       xfs_rtblock_t           rtb;
-       xfs_extlen_t            prod = 0;  /* product factor for allocators */
+       xfs_rtxnum_t            rtx;
+       xfs_rtxlen_t            prod = 0;  /* product factor for allocators */
        xfs_extlen_t            mod = 0;   /* product factor for allocators */
-       xfs_extlen_t            ralen = 0; /* realtime allocation length */
+       xfs_rtxlen_t            ralen = 0; /* realtime allocation length */
        xfs_extlen_t            align;     /* minimum allocation alignment */
        xfs_extlen_t            orig_length = ap->length;
        xfs_extlen_t            minlen = mp->m_sb.sb_rextsize;
-       xfs_extlen_t            raminlen;
+       xfs_rtxlen_t            raminlen;
        bool                    rtlocked = false;
        bool                    ignore_locality = false;
        int                     error;
 
        align = xfs_get_extsz_hint(ap->ip);
 retry:
-       prod = align / mp->m_sb.sb_rextsize;
+       prod = xfs_extlen_to_rtxlen(mp, align);
        error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
                                        align, 1, ap->eof, 0,
                                        ap->conv, &ap->offset, &ap->length);
        if (error)
                return error;
        ASSERT(ap->length);
-       ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
+       ASSERT(xfs_extlen_to_rtxmod(mp, ap->length) == 0);
 
        /*
         * If we shifted the file offset downward to satisfy an extent size
@@ -116,17 +117,14 @@ retry:
                prod = 1;
        /*
         * Set ralen to be the actual requested length in rtextents.
-        */
-       ralen = ap->length / mp->m_sb.sb_rextsize;
-       /*
+        *
         * If the old value was close enough to XFS_BMBT_MAX_EXTLEN that
         * we rounded up to it, cut it back so it's valid again.
         * Note that if it's a really large request (bigger than
         * XFS_BMBT_MAX_EXTLEN), we don't hear about that number, and can't
         * adjust the starting point to match it.
         */
-       if (ralen * mp->m_sb.sb_rextsize >= XFS_MAX_BMBT_EXTLEN)
-               ralen = XFS_MAX_BMBT_EXTLEN / mp->m_sb.sb_rextsize;
+       ralen = xfs_extlen_to_rtxlen(mp, min(ap->length, XFS_MAX_BMBT_EXTLEN));
 
        /*
         * Lock out modifications to both the RT bitmap and summary inodes
@@ -144,12 +142,10 @@ retry:
         * pick an extent that will space things out in the rt area.
         */
        if (ap->eof && ap->offset == 0) {
-               xfs_rtblock_t rtx; /* realtime extent no */
-
                error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
                if (error)
                        return error;
-               ap->blkno = rtx * mp->m_sb.sb_rextsize;
+               ap->blkno = xfs_rtx_to_rtb(mp, rtx);
        } else {
                ap->blkno = 0;
        }
@@ -160,20 +156,18 @@ retry:
         * Realtime allocation, done through xfs_rtallocate_extent.
         */
        if (ignore_locality)
-               ap->blkno = 0;
+               rtx = 0;
        else
-               do_div(ap->blkno, mp->m_sb.sb_rextsize);
-       rtb = ap->blkno;
-       ap->length = ralen;
-       raminlen = max_t(xfs_extlen_t, 1, minlen / mp->m_sb.sb_rextsize);
-       error = xfs_rtallocate_extent(ap->tp, ap->blkno, raminlen, ap->length,
-                       &ralen, ap->wasdel, prod, &rtb);
+               rtx = xfs_rtb_to_rtx(mp, ap->blkno);
+       raminlen = max_t(xfs_rtxlen_t, 1, xfs_extlen_to_rtxlen(mp, minlen));
+       error = xfs_rtallocate_extent(ap->tp, rtx, raminlen, ralen, &ralen,
+                       ap->wasdel, prod, &rtx);
        if (error)
                return error;
 
-       if (rtb != NULLRTBLOCK) {
-               ap->blkno = rtb * mp->m_sb.sb_rextsize;
-               ap->length = ralen * mp->m_sb.sb_rextsize;
+       if (rtx != NULLRTEXTNO) {
+               ap->blkno = xfs_rtx_to_rtb(mp, rtx);
+               ap->length = xfs_rtxlen_to_extlen(mp, ralen);
                ap->ip->i_nblocks += ap->length;
                xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
                if (ap->wasdel)
@@ -690,7 +684,7 @@ xfs_can_free_eofblocks(
         */
        end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
        if (XFS_IS_REALTIME_INODE(ip) && mp->m_sb.sb_rextsize > 1)
-               end_fsb = roundup_64(end_fsb, mp->m_sb.sb_rextsize);
+               end_fsb = xfs_rtb_roundup_rtx(mp, end_fsb);
        last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
        if (last_fsb <= end_fsb)
                return false;
@@ -780,12 +774,10 @@ xfs_alloc_file_space(
 {
        xfs_mount_t             *mp = ip->i_mount;
        xfs_off_t               count;
-       xfs_filblks_t           allocated_fsb;
        xfs_filblks_t           allocatesize_fsb;
        xfs_extlen_t            extsz, temp;
        xfs_fileoff_t           startoffset_fsb;
        xfs_fileoff_t           endoffset_fsb;
-       int                     nimaps;
        int                     rt;
        xfs_trans_t             *tp;
        xfs_bmbt_irec_t         imaps[1], *imapp;
@@ -808,7 +800,6 @@ xfs_alloc_file_space(
 
        count = len;
        imapp = &imaps[0];
-       nimaps = 1;
        startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
        endoffset_fsb = XFS_B_TO_FSB(mp, offset + count);
        allocatesize_fsb = endoffset_fsb - startoffset_fsb;
@@ -819,6 +810,7 @@ xfs_alloc_file_space(
        while (allocatesize_fsb && !error) {
                xfs_fileoff_t   s, e;
                unsigned int    dblocks, rblocks, resblks;
+               int             nimaps = 1;
 
                /*
                 * Determine space reservations for data/realtime.
@@ -884,15 +876,19 @@ xfs_alloc_file_space(
                if (error)
                        break;
 
-               allocated_fsb = imapp->br_blockcount;
-
-               if (nimaps == 0) {
-                       error = -ENOSPC;
-                       break;
+               /*
+                * If the allocator cannot find a single free extent large
+                * enough to cover the start block of the requested range,
+                * xfs_bmapi_write will return 0 but leave *nimaps set to 0.
+                *
+                * In that case we simply need to keep looping with the same
+                * startoffset_fsb so that one of the following allocations
+                * will eventually reach the requested range.
+                */
+               if (nimaps) {
+                       startoffset_fsb += imapp->br_blockcount;
+                       allocatesize_fsb -= imapp->br_blockcount;
                }
-
-               startoffset_fsb += allocated_fsb;
-               allocatesize_fsb -= allocated_fsb;
        }
 
        return error;
@@ -989,10 +985,8 @@ xfs_free_file_space(
 
        /* We can only free complete realtime extents. */
        if (XFS_IS_REALTIME_INODE(ip) && mp->m_sb.sb_rextsize > 1) {
-               startoffset_fsb = roundup_64(startoffset_fsb,
-                                            mp->m_sb.sb_rextsize);
-               endoffset_fsb = rounddown_64(endoffset_fsb,
-                                            mp->m_sb.sb_rextsize);
+               startoffset_fsb = xfs_rtb_roundup_rtx(mp, startoffset_fsb);
+               endoffset_fsb = xfs_rtb_rounddown_rtx(mp, endoffset_fsb);
        }
 
        /*
index 203700278ddbb620a6e9d7c95b68a86f4ea52c63..e33e5e13b95f462ffe33c232739af6c4762758a0 100644 (file)
@@ -214,6 +214,43 @@ xfs_ilock_iocb(
        return 0;
 }
 
+static int
+xfs_ilock_iocb_for_write(
+       struct kiocb            *iocb,
+       unsigned int            *lock_mode)
+{
+       ssize_t                 ret;
+       struct xfs_inode        *ip = XFS_I(file_inode(iocb->ki_filp));
+
+       ret = xfs_ilock_iocb(iocb, *lock_mode);
+       if (ret)
+               return ret;
+
+       if (*lock_mode == XFS_IOLOCK_EXCL)
+               return 0;
+       if (!xfs_iflags_test(ip, XFS_IREMAPPING))
+               return 0;
+
+       xfs_iunlock(ip, *lock_mode);
+       *lock_mode = XFS_IOLOCK_EXCL;
+       return xfs_ilock_iocb(iocb, *lock_mode);
+}
+
+static unsigned int
+xfs_ilock_for_write_fault(
+       struct xfs_inode        *ip)
+{
+       /* get a shared lock if no remapping in progress */
+       xfs_ilock(ip, XFS_MMAPLOCK_SHARED);
+       if (!xfs_iflags_test(ip, XFS_IREMAPPING))
+               return XFS_MMAPLOCK_SHARED;
+
+       /* wait for remapping to complete */
+       xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);
+       xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+       return XFS_MMAPLOCK_EXCL;
+}
+
 STATIC ssize_t
 xfs_file_dio_read(
        struct kiocb            *iocb,
@@ -551,7 +588,7 @@ xfs_file_dio_write_aligned(
        unsigned int            iolock = XFS_IOLOCK_SHARED;
        ssize_t                 ret;
 
-       ret = xfs_ilock_iocb(iocb, iolock);
+       ret = xfs_ilock_iocb_for_write(iocb, &iolock);
        if (ret)
                return ret;
        ret = xfs_file_write_checks(iocb, from, &iolock);
@@ -618,7 +655,7 @@ retry_exclusive:
                flags = IOMAP_DIO_FORCE_WAIT;
        }
 
-       ret = xfs_ilock_iocb(iocb, iolock);
+       ret = xfs_ilock_iocb_for_write(iocb, &iolock);
        if (ret)
                return ret;
 
@@ -1180,7 +1217,7 @@ xfs_file_remap_range(
        if (xfs_file_sync_writes(file_in) || xfs_file_sync_writes(file_out))
                xfs_log_force_inode(dest);
 out_unlock:
-       xfs_iunlock2_io_mmap(src, dest);
+       xfs_iunlock2_remapping(src, dest);
        if (ret)
                trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
        return remapped > 0 ? remapped : ret;
@@ -1328,6 +1365,7 @@ __xfs_filemap_fault(
        struct inode            *inode = file_inode(vmf->vma->vm_file);
        struct xfs_inode        *ip = XFS_I(inode);
        vm_fault_t              ret;
+       unsigned int            lock_mode = 0;
 
        trace_xfs_filemap_fault(ip, order, write_fault);
 
@@ -1336,25 +1374,24 @@ __xfs_filemap_fault(
                file_update_time(vmf->vma->vm_file);
        }
 
+       if (IS_DAX(inode) || write_fault)
+               lock_mode = xfs_ilock_for_write_fault(XFS_I(inode));
+
        if (IS_DAX(inode)) {
                pfn_t pfn;
 
-               xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
                ret = xfs_dax_fault(vmf, order, write_fault, &pfn);
                if (ret & VM_FAULT_NEEDDSYNC)
                        ret = dax_finish_sync_fault(vmf, order, pfn);
-               xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
+       } else if (write_fault) {
+               ret = iomap_page_mkwrite(vmf, &xfs_page_mkwrite_iomap_ops);
        } else {
-               if (write_fault) {
-                       xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
-                       ret = iomap_page_mkwrite(vmf,
-                                       &xfs_page_mkwrite_iomap_ops);
-                       xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
-               } else {
-                       ret = filemap_fault(vmf);
-               }
+               ret = filemap_fault(vmf);
        }
 
+       if (lock_mode)
+               xfs_iunlock(XFS_I(inode), lock_mode);
+
        if (write_fault)
                sb_end_pagefault(inode->i_sb);
        return ret;
index 736e5545f584025ec204dfc6059e83fc06e99bdb..5a72217f5feb9b990ff3a41d1cb79519cf2b3091 100644 (file)
@@ -23,7 +23,7 @@
 #include "xfs_refcount.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_alloc_btree.h"
-#include "xfs_rtalloc.h"
+#include "xfs_rtbitmap.h"
 #include "xfs_ag.h"
 
 /* Convert an xfs_fsmap to an fsmap. */
@@ -483,11 +483,11 @@ xfs_getfsmap_rtdev_rtbitmap_helper(
        xfs_rtblock_t                   rtbno;
        xfs_daddr_t                     rec_daddr, len_daddr;
 
-       rtbno = rec->ar_startext * mp->m_sb.sb_rextsize;
+       rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
        rec_daddr = XFS_FSB_TO_BB(mp, rtbno);
        irec.rm_startblock = rtbno;
 
-       rtbno = rec->ar_extcount * mp->m_sb.sb_rextsize;
+       rtbno = xfs_rtx_to_rtb(mp, rec->ar_extcount);
        len_daddr = XFS_FSB_TO_BB(mp, rtbno);
        irec.rm_blockcount = rtbno;
 
@@ -514,7 +514,7 @@ xfs_getfsmap_rtdev_rtbitmap(
        uint64_t                        eofs;
        int                             error;
 
-       eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rextents * mp->m_sb.sb_rextsize);
+       eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
        if (keys[0].fmr_physical >= eofs)
                return 0;
        start_rtb = XFS_BB_TO_FSBT(mp,
@@ -539,11 +539,8 @@ xfs_getfsmap_rtdev_rtbitmap(
         * Set up query parameters to return free rtextents covering the range
         * we want.
         */
-       alow.ar_startext = start_rtb;
-       ahigh.ar_startext = end_rtb;
-       do_div(alow.ar_startext, mp->m_sb.sb_rextsize);
-       if (do_div(ahigh.ar_startext, mp->m_sb.sb_rextsize))
-               ahigh.ar_startext++;
+       alow.ar_startext = xfs_rtb_to_rtx(mp, start_rtb);
+       ahigh.ar_startext = xfs_rtb_to_rtxup(mp, end_rtb);
        error = xfs_rtalloc_query_range(mp, tp, &alow, &ahigh,
                        xfs_getfsmap_rtdev_rtbitmap_helper, info);
        if (error)
index 36f5cf802c07b65ad74e9d158a79d36b36ad63a3..c0f1c89786c2ac083482ece0bb312692ab8255a3 100644 (file)
@@ -918,6 +918,13 @@ xfs_droplink(
        xfs_trans_t *tp,
        xfs_inode_t *ip)
 {
+       if (VFS_I(ip)->i_nlink == 0) {
+               xfs_alert(ip->i_mount,
+                         "%s: Attempt to drop inode (%llu) with nlink zero.",
+                         __func__, ip->i_ino);
+               return -EFSCORRUPTED;
+       }
+
        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
 
        drop_nlink(VFS_I(ip));
@@ -3621,6 +3628,23 @@ xfs_iunlock2_io_mmap(
                inode_unlock(VFS_I(ip1));
 }
 
+/* Drop the MMAPLOCK and the IOLOCK after a remap completes. */
+void
+xfs_iunlock2_remapping(
+       struct xfs_inode        *ip1,
+       struct xfs_inode        *ip2)
+{
+       xfs_iflags_clear(ip1, XFS_IREMAPPING);
+
+       if (ip1 != ip2)
+               xfs_iunlock(ip1, XFS_MMAPLOCK_SHARED);
+       xfs_iunlock(ip2, XFS_MMAPLOCK_EXCL);
+
+       if (ip1 != ip2)
+               inode_unlock_shared(VFS_I(ip1));
+       inode_unlock(VFS_I(ip2));
+}
+
 /*
  * Reload the incore inode list for this inode.  Caller should ensure that
  * the link count cannot change, either by taking ILOCK_SHARED or otherwise
index 0c5bdb91152e1cf920cfb5cb76268d0b025640fc..3dc47937da5d17d81e46fd590435f574d11558dc 100644 (file)
@@ -347,6 +347,14 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
 /* Quotacheck is running but inode has not been added to quota counts. */
 #define XFS_IQUOTAUNCHECKED    (1 << 14)
 
+/*
+ * Remap in progress. Callers that wish to update file data while
+ * holding a shared IOLOCK or MMAPLOCK must drop the lock and retake
+ * the lock in exclusive mode. Relocking the file will block until
+ * IREMAPPING is cleared.
+ */
+#define XFS_IREMAPPING         (1U << 15)
+
 /* All inode state flags related to inode reclaim. */
 #define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \
                                 XFS_IRECLAIM | \
@@ -595,6 +603,7 @@ void xfs_end_io(struct work_struct *work);
 
 int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
 void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
+void xfs_iunlock2_remapping(struct xfs_inode *ip1, struct xfs_inode *ip2);
 
 static inline bool
 xfs_inode_unlinked_incomplete(
index 17c51804f9c6aed2d3f4043172b67cf3754cd140..cd7803fda8b1be501af6d19d900d9d80bef5a391 100644 (file)
@@ -19,6 +19,7 @@
 #include "xfs_log.h"
 #include "xfs_log_priv.h"
 #include "xfs_error.h"
+#include "xfs_rtbitmap.h"
 
 #include <linux/iversion.h>
 
@@ -107,7 +108,7 @@ xfs_inode_item_precommit(
         */
        if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
            (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) &&
-           (ip->i_extsize % ip->i_mount->m_sb.sb_rextsize) > 0) {
+           xfs_extlen_to_rtxmod(ip->i_mount, ip->i_extsize) > 0) {
                ip->i_diflags &= ~(XFS_DIFLAG_EXTSIZE |
                                   XFS_DIFLAG_EXTSZINHERIT);
                ip->i_extsize = 0;
index 55bb01173cde8c06099a79b2bcd631fea25bf771..a82470e027f7278ac4b3271cd67a27ed97235c77 100644 (file)
@@ -38,6 +38,7 @@
 #include "xfs_reflink.h"
 #include "xfs_ioctl.h"
 #include "xfs_xattr.h"
+#include "xfs_rtbitmap.h"
 
 #include <linux/mount.h>
 #include <linux/namei.h>
@@ -1004,7 +1005,7 @@ xfs_fill_fsxattr(
                 * later.
                 */
                if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
-                   ip->i_extsize % mp->m_sb.sb_rextsize > 0) {
+                   xfs_extlen_to_rtxmod(mp, ip->i_extsize) > 0) {
                        fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE |
                                            FS_XFLAG_EXTSZINHERIT);
                        fa->fsx_extsize = 0;
@@ -1130,7 +1131,7 @@ xfs_ioctl_setattr_xflags(
        /* If realtime flag is set then must have realtime device */
        if (fa->fsx_xflags & FS_XFLAG_REALTIME) {
                if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 ||
-                   (ip->i_extsize % mp->m_sb.sb_rextsize))
+                   xfs_extlen_to_rtxmod(mp, ip->i_extsize))
                        return -EINVAL;
        }
 
index e9d317a3dafe4e673c439e504bc7fc24ca503dbe..d7873e0360f0b9f170fc8cdaffa0ce49b1c5ed37 100644 (file)
@@ -198,6 +198,18 @@ static inline uint64_t howmany_64(uint64_t x, uint32_t y)
        return x;
 }
 
+/* If @b is a power of 2, return log2(b).  Else return -1. */
+static inline int8_t log2_if_power2(unsigned long b)
+{
+       return is_power_of_2(b) ? ilog2(b) : -1;
+}
+
+/* If @b is a power of 2, return a mask of the lower bits, else return zero. */
+static inline unsigned long long mask64_if_power2(unsigned long b)
+{
+       return is_power_of_2(b) ? b - 1 : 0;
+}
+
 int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
                char *data, enum req_op op);
 
index 219681d29fbc496cd594c21ddb921b03918e3755..503fe3c7edbf82cd1f194b3fd3d33b27bb06167d 100644 (file)
@@ -101,9 +101,9 @@ typedef struct xfs_mount {
 
        /*
         * Optional cache of rt summary level per bitmap block with the
-        * invariant that m_rsum_cache[bbno] <= the minimum i for which
-        * rsum[i][bbno] != 0. Reads and writes are serialized by the rsumip
-        * inode lock.
+        * 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 */
@@ -119,6 +119,7 @@ typedef struct xfs_mount {
        uint8_t                 m_blkbb_log;    /* blocklog - BBSHIFT */
        uint8_t                 m_agno_log;     /* log #ag's */
        uint8_t                 m_sectbb_log;   /* sectlog - BBSHIFT */
+       int8_t                  m_rtxblklog;    /* log2 of rextsize, if possible */
        uint                    m_blockmask;    /* sb_blocksize-1 */
        uint                    m_blockwsize;   /* sb_blocksize in words */
        uint                    m_blockwmask;   /* blockwsize-1 */
@@ -152,6 +153,7 @@ typedef struct xfs_mount {
        uint64_t                m_features;     /* active filesystem features */
        uint64_t                m_low_space[XFS_LOWSP_MAX];
        uint64_t                m_low_rtexts[XFS_LOWSP_MAX];
+       uint64_t                m_rtxblkmask;   /* rt extent block mask */
        struct xfs_ino_geometry m_ino_geo;      /* inode geometry */
        struct xfs_trans_resv   m_resv;         /* precomputed res values */
                                                /* low free space thresholds */
index c4cc99b70dd303e84c6684220f1085ed22c343f3..21a7e350b4c58ee9b9e1cd164a73ee9a23cb7b7d 100644 (file)
@@ -72,6 +72,10 @@ xfs_check_ondisk_structs(void)
        XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_map_t,              4);
        XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_name_local_t,       4);
 
+       /* realtime structures */
+       XFS_CHECK_STRUCT_SIZE(union xfs_rtword_raw,             4);
+       XFS_CHECK_STRUCT_SIZE(union xfs_suminfo_raw,            4);
+
        /*
         * m68k has problems with xfs_attr_leaf_name_remote_t, but we pad it to
         * 4 bytes anyway so it's not obviously a problem.  Hence for the moment
index eb9102453affbf34c9378a7b354de22e16f6d7a3..658edee8381dcdca656135a74a9b5a1b6e13a8cb 100644 (file)
@@ -1540,6 +1540,10 @@ xfs_reflink_remap_prep(
        if (ret)
                goto out_unlock;
 
+       xfs_iflags_set(src, XFS_IREMAPPING);
+       if (inode_in != inode_out)
+               xfs_ilock_demote(src, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
+
        return 0;
 out_unlock:
        xfs_iunlock2_io_mmap(src, dest);
index 2e1a4e5cd03def7495310d7213d2b99dbe617a51..88c48de5c9c810c97e38170ecb4bf84fe42c7b35 100644 (file)
@@ -19,6 +19,7 @@
 #include "xfs_icache.h"
 #include "xfs_rtalloc.h"
 #include "xfs_sb.h"
+#include "xfs_rtbitmap.h"
 
 /*
  * Read and return the summary information for a given extent size,
  */
 static int
 xfs_rtget_summary(
-       xfs_mount_t     *mp,            /* file system mount structure */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       int             log,            /* log2 of extent size */
-       xfs_rtblock_t   bbno,           /* bitmap block number */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
-       xfs_suminfo_t   *sum)           /* out: summary info for this block */
+       struct xfs_rtalloc_args *args,
+       int                     log,    /* log2 of extent size */
+       xfs_fileoff_t           bbno,   /* bitmap block number */
+       xfs_suminfo_t           *sum)   /* out: summary info for this block */
 {
-       return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
+       return xfs_rtmodify_summary_int(args, log, bbno, 0, sum);
 }
 
 /*
  * Return whether there are any free extents in the size range given
  * by low and high, for the bitmap block bbno.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtany_summary(
-       xfs_mount_t     *mp,            /* file system mount structure */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       int             low,            /* low log2 extent size */
-       int             high,           /* high log2 extent size */
-       xfs_rtblock_t   bbno,           /* bitmap block number */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
-       int             *stat)          /* out: any good extents here? */
+       struct xfs_rtalloc_args *args,
+       int                     low,    /* low log2 extent size */
+       int                     high,   /* high log2 extent size */
+       xfs_fileoff_t           bbno,   /* bitmap block number */
+       int                     *maxlog) /* out: max log2 extent size free */
 {
-       int             error;          /* error value */
-       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 && low < mp->m_rsum_cache[bbno])
-               low = mp->m_rsum_cache[bbno];
+       struct xfs_mount        *mp = args->mp;
+       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);
+               if (low > high) {
+                       *maxlog = -1;
+                       return 0;
+               }
+       }
 
        /*
         * Loop over logs of extent sizes.
         */
-       for (log = low; log <= high; log++) {
+       for (log = high; log >= low; log--) {
                /*
                 * Get one summary datum.
                 */
-               error = xfs_rtget_summary(mp, tp, log, bbno, rbpp, rsb, &sum);
+               error = xfs_rtget_summary(args, log, bbno, &sum);
                if (error) {
                        return error;
                }
@@ -77,18 +78,18 @@ xfs_rtany_summary(
                 * If there are any, return success.
                 */
                if (sum) {
-                       *stat = 1;
+                       *maxlog = log;
                        goto out;
                }
        }
        /*
         * Found nothing, return failure.
         */
-       *stat = 0;
+       *maxlog = -1;
 out:
-       /* There were no extents at levels < log. */
-       if (mp->m_rsum_cache && log > mp->m_rsum_cache[bbno])
-               mp->m_rsum_cache[bbno] = log;
+       /* 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;
        return 0;
 }
 
@@ -97,60 +98,54 @@ out:
  * Copy and transform the summary file, given the old and new
  * parameters in the mount structures.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtcopy_summary(
-       xfs_mount_t     *omp,           /* old file system mount point */
-       xfs_mount_t     *nmp,           /* new file system mount point */
-       xfs_trans_t     *tp)            /* transaction pointer */
+       struct xfs_rtalloc_args *oargs,
+       struct xfs_rtalloc_args *nargs)
 {
-       xfs_rtblock_t   bbno;           /* bitmap block number */
-       struct xfs_buf  *bp;            /* summary buffer */
-       int             error;          /* error return value */
-       int             log;            /* summary level number (log length) */
-       xfs_suminfo_t   sum;            /* summary data */
-       xfs_fsblock_t   sumbno;         /* summary block number */
+       xfs_fileoff_t           bbno;   /* bitmap block number */
+       int                     error;
+       int                     log;    /* summary level number (log length) */
+       xfs_suminfo_t           sum;    /* summary data */
 
-       bp = NULL;
-       for (log = omp->m_rsumlevels - 1; log >= 0; log--) {
-               for (bbno = omp->m_sb.sb_rbmblocks - 1;
+       for (log = oargs->mp->m_rsumlevels - 1; log >= 0; log--) {
+               for (bbno = oargs->mp->m_sb.sb_rbmblocks - 1;
                     (xfs_srtblock_t)bbno >= 0;
                     bbno--) {
-                       error = xfs_rtget_summary(omp, tp, log, bbno, &bp,
-                               &sumbno, &sum);
+                       error = xfs_rtget_summary(oargs, log, bbno, &sum);
                        if (error)
-                               return error;
+                               goto out;
                        if (sum == 0)
                                continue;
-                       error = xfs_rtmodify_summary(omp, tp, log, bbno, -sum,
-                               &bp, &sumbno);
+                       error = xfs_rtmodify_summary(oargs, log, bbno, -sum);
                        if (error)
-                               return error;
-                       error = xfs_rtmodify_summary(nmp, tp, log, bbno, sum,
-                               &bp, &sumbno);
+                               goto out;
+                       error = xfs_rtmodify_summary(nargs, log, bbno, sum);
                        if (error)
-                               return error;
+                               goto out;
                        ASSERT(sum > 0);
                }
        }
+       error = 0;
+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.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtallocate_range(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   start,          /* start block to allocate */
-       xfs_extlen_t    len,            /* length to allocate */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb)           /* in/out: summary block number */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* start rtext to allocate */
+       xfs_rtxlen_t            len)    /* in/out: summary block number */
 {
-       xfs_rtblock_t   end;            /* end of the allocated extent */
-       int             error;          /* error value */
-       xfs_rtblock_t   postblock = 0;  /* first block allocated > end */
-       xfs_rtblock_t   preblock = 0;   /* first block allocated < start */
+       struct xfs_mount        *mp = args->mp;
+       xfs_rtxnum_t            end;    /* end of the allocated rtext */
+       int                     error;
+       xfs_rtxnum_t            postblock = 0; /* first rtext allocated > end */
+       xfs_rtxnum_t            preblock = 0; /* first rtext allocated < start */
 
        end = start + len - 1;
        /*
@@ -158,15 +153,15 @@ xfs_rtallocate_range(
         * We need to find the beginning and end of the extent so we can
         * properly update the summary.
         */
-       error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
+       error = xfs_rtfind_back(args, start, 0, &preblock);
        if (error) {
                return error;
        }
        /*
         * Find the next allocated block (end of free extent).
         */
-       error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
-               &postblock);
+       error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
+                       &postblock);
        if (error) {
                return error;
        }
@@ -174,9 +169,9 @@ xfs_rtallocate_range(
         * Decrement the summary information corresponding to the entire
         * (old) free extent.
         */
-       error = xfs_rtmodify_summary(mp, tp,
-               XFS_RTBLOCKLOG(postblock + 1 - preblock),
-               XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
+       error = xfs_rtmodify_summary(args,
+                       XFS_RTBLOCKLOG(postblock + 1 - preblock),
+                       xfs_rtx_to_rbmblock(mp, preblock), -1);
        if (error) {
                return error;
        }
@@ -185,9 +180,9 @@ xfs_rtallocate_range(
         * old extent, add summary data for them to be free.
         */
        if (preblock < start) {
-               error = xfs_rtmodify_summary(mp, tp,
-                       XFS_RTBLOCKLOG(start - preblock),
-                       XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
+               error = xfs_rtmodify_summary(args,
+                               XFS_RTBLOCKLOG(start - preblock),
+                               xfs_rtx_to_rbmblock(mp, preblock), 1);
                if (error) {
                        return error;
                }
@@ -197,9 +192,9 @@ xfs_rtallocate_range(
         * old extent, add summary data for them to be free.
         */
        if (postblock > end) {
-               error = xfs_rtmodify_summary(mp, tp,
-                       XFS_RTBLOCKLOG(postblock - end),
-                       XFS_BITTOBLOCK(mp, end + 1), 1, rbpp, rsb);
+               error = xfs_rtmodify_summary(args,
+                               XFS_RTBLOCKLOG(postblock - end),
+                               xfs_rtx_to_rbmblock(mp, end + 1), 1);
                if (error) {
                        return error;
                }
@@ -207,54 +202,69 @@ xfs_rtallocate_range(
        /*
         * Modify the bitmap to mark this extent allocated.
         */
-       error = xfs_rtmodify_range(mp, tp, start, len, 0);
+       error = xfs_rtmodify_range(args, start, len, 0);
        return error;
 }
 
+/*
+ * Make sure we don't run off the end of the rt volume.  Be careful that
+ * adjusting maxlen downwards doesn't cause us to fail the alignment checks.
+ */
+static inline xfs_rtxlen_t
+xfs_rtallocate_clamp_len(
+       struct xfs_mount        *mp,
+       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;
+       return rounddown(ret, prod);
+}
+
 /*
  * Attempt to allocate an extent minlen<=len<=maxlen starting from
  * bitmap block bbno.  If we don't get maxlen then use prod to trim
- * the length, if given.  Returns error; returns starting block in *rtblock.
+ * the length, if given.  Returns error; returns starting block in *rtx.
  * The lengths are all in rtextents.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtallocate_extent_block(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   bbno,           /* bitmap block number */
-       xfs_extlen_t    minlen,         /* minimum length to allocate */
-       xfs_extlen_t    maxlen,         /* maximum length to allocate */
-       xfs_extlen_t    *len,           /* out: actual length allocated */
-       xfs_rtblock_t   *nextp,         /* out: next block to try */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
-       xfs_extlen_t    prod,           /* extent product factor */
-       xfs_rtblock_t   *rtblock)       /* out: start block allocated */
+       struct xfs_rtalloc_args *args,
+       xfs_fileoff_t           bbno,   /* bitmap block number */
+       xfs_rtxlen_t            minlen, /* minimum length to allocate */
+       xfs_rtxlen_t            maxlen, /* maximum length to allocate */
+       xfs_rtxlen_t            *len,   /* out: actual length allocated */
+       xfs_rtxnum_t            *nextp, /* out: next rtext to try */
+       xfs_rtxlen_t            prod,   /* extent product factor */
+       xfs_rtxnum_t            *rtx)   /* out: start rtext allocated */
 {
-       xfs_rtblock_t   besti;          /* best rtblock found so far */
-       xfs_rtblock_t   bestlen;        /* best length found so far */
-       xfs_rtblock_t   end;            /* last rtblock in chunk */
-       int             error;          /* error value */
-       xfs_rtblock_t   i;              /* current rtblock trying */
-       xfs_rtblock_t   next;           /* next rtblock to try */
-       int             stat;           /* status from internal calls */
+       struct xfs_mount        *mp = args->mp;
+       xfs_rtxnum_t            besti;  /* best rtext found so far */
+       xfs_rtxnum_t            bestlen;/* best length found so far */
+       xfs_rtxnum_t            end;    /* last rtext in chunk */
+       int                     error;
+       xfs_rtxnum_t            i;      /* current rtext trying */
+       xfs_rtxnum_t            next;   /* next rtext to try */
+       int                     stat;   /* status from internal calls */
 
        /*
         * Loop over all the extents starting in this bitmap block,
         * looking for one that's long enough.
         */
-       for (i = XFS_BLOCKTOBIT(mp, bbno), besti = -1, bestlen = 0,
-               end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1;
+       for (i = xfs_rbmblock_to_rtx(mp, bbno), besti = -1, bestlen = 0,
+               end = xfs_rbmblock_to_rtx(mp, bbno + 1) - 1;
             i <= end;
             i++) {
                /* Make sure we don't scan off the end of the rt volume. */
-               maxlen = min(mp->m_sb.sb_rextents, i + maxlen) - i;
+               maxlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
 
                /*
                 * See if there's a free extent of maxlen starting at i.
                 * If it's not so then next will contain the first non-free.
                 */
-               error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat);
+               error = xfs_rtcheck_range(args, i, maxlen, 1, &next, &stat);
                if (error) {
                        return error;
                }
@@ -262,13 +272,12 @@ xfs_rtallocate_extent_block(
                        /*
                         * i for maxlen is all free, allocate and return that.
                         */
-                       error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp,
-                               rsb);
+                       error = xfs_rtallocate_range(args, i, maxlen);
                        if (error) {
                                return error;
                        }
                        *len = maxlen;
-                       *rtblock = i;
+                       *rtx = i;
                        return 0;
                }
                /*
@@ -278,7 +287,7 @@ xfs_rtallocate_extent_block(
                 * so far, remember it.
                 */
                if (minlen < maxlen) {
-                       xfs_rtblock_t   thislen;        /* this extent size */
+                       xfs_rtxnum_t    thislen;        /* this extent size */
 
                        thislen = next - i;
                        if (thislen >= minlen && thislen > bestlen) {
@@ -290,7 +299,7 @@ xfs_rtallocate_extent_block(
                 * If not done yet, find the start of the next free space.
                 */
                if (next < end) {
-                       error = xfs_rtfind_forw(mp, tp, next, end, &i);
+                       error = xfs_rtfind_forw(args, next, end, &i);
                        if (error) {
                                return error;
                        }
@@ -301,7 +310,7 @@ xfs_rtallocate_extent_block(
         * Searched the whole thing & didn't find a maxlen free extent.
         */
        if (minlen < maxlen && besti != -1) {
-               xfs_extlen_t    p;      /* amount to trim length by */
+               xfs_rtxlen_t    p;      /* amount to trim length by */
 
                /*
                 * If size should be a multiple of prod, make that so.
@@ -315,51 +324,49 @@ xfs_rtallocate_extent_block(
                /*
                 * Allocate besti for bestlen & return that.
                 */
-               error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb);
+               error = xfs_rtallocate_range(args, besti, bestlen);
                if (error) {
                        return error;
                }
                *len = bestlen;
-               *rtblock = besti;
+               *rtx = besti;
                return 0;
        }
        /*
         * Allocation failed.  Set *nextp to the next block to try.
         */
        *nextp = next;
-       *rtblock = NULLRTBLOCK;
+       *rtx = NULLRTEXTNO;
        return 0;
 }
 
 /*
  * Allocate an extent of length minlen<=len<=maxlen, starting at block
  * bno.  If we don't get maxlen then use prod to trim the length, if given.
- * Returns error; returns starting block in *rtblock.
+ * Returns error; returns starting block in *rtx.
  * The lengths are all in rtextents.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtallocate_extent_exact(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   bno,            /* starting block number to allocate */
-       xfs_extlen_t    minlen,         /* minimum length to allocate */
-       xfs_extlen_t    maxlen,         /* maximum length to allocate */
-       xfs_extlen_t    *len,           /* out: actual length allocated */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
-       xfs_extlen_t    prod,           /* extent product factor */
-       xfs_rtblock_t   *rtblock)       /* out: start block allocated */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext number to allocate */
+       xfs_rtxlen_t            minlen, /* minimum length to allocate */
+       xfs_rtxlen_t            maxlen, /* maximum length to allocate */
+       xfs_rtxlen_t            *len,   /* out: actual length allocated */
+       xfs_rtxlen_t            prod,   /* extent product factor */
+       xfs_rtxnum_t            *rtx)   /* out: start rtext allocated */
 {
-       int             error;          /* error value */
-       xfs_extlen_t    i;              /* extent length trimmed due to prod */
-       int             isfree;         /* extent is free */
-       xfs_rtblock_t   next;           /* next block to try (dummy) */
+       int                     error;
+       xfs_rtxlen_t            i;      /* extent length trimmed due to prod */
+       int                     isfree; /* extent is free */
+       xfs_rtxnum_t            next;   /* next rtext to try (dummy) */
 
-       ASSERT(minlen % prod == 0 && maxlen % prod == 0);
+       ASSERT(minlen % prod == 0);
+       ASSERT(maxlen % prod == 0);
        /*
         * Check if the range in question (for maxlen) is free.
         */
-       error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree);
+       error = xfs_rtcheck_range(args, start, maxlen, 1, &next, &isfree);
        if (error) {
                return error;
        }
@@ -367,23 +374,23 @@ xfs_rtallocate_extent_exact(
                /*
                 * If it is, allocate it and return success.
                 */
-               error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
+               error = xfs_rtallocate_range(args, start, maxlen);
                if (error) {
                        return error;
                }
                *len = maxlen;
-               *rtblock = bno;
+               *rtx = start;
                return 0;
        }
        /*
         * If not, allocate what there is, if it's at least minlen.
         */
-       maxlen = next - bno;
+       maxlen = next - start;
        if (maxlen < minlen) {
                /*
                 * Failed, return failure status.
                 */
-               *rtblock = NULLRTBLOCK;
+               *rtx = NULLRTEXTNO;
                return 0;
        }
        /*
@@ -395,81 +402,82 @@ xfs_rtallocate_extent_exact(
                        /*
                         * Now we can't do it, return failure status.
                         */
-                       *rtblock = NULLRTBLOCK;
+                       *rtx = NULLRTEXTNO;
                        return 0;
                }
        }
        /*
         * Allocate what we can and return it.
         */
-       error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
+       error = xfs_rtallocate_range(args, start, maxlen);
        if (error) {
                return error;
        }
        *len = maxlen;
-       *rtblock = bno;
+       *rtx = start;
        return 0;
 }
 
 /*
  * Allocate an extent of length minlen<=len<=maxlen, starting as near
- * to bno as possible.  If we don't get maxlen then use prod to trim
+ * to start as possible.  If we don't get maxlen then use prod to trim
  * the length, if given.  The lengths are all in rtextents.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtallocate_extent_near(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   bno,            /* starting block number to allocate */
-       xfs_extlen_t    minlen,         /* minimum length to allocate */
-       xfs_extlen_t    maxlen,         /* maximum length to allocate */
-       xfs_extlen_t    *len,           /* out: actual length allocated */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
-       xfs_extlen_t    prod,           /* extent product factor */
-       xfs_rtblock_t   *rtblock)       /* out: start block allocated */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxnum_t            start,  /* starting rtext number to allocate */
+       xfs_rtxlen_t            minlen, /* minimum length to allocate */
+       xfs_rtxlen_t            maxlen, /* maximum length to allocate */
+       xfs_rtxlen_t            *len,   /* out: actual length allocated */
+       xfs_rtxlen_t            prod,   /* extent product factor */
+       xfs_rtxnum_t            *rtx)   /* out: start rtext allocated */
 {
-       int             any;            /* any useful extents from summary */
-       xfs_rtblock_t   bbno;           /* bitmap block number */
-       int             error;          /* error value */
-       int             i;              /* bitmap block offset (loop control) */
-       int             j;              /* secondary loop control */
-       int             log2len;        /* log2 of minlen */
-       xfs_rtblock_t   n;              /* next block to try */
-       xfs_rtblock_t   r;              /* result block */
-
-       ASSERT(minlen % prod == 0 && maxlen % prod == 0);
+       struct xfs_mount        *mp = args->mp;
+       int                     maxlog; /* max useful extent from summary */
+       xfs_fileoff_t           bbno;   /* bitmap block number */
+       int                     error;
+       int                     i;      /* bitmap block offset (loop control) */
+       int                     j;      /* secondary loop control */
+       int                     log2len; /* log2 of minlen */
+       xfs_rtxnum_t            n;      /* next rtext to try */
+       xfs_rtxnum_t            r;      /* result rtext */
+
+       ASSERT(minlen % prod == 0);
+       ASSERT(maxlen % prod == 0);
+
        /*
         * If the block number given is off the end, silently set it to
         * the last block.
         */
-       if (bno >= mp->m_sb.sb_rextents)
-               bno = mp->m_sb.sb_rextents - 1;
+       if (start >= mp->m_sb.sb_rextents)
+               start = mp->m_sb.sb_rextents - 1;
 
        /* Make sure we don't run off the end of the rt volume. */
-       maxlen = min(mp->m_sb.sb_rextents, bno + maxlen) - bno;
+       maxlen = xfs_rtallocate_clamp_len(mp, start, maxlen, prod);
        if (maxlen < minlen) {
-               *rtblock = NULLRTBLOCK;
+               *rtx = NULLRTEXTNO;
                return 0;
        }
 
        /*
         * Try the exact allocation first.
         */
-       error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len,
-               rbpp, rsb, prod, &r);
+       error = xfs_rtallocate_extent_exact(args, start, minlen, maxlen, len,
+                       prod, &r);
        if (error) {
                return error;
        }
        /*
         * If the exact allocation worked, return that.
         */
-       if (r != NULLRTBLOCK) {
-               *rtblock = r;
+       if (r != NULLRTEXTNO) {
+               *rtx = r;
                return 0;
        }
-       bbno = XFS_BITTOBLOCK(mp, bno);
+       bbno = xfs_rtx_to_rbmblock(mp, start);
        i = 0;
+       j = -1;
        ASSERT(minlen != 0);
        log2len = xfs_highbit32(minlen);
        /*
@@ -480,8 +488,8 @@ xfs_rtallocate_extent_near(
                 * Get summary information of extents of all useful levels
                 * starting in this bitmap block.
                 */
-               error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1,
-                       bbno + i, rbpp, rsb, &any);
+               error = xfs_rtany_summary(args, log2len, mp->m_rsumlevels - 1,
+                               bbno + i, &maxlog);
                if (error) {
                        return error;
                }
@@ -489,7 +497,10 @@ xfs_rtallocate_extent_near(
                 * If there are any useful extents starting here, try
                 * allocating one.
                 */
-               if (any) {
+               if (maxlog >= 0) {
+                       xfs_extlen_t maxavail =
+                               min_t(xfs_rtblock_t, maxlen,
+                                     (1ULL << (maxlog + 1)) - 1);
                        /*
                         * On the positive side of the starting location.
                         */
@@ -498,17 +509,17 @@ xfs_rtallocate_extent_near(
                                 * Try to allocate an extent starting in
                                 * this block.
                                 */
-                               error = xfs_rtallocate_extent_block(mp, tp,
-                                       bbno + i, minlen, maxlen, len, &n, rbpp,
-                                       rsb, prod, &r);
+                               error = xfs_rtallocate_extent_block(args,
+                                               bbno + i, minlen, maxavail, len,
+                                               &n, prod, &r);
                                if (error) {
                                        return error;
                                }
                                /*
                                 * If it worked, return it.
                                 */
-                               if (r != NULLRTBLOCK) {
-                                       *rtblock = r;
+                               if (r != NULLRTEXTNO) {
+                                       *rtx = r;
                                        return 0;
                                }
                        }
@@ -516,68 +527,46 @@ xfs_rtallocate_extent_near(
                         * On the negative side of the starting location.
                         */
                        else {          /* i < 0 */
+                               int     maxblocks;
+
                                /*
-                                * Loop backwards through the bitmap blocks from
-                                * the starting point-1 up to where we are now.
-                                * There should be an extent which ends in this
-                                * bitmap block and is long enough.
+                                * Loop backwards to find the end of the extent
+                                * we found in the realtime summary.
+                                *
+                                * maxblocks is the maximum possible number of
+                                * bitmap blocks from the start of the extent
+                                * to the end of the extent.
                                 */
-                               for (j = -1; j > i; j--) {
-                                       /*
-                                        * Grab the summary information for
-                                        * this bitmap block.
-                                        */
-                                       error = xfs_rtany_summary(mp, tp,
-                                               log2len, mp->m_rsumlevels - 1,
-                                               bbno + j, rbpp, rsb, &any);
-                                       if (error) {
-                                               return error;
-                                       }
-                                       /*
-                                        * If there's no extent given in the
-                                        * summary that means the extent we
-                                        * found must carry over from an
-                                        * earlier block.  If there is an
-                                        * extent given, we've already tried
-                                        * that allocation, don't do it again.
-                                        */
-                                       if (any)
-                                               continue;
-                                       error = xfs_rtallocate_extent_block(mp,
-                                               tp, bbno + j, minlen, maxlen,
-                                               len, &n, rbpp, rsb, prod, &r);
+                               if (maxlog == 0)
+                                       maxblocks = 0;
+                               else if (maxlog < mp->m_blkbit_log)
+                                       maxblocks = 1;
+                               else
+                                       maxblocks = 2 << (maxlog - mp->m_blkbit_log);
+
+                               /*
+                                * We need to check bbno + i + maxblocks down to
+                                * bbno + i. We already checked bbno down to
+                                * bbno + j + 1, so we don't need to check those
+                                * again.
+                                */
+                               j = min(i + maxblocks, j);
+                               for (; j >= i; j--) {
+                                       error = xfs_rtallocate_extent_block(args,
+                                                       bbno + j, minlen,
+                                                       maxavail, len, &n, prod,
+                                                       &r);
                                        if (error) {
                                                return error;
                                        }
                                        /*
                                         * If it works, return the extent.
                                         */
-                                       if (r != NULLRTBLOCK) {
-                                               *rtblock = r;
+                                       if (r != NULLRTEXTNO) {
+                                               *rtx = r;
                                                return 0;
                                        }
                                }
-                               /*
-                                * There weren't intervening bitmap blocks
-                                * with a long enough extent, or the
-                                * allocation didn't work for some reason
-                                * (i.e. it's a little * too short).
-                                * Try to allocate from the summary block
-                                * that we found.
-                                */
-                               error = xfs_rtallocate_extent_block(mp, tp,
-                                       bbno + i, minlen, maxlen, len, &n, rbpp,
-                                       rsb, prod, &r);
-                               if (error) {
-                                       return error;
-                               }
-                               /*
-                                * If it works, return the extent.
-                                */
-                               if (r != NULLRTBLOCK) {
-                                       *rtblock = r;
-                                       return 0;
-                               }
                        }
                }
                /*
@@ -610,7 +599,7 @@ xfs_rtallocate_extent_near(
                else
                        break;
        }
-       *rtblock = NULLRTBLOCK;
+       *rtx = NULLRTEXTNO;
        return 0;
 }
 
@@ -619,26 +608,25 @@ xfs_rtallocate_extent_near(
  * specified.  If we don't get maxlen then use prod to trim
  * the length, if given.  The lengths are all in rtextents.
  */
-STATIC int                             /* error */
+STATIC int
 xfs_rtallocate_extent_size(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_extlen_t    minlen,         /* minimum length to allocate */
-       xfs_extlen_t    maxlen,         /* maximum length to allocate */
-       xfs_extlen_t    *len,           /* out: actual length allocated */
-       struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
-       xfs_fsblock_t   *rsb,           /* in/out: summary block number */
-       xfs_extlen_t    prod,           /* extent product factor */
-       xfs_rtblock_t   *rtblock)       /* out: start block allocated */
+       struct xfs_rtalloc_args *args,
+       xfs_rtxlen_t            minlen, /* minimum length to allocate */
+       xfs_rtxlen_t            maxlen, /* maximum length to allocate */
+       xfs_rtxlen_t            *len,   /* out: actual length allocated */
+       xfs_rtxlen_t            prod,   /* extent product factor */
+       xfs_rtxnum_t            *rtx)   /* out: start rtext allocated */
 {
-       int             error;          /* error value */
-       int             i;              /* bitmap block number */
-       int             l;              /* level number (loop control) */
-       xfs_rtblock_t   n;              /* next block to be tried */
-       xfs_rtblock_t   r;              /* result block number */
-       xfs_suminfo_t   sum;            /* summary information for extents */
-
-       ASSERT(minlen % prod == 0 && maxlen % prod == 0);
+       struct xfs_mount        *mp = args->mp;
+       int                     error;
+       xfs_fileoff_t           i;      /* bitmap block number */
+       int                     l;      /* level number (loop control) */
+       xfs_rtxnum_t            n;      /* next rtext to be tried */
+       xfs_rtxnum_t            r;      /* result rtext number */
+       xfs_suminfo_t           sum;    /* summary information for extents */
+
+       ASSERT(minlen % prod == 0);
+       ASSERT(maxlen % prod == 0);
        ASSERT(maxlen != 0);
 
        /*
@@ -656,8 +644,7 @@ xfs_rtallocate_extent_size(
                        /*
                         * Get the summary for this level/block.
                         */
-                       error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
-                               &sum);
+                       error = xfs_rtget_summary(args, l, i, &sum);
                        if (error) {
                                return error;
                        }
@@ -669,16 +656,16 @@ xfs_rtallocate_extent_size(
                        /*
                         * Try allocating the extent.
                         */
-                       error = xfs_rtallocate_extent_block(mp, tp, i, maxlen,
-                               maxlen, len, &n, rbpp, rsb, prod, &r);
+                       error = xfs_rtallocate_extent_block(args, i, maxlen,
+                                       maxlen, len, &n, prod, &r);
                        if (error) {
                                return error;
                        }
                        /*
                         * If it worked, return that.
                         */
-                       if (r != NULLRTBLOCK) {
-                               *rtblock = r;
+                       if (r != NULLRTEXTNO) {
+                               *rtx = r;
                                return 0;
                        }
                        /*
@@ -686,8 +673,8 @@ xfs_rtallocate_extent_size(
                         * allocator is beyond the next bitmap block,
                         * skip to that bitmap block.
                         */
-                       if (XFS_BITTOBLOCK(mp, n) > i + 1)
-                               i = XFS_BITTOBLOCK(mp, n) - 1;
+                       if (xfs_rtx_to_rbmblock(mp, n) > i + 1)
+                               i = xfs_rtx_to_rbmblock(mp, n) - 1;
                }
        }
        /*
@@ -695,7 +682,7 @@ xfs_rtallocate_extent_size(
         * we're asking for a fixed size extent.
         */
        if (minlen > --maxlen) {
-               *rtblock = NULLRTBLOCK;
+               *rtx = NULLRTEXTNO;
                return 0;
        }
        ASSERT(minlen != 0);
@@ -715,8 +702,7 @@ xfs_rtallocate_extent_size(
                        /*
                         * Get the summary information for this level/block.
                         */
-                       error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
-                                                 &sum);
+                       error = xfs_rtget_summary(args, l, i, &sum);
                        if (error) {
                                return error;
                        }
@@ -730,18 +716,18 @@ xfs_rtallocate_extent_size(
                         * minlen/maxlen are in the possible range for
                         * this summary level.
                         */
-                       error = xfs_rtallocate_extent_block(mp, tp, i,
+                       error = xfs_rtallocate_extent_block(args, i,
                                        XFS_RTMAX(minlen, 1 << l),
                                        XFS_RTMIN(maxlen, (1 << (l + 1)) - 1),
-                                       len, &n, rbpp, rsb, prod, &r);
+                                       len, &n, prod, &r);
                        if (error) {
                                return error;
                        }
                        /*
                         * If it worked, return that extent.
                         */
-                       if (r != NULLRTBLOCK) {
-                               *rtblock = r;
+                       if (r != NULLRTEXTNO) {
+                               *rtx = r;
                                return 0;
                        }
                        /*
@@ -749,14 +735,14 @@ xfs_rtallocate_extent_size(
                         * allocator is beyond the next bitmap block,
                         * skip to that bitmap block.
                         */
-                       if (XFS_BITTOBLOCK(mp, n) > i + 1)
-                               i = XFS_BITTOBLOCK(mp, n) - 1;
+                       if (xfs_rtx_to_rbmblock(mp, n) > i + 1)
+                               i = xfs_rtx_to_rbmblock(mp, n) - 1;
                }
        }
        /*
         * Got nothing, return failure.
         */
-       *rtblock = NULLRTBLOCK;
+       *rtx = NULLRTEXTNO;
        return 0;
 }
 
@@ -886,12 +872,14 @@ xfs_alloc_rsum_cache(
        xfs_extlen_t    rbmblocks)      /* number of rt bitmap blocks */
 {
        /*
-        * The rsum cache is initialized to all zeroes, which is trivially a
-        * lower bound on the minimum level with any free extents. We can
-        * continue without the cache if it couldn't be allocated.
+        * The rsum cache is initialized to the maximum value, which is
+        * trivially an upper bound on the maximum level with any free extents.
+        * We can continue without the cache if it couldn't be allocated.
         */
-       mp->m_rsum_cache = kvzalloc(rbmblocks, GFP_KERNEL);
-       if (!mp->m_rsum_cache)
+       mp->m_rsum_cache = kvmalloc(rbmblocks, GFP_KERNEL);
+       if (mp->m_rsum_cache)
+               memset(mp->m_rsum_cache, -1, rbmblocks);
+       else
                xfs_warn(mp, "could not allocate realtime summary cache");
 }
 
@@ -907,13 +895,13 @@ xfs_growfs_rt(
        xfs_mount_t     *mp,            /* mount point for filesystem */
        xfs_growfs_rt_t *in)            /* growfs rt input struct */
 {
-       xfs_rtblock_t   bmbno;          /* bitmap block number */
+       xfs_fileoff_t   bmbno;          /* bitmap block number */
        struct xfs_buf  *bp;            /* temporary buffer */
        int             error;          /* error return value */
        xfs_mount_t     *nmp;           /* new (fake) mount structure */
        xfs_rfsblock_t  nrblocks;       /* new number of realtime blocks */
        xfs_extlen_t    nrbmblocks;     /* new number of rt bitmap blocks */
-       xfs_rtblock_t   nrextents;      /* new number of realtime extents */
+       xfs_rtxnum_t    nrextents;      /* new number of realtime extents */
        uint8_t         nrextslog;      /* new log2 of sb_rextents */
        xfs_extlen_t    nrsumblocks;    /* new number of summary blocks */
        uint            nrsumlevels;    /* new rt summary levels */
@@ -922,7 +910,6 @@ xfs_growfs_rt(
        xfs_extlen_t    rbmblocks;      /* current number of rt bitmap blocks */
        xfs_extlen_t    rsumblocks;     /* current number of rt summary blks */
        xfs_sb_t        *sbp;           /* old superblock */
-       xfs_fsblock_t   sumbno;         /* summary block number */
        uint8_t         *rsum_cache;    /* old summary cache */
 
        sbp = &mp->m_sb;
@@ -954,7 +941,7 @@ xfs_growfs_rt(
                return -EINVAL;
 
        /* Unsupported realtime features. */
-       if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp))
+       if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp))
                return -EOPNOTSUPP;
 
        nrblocks = in->newblocks;
@@ -976,11 +963,10 @@ xfs_growfs_rt(
         */
        nrextents = nrblocks;
        do_div(nrextents, in->extsize);
-       nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
+       nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents);
        nrextslog = xfs_highbit32(nrextents);
        nrsumlevels = nrextslog + 1;
-       nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
-       nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
+       nrsumblocks = xfs_rtsummary_blockcount(mp, nrsumlevels, nrbmblocks);
        nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
        /*
         * New summary size can't be more than half the size of
@@ -1023,6 +1009,12 @@ xfs_growfs_rt(
                     ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
             bmbno < nrbmblocks;
             bmbno++) {
+               struct xfs_rtalloc_args args = {
+                       .mp             = mp,
+               };
+               struct xfs_rtalloc_args nargs = {
+                       .mp             = nmp,
+               };
                struct xfs_trans        *tp;
                xfs_rfsblock_t          nrblocks_step;
 
@@ -1032,19 +1024,17 @@ xfs_growfs_rt(
                 * Calculate new sb and mount fields for this round.
                 */
                nsbp->sb_rextsize = in->extsize;
+               nmp->m_rtxblklog = -1; /* don't use shift or masking */
                nsbp->sb_rbmblocks = bmbno + 1;
                nrblocks_step = (bmbno + 1) * NBBY * nsbp->sb_blocksize *
                                nsbp->sb_rextsize;
                nsbp->sb_rblocks = min(nrblocks, nrblocks_step);
-               nsbp->sb_rextents = nsbp->sb_rblocks;
-               do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
+               nsbp->sb_rextents = xfs_rtb_to_rtx(nmp, nsbp->sb_rblocks);
                ASSERT(nsbp->sb_rextents != 0);
                nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
                nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
-               nrsumsize =
-                       (uint)sizeof(xfs_suminfo_t) * nrsumlevels *
-                       nsbp->sb_rbmblocks;
-               nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
+               nrsumblocks = xfs_rtsummary_blockcount(mp, nrsumlevels,
+                               nsbp->sb_rbmblocks);
                nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
                /*
                 * Start a transaction, get the log reservation.
@@ -1053,6 +1043,9 @@ xfs_growfs_rt(
                                &tp);
                if (error)
                        break;
+               args.tp = tp;
+               nargs.tp = tp;
+
                /*
                 * Lock out other callers by grabbing the bitmap inode lock.
                 */
@@ -1086,7 +1079,7 @@ xfs_growfs_rt(
                 */
                if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks ||
                    mp->m_rsumlevels != nmp->m_rsumlevels) {
-                       error = xfs_rtcopy_summary(mp, nmp, tp);
+                       error = xfs_rtcopy_summary(&args, &nargs);
                        if (error)
                                goto error_cancel;
                }
@@ -1111,9 +1104,9 @@ xfs_growfs_rt(
                /*
                 * Free new extent.
                 */
-               bp = NULL;
-               error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
-                       nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
+               error = xfs_rtfree_range(&nargs, sbp->sb_rextents,
+                               nsbp->sb_rextents - sbp->sb_rextents);
+               xfs_rtbuf_cache_relse(&nargs);
                if (error) {
 error_cancel:
                        xfs_trans_cancel(tp);
@@ -1171,59 +1164,60 @@ out_free:
  * parameters.  The length units are all in realtime extents, as is the
  * result block number.
  */
-int                                    /* error */
+int
 xfs_rtallocate_extent(
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_rtblock_t   bno,            /* starting block number to allocate */
-       xfs_extlen_t    minlen,         /* minimum length to allocate */
-       xfs_extlen_t    maxlen,         /* maximum length to allocate */
-       xfs_extlen_t    *len,           /* out: actual length allocated */
-       int             wasdel,         /* was a delayed allocation extent */
-       xfs_extlen_t    prod,           /* extent product factor */
-       xfs_rtblock_t   *rtblock)       /* out: start block allocated */
+       struct xfs_trans        *tp,
+       xfs_rtxnum_t            start,  /* starting rtext number to allocate */
+       xfs_rtxlen_t            minlen, /* minimum length to allocate */
+       xfs_rtxlen_t            maxlen, /* maximum length to allocate */
+       xfs_rtxlen_t            *len,   /* out: actual length allocated */
+       int                     wasdel, /* was a delayed allocation extent */
+       xfs_rtxlen_t            prod,   /* extent product factor */
+       xfs_rtxnum_t            *rtblock) /* out: start rtext allocated */
 {
-       xfs_mount_t     *mp = tp->t_mountp;
-       int             error;          /* error value */
-       xfs_rtblock_t   r;              /* result allocated block */
-       xfs_fsblock_t   sb;             /* summary file block number */
-       struct xfs_buf  *sumbp;         /* summary file block buffer */
-
-       ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
+       struct xfs_rtalloc_args args = {
+               .mp             = tp->t_mountp,
+               .tp             = tp,
+       };
+       int                     error;  /* error value */
+       xfs_rtxnum_t            r;      /* result allocated rtext */
+
+       ASSERT(xfs_isilocked(args.mp->m_rbmip, XFS_ILOCK_EXCL));
        ASSERT(minlen > 0 && minlen <= maxlen);
 
        /*
         * If prod is set then figure out what to do to minlen and maxlen.
         */
        if (prod > 1) {
-               xfs_extlen_t    i;
+               xfs_rtxlen_t    i;
 
                if ((i = maxlen % prod))
                        maxlen -= i;
                if ((i = minlen % prod))
                        minlen += prod - i;
                if (maxlen < minlen) {
-                       *rtblock = NULLRTBLOCK;
+                       *rtblock = NULLRTEXTNO;
                        return 0;
                }
        }
 
 retry:
-       sumbp = NULL;
-       if (bno == 0) {
-               error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len,
-                               &sumbp, &sb, prod, &r);
+       if (start == 0) {
+               error = xfs_rtallocate_extent_size(&args, minlen,
+                               maxlen, len, prod, &r);
        } else {
-               error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen,
-                               len, &sumbp, &sb, prod, &r);
+               error = xfs_rtallocate_extent_near(&args, start, minlen,
+                               maxlen, len, prod, &r);
        }
 
+       xfs_rtbuf_cache_relse(&args);
        if (error)
                return error;
 
        /*
         * If it worked, update the superblock.
         */
-       if (r != NULLRTBLOCK) {
+       if (r != NULLRTEXTNO) {
                long    slen = (long)*len;
 
                ASSERT(*len >= minlen && *len <= maxlen);
@@ -1250,6 +1244,7 @@ xfs_rtmount_init(
        struct xfs_buf          *bp;    /* buffer for last block of subvolume */
        struct xfs_sb           *sbp;   /* filesystem superblock copy in mount */
        xfs_daddr_t             d;      /* address of last block of subvolume */
+       unsigned int            rsumblocks;
        int                     error;
 
        sbp = &mp->m_sb;
@@ -1261,10 +1256,9 @@ xfs_rtmount_init(
                return -ENODEV;
        }
        mp->m_rsumlevels = sbp->sb_rextslog + 1;
-       mp->m_rsumsize =
-               (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels *
-               sbp->sb_rbmblocks;
-       mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize);
+       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.
@@ -1418,27 +1412,27 @@ xfs_rtunmount_inodes(
  * of rtextents and the fraction.
  * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ...
  */
-int                                    /* error */
+int                                            /* error */
 xfs_rtpick_extent(
        xfs_mount_t             *mp,            /* file system mount point */
        xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_extlen_t            len,            /* allocation length (rtextents) */
-       xfs_rtblock_t           *pick)          /* result rt extent */
-       {
-       xfs_rtblock_t           b;              /* result block */
+       xfs_rtxlen_t            len,            /* allocation length (rtextents) */
+       xfs_rtxnum_t            *pick)          /* result rt extent */
+{
+       xfs_rtxnum_t            b;              /* 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;             /* temporary timespec64 storage */
+       struct timespec64       ts;             /* timespec in inode */
 
        ASSERT(xfs_isilocked(mp->m_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;
                seq = 0;
        } else {
-               ts = inode_get_atime(VFS_I(mp->m_rbmip));
-               seq = (uint64_t)ts.tv_sec;
+               seq = ts.tv_sec;
        }
        if ((log2 = xfs_highbit64(seq)) == -1)
                b = 0;
@@ -1451,7 +1445,7 @@ xfs_rtpick_extent(
                if (b + len > mp->m_sb.sb_rextents)
                        b = mp->m_sb.sb_rextents - len;
        }
-       ts.tv_sec = (time64_t)seq + 1;
+       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);
        *pick = b;
index 62c7ad79cbb618af46c8b21a325b038b6c5cc205..f7cb9ffe51ca68fbf8a87e6f64be68dc399c9d5f 100644 (file)
 struct xfs_mount;
 struct xfs_trans;
 
-/*
- * XXX: Most of the realtime allocation functions deal in units of realtime
- * extents, not realtime blocks.  This looks funny when paired with the type
- * name and screams for a larger cleanup.
- */
-struct xfs_rtalloc_rec {
-       xfs_rtblock_t           ar_startext;
-       xfs_rtblock_t           ar_extcount;
-};
-
-typedef int (*xfs_rtalloc_query_range_fn)(
-       struct xfs_mount                *mp,
-       struct xfs_trans                *tp,
-       const struct xfs_rtalloc_rec    *rec,
-       void                            *priv);
-
 #ifdef CONFIG_XFS_RT
 /*
  * Function prototypes for exported functions.
@@ -40,23 +24,14 @@ typedef int (*xfs_rtalloc_query_range_fn)(
 int                                    /* error */
 xfs_rtallocate_extent(
        struct xfs_trans        *tp,    /* transaction pointer */
-       xfs_rtblock_t           bno,    /* starting block number to allocate */
-       xfs_extlen_t            minlen, /* minimum length to allocate */
-       xfs_extlen_t            maxlen, /* maximum length to allocate */
-       xfs_extlen_t            *len,   /* out: actual length allocated */
+       xfs_rtxnum_t            start,  /* starting rtext number to allocate */
+       xfs_rtxlen_t            minlen, /* minimum length to allocate */
+       xfs_rtxlen_t            maxlen, /* maximum length to allocate */
+       xfs_rtxlen_t            *len,   /* out: actual length allocated */
        int                     wasdel, /* was a delayed allocation extent */
-       xfs_extlen_t            prod,   /* extent product factor */
-       xfs_rtblock_t           *rtblock); /* out: start block allocated */
+       xfs_rtxlen_t            prod,   /* extent product factor */
+       xfs_rtxnum_t            *rtblock); /* out: start rtext allocated */
 
-/*
- * 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_rtblock_t           bno,    /* starting block number to free */
-       xfs_extlen_t            len);   /* length of extent freed */
 
 /*
  * Initialize realtime fields in the mount structure.
@@ -87,8 +62,8 @@ int                                   /* error */
 xfs_rtpick_extent(
        struct xfs_mount        *mp,    /* file system mount point */
        struct xfs_trans        *tp,    /* transaction pointer */
-       xfs_extlen_t            len,    /* allocation length (rtextents) */
-       xfs_rtblock_t           *pick); /* result rt extent */
+       xfs_rtxlen_t            len,    /* allocation length (rtextents) */
+       xfs_rtxnum_t            *pick); /* result rt extent */
 
 /*
  * Grow the realtime area of the filesystem.
@@ -98,55 +73,12 @@ xfs_growfs_rt(
        struct xfs_mount        *mp,    /* file system mount structure */
        xfs_growfs_rt_t         *in);   /* user supplied growfs struct */
 
-/*
- * From xfs_rtbitmap.c
- */
-int xfs_rtbuf_get(struct xfs_mount *mp, struct xfs_trans *tp,
-                 xfs_rtblock_t block, int issum, struct xfs_buf **bpp);
-int xfs_rtcheck_range(struct xfs_mount *mp, struct xfs_trans *tp,
-                     xfs_rtblock_t start, xfs_extlen_t len, int val,
-                     xfs_rtblock_t *new, int *stat);
-int xfs_rtfind_back(struct xfs_mount *mp, struct xfs_trans *tp,
-                   xfs_rtblock_t start, xfs_rtblock_t limit,
-                   xfs_rtblock_t *rtblock);
-int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp,
-                   xfs_rtblock_t start, xfs_rtblock_t limit,
-                   xfs_rtblock_t *rtblock);
-int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp,
-                      xfs_rtblock_t start, xfs_extlen_t len, int val);
-int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp,
-                            int log, xfs_rtblock_t bbno, int delta,
-                            struct xfs_buf **rbpp, xfs_fsblock_t *rsb,
-                            xfs_suminfo_t *sum);
-int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log,
-                        xfs_rtblock_t bbno, int delta, struct xfs_buf **rbpp,
-                        xfs_fsblock_t *rsb);
-int xfs_rtfree_range(struct xfs_mount *mp, struct xfs_trans *tp,
-                    xfs_rtblock_t start, xfs_extlen_t len,
-                    struct xfs_buf **rbpp, xfs_fsblock_t *rsb);
-int xfs_rtalloc_query_range(struct xfs_mount *mp, struct xfs_trans *tp,
-               const struct xfs_rtalloc_rec *low_rec,
-               const struct xfs_rtalloc_rec *high_rec,
-               xfs_rtalloc_query_range_fn fn, void *priv);
-int xfs_rtalloc_query_all(struct xfs_mount *mp, struct xfs_trans *tp,
-                         xfs_rtalloc_query_range_fn fn,
-                         void *priv);
-bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno);
-int xfs_rtalloc_extent_is_free(struct xfs_mount *mp, struct xfs_trans *tp,
-                              xfs_rtblock_t start, xfs_extlen_t len,
-                              bool *is_free);
 int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
 #else
-# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb)    (ENOSYS)
-# define xfs_rtfree_extent(t,b,l)                       (ENOSYS)
-# define xfs_rtpick_extent(m,t,l,rb)                    (ENOSYS)
-# define xfs_growfs_rt(mp,in)                           (ENOSYS)
-# define xfs_rtalloc_query_range(t,l,h,f,p)             (ENOSYS)
-# define xfs_rtalloc_query_all(m,t,f,p)                 (ENOSYS)
-# define xfs_rtbuf_get(m,t,b,i,p)                       (ENOSYS)
-# define xfs_verify_rtbno(m, r)                        (false)
-# define xfs_rtalloc_extent_is_free(m,t,s,l,i)          (ENOSYS)
-# define xfs_rtalloc_reinit_frextents(m)                (0)
+# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb)   (-ENOSYS)
+# define xfs_rtpick_extent(m,t,l,rb)                   (-ENOSYS)
+# define xfs_growfs_rt(mp,in)                          (-ENOSYS)
+# define xfs_rtalloc_reinit_frextents(m)               (0)
 static inline int              /* error */
 xfs_rtmount_init(
        xfs_mount_t     *mp)    /* file system mount structure */
@@ -157,7 +89,7 @@ xfs_rtmount_init(
        xfs_warn(mp, "Not built with CONFIG_XFS_RT");
        return -ENOSYS;
 }
-# define xfs_rtmount_inodes(m)  (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
+# define xfs_rtmount_inodes(m)  (((mp)->m_sb.sb_rblocks == 0)? 0 : (-ENOSYS))
 # define xfs_rtunmount_inodes(m)
 #endif /* CONFIG_XFS_RT */
 
index f0ae07828153130004b3fb8fef4a12f19520a9fb..764304595e8b00b38c5a38e0673d88152a532e93 100644 (file)
@@ -42,6 +42,7 @@
 #include "xfs_xattr.h"
 #include "xfs_iunlink_item.h"
 #include "xfs_dahash_test.h"
+#include "xfs_rtbitmap.h"
 #include "scrub/stats.h"
 
 #include <linux/magic.h>
@@ -896,7 +897,7 @@ xfs_fs_statfs(
 
                statp->f_blocks = sbp->sb_rblocks;
                freertx = percpu_counter_sum_positive(&mp->m_frextents);
-               statp->f_bavail = statp->f_bfree = freertx * sbp->sb_rextsize;
+               statp->f_bavail = statp->f_bfree = xfs_rtx_to_rtb(mp, freertx);
        }
 
        return 0;
index 8c0bfc9a33b116cd74606daa2d6de4fc8362f004..305c9d07bf1b27f7c7289d746fa0f84170e60b46 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_dquot_item.h"
 #include "xfs_dquot.h"
 #include "xfs_icache.h"
+#include "xfs_rtbitmap.h"
 
 struct kmem_cache      *xfs_trans_cache;
 
@@ -655,6 +656,10 @@ xfs_trans_unreserve_and_mod_sb(
        mp->m_sb.sb_agcount += tp->t_agcount_delta;
        mp->m_sb.sb_imax_pct += tp->t_imaxpct_delta;
        mp->m_sb.sb_rextsize += tp->t_rextsize_delta;
+       if (tp->t_rextsize_delta) {
+               mp->m_rtxblklog = log2_if_power2(mp->m_sb.sb_rextsize);
+               mp->m_rtxblkmask = mask64_if_power2(mp->m_sb.sb_rextsize);
+       }
        mp->m_sb.sb_rbmblocks += tp->t_rbmblocks_delta;
        mp->m_sb.sb_rblocks += tp->t_rblocks_delta;
        mp->m_sb.sb_rextents += tp->t_rextents_delta;
@@ -1196,7 +1201,7 @@ xfs_trans_alloc_inode(
 
 retry:
        error = xfs_trans_alloc(mp, resv, dblocks,
-                       rblocks / mp->m_sb.sb_rextsize,
+                       xfs_extlen_to_rtxlen(mp, rblocks),
                        force ? XFS_TRANS_RESERVE : 0, &tp);
        if (error)
                return error;