]> Git Repo - J-linux.git/commitdiff
Merge tag 'xfs-6.7-merge-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
authorLinus Torvalds <[email protected]>
Wed, 8 Nov 2023 21:22:16 +0000 (13:22 -0800)
committerLinus Torvalds <[email protected]>
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
  ...

1  2 
fs/xfs/libxfs/xfs_rtbitmap.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_super.c

index 396648acb5be169dc54f98c657780a34d164f1f3,b332ab490a4875e32c542c885f2b0d9bfeb202a4..c269d704314d7d5afc0497985f46c936ea275f27
@@@ -16,6 -16,7 +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 +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)
                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;
  }
  
   */
  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.
                 * 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;
                        /*
                         * 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 {
                /*
                /*
                 * 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;
                        /*
                         * 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;
                }
        }
        /*
                /*
                 * 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;
        /*
         * No match, return that we scanned the whole area.
         */
-       xfs_trans_brelse(tp, bp);
-       *rtblock = start - i + 1;
+       *rtx = start - i + 1;
        return 0;
  }
  
   */
  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.
                 * 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;
                 * 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 {
                /*
                /*
                 * 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;
                 * 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++;
                }
        }
        /*
                /*
                 * 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;
        /*
         * 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.
   */
  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);
  }
  
  /*
   */
  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.
                /*
                 * 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 {
                /*
                /*
                 * 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;
                }
        }
        /*
                /*
                 * 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;
  }
  
   */
  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;
        }
         * 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;
        /*
         * 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;
                }
         * 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;
                }
         * 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);
  }
  
  /*
   */
  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.
                /*
                 * 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;
                 * 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 {
                /*
                /*
                 * 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;
                 * 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++;
                }
        }
        /*
                /*
                 * 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;
        /*
         * Successful, return.
         */
-       xfs_trans_brelse(tp, bp);
        *new = start + i;
        *stat = 1;
        return 0;
  /*
   * 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.
         */
            mp->m_sb.sb_rextents) {
                if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM))
                        mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
 -              *(uint64_t *)&VFS_I(mp->m_rbmip)->i_atime = 0;
 +
 +              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 -1022,14 +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;
  
        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;
  
                rtstart = rtend + 1;
        }
  
+       xfs_rtbuf_cache_relse(&args);
        return error;
  }
  
  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 --combined fs/xfs/xfs_bmap_util.c
