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