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