]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/fscounters.c
misc: convert xfrog_bulkstat functions to have v5 semantics
[thirdparty/xfsprogs-dev.git] / scrub / fscounters.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
604dd334
DW
2/*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
604dd334 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
604dd334 5 */
a440f877 6#include "xfs.h"
604dd334
DW
7#include <stdint.h>
8#include <stdlib.h>
9#include <sys/statvfs.h>
10#include "platform_defs.h"
604dd334 11#include "xfs_arch.h"
604dd334 12#include "xfs_format.h"
42b4c8e8 13#include "libfrog/paths.h"
56598728 14#include "libfrog/workqueue.h"
604dd334
DW
15#include "xfs_scrub.h"
16#include "common.h"
17#include "fscounters.h"
621f3374 18#include "libfrog/bulkstat.h"
604dd334
DW
19
20/*
21 * Filesystem counter collection routines. We can count the number of
22 * inodes in the filesystem, and we can estimate the block counters.
23 */
24
25/* Count the number of inodes in the filesystem. */
26
27/* INUMBERS wrapper routines. */
28struct xfs_count_inodes {
29 bool moveon;
30 uint64_t counters[0];
31};
32
33/*
34 * Count the number of inodes. Use INUMBERS to figure out how many inodes
35 * exist in the filesystem, assuming we've already scrubbed that.
36 */
37static bool
38xfs_count_inodes_range(
39 struct scrub_ctx *ctx,
40 const char *descr,
41 uint64_t first_ino,
42 uint64_t last_ino,
43 uint64_t *count)
44{
604dd334 45 struct xfs_inogrp inogrp;
621f3374 46 uint64_t igrp_ino;
604dd334 47 uint64_t nr = 0;
621f3374 48 uint32_t igrplen = 0;
604dd334
DW
49 int error;
50
51 ASSERT(!(first_ino & (XFS_INODES_PER_CHUNK - 1)));
52 ASSERT((last_ino & (XFS_INODES_PER_CHUNK - 1)));
53
604dd334 54 igrp_ino = first_ino;
621f3374
DW
55 while (!(error = xfrog_inumbers(&ctx->mnt, &igrp_ino, 1, &inogrp,
56 &igrplen))) {
57 if (igrplen == 0 || inogrp.xi_startino >= last_ino)
58 break;
604dd334 59 nr += inogrp.xi_alloccount;
604dd334
DW
60 }
61
62 if (error) {
621f3374 63 str_liberror(ctx, error, descr);
604dd334
DW
64 return false;
65 }
66
67 *count = nr;
68 return true;
69}
70
71/* Scan all the inodes in an AG. */
72static void
73xfs_count_ag_inodes(
74 struct workqueue *wq,
75 xfs_agnumber_t agno,
76 void *arg)
77{
78 struct xfs_count_inodes *ci = arg;
79 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
80 char descr[DESCR_BUFSZ];
81 uint64_t ag_ino;
82 uint64_t next_ag_ino;
83 bool moveon;
84
85 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"),
86 major(ctx->fsinfo.fs_datadev),
87 minor(ctx->fsinfo.fs_datadev),
88 agno);
89
a749451c
DW
90 ag_ino = cvt_agino_to_ino(&ctx->mnt, agno, 0);
91 next_ag_ino = cvt_agino_to_ino(&ctx->mnt, agno + 1, 0);
604dd334
DW
92
93 moveon = xfs_count_inodes_range(ctx, descr, ag_ino, next_ag_ino - 1,
94 &ci->counters[agno]);
95 if (!moveon)
96 ci->moveon = false;
97}
98
99/* Count all the inodes in a filesystem. */
100bool
101xfs_count_all_inodes(
102 struct scrub_ctx *ctx,
103 uint64_t *count)
104{
105 struct xfs_count_inodes *ci;
106 xfs_agnumber_t agno;
107 struct workqueue wq;
108 bool moveon;
109 int ret;
110
111 ci = calloc(1, sizeof(struct xfs_count_inodes) +
3f9efb2e 112 (ctx->mnt.fsgeom.agcount * sizeof(uint64_t)));
604dd334
DW
113 if (!ci)
114 return false;
115 ci->moveon = true;
116
117 ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
118 scrub_nproc_workqueue(ctx));
119 if (ret) {
120 moveon = false;
82377bde 121 str_info(ctx, ctx->mntpoint, _("Could not create workqueue."));
604dd334
DW
122 goto out_free;
123 }
3f9efb2e 124 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
604dd334
DW
125 ret = workqueue_add(&wq, xfs_count_ag_inodes, agno, ci);
126 if (ret) {
127 moveon = false;
82377bde 128 str_info(ctx, ctx->mntpoint,
604dd334
DW
129_("Could not queue AG %u icount work."), agno);
130 break;
131 }
132 }
133 workqueue_destroy(&wq);
134
3f9efb2e 135 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++)
604dd334
DW
136 *count += ci->counters[agno];
137 moveon = ci->moveon;
138
139out_free:
140 free(ci);
141 return moveon;
142}
143
144/* Estimate the number of blocks and inodes in the filesystem. */
145bool
146xfs_scan_estimate_blocks(
147 struct scrub_ctx *ctx,
148 unsigned long long *d_blocks,
149 unsigned long long *d_bfree,
150 unsigned long long *r_blocks,
151 unsigned long long *r_bfree,
152 unsigned long long *f_files,
153 unsigned long long *f_free)
154{
155 struct xfs_fsop_counts fc;
156 struct xfs_fsop_resblks rb;
157 struct statvfs sfs;
158 int error;
159
160 /* Grab the fstatvfs counters, since it has to report accurately. */
3f9efb2e 161 error = fstatvfs(ctx->mnt.fd, &sfs);
604dd334
DW
162 if (error) {
163 str_errno(ctx, ctx->mntpoint);
164 return false;
165 }
166
167 /* Fetch the filesystem counters. */
3f9efb2e 168 error = ioctl(ctx->mnt.fd, XFS_IOC_FSCOUNTS, &fc);
604dd334
DW
169 if (error) {
170 str_errno(ctx, ctx->mntpoint);
171 return false;
172 }
173
174 /*
175 * XFS reserves some blocks to prevent hard ENOSPC, so add those
176 * blocks back to the free data counts.
177 */
3f9efb2e 178 error = ioctl(ctx->mnt.fd, XFS_IOC_GET_RESBLKS, &rb);
604dd334
DW
179 if (error)
180 str_errno(ctx, ctx->mntpoint);
181 sfs.f_bfree += rb.resblks_avail;
182
3f9efb2e
DW
183 *d_blocks = sfs.f_blocks;
184 if (ctx->mnt.fsgeom.logstart > 0)
185 *d_blocks += ctx->mnt.fsgeom.logblocks;
604dd334 186 *d_bfree = sfs.f_bfree;
3f9efb2e 187 *r_blocks = ctx->mnt.fsgeom.rtblocks;
604dd334
DW
188 *r_bfree = fc.freertx;
189 *f_files = sfs.f_files;
190 *f_free = sfs.f_ffree;
191
192 return true;
193}