index 40e0a1f1f7530cba2193655b0be5ff661bfb107e,93829d86751dad6625091663000b43fb8981bcd6..731260a5af6db43d06849d32a7384a90188f4031
@@@ -28,6 -28,7 +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 +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
                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
         * 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;
        }
         * 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 +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 +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;
  
        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;
        while (allocatesize_fsb && !error) {
                xfs_fileoff_t   s, e;
                unsigned int    dblocks, rblocks, resblks;
+               int             nimaps = 1;
  
                /*
                 * Determine space reservations for data/realtime.
                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 +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);
        }
  
        /*
@@@ -1644,7 -1638,7 +1638,7 @@@ xfs_swap_extents
        uint64_t                f;
        int                     resblks = 0;
        unsigned int            flags = 0;
 -      struct timespec64       ctime;
 +      struct timespec64       ctime, mtime;
  
        /*
         * Lock the inodes against other IO, page faults and truncate to
         * under it.
         */
        ctime = inode_get_ctime(VFS_I(ip));
 +      mtime = inode_get_mtime(VFS_I(ip));
        if ((sbp->bs_ctime.tv_sec != ctime.tv_sec) ||
            (sbp->bs_ctime.tv_nsec != ctime.tv_nsec) ||
 -          (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
 -          (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
 +          (sbp->bs_mtime.tv_sec != mtime.tv_sec) ||
 +          (sbp->bs_mtime.tv_nsec != mtime.tv_nsec)) {
                error = -EBUSY;
                goto out_trans_cancel;
        }
diff --combined fs/xfs/xfs_inode.c
index 36f5cf802c07b65ad74e9d158a79d36b36ad63a3,f9d29acd72b9eea15fd108420d5d86a839696cce..c0f1c89786c2ac083482ece0bb312692ab8255a3
@@@ -844,8 -844,8 +844,8 @@@ xfs_init_new_inode
        ASSERT(ip->i_nblocks == 0);
  
        tv = inode_set_ctime_current(inode);
 -      inode->i_mtime = tv;
 -      inode->i_atime = tv;
 +      inode_set_mtime_to_ts(inode, tv);
 +      inode_set_atime_to_ts(inode, tv);
  
        ip->i_extsize = 0;
        ip->i_diflags = 0;
@@@ -918,6 -918,13 +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 +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
diff --combined fs/xfs/xfs_inode_item.c
index 17c51804f9c6aed2d3f4043172b67cf3754cd140,3183d0b03e0bc7abe1cd9104e1c712bc5e985820..cd7803fda8b1be501af6d19d900d9d80bef5a391
@@@ -19,6 -19,7 +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 +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;
@@@ -526,8 -527,8 +527,8 @@@ xfs_inode_to_log_dinode
        to->di_projid_hi = ip->i_projid >> 16;
  
        memset(to->di_pad3, 0, sizeof(to->di_pad3));
 -      to->di_atime = xfs_inode_to_log_dinode_ts(ip, inode->i_atime);
 -      to->di_mtime = xfs_inode_to_log_dinode_ts(ip, inode->i_mtime);
 +      to->di_atime = xfs_inode_to_log_dinode_ts(ip, inode_get_atime(inode));
 +      to->di_mtime = xfs_inode_to_log_dinode_ts(ip, inode_get_mtime(inode));
        to->di_ctime = xfs_inode_to_log_dinode_ts(ip, inode_get_ctime(inode));
        to->di_nlink = inode->i_nlink;
        to->di_gen = inode->i_generation;
diff --combined fs/xfs/xfs_mount.h
index 219681d29fbc496cd594c21ddb921b03918e3755,9cd1d570d24d1d55dea38ee038d9a51733c0f623..503fe3c7edbf82cd1f194b3fd3d33b27bb06167d
@@@ -101,9 -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 */
        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 */
        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 */
        atomic_t                m_agirotor;     /* last ag dir inode alloced */
  
        /* Memory shrinker to throttle and reprioritize inodegc */
 -      struct shrinker         m_inodegc_shrinker;
 +      struct shrinker         *m_inodegc_shrinker;
        /*
         * Workqueue item so that we can coalesce multiple inode flush attempts
         * into a single flush.
diff --combined fs/xfs/xfs_rtalloc.c
index 2e1a4e5cd03def7495310d7213d2b99dbe617a51,ba66442910b1f1c81f90604d8a40356441dc0356..88c48de5c9c810c97e38170ecb4bf84fe42c7b35
@@@ -19,6 -19,7 +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;
                }
                 * 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;
  }
  
   * 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;
        /*
         * 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;
        }
         * 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;
        }
         * 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;
                }
         * 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;
                }
        /*
         * 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;
                }
                        /*
                         * 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;
                }
                /*
                 * 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) {
                 * 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;
                        }
         * 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.
                /*
                 * 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;
        }
                /*
                 * 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;
        }
        /*
                        /*
                         * 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);
        /*
                 * 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;
                }
                 * 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.
                         */
                                 * 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;
                                }
                        }
                         * 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;
-                               }
                        }
                }
                /*
                else
                        break;
        }
-       *rtblock = NULLRTBLOCK;
+       *rtx = NULLRTEXTNO;
        return 0;
  }
  
   * 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);
  
        /*
                        /*
                         * 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;
                        }
                        /*
                         * 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;
                        }
                        /*
                         * 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;
                }
        }
        /*
         * we're asking for a fixed size extent.
         */
        if (minlen > --maxlen) {
-               *rtblock = NULLRTBLOCK;
+               *rtx = NULLRTEXTNO;
                return 0;
        }
        ASSERT(minlen != 0);
                        /*
                         * 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;
                        }
                         * 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;
                        }
                        /*
                         * 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 +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 +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 */
        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;
                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;
         */
        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
                     ((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;
  
                 * 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.
                                &tp);
                if (error)
                        break;
+               args.tp = tp;
+               nargs.tp = tp;
                /*
                 * Lock out other callers by grabbing the bitmap inode lock.
                 */
                 */
                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;
                }
                /*
                 * 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 +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 +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;
                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,28 -1412,27 +1412,28 @@@ 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_rtxlen_t    len,            /* allocation length (rtextents) */
 -      xfs_rtxnum_t    *pick)          /* result rt 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 */
 -      uint64_t        *seqp;          /* pointer to seqno in inode */
++      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));
  
 -      seqp = (uint64_t *)&VFS_I(mp->m_rbmip)->i_atime;
++      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;
 -              *seqp = 0;
 +              seq = 0;
 +      } else {
-               ts = inode_get_atime(VFS_I(mp->m_rbmip));
-               seq = (uint64_t)ts.tv_sec;
++              seq = ts.tv_sec;
        }
 -      seq = *seqp;
        if ((log2 = xfs_highbit64(seq)) == -1)
                b = 0;
        else {
                if (b + len > mp->m_sb.sb_rextents)
                        b = mp->m_sb.sb_rextents - len;
        }
