]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/fscounters.c
xfs_spaceman: remove open-coded per-ag bulkstat
[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{
b94a69ac 45 struct xfs_inumbers_req *ireq;
604dd334 46 uint64_t nr = 0;
604dd334
DW
47 int error;
48
49 ASSERT(!(first_ino & (XFS_INODES_PER_CHUNK - 1)));
50 ASSERT((last_ino & (XFS_INODES_PER_CHUNK - 1)));
51
b94a69ac
DW
52 ireq = xfrog_inumbers_alloc_req(1, first_ino);
53 if (!ireq) {
54 str_info(ctx, descr, _("Insufficient memory; giving up."));
55 return false;
56 }
57
58 while (!(error = xfrog_inumbers(&ctx->mnt, ireq))) {
59 if (ireq->hdr.ocount == 0 ||
60 ireq->inumbers[0].xi_startino >= last_ino)
621f3374 61 break;
b94a69ac 62 nr += ireq->inumbers[0].xi_alloccount;
604dd334
DW
63 }
64
b94a69ac
DW
65 free(ireq);
66
604dd334 67 if (error) {
621f3374 68 str_liberror(ctx, error, descr);
604dd334
DW
69 return false;
70 }
71
72 *count = nr;
73 return true;
74}
75
76/* Scan all the inodes in an AG. */
77static void
78xfs_count_ag_inodes(
79 struct workqueue *wq,
80 xfs_agnumber_t agno,
81 void *arg)
82{
83 struct xfs_count_inodes *ci = arg;
84 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
85 char descr[DESCR_BUFSZ];
86 uint64_t ag_ino;
87 uint64_t next_ag_ino;
88 bool moveon;
89
90 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"),
91 major(ctx->fsinfo.fs_datadev),
92 minor(ctx->fsinfo.fs_datadev),
93 agno);
94
a749451c
DW
95 ag_ino = cvt_agino_to_ino(&ctx->mnt, agno, 0);
96 next_ag_ino = cvt_agino_to_ino(&ctx->mnt, agno + 1, 0);
604dd334
DW
97
98 moveon = xfs_count_inodes_range(ctx, descr, ag_ino, next_ag_ino - 1,
99 &ci->counters[agno]);
100 if (!moveon)
101 ci->moveon = false;
102}
103
104/* Count all the inodes in a filesystem. */
105bool
106xfs_count_all_inodes(
107 struct scrub_ctx *ctx,
108 uint64_t *count)
109{
110 struct xfs_count_inodes *ci;
111 xfs_agnumber_t agno;
112 struct workqueue wq;
113 bool moveon;
114 int ret;
115
116 ci = calloc(1, sizeof(struct xfs_count_inodes) +
3f9efb2e 117 (ctx->mnt.fsgeom.agcount * sizeof(uint64_t)));
604dd334
DW
118 if (!ci)
119 return false;
120 ci->moveon = true;
121
122 ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
123 scrub_nproc_workqueue(ctx));
124 if (ret) {
125 moveon = false;
82377bde 126 str_info(ctx, ctx->mntpoint, _("Could not create workqueue."));
604dd334
DW
127 goto out_free;
128 }
3f9efb2e 129 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
604dd334
DW
130 ret = workqueue_add(&wq, xfs_count_ag_inodes, agno, ci);
131 if (ret) {
132 moveon = false;
82377bde 133 str_info(ctx, ctx->mntpoint,
604dd334
DW
134_("Could not queue AG %u icount work."), agno);
135 break;
136 }
137 }
138 workqueue_destroy(&wq);
139
3f9efb2e 140 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++)
604dd334
DW
141 *count += ci->counters[agno];
142 moveon = ci->moveon;
143
144out_free:
145 free(ci);
146 return moveon;
147}
148
149/* Estimate the number of blocks and inodes in the filesystem. */
150bool
151xfs_scan_estimate_blocks(
152 struct scrub_ctx *ctx,
153 unsigned long long *d_blocks,
154 unsigned long long *d_bfree,
155 unsigned long long *r_blocks,
156 unsigned long long *r_bfree,
157 unsigned long long *f_files,
158 unsigned long long *f_free)
159{
160 struct xfs_fsop_counts fc;
161 struct xfs_fsop_resblks rb;
162 struct statvfs sfs;
163 int error;
164
165 /* Grab the fstatvfs counters, since it has to report accurately. */
3f9efb2e 166 error = fstatvfs(ctx->mnt.fd, &sfs);
604dd334
DW
167 if (error) {
168 str_errno(ctx, ctx->mntpoint);
169 return false;
170 }
171
172 /* Fetch the filesystem counters. */
3f9efb2e 173 error = ioctl(ctx->mnt.fd, XFS_IOC_FSCOUNTS, &fc);
604dd334
DW
174 if (error) {
175 str_errno(ctx, ctx->mntpoint);
176 return false;
177 }
178
179 /*
180 * XFS reserves some blocks to prevent hard ENOSPC, so add those
181 * blocks back to the free data counts.
182 */
3f9efb2e 183 error = ioctl(ctx->mnt.fd, XFS_IOC_GET_RESBLKS, &rb);
604dd334
DW
184 if (error)
185 str_errno(ctx, ctx->mntpoint);
186 sfs.f_bfree += rb.resblks_avail;
187
3f9efb2e
DW
188 *d_blocks = sfs.f_blocks;
189 if (ctx->mnt.fsgeom.logstart > 0)
190 *d_blocks += ctx->mnt.fsgeom.logblocks;
604dd334 191 *d_bfree = sfs.f_bfree;
3f9efb2e 192 *r_blocks = ctx->mnt.fsgeom.rtblocks;
604dd334
DW
193 *r_bfree = fc.freertx;
194 *f_files = sfs.f_files;
195 *f_free = sfs.f_ffree;
196
197 return true;
198}