From: Christoph Hellwig Date: Wed, 31 Jul 2024 14:42:04 +0000 (-0700) Subject: fixup X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fxfs-per-rtg-bitmap;p=users%2Fhch%2Fxfsprogs.git fixup Now also loads rtbitmap/summary inodes early. Uses the AG btree based code in repair. Needs to be maybe split and grow an actual commit log. Signed-off-by: Christoph Hellwig --- diff --git a/db/block.c b/db/block.c index e8326f780..dc7c830cc 100644 --- a/db/block.c +++ b/db/block.c @@ -395,7 +395,7 @@ rtextent_f( char **argv) { xfs_rtblock_t rtbno; - xfs_rtxnum_t rtx; + uint64_t rtx; char *p; if (argc == 1) { @@ -419,7 +419,11 @@ rtextent_f( return 0; } - rtbno = xfs_rtx_to_rtb(mp, rtx); + /* + * The user interface assumes a global RT extent number, while the + * in-kernel rtx is per-RTG now, thus the open coded conversion here. + */ + rtbno = rtx * mp->m_sb.sb_rextsize; ASSERT(typtab[TYP_DATA].typnm == TYP_DATA); set_rt_cur(&typtab[TYP_DATA], XFS_FSB_TO_BB(mp, rtbno), mp->m_sb.sb_rextsize * blkbb, DB_RING_ADD, NULL); diff --git a/db/frag.c b/db/frag.c index 1165e824a..10c17e2f5 100644 --- a/db/frag.c +++ b/db/frag.c @@ -13,6 +13,10 @@ #include "output.h" #include "type.h" #include "init.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" #include "malloc.h" typedef struct extent { @@ -148,9 +152,17 @@ frag_f( { xfs_agnumber_t agno; double answer; + int ret; if (!init(argc, argv)) return 0; + + ret = init_rtmeta_inode_bitmaps(mp); + if (ret) { + dbprintf(_("error %d setting up rt metadata inode bitmaps\n"), + ret); + return 3; + } for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) scan_ag(agno); if (extcount_actual) @@ -314,7 +326,9 @@ process_inode( skipd = 1; else if (!Rflag && (ino == mp->m_sb.sb_rbmino || - ino == mp->m_sb.sb_rsumino)) + is_rtbitmap_inode(ino) || + ino == mp->m_sb.sb_rsumino || + is_rtsummary_inode(ino))) skipd = 1; else if (!qflag && (ino == mp->m_sb.sb_uquotino || diff --git a/db/inode.c b/db/inode.c index 4f813c994..5d2f06411 100644 --- a/db/inode.c +++ b/db/inode.c @@ -756,11 +756,13 @@ inode_next_type(void) case S_IFLNK: return TYP_SYMLINK; case S_IFREG: - if (iocur_top->ino == mp->m_sb.sb_rbmino) { + if (iocur_top->ino == mp->m_sb.sb_rbmino || + is_rtbitmap_inode(iocur_top->ino)) { if (xfs_has_rtgroups(mp)) return TYP_RGBITMAP; return TYP_RTBITMAP; - } else if (iocur_top->ino == mp->m_sb.sb_rsumino) { + } else if (iocur_top->ino == mp->m_sb.sb_rsumino || + is_rtsummary_inode(iocur_top->ino)) { if (xfs_has_rtgroups(mp)) return TYP_RGSUMMARY; return TYP_RTSUMMARY; diff --git a/db/inode.h b/db/inode.h index 0f62d84e9..84b68150c 100644 --- a/db/inode.h +++ b/db/inode.h @@ -36,6 +36,15 @@ rtgroup_for_rtrmap_ino(struct xfs_mount *mp, xfs_ino_t ino) bool is_rtgroup_inode(xfs_ino_t ino, enum xfs_rtg_inodes type); +static inline bool is_rtbitmap_inode(xfs_ino_t ino) +{ + return is_rtgroup_inode(ino, XFS_RTG_BITMAP); +} +static inline bool is_rtsummary_inode(xfs_ino_t ino) +{ + return is_rtgroup_inode(ino, XFS_RTG_SUMMARY); +} + static inline bool is_rtrmap_inode(xfs_ino_t ino) { return is_rtgroup_inode(ino, XFS_RTG_RMAP); diff --git a/db/metadump.c b/db/metadump.c index f33d375ba..639a78822 100644 --- a/db/metadump.c +++ b/db/metadump.c @@ -18,6 +18,7 @@ #include "fprint.h" #include "faddr.h" #include "field.h" +#include "inode.h" #include "dir2.h" #include "obfuscate.h" @@ -2103,9 +2104,11 @@ ifork_data_type( case S_IFLNK: return TYP_SYMLINK; case S_IFREG: - if (ino == mp->m_sb.sb_rbmino) + if (ino == mp->m_sb.sb_rbmino || + is_rtbitmap_inode(ino)) return TYP_RTBITMAP; - if (ino == mp->m_sb.sb_rsumino) + if (ino == mp->m_sb.sb_rsumino || + is_rtsummary_inode(ino)) return TYP_RTSUMMARY; if (ino == mp->m_sb.sb_uquotino) return TYP_DQBLK; @@ -3539,6 +3542,14 @@ metadump_f( } } + ret = init_rtmeta_inode_bitmaps(mp); + if (ret) { + dbprintf(_("error %d setting up rt metadata inode bitmaps\n"), + ret); + exitcode = 3; + goto out; + } + if (metadump.version == 1) metadump.mdops = &metadump1_ops; else diff --git a/include/xfs_mount.h b/include/xfs_mount.h index c1da38793..3f518ba46 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -54,15 +54,6 @@ typedef struct xfs_mount { uint m_rsumlevels; /* rt summary levels */ uint m_rsumsize; /* size of rt summary, bytes */ uint32_t m_rgblocks; /* size of rtgroup in rtblocks */ - /* - * Optional cache of rt summary level per bitmap block with the - * invariant that m_rsum_cache[bbno] <= the minimum i for which - * rsum[i][bbno] != 0. Reads and writes are serialized by the rsumip - * inode lock. - */ - uint8_t *m_rsum_cache; - struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ - struct xfs_inode *m_rsumip; /* pointer to summary inode */ struct xfs_inode *m_metadirip; /* ptr to metadata directory */ struct xfs_inode *m_rtdirip; /* ptr to realtime metadir */ struct xfs_buftarg *m_ddev_targp; diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c index a9d17fbb4..9ebaa9f1f 100644 --- a/libxfs/defer_item.c +++ b/libxfs/defer_item.c @@ -214,7 +214,7 @@ xfs_rtextent_free_finish_item( struct xfs_extent_free_item *xefi = xefi_entry(item); int error; - error = xfs_rtfree_blocks(tp, xefi->xefi_startblock, + error = xfs_rtfree_blocks(tp, xefi->xefi_rtg, xefi->xefi_startblock, xefi->xefi_blockcount); if (error != -EAGAIN) xfs_rtextent_free_cancel_item(item); diff --git a/libxfs/init.c b/libxfs/init.c index 0edde09d8..36d61d73e 100644 --- a/libxfs/init.c +++ b/libxfs/init.c @@ -313,11 +313,10 @@ rtmount_init( progname); return -1; } - mp->m_rsumlevels = mp->m_sb.sb_rextslog + 1; + mp->m_rsumlevels = xfs_compute_rsumlevels(mp, mp->m_sb.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; /* * Allow debugger to be run without the realtime device present. @@ -893,10 +892,8 @@ libxfs_mount( exit(1); } - for_each_rtgroup(mp, rgno, rtg) { - rtg->rtg_blockcount = xfs_rtgroup_block_count(mp, - rtg->rtg_rgno); - } + for_each_rtgroup(mp, rgno, rtg) + rtg->rtg_extents = xfs_rtgroup_extents(mp, rtg->rtg_rgno); xfs_set_rtgroup_data_loaded(mp); @@ -921,13 +918,9 @@ libxfs_rtmount_destroy( rtg->rtg_inodes[i] = NULL; } } + if (mp->m_rtdirip) libxfs_irele(mp->m_rtdirip); - if (mp->m_rsumip) - libxfs_irele(mp->m_rsumip); - if (mp->m_rbmip) - libxfs_irele(mp->m_rbmip); - mp->m_rsumip = mp->m_rbmip = mp->m_rtdirip = NULL; } /* Flush a device and report on writes that didn't make it to stable storage. */ diff --git a/libxfs/trans.c b/libxfs/trans.c index 01834eff4..271a22c6b 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -1202,7 +1202,7 @@ libxfs_trans_alloc_inode( int error; error = libxfs_trans_alloc(mp, resv, dblocks, - xfs_rtb_to_rtx(mp, rblocks), + xfs_blen_to_rtbxlen(mp, rblocks), force ? XFS_TRANS_RESERVE : 0, &tp); if (error) return error; diff --git a/mkfs/proto.c b/mkfs/proto.c index c63eac4ac..a0683481c 100644 --- a/mkfs/proto.c +++ b/mkfs/proto.c @@ -801,17 +801,22 @@ out_rele: static void create_sb_metadata_file( - struct xfs_mount *mp, - void (*create)(struct xfs_inode *ip)) + struct xfs_rtgroup *rtg, + enum xfs_rtg_inodes type, + int (*create)(struct xfs_rtgroup *rtg, + struct xfs_inode *ip, + struct xfs_trans *tp, + bool init)) { + struct xfs_mount *mp = rtg->rtg_mount; struct xfs_icreate_args args = { .mode = S_IFREG, .flags = XFS_ICREATE_UNLINKABLE, }; + struct xfs_inode *ip; + struct xfs_trans *tp; xfs_ino_t ino; int error; - struct xfs_trans *tp; - struct xfs_inode *ip; error = -libxfs_trans_alloc_rollable(mp, MKFS_BLOCKRES_INODE, &tp); if (error) @@ -828,57 +833,43 @@ create_sb_metadata_file( if (xfs_has_metadir(mp)) libxfs_metafile_set_iflag(tp, ip); - create(ip); + error = -create(rtg, ip, tp, true); + if (error) + goto fail; - libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + switch (type) { + case XFS_RTG_BITMAP: + mp->m_sb.sb_rbmino = ino; + break; + case XFS_RTG_SUMMARY: + mp->m_sb.sb_rsumino = ino; + break; + default: + fail(_("Incorrect SB inode type"), EINVAL); + break; + } libxfs_log_sb(tp); error = -libxfs_trans_commit(tp); if (error) goto fail; + rtg->rtg_inodes[type] = ip; return; + fail: if (error) fail(_("Realtime inode allocation failed"), error); } -/* Create the realtime bitmap inode. */ -static void -rtbitmap_create( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - - ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; - ip->i_diflags |= XFS_DIFLAG_NEWRTBM; - if (!xfs_has_rtgroups(mp)) - inode_set_atime(VFS_I(ip), 0, 0); - - mp->m_sb.sb_rbmino = ip->i_ino; - mp->m_rbmip = ip; -} - -/* Create the realtime summary inode. */ -static void -rtsummary_create( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - - ip->i_disk_size = mp->m_rsumsize; - - mp->m_sb.sb_rsumino = ip->i_ino; - mp->m_rsumip = ip; -} - /* * Free the whole realtime area using transactions. Each transaction may clear * up to 32 rtbitmap blocks. */ static void rtfreesp_init( - struct xfs_mount *mp) + struct xfs_rtgroup *rtg) { + struct xfs_mount *mp = rtg->rtg_mount; struct xfs_trans *tp; const xfs_rtxnum_t max_rtx = mp->m_rtx_per_rbmblock * 32; xfs_rtxnum_t start_rtx = 0; @@ -887,32 +878,34 @@ rtfreesp_init( /* * First zero the realtime bitmap and summary files. */ - error = -libxfs_rtfile_initialize_blocks(mp->m_rbmip, 0, + error = -libxfs_rtfile_initialize_blocks(rtg, XFS_RTG_BITMAP, 0, mp->m_sb.sb_rbmblocks, NULL); if (error) fail(_("Initialization of rtbitmap inode failed"), error); - error = -libxfs_rtfile_initialize_blocks(mp->m_rsumip, 0, + error = -libxfs_rtfile_initialize_blocks(rtg, XFS_RTG_SUMMARY, 0, XFS_B_TO_FSB(mp, mp->m_rsumsize), NULL); if (error) fail(_("Initialization of rtsummary inode failed"), error); + if (!mp->m_sb.sb_rbmblocks) + return; + /* * Then free the blocks into the allocator, one bitmap block at a time. */ - while (start_rtx < mp->m_sb.sb_rextents) { - xfs_rtxlen_t nr = min(mp->m_sb.sb_rextents - start_rtx, - max_rtx); + while (start_rtx < rtg->rtg_extents) { + xfs_rtxlen_t nr = min(rtg->rtg_extents - start_rtx, max_rtx); /* * The rt superblock, if present, must not be marked free. * This may be the only rtx in the entire volume. */ - if (xfs_has_rtsb(mp) && start_rtx == 0) { + if (xfs_has_rtsb(mp) && rtg->rtg_rgno == 0 && start_rtx == 0) { start_rtx++; nr--; - if (start_rtx == mp->m_sb.sb_rextents) + if (start_rtx == rtg->rtg_extents) break; } @@ -921,13 +914,15 @@ rtfreesp_init( if (error) res_failed(error); - libxfs_trans_ijoin(tp, mp->m_rbmip, 0); - error = -libxfs_rtfree_extent(tp, start_rtx, nr); + libxfs_trans_ijoin(tp, rtg->rtg_inodes[XFS_RTG_BITMAP], 0); + error = -libxfs_rtfree_extent(tp, rtg, start_rtx, nr); if (error) { fprintf(stderr, - _("Error initializing the realtime free space near rtx 0x%llx-0x%llx: %s"), + _("Error initializing the realtime free space near rgno %u rtx %lld-%lld (max %lld): %s\n"), + rtg->rtg_rgno, (unsigned long long)start_rtx, (unsigned long long)start_rtx + nr - 1, + (unsigned long long)rtg->rtg_extents, strerror(error)); exit(1); } @@ -941,9 +936,11 @@ rtfreesp_init( } } -/* Allocate rtgroup inodes and directory tree. */ +/* + * Allocate the realtime bitmap and summary inodes, and fill in data if any. + */ static void -rtgroups_create( +rtinit( struct xfs_mount *mp) { struct xfs_rtgroup *rtg; @@ -951,36 +948,32 @@ rtgroups_create( unsigned int i; int error; - error = -libxfs_rtginode_mkdir_parent(mp); - if (error) - fail(_("rtgroup directory allocation failed"), error); + if (xfs_has_rtgroups(mp)) { + error = -libxfs_rtginode_mkdir_parent(mp); + if (error) + fail(_("rtgroup directory allocation failed"), error); + } for_each_rtgroup(mp, rgno, rtg) { - for (i = 0; i < XFS_RTG_MAX; i++) { - error = -libxfs_rtginode_create(rtg, i, true); - if (error) - fail(_("rt group inode creation failed"), - error); + if (!xfs_has_rtgroups(mp)) { + create_sb_metadata_file(rtg, XFS_RTG_BITMAP, + xfs_rtbitmap_create); + create_sb_metadata_file(rtg, XFS_RTG_SUMMARY, + xfs_rtsummary_create); + } else { + + for (i = 0; i < XFS_RTG_MAX; i++) { + error = -libxfs_rtginode_create(rtg, i, true); + if (error) + fail(_("rt group inode creation failed"), + error); + } } + + rtfreesp_init(rtg); } } -/* - * Allocate the realtime bitmap and summary inodes, and fill in data if any. - */ -static void -rtinit( - struct xfs_mount *mp) -{ - create_sb_metadata_file(mp, rtbitmap_create); - create_sb_metadata_file(mp, rtsummary_create); - - if (xfs_has_rtgroups(mp)) - rtgroups_create(mp); - - rtfreesp_init(mp); -} - static long filesize( int fd) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index 2690f5dca..fc24812c7 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3378,7 +3378,6 @@ validate_rtdev( struct cli_params *cli) { struct libxfs_init *xi = cli->xi; - unsigned int rbmblocksize = cfg->blocksize; if (!xi->rt.dev) { if (cli->rtsize) { @@ -3422,10 +3421,13 @@ reported by the device (%u).\n"), _("cannot have an rt subvolume with zero extents\n")); usage(); } - if (cfg->sb_feat.rtgroups) - rbmblocksize -= sizeof(struct xfs_rtbuf_blkinfo); + + /* + * Note for rtgroup file systems this will be overriden in + * calculate_rtgroup_geometry. + */ cfg->rtbmblocks = (xfs_extlen_t)howmany(cfg->rtextents, - NBBY * rbmblocksize); + NBBY * cfg->blocksize); } static bool @@ -3843,6 +3845,9 @@ _("realtime group count (%llu) must be less than the maximum (%u)\n"), XFS_MAX_RGNUMBER); usage(); } + + cfg->rtbmblocks = howmany(cfg->rgsize / cfg->rtextblocks, + NBBY * (cfg->blocksize - sizeof(struct xfs_rtbuf_blkinfo))); } static void @@ -3941,6 +3946,10 @@ sb_set_features( */ sbp->sb_bad_features2 = sbp->sb_features2; + /* This will be overriden later for real rtgroup file systems: */ + sbp->sb_rgcount = 1; + sbp->sb_rgextents = UINT_MAX; + if (!fp->crcs_enabled) return; diff --git a/repair/bmap_repair.c b/repair/bmap_repair.c index eca8cfe25..36f93124e 100644 --- a/repair/bmap_repair.c +++ b/repair/bmap_repair.c @@ -322,11 +322,13 @@ xrep_bmap_find_mappings( int error; /* Iterate the rtrmaps for extents. */ - for_each_rtgroup(rb->sc->mp, rgno, rtg) { - error = xrep_bmap_scan_rt(rb, rtg); - if (error) { - libxfs_rtgroup_put(rtg); - return error; + if (xfs_has_rtgroups(rb->sc->mp)) { + for_each_rtgroup(rb->sc->mp, rgno, rtg) { + error = xrep_bmap_scan_rt(rb, rtg); + if (error) { + libxfs_rtgroup_put(rtg); + return error; + } } } diff --git a/repair/dinode.c b/repair/dinode.c index dd35bc8b8..f6b5f858b 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -178,19 +178,32 @@ clear_dinode(xfs_mount_t *mp, struct xfs_dinode *dino, xfs_ino_t ino_num) static __inline int verify_dfsbno_range( struct xfs_mount *mp, - xfs_fsblock_t fsbno, - xfs_filblks_t count) + struct xfs_bmbt_irec *irec, + bool isrt) { + xfs_fsblock_t end = + irec->br_startblock + irec->br_blockcount - 1; + /* the start and end blocks better be in the same allocation group */ - if (XFS_FSB_TO_AGNO(mp, fsbno) != - XFS_FSB_TO_AGNO(mp, fsbno + count - 1)) { - return XR_DFSBNORANGE_OVERFLOW; - } + if (isrt) { + if (xfs_rtb_to_rgno(mp, irec->br_startblock) != + xfs_rtb_to_rgno(mp, end)) + return XR_DFSBNORANGE_OVERFLOW; + + if (!libxfs_verify_rtbno(mp, irec->br_startblock)) + return XR_DFSBNORANGE_BADSTART; + if (!libxfs_verify_rtbno(mp, end)) + return XR_DFSBNORANGE_BADEND; + } else { + if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) != + XFS_FSB_TO_AGNO(mp, end)) + return XR_DFSBNORANGE_OVERFLOW; - if (!libxfs_verify_fsbno(mp, fsbno)) - return XR_DFSBNORANGE_BADSTART; - if (!libxfs_verify_fsbno(mp, fsbno + count - 1)) - return XR_DFSBNORANGE_BADEND; + if (!libxfs_verify_fsbno(mp, irec->br_startblock)) + return XR_DFSBNORANGE_BADSTART; + if (!libxfs_verify_fsbno(mp, end)) + return XR_DFSBNORANGE_BADEND; + } return XR_DFSBNORANGE_VALID; } @@ -479,17 +492,21 @@ process_bmbt_reclist_int( xfs_extnum_t i; int state; xfs_agnumber_t agno; - xfs_agblock_t agbno; + xfs_agblock_t agbno, first_agbno; xfs_agblock_t ebno; xfs_extlen_t blen; xfs_agnumber_t locked_agno = -1; int error = 1; int error2; + bool isrt = false; - if (type == XR_INO_RTDATA) + if (type == XR_INO_RTDATA) { + if (whichfork == XFS_DATA_FORK) + isrt = true; ftype = ftype_real_time; - else + } else { ftype = ftype_regular; + } for (i = 0; i < *numrecs; i++) { libxfs_bmbt_disk_get_all((rp +i), &irec); @@ -544,7 +561,7 @@ _("zero length extent (off = %" PRIu64 ", fsbno = %" PRIu64 ") in ino %" PRIu64 goto done; } - if (type == XR_INO_RTDATA && whichfork == XFS_DATA_FORK) { + if (isrt && !xfs_has_rtgroups(mp)) { pthread_mutex_lock(&rt_lock.lock); error2 = process_rt_rec(mp, &irec, ino, tot, check_dups, zap_metadata); @@ -562,8 +579,7 @@ _("zero length extent (off = %" PRIu64 ", fsbno = %" PRIu64 ") in ino %" PRIu64 /* * regular file data fork or attribute fork */ - switch (verify_dfsbno_range(mp, irec.br_startblock, - irec.br_blockcount)) { + switch (verify_dfsbno_range(mp, &irec, isrt)) { case XR_DFSBNORANGE_VALID: break; @@ -626,12 +642,23 @@ _("Fatal error: inode %" PRIu64 " - blkmap_set_ext(): %s\n" } /* - * Profiling shows that the following loop takes the - * most time in all of xfs_repair. + * For rtgroup enabled file systems we treat the RTGs as + * basically another set of AGs tacked on at the end, but + * otherwise reuse all the existing code. That's why we'll + * see odd "agno" value here. */ - agno = XFS_FSB_TO_AGNO(mp, irec.br_startblock); - agbno = XFS_FSB_TO_AGBNO(mp, irec.br_startblock); - ebno = agbno + irec.br_blockcount; + if (isrt) { + xfs_rgnumber_t rgno; + + first_agbno = xfs_rtb_to_rgbno(mp, irec.br_startblock, + &rgno); + agno = mp->m_sb.sb_agcount + rgno; + } else { + agno = XFS_FSB_TO_AGNO(mp, irec.br_startblock); + first_agbno = XFS_FSB_TO_AGBNO(mp, irec.br_startblock); + } + agbno = first_agbno; + ebno = first_agbno + irec.br_blockcount; if (agno != locked_agno) { if (locked_agno != -1) pthread_mutex_unlock(&ag_locks[locked_agno].lock); @@ -639,12 +666,23 @@ _("Fatal error: inode %" PRIu64 " - blkmap_set_ext(): %s\n" locked_agno = agno; } + /* + * Profiling shows that the following loop takes the most time + * in all of xfs_repair. + */ for (b = irec.br_startblock; agbno < ebno; b += blen, agbno += blen) { state = get_bmap_ext(agno, agbno, ebno, &blen); switch (state) { case XR_E_FREE: + /* + * We never do a scan pass of the rt bitmap, so unknown + * blocks are marked as free. + */ + if (isrt) + break; + fallthrough; case XR_E_FREE1: do_warn( _("%s fork in ino %" PRIu64 " claims free block %" PRIu64 "\n"), @@ -678,7 +716,8 @@ _("%s fork in inode %" PRIu64 " claims metadata block %" PRIu64 "\n"), case XR_E_INUSE: case XR_E_MULT: - if (type == XR_INO_DATA && + if ((type == XR_INO_DATA || + type == XR_INO_RTDATA) && xfs_has_reflink(mp)) { if (irec.br_state == XFS_EXT_NORM) break; @@ -724,8 +763,8 @@ _("illegal state %d in block map %" PRIu64 "\n"), * After a successful rebuild we'll try this scan again. * (If the rebuild fails we won't come back here.) */ - agbno = XFS_FSB_TO_AGBNO(mp, irec.br_startblock); - ebno = agbno + irec.br_blockcount; + agbno = first_agbno; + ebno = first_agbno + irec.br_blockcount; for (; agbno < ebno; agbno += blen) { state = get_bmap_ext(agno, agbno, ebno, &blen); switch (state) { @@ -757,7 +796,7 @@ _("illegal state %d in block map %" PRIu64 "\n"), } } if (collect_rmaps && !zap_metadata) /* && !check_dups */ - rmap_add_rec(mp, ino, whichfork, &irec, false); + rmap_add_rec(mp, ino, whichfork, &irec, isrt); *tot += irec.br_blockcount; } error = 0; @@ -2039,6 +2078,7 @@ _("bad # of extents (%" PRIu64 ") for %s inode %" PRIu64 "\n"), * Returns 0 if it's valid, non-zero if it needs to be cleared. */ +/* XXX: this isn't just sb but metadata inodes now? */ static int process_check_sb_inodes( xfs_mount_t *mp, @@ -2088,10 +2128,12 @@ process_check_sb_inodes( } return 0; } - if (lino == mp->m_sb.sb_rsumino) + if (lino == mp->m_sb.sb_rsumino || + is_rtsummary_inode(lino)) return process_check_rt_inode(mp, dinoc, lino, type, dirty, XR_INO_RTSUM, _("realtime summary")); - if (lino == mp->m_sb.sb_rbmino) + if (lino == mp->m_sb.sb_rbmino || + is_rtbitmap_inode(lino)) return process_check_rt_inode(mp, dinoc, lino, type, dirty, XR_INO_RTBITMAP, _("realtime bitmap")); if (is_rtrmap_inode(lino)) @@ -3425,9 +3467,11 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), case S_IFREG: if (be16_to_cpu(dino->di_flags) & XFS_DIFLAG_REALTIME) type = XR_INO_RTDATA; - else if (lino == mp->m_sb.sb_rbmino) + else if (lino == mp->m_sb.sb_rbmino || + is_rtbitmap_inode(lino)) type = XR_INO_RTBITMAP; - else if (lino == mp->m_sb.sb_rsumino) + else if (lino == mp->m_sb.sb_rsumino || + is_rtsummary_inode(lino)) type = XR_INO_RTSUM; else if (lino == mp->m_sb.sb_uquotino) type = XR_INO_UQUOTA; diff --git a/repair/dir2.c b/repair/dir2.c index 25fa151ca..d489a742a 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -259,10 +259,12 @@ process_sf_dir2( * bother checking if the child inode is free or not. */ junkit = 0; - } else if (lino == mp->m_sb.sb_rbmino) { + } else if (lino == mp->m_sb.sb_rbmino || + is_rtbitmap_inode(lino)) { junkit = 1; junkreason = _("realtime bitmap"); - } else if (lino == mp->m_sb.sb_rsumino) { + } else if (lino == mp->m_sb.sb_rsumino || + is_rtsummary_inode(lino)) { junkit = 1; junkreason = _("realtime summary"); } else if (lino == mp->m_sb.sb_uquotino) { @@ -746,9 +748,11 @@ process_dir2_data( * bother checking if the child inode is free or not. */ clearino = 0; - } else if (ent_ino == mp->m_sb.sb_rbmino) { + } else if (ent_ino == mp->m_sb.sb_rbmino || + is_rtbitmap_inode(ent_ino)) { clearreason = _("realtime bitmap"); - } else if (ent_ino == mp->m_sb.sb_rsumino) { + } else if (ent_ino == mp->m_sb.sb_rsumino || + is_rtsummary_inode(ent_ino)) { clearreason = _("realtime summary"); } else if (ent_ino == mp->m_sb.sb_uquotino) { clearreason = _("user quota"); diff --git a/repair/incore.c b/repair/incore.c index 98afa6911..869c3a066 100644 --- a/repair/incore.c +++ b/repair/incore.c @@ -243,7 +243,8 @@ free_rt_bmap(xfs_mount_t *mp) void reset_bmaps(xfs_mount_t *mp) { - xfs_agnumber_t agno; + unsigned int nr_groups = mp->m_sb.sb_agcount + mp->m_sb.sb_rgcount; + unsigned int agno; xfs_agblock_t ag_size; int ag_hdr_block; @@ -275,6 +276,22 @@ reset_bmaps(xfs_mount_t *mp) btree_insert(ag_bmap[agno], ag_size, &states[XR_E_BAD_STATE]); } + for ( ; agno < nr_groups; agno++) { + btree_clear(ag_bmap[agno]); + if (agno == mp->m_sb.sb_agcount && xfs_has_rtsb(mp)) { + btree_insert(ag_bmap[agno], 0, &states[XR_E_INUSE_FS]); + btree_insert(ag_bmap[agno], mp->m_sb.sb_rextsize, + &states[XR_E_FREE]); + } else { + btree_insert(ag_bmap[agno], 0, &states[XR_E_FREE]); + } + + btree_insert(ag_bmap[agno], + xfs_rtgroup_extents(mp, (agno - mp->m_sb.sb_agcount)) << + mp->m_sb.sb_rextslog, + &states[XR_E_BAD_STATE]); + } + if (mp->m_sb.sb_logstart != 0) { set_bmap_ext(XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart), XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart), @@ -286,19 +303,22 @@ reset_bmaps(xfs_mount_t *mp) } void -init_bmaps(xfs_mount_t *mp) +init_bmaps( + struct xfs_mount *mp) { - xfs_agnumber_t i; + unsigned int nr_groups = + mp->m_sb.sb_agcount + mp->m_sb.sb_rgcount; + unsigned int i; - ag_bmap = calloc(mp->m_sb.sb_agcount, sizeof(struct btree_root *)); + ag_bmap = calloc(nr_groups, sizeof(struct btree_root *)); if (!ag_bmap) do_error(_("couldn't allocate block map btree roots\n")); - ag_locks = calloc(mp->m_sb.sb_agcount, sizeof(struct aglock)); + ag_locks = calloc(nr_groups, sizeof(struct aglock)); if (!ag_locks) do_error(_("couldn't allocate block map locks\n")); - for (i = 0; i < mp->m_sb.sb_agcount; i++) { + for (i = 0; i < nr_groups; i++) { btree_init(&ag_bmap[i]); pthread_mutex_init(&ag_locks[i].lock, NULL); } @@ -309,19 +329,22 @@ init_bmaps(xfs_mount_t *mp) } void -free_bmaps(xfs_mount_t *mp) +free_bmaps( + struct xfs_mount *mp) { - xfs_agnumber_t i; + unsigned int nr_groups = + mp->m_sb.sb_agcount + mp->m_sb.sb_rgcount; + unsigned int i; pthread_mutex_destroy(&rt_lock.lock); - for (i = 0; i < mp->m_sb.sb_agcount; i++) + for (i = 0; i < nr_groups; i++) pthread_mutex_destroy(&ag_locks[i].lock); free(ag_locks); ag_locks = NULL; - for (i = 0; i < mp->m_sb.sb_agcount; i++) + for (i = 0; i < nr_groups; i++) btree_destroy(ag_bmap[i]); free(ag_bmap); diff --git a/repair/incore.h b/repair/incore.h index 9b8227e74..058c23374 100644 --- a/repair/incore.h +++ b/repair/incore.h @@ -698,7 +698,7 @@ xfs_rootrec_inodes_inuse( struct xfs_mount *mp) { if (xfs_has_metadir(mp)) - return 4; /* sb_rootino, sb_rbmino, sb_rsumino, sb_metadirino */ + return 2; /* sb_rootino, sb_metadirino */ return 3; /* sb_rootino, sb_rbmino, sb_rsumino */ } diff --git a/repair/incore_ext.c b/repair/incore_ext.c index 59c5d6f50..a31ef066e 100644 --- a/repair/incore_ext.c +++ b/repair/incore_ext.c @@ -593,7 +593,6 @@ release_rt_extent_tree() void free_rt_dup_extent_tree(xfs_mount_t *mp) { - ASSERT(mp->m_sb.sb_rblocks != 0); free(rt_ext_tree_ptr); rt_ext_tree_ptr = NULL; } @@ -726,8 +725,8 @@ static avl64ops_t avl64_extent_tree_ops = { void incore_ext_init(xfs_mount_t *mp) { + xfs_agnumber_t agcount = mp->m_sb.sb_agcount + mp->m_sb.sb_rgcount; int i; - xfs_agnumber_t agcount = mp->m_sb.sb_agcount; pthread_mutex_init(&rt_ext_tree_lock, NULL); @@ -779,9 +778,10 @@ incore_ext_init(xfs_mount_t *mp) void incore_ext_teardown(xfs_mount_t *mp) { + xfs_agnumber_t agcount = mp->m_sb.sb_agcount + mp->m_sb.sb_rgcount; xfs_agnumber_t i; - for (i = 0; i < mp->m_sb.sb_agcount; i++) { + for (i = 0; i < agcount; i++) { btree_destroy(dup_extent_trees[i]); free(extent_bno_ptrs[i]); free(extent_bcnt_ptrs[i]); diff --git a/repair/phase2.c b/repair/phase2.c index d99ba5745..2d5965ec4 100644 --- a/repair/phase2.c +++ b/repair/phase2.c @@ -937,16 +937,14 @@ phase2( struct xfs_sb *sb = &mp->m_sb; if (xfs_has_metadir(mp)) - ASSERT(sb->sb_metadirino == sb->sb_rootino + 1 && - sb->sb_rbmino == sb->sb_rootino + 2 && - sb->sb_rsumino == sb->sb_rootino + 3); + ASSERT(sb->sb_metadirino == sb->sb_rootino + 1); else ASSERT(sb->sb_rbmino == sb->sb_rootino + 1 && sb->sb_rsumino == sb->sb_rootino + 2); do_warn(_("root inode chunk not found\n")); /* - * mark the first 3-4 inodes used, the rest are free + * mark the first 2-3 inodes used, the rest are free */ ino_rec = set_inode_used_alloc(mp, 0, XFS_INO_TO_AGINO(mp, sb->sb_rootino)); @@ -993,27 +991,29 @@ phase2( j++; } - if (is_inode_free(ino_rec, j)) { - do_warn(_("realtime bitmap inode marked free, ")); - set_inode_used(ino_rec, j); - if (!no_modify) - do_warn(_("correcting\n")); - else - do_warn(_("would correct\n")); - } - set_inode_is_meta(ino_rec, j); - j++; + if (!xfs_has_rtgroups(mp)) { + if (is_inode_free(ino_rec, j)) { + do_warn(_("realtime bitmap inode marked free, ")); + set_inode_used(ino_rec, j); + if (!no_modify) + do_warn(_("correcting\n")); + else + do_warn(_("would correct\n")); + } + set_inode_is_meta(ino_rec, j); + j++; - if (is_inode_free(ino_rec, j)) { - do_warn(_("realtime summary inode marked free, ")); - set_inode_used(ino_rec, j); - if (!no_modify) - do_warn(_("correcting\n")); - else - do_warn(_("would correct\n")); + if (is_inode_free(ino_rec, j)) { + do_warn(_("realtime summary inode marked free, ")); + set_inode_used(ino_rec, j); + if (!no_modify) + do_warn(_("correcting\n")); + else + do_warn(_("would correct\n")); + } + set_inode_is_meta(ino_rec, j); + j++; } - set_inode_is_meta(ino_rec, j); - j++; } /* diff --git a/repair/phase4.c b/repair/phase4.c index 8d97b63b2..167093da9 100644 --- a/repair/phase4.c +++ b/repair/phase4.c @@ -241,8 +241,10 @@ process_rmap_data( create_work_queue(&wq, mp, platform_nproc()); for (i = 0; i < mp->m_sb.sb_agcount; i++) queue_work(&wq, check_rmap_btrees, i, NULL); - for (i = 0; i < mp->m_sb.sb_rgcount; i++) - queue_work(&wq, check_rtrmap_btrees, i, NULL); + if (xfs_has_rtgroups(mp)) { + for (i = 0; i < mp->m_sb.sb_rgcount; i++) + queue_work(&wq, check_rtrmap_btrees, i, NULL); + } destroy_work_queue(&wq); if (!xfs_has_reflink(mp)) @@ -251,8 +253,10 @@ process_rmap_data( create_work_queue(&wq, mp, platform_nproc()); for (i = 0; i < mp->m_sb.sb_agcount; i++) queue_work(&wq, compute_ag_refcounts, i, NULL); - for (i = 0; i < mp->m_sb.sb_rgcount; i++) - queue_work(&wq, compute_rt_refcounts, i, NULL); + if (xfs_has_rtgroups(mp)) { + for (i = 0; i < mp->m_sb.sb_rgcount; i++) + queue_work(&wq, compute_rt_refcounts, i, NULL); + } destroy_work_queue(&wq); create_work_queue(&wq, mp, platform_nproc()); @@ -260,25 +264,129 @@ process_rmap_data( queue_work(&wq, process_inode_reflink_flags, i, NULL); queue_work(&wq, check_refcount_btrees, i, NULL); } - for (i = 0; i < mp->m_sb.sb_rgcount; i++) - queue_work(&wq, check_rt_refcount_btrees, i, NULL); + if (xfs_has_rtgroups(mp)) { + for (i = 0; i < mp->m_sb.sb_rgcount; i++) + queue_work(&wq, check_rt_refcount_btrees, i, NULL); + } destroy_work_queue(&wq); } +static void +process_dup_rt_extents( + struct xfs_mount *mp) +{ + xfs_rtxnum_t rt_start = 0; + xfs_rtxlen_t rt_len = 0; + xfs_rtxnum_t rtx; + + for (rtx = 0; rtx < mp->m_sb.sb_rextents; rtx++) { + int state; + + state = get_rtbmap(rtx); + switch (state) { + case XR_E_BAD_STATE: + default: + do_warn( + _("unknown rt extent state %d, extent %" PRIu64 "\n"), + state, rtx); + fallthrough; + case XR_E_METADATA: + case XR_E_UNKNOWN: + case XR_E_FREE1: + case XR_E_FREE: + case XR_E_INUSE: + case XR_E_INUSE_FS: + case XR_E_INO: + case XR_E_FS_MAP: + if (rt_start == 0) + continue; + /* + * Add extent and reset extent state. + */ + add_rt_dup_extent(rt_start, rt_len); + rt_start = 0; + rt_len = 0; + break; + case XR_E_MULT: + switch (rt_start) { + case 0: + rt_start = rtx; + rt_len = 1; + break; + case XFS_MAX_BMBT_EXTLEN: + /* + * Large extent case. + */ + add_rt_dup_extent(rt_start, rt_len); + rt_start = rtx; + rt_len = 1; + break; + default: + rt_len++; + break; + } + break; + } + } + + /* + * Catch the tail case, extent hitting the end of the RTG. + */ + if (rt_start != 0) + add_rt_dup_extent(rt_start, rt_len); +} + +/* + * Set up duplicate extent list for an AG or RTG. + */ +static void +process_dup_extents( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_agblock_t ag_end) +{ + do { + int bstate; + xfs_extlen_t blen; + + bstate = get_bmap_ext(agno, agbno, ag_end, &blen); + switch (bstate) { + case XR_E_FREE1: + if (no_modify) + do_warn( +_("free space (%u,%u-%u) only seen by one free space btree\n"), + agno, agbno, agbno + blen - 1); + break; + case XR_E_METADATA: + case XR_E_UNKNOWN: + case XR_E_FREE: + case XR_E_INUSE: + case XR_E_INUSE_FS: + case XR_E_INO: + case XR_E_FS_MAP: + break; + case XR_E_MULT: + add_dup_extent(agno, agbno, blen); + break; + case XR_E_BAD_STATE: + default: + do_warn( +_("unknown block state, ag %d, blocks %u-%u\n"), + agno, agbno, agbno + blen - 1); + break; + } + + agbno += blen; + } while (agbno < ag_end); +} + void phase4(xfs_mount_t *mp) { ino_tree_node_t *irec; - xfs_rtxnum_t rtx; - xfs_rtxnum_t rt_start; - xfs_rtxlen_t rt_len; xfs_agnumber_t i; - xfs_agblock_t j; - xfs_agblock_t ag_end; - xfs_extlen_t blen; int ag_hdr_len = 4 * mp->m_sb.sb_sectsize; int ag_hdr_block; - int bstate; if (rmap_needs_work(mp)) collect_rmaps = true; @@ -324,103 +432,28 @@ phase4(xfs_mount_t *mp) } for (i = 0; i < mp->m_sb.sb_agcount; i++) { + xfs_agblock_t ag_end; + ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : mp->m_sb.sb_dblocks - (xfs_rfsblock_t) mp->m_sb.sb_agblocks * i; - /* - * set up duplicate extent list for this ag - */ - for (j = ag_hdr_block; j < ag_end; j += blen) { - bstate = get_bmap_ext(i, j, ag_end, &blen); - switch (bstate) { - case XR_E_FREE1: - if (no_modify) - do_warn( - _("free space (%u,%u-%u) only seen by one free space btree\n"), - i, j, j + blen - 1); - break; - case XR_E_BAD_STATE: - default: - do_warn( - _("unknown block state, ag %d, blocks %u-%u\n"), - i, j, j + blen - 1); - fallthrough; - case XR_E_METADATA: - case XR_E_UNKNOWN: - case XR_E_FREE: - case XR_E_INUSE: - case XR_E_INUSE_FS: - case XR_E_INO: - case XR_E_FS_MAP: - break; - case XR_E_MULT: - add_dup_extent(i, j, blen); - break; - } - } + process_dup_extents(i, ag_hdr_block, ag_end); PROG_RPT_INC(prog_rpt_done[i], 1); } print_final_rpt(); - /* - * initialize realtime bitmap - */ - rt_start = 0; - rt_len = 0; - - for (rtx = 0; rtx < mp->m_sb.sb_rextents; rtx++) { - bstate = get_rtbmap(rtx); - switch (bstate) { - case XR_E_BAD_STATE: - default: - do_warn( - _("unknown rt extent state, extent %" PRIu64 "\n"), - rtx); - fallthrough; - case XR_E_METADATA: - case XR_E_UNKNOWN: - case XR_E_FREE1: - case XR_E_FREE: - case XR_E_INUSE: - case XR_E_INUSE_FS: - case XR_E_INO: - case XR_E_FS_MAP: - if (rt_start == 0) - continue; - else { - /* - * add extent and reset extent state - */ - add_rt_dup_extent(rt_start, rt_len); - rt_start = 0; - rt_len = 0; - } - break; - case XR_E_MULT: - if (rt_start == 0) { - rt_start = rtx; - rt_len = 1; - } else if (rt_len == XFS_MAX_BMBT_EXTLEN) { - /* - * large extent case - */ - add_rt_dup_extent(rt_start, rt_len); - rt_start = rtx; - rt_len = 1; - } else - rt_len++; - break; + if (xfs_has_rtgroups(mp)) { + for (i = 0; i < mp->m_sb.sb_rgcount; i++) { + process_dup_extents(mp->m_sb.sb_agcount + i, 0, + xfs_rtgroup_extents(mp, i) << + mp->m_sb.sb_rextslog); } + } else { + process_dup_rt_extents(mp); } - /* - * catch tail-case, extent hitting the end of the ag - */ - if (rt_start != 0) - add_rt_dup_extent(rt_start, rt_len); - /* * initialize bitmaps for all AGs */ @@ -453,8 +486,7 @@ phase4(xfs_mount_t *mp) /* * free up memory used to track trealtime duplicate extents */ - if (rt_start != 0) - free_rt_dup_extent_tree(mp); + free_rt_dup_extent_tree(mp); /* * ensure consistency of quota inode pointers in superblock, diff --git a/repair/phase6.c b/repair/phase6.c index 05cc5fb18..511062065 100644 --- a/repair/phase6.c +++ b/repair/phase6.c @@ -495,53 +495,52 @@ mark_ino_metadata( set_inode_is_meta(irec, ino_offset); } -/* Load a realtime freespace metadata inode from disk and reset it. */ -static int -ensure_rtino( - struct xfs_trans *tp, - xfs_ino_t ino, - struct xfs_inode **ipp) -{ - struct xfs_mount *mp = tp->t_mountp; - int error; - - error = -libxfs_iget(mp, tp, ino, 0, ipp); - if (error) - return error; - - reset_sbroot_ino(tp, S_IFREG, *ipp); - if (xfs_has_metadir(mp)) - libxfs_metafile_set_iflag(tp, *ipp); - return 0; -} - static void -mk_rbmino( - struct xfs_mount *mp) +mk_rtino( + struct xfs_rtgroup *rtg, + enum xfs_rtg_inodes type) { + struct xfs_mount *mp = rtg->rtg_mount; + struct xfs_inode *ip = rtg->rtg_inodes[type]; struct xfs_trans *tp; - struct xfs_inode *ip; int error; + if (!ip) { + /* + * XXX: we probably should still re-initialize / re-create the + * inode if the earlier validations failed. + */ + do_error(_("no %s inode for rtgroup %u\n"), + xfs_rtginode_name(type), rtg->rtg_rgno); + } + error = -libxfs_trans_alloc_rollable(mp, 10, &tp); if (error) res_failed(error); - /* Reset the realtime bitmap inode. */ - error = ensure_rtino(tp, mp->m_sb.sb_rbmino, &ip); - if (error) { - do_error( - _("couldn't iget realtime bitmap inode -- error - %d\n"), - error); + reset_sbroot_ino(tp, S_IFREG, ip); + + switch (type) { + case XFS_RTG_BITMAP: + error = -xfs_rtbitmap_create(rtg, ip, tp, false); + break; + case XFS_RTG_SUMMARY: + error = -xfs_rtsummary_create(rtg, ip, tp, false); + break; + default: + error = EINVAL; } - ip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; - libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + if (error) + do_error(_("%s inode re-initialization failed for rtgroup %u\n"), + xfs_rtginode_name(type), rtg->rtg_rgno); + error = -libxfs_trans_commit(tp); if (error) do_error(_("%s: commit failed, error %d\n"), __func__, error); - libxfs_irele(ip); } +#if 0 static void mk_rsumino( struct xfs_mount *mp) @@ -568,6 +567,7 @@ mk_rsumino( do_error(_("%s: commit failed, error %d\n"), __func__, error); libxfs_irele(ip); } +#endif /* Mark a newly allocated inode in use in the incore bitmap. */ static void @@ -701,6 +701,34 @@ ensure_rtgroup_file( return true; } +static void +ensure_rtgroup_bitmap( + struct xfs_rtgroup *rtg) +{ + struct xfs_mount *mp = rtg->rtg_mount; + + if (!xfs_has_rtgroups(mp)) + return; + if (!ensure_rtgroup_file(rtg, XFS_RTG_BITMAP)) + return; + + fill_rtbitmap(rtg); +} + +static void +ensure_rtgroup_summary( + struct xfs_rtgroup *rtg) +{ + struct xfs_mount *mp = rtg->rtg_mount; + + if (!xfs_has_rtgroups(mp)) + return; + if (!ensure_rtgroup_file(rtg, XFS_RTG_SUMMARY)) + return; + + fill_rtsummary(rtg); +} + static void ensure_rtgroup_rmapbt( struct xfs_rtgroup *rtg, @@ -3214,8 +3242,10 @@ mark_inode( static void mark_standalone_inodes(xfs_mount_t *mp) { - mark_inode(mp, mp->m_sb.sb_rbmino); - mark_inode(mp, mp->m_sb.sb_rsumino); + if (!xfs_has_rtgroups(mp)) { + mark_inode(mp, mp->m_sb.sb_rbmino); + mark_inode(mp, mp->m_sb.sb_rsumino); + } if (!fs_quotas) return; @@ -3359,6 +3389,43 @@ traverse_ags( do_inode_prefetch(mp, ag_stride, traverse_function, false, true); } +static void +reset_rt_sb_inodes( + struct xfs_mount *mp) +{ + struct xfs_rtgroup *rtg; + + if (no_modify) { + if (need_rbmino) + do_warn(_("would reinitialize realtime bitmap inode\n")); + if (need_rsumino) + do_warn(_("would reinitialize realtime summary inode\n")); + return; + } + + rtg = xfs_rtgroup_grab(mp, 0); + + if (need_rbmino) { + do_warn(_("reinitializing realtime bitmap inode\n")); + mk_rtino(rtg, XFS_RTG_BITMAP); + need_rbmino = 0; + } + + if (need_rsumino) { + do_warn(_("reinitializing realtime summary inode\n")); + mk_rtino(rtg, XFS_RTG_SUMMARY); + need_rsumino = 0; + } + + do_log( +_(" - resetting contents of realtime bitmap and summary inodes\n")); + + fill_rtbitmap(rtg); + fill_rtsummary(rtg); + + xfs_rtgroup_rele(rtg); +} + static void reset_rt_metadata_inodes( struct xfs_mount *mp) @@ -3394,7 +3461,17 @@ reset_rt_metadata_inodes( est_fdblocks = mp->m_sb.sb_fdblocks - metadata_blocks; } + /* + * This isn't the whole story, but it keeps the message that we've had + * for years and which is expected in xfstests and more. + */ + if (!no_modify) + do_log( +_(" - resetting contents of realtime bitmap and summary inodes\n")); + for_each_rtgroup(mp, rgno, rtg) { + ensure_rtgroup_bitmap(rtg); + ensure_rtgroup_summary(rtg); ensure_rtgroup_rmapbt(rtg, est_fdblocks); ensure_rtgroup_refcountbt(rtg, est_fdblocks); } @@ -3492,35 +3569,10 @@ phase6(xfs_mount_t *mp) } } - if (need_rbmino) { - if (!no_modify) { - do_warn(_("reinitializing realtime bitmap inode\n")); - mk_rbmino(mp); - need_rbmino = 0; - } else { - do_warn(_("would reinitialize realtime bitmap inode\n")); - } - } - - if (need_rsumino) { - if (!no_modify) { - do_warn(_("reinitializing realtime summary inode\n")); - mk_rsumino(mp); - need_rsumino = 0; - } else { - do_warn(_("would reinitialize realtime summary inode\n")); - } - } - if (xfs_has_rtgroups(mp)) reset_rt_metadata_inodes(mp); - - if (!no_modify) { - do_log( -_(" - resetting contents of realtime bitmap and summary inodes\n")); - fill_rtbitmap(mp); - fill_rtsummary(mp); - } + else + reset_rt_sb_inodes(mp); if (reserve_perag) unreserve_ag_blocks(mp); diff --git a/repair/rt.c b/repair/rt.c index 221074eda..df0e13967 100644 --- a/repair/rt.c +++ b/repair/rt.c @@ -19,8 +19,11 @@ static struct bitmap *rtg_inodes[XFS_RTG_MAX]; /* Computed rt bitmap/summary data */ -static union xfs_rtword_raw *btmcompute; -static union xfs_suminfo_raw *sumcompute; +struct rtg_computed { + union xfs_rtword_raw *bmp; + union xfs_suminfo_raw *sum; +}; +struct rtg_computed *rt_computed; static inline void set_rtword( @@ -48,14 +51,13 @@ inc_sumcount( p->old++; } -/* - * generate the real-time bitmap and summary info based on the - * incore realtime extent map. - */ -void -generate_rtinfo( - struct xfs_mount *mp) +static void +generate_rtg_rtinfo( + struct xfs_rtgroup *rtg) { + struct rtg_computed *comp = &rt_computed[rtg->rtg_rgno]; + struct xfs_mount *mp = rtg->rtg_mount; + unsigned int idx = mp->m_sb.sb_agcount + rtg->rtg_rgno; unsigned int bitsperblock = mp->m_blockwsize << XFS_NBWORDLOG; xfs_rtxnum_t extno = 0; @@ -65,36 +67,46 @@ generate_rtinfo( bool in_extent = false; union xfs_rtword_raw *words; - btmcompute = calloc(libxfs_rtbitmap_wordcount(mp, mp->m_sb.sb_rextents), + comp->bmp = calloc(libxfs_rtbitmap_wordcount(mp), sizeof(union xfs_rtword_raw)); - if (!btmcompute) + if (!comp->bmp) do_error( _("couldn't allocate memory for incore realtime bitmap.\n")); - words = btmcompute; + words = comp->bmp; - sumcompute = calloc(libxfs_rtsummary_wordcount(mp, mp->m_rsumlevels, + comp->sum = calloc(libxfs_rtsummary_wordcount(mp, mp->m_rsumlevels, mp->m_sb.sb_rbmblocks), sizeof(union xfs_suminfo_raw)); - if (!sumcompute) + if (!comp->sum) do_error( _("couldn't allocate memory for incore realtime summary info.\n")); - ASSERT(mp->m_rbmip == NULL); - /* * Slower but simple, don't play around with trying to set things one * word at a time, just set bit as required. Have to track start and * end (size) of each range of free extents to set the summary info * properly. */ - while (extno < mp->m_sb.sb_rextents) { + while (extno < rtg->rtg_extents) { xfs_rtword_t freebit = 1; xfs_rtword_t bits = 0; - int i; + int state, i; set_rtword(mp, words, 0); - for (i = 0; i < sizeof(xfs_rtword_t) * NBBY && - extno < mp->m_sb.sb_rextents; i++, extno++) { - if (get_rtbmap(extno) == XR_E_FREE) { + for (i = 0; i < sizeof(xfs_rtword_t) * NBBY; i++) { + if (extno == rtg->rtg_extents) + break; + + /* + * Note: for the RTG case it might make sense to use + * get_bmap_ext here and generate multiple bitmap + * entries per lookup. + */ + if (xfs_has_rtgroups(mp)) + state = get_bmap(idx, + extno * mp->m_sb.sb_rextsize); + else + state = get_rtbmap(extno); + if (state == XR_E_FREE) { sb_frextents++; bits |= freebit; @@ -109,11 +121,12 @@ _("couldn't allocate memory for incore realtime summary info.\n")); offs = xfs_rtsumoffs(mp, libxfs_highbit64(len), start_bmbno); - inc_sumcount(mp, sumcompute, offs); + inc_sumcount(mp, comp->sum, offs); in_extent = false; } freebit <<= 1; + extno++; } set_rtword(mp, words, bits); words++; @@ -127,8 +140,28 @@ _("couldn't allocate memory for incore realtime summary info.\n")); xfs_rtsumoff_t offs; offs = xfs_rtsumoffs(mp, libxfs_highbit64(len), start_bmbno); - inc_sumcount(mp, sumcompute, offs); + inc_sumcount(mp, comp->sum, offs); } +} + +/* + * generate the real-time bitmap and summary info based on the + * incore realtime extent map. + */ +void +generate_rtinfo( + struct xfs_mount *mp) +{ + struct xfs_rtgroup *rtg; + xfs_rgnumber_t rgno; + + rt_computed = calloc(mp->m_sb.sb_rgcount, sizeof(struct rtg_computed)); + if (!rt_computed) + do_error( + _("couldn't allocate memory for incore realtime info.\n")); + + for_each_rtgroup(mp, rgno, rtg) + generate_rtg_rtinfo(rtg); if (mp->m_sb.sb_frextents != sb_frextents) { do_warn(_("sb_frextents %" PRIu64 ", counted %" PRIu64 "\n"), @@ -138,12 +171,13 @@ _("couldn't allocate memory for incore realtime summary info.\n")); static void check_rtwords( - struct xfs_mount *mp, + struct xfs_rtgroup *rtg, const char *filename, unsigned long long bno, void *ondisk, void *incore) { + struct xfs_mount *mp = rtg->rtg_mount; unsigned int wordcnt = mp->m_blockwsize; union xfs_rtword_raw *o = ondisk, *i = incore; int badstart = -1; @@ -157,8 +191,9 @@ check_rtwords( /* Report a range of inconsistency that just ended. */ if (badstart >= 0) do_warn( - _("discrepancy in %s at dblock 0x%llx words 0x%x-0x%x/0x%x\n"), - filename, bno, badstart, j - 1, wordcnt); + _("discrepancy in %s (%u) at dblock 0x%llx words 0x%x-0x%x/0x%x\n"), + filename, rtg->rtg_rgno, bno, + badstart, j - 1, wordcnt); badstart = -1; continue; } @@ -169,40 +204,39 @@ check_rtwords( if (badstart >= 0) do_warn( - _("discrepancy in %s at dblock 0x%llx words 0x%x-0x%x/0x%x\n"), - filename, bno, badstart, wordcnt, - wordcnt); + _("discrepancy in %s (%u) at dblock 0x%llx words 0x%x-0x%x/0x%x\n"), + filename, rtg->rtg_rgno, bno, + badstart, wordcnt, wordcnt); } static void check_rtfile_contents( - struct xfs_mount *mp, - bool is_summary) + struct xfs_rtgroup *rtg, + enum xfs_rtg_inodes type) { - struct xfs_inode *ip; - const struct xfs_buf_ops *buf_ops = xfs_rtblock_ops(mp, is_summary); - const char *filename; - xfs_ino_t ino; + struct xfs_mount *mp = rtg->rtg_mount; + const char *filename = xfs_rtginode_name(type); + struct xfs_inode *ip = rtg->rtg_inodes[type]; + const struct xfs_buf_ops *buf_ops = NULL; void *buf; - xfs_filblks_t filelen; + xfs_fileoff_t filelen; xfs_fileoff_t bno = 0; int error; - if (is_summary) { - filename = _("rtsummary"); - ino = mp->m_sb.sb_rsumino; - buf = sumcompute; - filelen = XFS_B_TO_FSB(mp, mp->m_rsumsize); - } else { - filename = _("rtbitmap"); - ino = mp->m_sb.sb_rbmino; - buf = btmcompute; + if (type == XFS_RTG_BITMAP) { + if (xfs_has_rtgroups(mp)) + buf_ops = &xfs_rtbitmap_buf_ops; + buf = rt_computed[rtg->rtg_rgno].bmp; filelen = mp->m_sb.sb_rbmblocks; + } else { + if (xfs_has_rtgroups(mp)) + buf_ops = &xfs_rtsummary_buf_ops; + buf = rt_computed[rtg->rtg_rgno].sum; + filelen = XFS_B_TO_FSB(mp, mp->m_rsumsize); } - error = -libxfs_iget(mp, NULL, ino, 0, &ip); - if (error) { - do_warn(_("unable to open %s file, err %d\n"), filename, error); + if (!ip) { + do_warn(_("unable to open %s file\n"), filename); return; } @@ -245,7 +279,7 @@ check_rtfile_contents( if (xfs_has_rtgroups(mp)) { struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; - if (hdr->rt_owner != cpu_to_be64(ino)) { + if (hdr->rt_owner != cpu_to_be64(ip->i_ino)) { do_warn( _("corrupt owner in %s at dblock 0x%llx\n"), filename, (unsigned long long)bno); @@ -254,90 +288,85 @@ check_rtfile_contents( offset = sizeof(*hdr); } - check_rtwords(mp, filename, bno, bp->b_addr + offset, buf); + check_rtwords(rtg, filename, bno, bp->b_addr + offset, buf); + buf += mp->m_blockwsize << XFS_WORDLOG; bno++; libxfs_buf_relse(bp); } - - libxfs_irele(ip); } void check_rtbitmap( struct xfs_mount *mp) { + struct xfs_rtgroup *rtg; + xfs_rgnumber_t rgno; + if (need_rbmino) return; - check_rtfile_contents(mp, false); + for_each_rtgroup(mp, rgno, rtg) + check_rtfile_contents(rtg, XFS_RTG_BITMAP); } void check_rtsummary( struct xfs_mount *mp) { + struct xfs_rtgroup *rtg; + xfs_rgnumber_t rgno; + if (need_rsumino) return; - check_rtfile_contents(mp, true); + for_each_rtgroup(mp, rgno, rtg) + check_rtfile_contents(rtg, XFS_RTG_SUMMARY); } void fill_rtbitmap( - struct xfs_mount *mp) + struct xfs_rtgroup *rtg) { - struct xfs_trans *tp; - struct xfs_inode *ip; int error; - error = -libxfs_trans_alloc_empty(mp, &tp); - if (error) - do_error( -_("couldn't allocate empty transaction, error %d\n"), error); - error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip); - if (error) - do_error( -_("couldn't iget realtime bitmap inode, error %d\n"), error); - libxfs_trans_cancel(tp); + /* + * For file systems without a RT subvolume we have the bitmap and + * summary files, but they are empty. In that case rt_computed is + * NULL. + */ + if (!rt_computed) + return; - error = -libxfs_rtfile_initialize_blocks(ip, 0, mp->m_sb.sb_rbmblocks, - btmcompute); + error = -libxfs_rtfile_initialize_blocks(rtg, XFS_RTG_BITMAP, + 0, rtg->rtg_mount->m_sb.sb_rbmblocks, + rt_computed[rtg->rtg_rgno].bmp); if (error) do_error( _("couldn't re-initialize realtime bitmap inode, error %d\n"), error); - libxfs_irele(ip); } void fill_rtsummary( - struct xfs_mount *mp) + struct xfs_rtgroup *rtg) { - struct xfs_trans *tp; - struct xfs_inode *ip; + struct xfs_mount *mp = rtg->rtg_mount; int error; - error = -libxfs_trans_alloc_empty(mp, &tp); - if (error) - do_error( -_("couldn't allocate empty transaction, error %d\n"), error); - error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip); - if (error) { - do_error( -_("couldn't iget realtime summary inode, error - %d\n"), error); - } - libxfs_trans_cancel(tp); + /* + * For file systems without a RT subvolume we have the bitmap and + * summary files, but they are empty. In that case rt_computed is + * NULL. + */ + if (!rt_computed) + return; - mp->m_rsumip = ip; - error = -libxfs_rtfile_initialize_blocks(ip, 0, - mp->m_rsumsize >> mp->m_sb.sb_blocklog, - sumcompute); - mp->m_rsumip = NULL; + error = -libxfs_rtfile_initialize_blocks(rtg, XFS_RTG_SUMMARY, + 0, mp->m_rsumsize >> mp->m_sb.sb_blocklog, + rt_computed[rtg->rtg_rgno].sum); if (error) do_error( _("couldn't re-initialize realtime summary inode, error %d\n"), error); - - libxfs_irele(ip); } void @@ -453,7 +482,8 @@ set_rtginode( return error; ip = rtg->rtg_inodes[type]; - if (!ip) /* inode type not enabled */ + if (!ip /* inode type not enabled */ || + !xfs_has_rtgroups(rtg->rtg_mount)) return 0; if (bitmap_test(rtg_inodes[type], ip->i_ino, 1)) @@ -471,8 +501,8 @@ discover_rtgroup_inodes( int error, err2; int i; - if (!xfs_has_rtgroups(mp)) - return; +// if (!xfs_has_rtgroups(mp)) +// return; for (i = 0; i < XFS_RTG_MAX; i++) { error = bitmap_alloc(&rtg_inodes[i]); @@ -513,8 +543,8 @@ free_rtgroup_inodes( { int i; - if (!xfs_has_rtgroups(mp)) - return; +// if (!xfs_has_rtgroups(mp)) +// return; for (i = 0; i < XFS_RTG_MAX; i++) bitmap_free(&rtg_inodes[i]); diff --git a/repair/rt.h b/repair/rt.h index 8e80f1719..56e265340 100644 --- a/repair/rt.h +++ b/repair/rt.h @@ -10,8 +10,8 @@ void generate_rtinfo(struct xfs_mount *mp); void check_rtbitmap(struct xfs_mount *mp); void check_rtsummary(struct xfs_mount *mp); -void fill_rtbitmap(struct xfs_mount *mp); -void fill_rtsummary(struct xfs_mount *mp); +void fill_rtbitmap(struct xfs_rtgroup *rtg); +void fill_rtsummary(struct xfs_rtgroup *rtg); void check_rtsb(struct xfs_mount *mp); void rewrite_rtsb(struct xfs_mount *mp); @@ -36,6 +36,15 @@ rtgroup_for_rtrefcount_inode(struct xfs_mount *mp, xfs_ino_t ino) bool is_rtgroup_inode(xfs_ino_t ino, enum xfs_rtg_inodes type); +static inline bool is_rtbitmap_inode(xfs_ino_t ino) +{ + return is_rtgroup_inode(ino, XFS_RTG_BITMAP); +} +static inline bool is_rtsummary_inode(xfs_ino_t ino) +{ + return is_rtgroup_inode(ino, XFS_RTG_SUMMARY); +} + static inline bool is_rtrmap_inode(xfs_ino_t ino) { return is_rtgroup_inode(ino, XFS_RTG_RMAP); diff --git a/repair/scan.c b/repair/scan.c index 8bfd0c36b..55f4c6f5e 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -1989,6 +1989,7 @@ process_rtrefc_reclist( struct refc_priv *refc_priv, const char *name) { + xfs_rgnumber_t rgno = refc_priv->rgno; xfs_rtblock_t lastblock = 0; xfs_rtblock_t rtbno, next_rtbno; int state; @@ -2028,7 +2029,7 @@ _("leftover rt CoW extent has invalid startblock in record %u of %s\n"), } end = rgbno + len; - rtbno = xfs_rgbno_to_rtb(mp, refc_priv->rgno, rgbno); + rtbno = xfs_rgbno_to_rtb(mp, rgno, rgbno); if (!libxfs_verify_rtbno(mp, rtbno)) { do_warn( _("invalid start block %llu in record %u of %s\n"), @@ -2037,7 +2038,7 @@ _("invalid start block %llu in record %u of %s\n"), continue; } - next_rtbno = xfs_rgbno_to_rtb(mp, refc_priv->rgno, end); + next_rtbno = xfs_rgbno_to_rtb(mp, rgno, end); if (len == 0 || end <= rgbno || !libxfs_verify_rtbno(mp, next_rtbno - 1)) { do_warn( @@ -2047,36 +2048,38 @@ _("invalid length %llu in record %u of %s\n"), continue; } + if (nr < 2 || nr > XFS_REFC_REFCOUNT_MAX) { + do_warn( +_("invalid rt reference count %u in record %u of %s\n"), + nr, i, name); + suspect++; + continue; + } + if (nr == 1) { - xfs_rtxnum_t rtx, next_rtx; + xfs_rgblock_t b; + xfs_extlen_t blen; + + for (b = rgbno; b < end; b += len) { + state = get_bmap_ext(rgno, b, end, &blen); + blen = min(blen, len); - rtx = xfs_rtb_to_rtx(mp, rtbno); - next_rtx = xfs_rtb_to_rtx(mp, next_rtbno); - for (; rtx < next_rtx; rtx++) { - state = get_rtbmap(rtx); switch (state) { case XR_E_UNKNOWN: case XR_E_COW: do_warn( _("leftover CoW rtextent (%llu)\n"), - (unsigned long long)rtx); - suspect++; - set_rtbmap(rtx, XR_E_FREE); + (unsigned long long)rgbno); + set_bmap_ext(rgno, b, len, XR_E_FREE); break; default: do_warn( _("rtextent (%llu) claimed, state is %d\n"), - (unsigned long long)rtx, state); - suspect++; + (unsigned long long)rgbno, state); break; } + suspect++; } - } else if (nr < 2 || nr > XFS_REFC_REFCOUNT_MAX) { - do_warn( -_("invalid rt reference count %u in record %u of %s\n"), - nr, i, name); - suspect++; - continue; } if (b && b <= lastblock) { diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c index c3f1fa8f4..aebfd84b0 100644 --- a/repair/xfs_repair.c +++ b/repair/xfs_repair.c @@ -814,13 +814,14 @@ _("sb root inode value %" PRIu64 " valid but in unaligned location (expected %"P * directory. */ check_metadir_inode(mp, rootino); - rootino++; } - validate_sb_ino(&mp->m_sb.sb_rbmino, rootino + 1, - _("realtime bitmap")); - validate_sb_ino(&mp->m_sb.sb_rsumino, rootino + 2, - _("realtime summary")); + if (!xfs_has_rtgroups(mp)) { + validate_sb_ino(&mp->m_sb.sb_rbmino, rootino + 1, + _("realtime bitmap")); + validate_sb_ino(&mp->m_sb.sb_rsumino, rootino + 2, + _("realtime summary")); + } } /*