-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (C) 2018 Oracle. All Rights Reserved.
- * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ * Copyright (C) 2018-2024 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
*/
#include "xfs.h"
#include <stdint.h>
#include <sys/statvfs.h>
#include "platform_defs.h"
#include "xfs_arch.h"
-#include "xfs_format.h"
-#include "path.h"
-#include "workqueue.h"
+#include "libfrog/paths.h"
+#include "libfrog/workqueue.h"
#include "xfs_scrub.h"
#include "common.h"
#include "fscounters.h"
+#include "libfrog/bulkstat.h"
/*
* Filesystem counter collection routines. We can count the number of
/* Count the number of inodes in the filesystem. */
/* INUMBERS wrapper routines. */
-struct xfs_count_inodes {
- bool moveon;
+struct count_inodes {
+ int error;
uint64_t counters[0];
};
* Count the number of inodes. Use INUMBERS to figure out how many inodes
* exist in the filesystem, assuming we've already scrubbed that.
*/
-static bool
-xfs_count_inodes_range(
- struct scrub_ctx *ctx,
- const char *descr,
- uint64_t first_ino,
- uint64_t last_ino,
- uint64_t *count)
+static void
+count_ag_inodes(
+ struct workqueue *wq,
+ xfs_agnumber_t agno,
+ void *arg)
{
- struct xfs_fsop_bulkreq igrpreq = {NULL};
- struct xfs_inogrp inogrp;
- __u64 igrp_ino;
+ struct count_inodes *ci = arg;
+ struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
+ struct xfs_inumbers_req *ireq;
uint64_t nr = 0;
- __s32 igrplen = 0;
+ unsigned int i;
int error;
- ASSERT(!(first_ino & (XFS_INODES_PER_CHUNK - 1)));
- ASSERT((last_ino & (XFS_INODES_PER_CHUNK - 1)));
-
- igrpreq.lastip = &igrp_ino;
- igrpreq.icount = 1;
- igrpreq.ubuffer = &inogrp;
- igrpreq.ocount = &igrplen;
-
- igrp_ino = first_ino;
- error = ioctl(ctx->mnt.fd, XFS_IOC_FSINUMBERS, &igrpreq);
- while (!error && igrplen && inogrp.xi_startino < last_ino) {
- nr += inogrp.xi_alloccount;
- error = ioctl(ctx->mnt.fd, XFS_IOC_FSINUMBERS, &igrpreq);
+ error = -xfrog_inumbers_alloc_req(64, 0, &ireq);
+ if (error) {
+ ci->error = error;
+ return;
}
+ xfrog_inumbers_set_ag(ireq, agno);
- if (error) {
- str_errno(ctx, descr);
- return false;
+ while (!ci->error && (error = -xfrog_inumbers(&ctx->mnt, ireq)) == 0) {
+ if (ireq->hdr.ocount == 0)
+ break;
+ for (i = 0; i < ireq->hdr.ocount; i++)
+ nr += ireq->inumbers[i].xi_alloccount;
}
+ if (error)
+ ci->error = error;
- *count = nr;
- return true;
-}
+ free(ireq);
-/* Scan all the inodes in an AG. */
-static void
-xfs_count_ag_inodes(
- struct workqueue *wq,
- xfs_agnumber_t agno,
- void *arg)
-{
- struct xfs_count_inodes *ci = arg;
- struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
- char descr[DESCR_BUFSZ];
- uint64_t ag_ino;
- uint64_t next_ag_ino;
- bool moveon;
-
- snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"),
- major(ctx->fsinfo.fs_datadev),
- minor(ctx->fsinfo.fs_datadev),
- agno);
-
- ag_ino = (__u64)agno << (ctx->mnt.inopblog + ctx->mnt.agblklog);
- next_ag_ino = (__u64)(agno + 1) << (ctx->mnt.inopblog + ctx->mnt.agblklog);
-
- moveon = xfs_count_inodes_range(ctx, descr, ag_ino, next_ag_ino - 1,
- &ci->counters[agno]);
- if (!moveon)
- ci->moveon = false;
+ ci->counters[agno] = nr;
}
-/* Count all the inodes in a filesystem. */
-bool
-xfs_count_all_inodes(
+/*
+ * Count all the inodes in a filesystem. Returns 0 or a positive error number.
+ */
+int
+scrub_count_all_inodes(
struct scrub_ctx *ctx,
uint64_t *count)
{
- struct xfs_count_inodes *ci;
+ struct count_inodes *ci;
xfs_agnumber_t agno;
struct workqueue wq;
- bool moveon;
- int ret;
+ int ret, ret2;
- ci = calloc(1, sizeof(struct xfs_count_inodes) +
+ ci = calloc(1, sizeof(struct count_inodes) +
(ctx->mnt.fsgeom.agcount * sizeof(uint64_t)));
if (!ci)
- return false;
- ci->moveon = true;
+ return errno;
- ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
+ ret = -workqueue_create(&wq, (struct xfs_mount *)ctx,
scrub_nproc_workqueue(ctx));
- if (ret) {
- moveon = false;
- str_info(ctx, ctx->mntpoint, _("Could not create workqueue."));
+ if (ret)
goto out_free;
- }
- for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
- ret = workqueue_add(&wq, xfs_count_ag_inodes, agno, ci);
- if (ret) {
- moveon = false;
- str_info(ctx, ctx->mntpoint,
-_("Could not queue AG %u icount work."), agno);
+
+ for (agno = 0; agno < ctx->mnt.fsgeom.agcount && !ci->error; agno++) {
+ ret = -workqueue_add(&wq, count_ag_inodes, agno, ci);
+ if (ret)
break;
- }
}
+
+ ret2 = -workqueue_terminate(&wq);
+ if (!ret && ret2)
+ ret = ret2;
workqueue_destroy(&wq);
+ if (ci->error) {
+ ret = ci->error;
+ goto out_free;
+ }
+
for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++)
*count += ci->counters[agno];
- moveon = ci->moveon;
out_free:
free(ci);
- return moveon;
+ return ret;
}
-/* Estimate the number of blocks and inodes in the filesystem. */
-bool
-xfs_scan_estimate_blocks(
+/*
+ * Estimate the number of blocks and used inodes in the filesystem. Returns 0
+ * or a positive error number.
+ */
+int
+scrub_scan_estimate_blocks(
struct scrub_ctx *ctx,
unsigned long long *d_blocks,
unsigned long long *d_bfree,
unsigned long long *r_blocks,
unsigned long long *r_bfree,
- unsigned long long *f_files,
- unsigned long long *f_free)
+ unsigned long long *f_files_used)
{
struct xfs_fsop_counts fc;
- struct xfs_fsop_resblks rb;
- struct statvfs sfs;
int error;
- /* Grab the fstatvfs counters, since it has to report accurately. */
- error = fstatvfs(ctx->mnt.fd, &sfs);
- if (error) {
- str_errno(ctx, ctx->mntpoint);
- return false;
- }
-
/* Fetch the filesystem counters. */
error = ioctl(ctx->mnt.fd, XFS_IOC_FSCOUNTS, &fc);
- if (error) {
- str_errno(ctx, ctx->mntpoint);
- return false;
- }
-
- /*
- * XFS reserves some blocks to prevent hard ENOSPC, so add those
- * blocks back to the free data counts.
- */
- error = ioctl(ctx->mnt.fd, XFS_IOC_GET_RESBLKS, &rb);
if (error)
- str_errno(ctx, ctx->mntpoint);
- sfs.f_bfree += rb.resblks_avail;
+ return errno;
- *d_blocks = sfs.f_blocks;
- if (ctx->mnt.fsgeom.logstart > 0)
- *d_blocks += ctx->mnt.fsgeom.logblocks;
- *d_bfree = sfs.f_bfree;
+ *d_blocks = ctx->mnt.fsgeom.datablocks;
+ *d_bfree = fc.freedata;
*r_blocks = ctx->mnt.fsgeom.rtblocks;
- *r_bfree = fc.freertx;
- *f_files = sfs.f_files;
- *f_free = sfs.f_ffree;
+ *r_bfree = fc.freertx * ctx->mnt.fsgeom.rtextsize;
+ *f_files_used = fc.allocino - fc.freeino;
- return true;
+ return 0;
}