-       ts.tv_sec = (time64_t)seq + 1;
 -      *seqp = 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;
        return 0;
diff --combined fs/xfs/xfs_super.c
index f0ae07828153130004b3fb8fef4a12f19520a9fb,991a31089dc7fc30512f80b330d9d07e9bbb58ef..764304595e8b00b38c5a38e0673d88152a532e93
@@@ -42,6 -42,7 +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>
@@@ -361,15 -362,14 +362,15 @@@ STATIC in
  xfs_blkdev_get(
        xfs_mount_t             *mp,
        const char              *name,
 -      struct block_device     **bdevp)
 +      struct bdev_handle      **handlep)
  {
        int                     error = 0;
  
 -      *bdevp = blkdev_get_by_path(name, BLK_OPEN_READ | BLK_OPEN_WRITE,
 -                                  mp->m_super, &fs_holder_ops);
 -      if (IS_ERR(*bdevp)) {
 -              error = PTR_ERR(*bdevp);
 +      *handlep = bdev_open_by_path(name, BLK_OPEN_READ | BLK_OPEN_WRITE,
 +                                   mp->m_super, &fs_holder_ops);
 +      if (IS_ERR(*handlep)) {
 +              error = PTR_ERR(*handlep);
 +              *handlep = NULL;
                xfs_warn(mp, "Invalid device [%s], error=%d", name, error);
        }
  
@@@ -434,7 -434,7 +435,7 @@@ xfs_open_devices
  {
        struct super_block      *sb = mp->m_super;
        struct block_device     *ddev = sb->s_bdev;
 -      struct block_device     *logdev = NULL, *rtdev = NULL;
 +      struct bdev_handle      *logdev_handle = NULL, *rtdev_handle = NULL;
        int                     error;
  
        /*
         * Open real time and log devices - order is important.
         */
        if (mp->m_logname) {
 -              error = xfs_blkdev_get(mp, mp->m_logname, &logdev);
 +              error = xfs_blkdev_get(mp, mp->m_logname, &logdev_handle);
                if (error)
                        goto out_relock;
        }
  
        if (mp->m_rtname) {
 -              error = xfs_blkdev_get(mp, mp->m_rtname, &rtdev);
 +              error = xfs_blkdev_get(mp, mp->m_rtname, &rtdev_handle);
                if (error)
                        goto out_close_logdev;
  
 -              if (rtdev == ddev || rtdev == logdev) {
 +              if (rtdev_handle->bdev == ddev ||
 +                  (logdev_handle &&
 +                   rtdev_handle->bdev == logdev_handle->bdev)) {
                        xfs_warn(mp,
        "Cannot mount filesystem with identical rtdev and ddev/logdev.");
                        error = -EINVAL;
         * Setup xfs_mount buffer target pointers
         */
        error = -ENOMEM;
 -      mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev);
 +      mp->m_ddev_targp = xfs_alloc_buftarg(mp, sb->s_bdev_handle);
        if (!mp->m_ddev_targp)
                goto out_close_rtdev;
  
 -      if (rtdev) {
 -              mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev);
 +      if (rtdev_handle) {
 +              mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev_handle);
                if (!mp->m_rtdev_targp)
                        goto out_free_ddev_targ;
        }
  
 -      if (logdev && logdev != ddev) {
 -              mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev);
 +      if (logdev_handle && logdev_handle->bdev != ddev) {
 +              mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev_handle);
                if (!mp->m_logdev_targp)
                        goto out_free_rtdev_targ;
        } else {
                mp->m_logdev_targp = mp->m_ddev_targp;
 +              /* Handle won't be used, drop it */
 +              if (logdev_handle)
 +                      bdev_release(logdev_handle);
        }
  
        error = 0;
@@@ -503,11 -498,11 +504,11 @@@ out_relock
   out_free_ddev_targ:
        xfs_free_buftarg(mp->m_ddev_targp);
   out_close_rtdev:
 -       if (rtdev)
 -               blkdev_put(rtdev, sb);
 +       if (rtdev_handle)
 +              bdev_release(rtdev_handle);
   out_close_logdev:
 -      if (logdev && logdev != ddev)
 -              blkdev_put(logdev, sb);
 +      if (logdev_handle)
 +              bdev_release(logdev_handle);
        goto out_relock;
  }
  
@@@ -896,7 -891,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;
This page took 0.203404 seconds and 4 git commands to generate.