char **argv)
{
xfs_rtblock_t rtbno;
- xfs_rtxnum_t rtx;
+ uint64_t rtx;
char *p;
if (argc == 1) {
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);
#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 {
{
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)
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 ||
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;
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);
#include "fprint.h"
#include "faddr.h"
#include "field.h"
+#include "inode.h"
#include "dir2.h"
#include "obfuscate.h"
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;
}
}
+ 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
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;
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);
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.
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);
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. */
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;
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)
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;
/*
* 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;
}
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);
}
}
}
-/* 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;
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)
struct cli_params *cli)
{
struct libxfs_init *xi = cli->xi;
- unsigned int rbmblocksize = cfg->blocksize;
if (!xi->rt.dev) {
if (cli->rtsize) {
_("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
XFS_MAX_RGNUMBER);
usage();
}
+
+ cfg->rtbmblocks = howmany(cfg->rgsize / cfg->rtextblocks,
+ NBBY * (cfg->blocksize - sizeof(struct xfs_rtbuf_blkinfo)));
}
static void
*/
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;
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;
+ }
}
}
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;
}
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);
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);
/*
* 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;
}
/*
- * 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);
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"),
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;
* 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) {
}
}
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;
* 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,
}
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))
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;
* 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) {
* 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");
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;
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),
}
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);
}
}
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);
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 */
}
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;
}
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);
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]);
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));
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++;
}
/*
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))
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());
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;
}
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
*/
/*
* 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,
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)
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
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,
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;
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)
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);
}
}
}
- 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);
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(
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;
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;
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++;
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"),
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;
/* 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;
}
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;
}
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);
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
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))
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]);
{
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]);
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);
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);
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;
}
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"),
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(
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) {
* 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"));
+ }
}
/*