]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/fscounters.c
xfs_scrub: in phase 3, use the opened file descriptor for repair calls
[thirdparty/xfsprogs-dev.git] / scrub / fscounters.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6 #include "xfs.h"
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <sys/statvfs.h>
10 #include "platform_defs.h"
11 #include "xfs_arch.h"
12 #include "libfrog/paths.h"
13 #include "libfrog/workqueue.h"
14 #include "xfs_scrub.h"
15 #include "common.h"
16 #include "fscounters.h"
17 #include "libfrog/bulkstat.h"
18
19 /*
20 * Filesystem counter collection routines. We can count the number of
21 * inodes in the filesystem, and we can estimate the block counters.
22 */
23
24 /* Count the number of inodes in the filesystem. */
25
26 /* INUMBERS wrapper routines. */
27 struct count_inodes {
28 int error;
29 uint64_t counters[0];
30 };
31
32 /*
33 * Count the number of inodes. Use INUMBERS to figure out how many inodes
34 * exist in the filesystem, assuming we've already scrubbed that.
35 */
36 static void
37 count_ag_inodes(
38 struct workqueue *wq,
39 xfs_agnumber_t agno,
40 void *arg)
41 {
42 struct count_inodes *ci = arg;
43 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
44 struct xfs_inumbers_req *ireq;
45 uint64_t nr = 0;
46 unsigned int i;
47 int error;
48
49 error = -xfrog_inumbers_alloc_req(64, 0, &ireq);
50 if (error) {
51 ci->error = error;
52 return;
53 }
54 xfrog_inumbers_set_ag(ireq, agno);
55
56 while (!ci->error && (error = -xfrog_inumbers(&ctx->mnt, ireq)) == 0) {
57 if (ireq->hdr.ocount == 0)
58 break;
59 for (i = 0; i < ireq->hdr.ocount; i++)
60 nr += ireq->inumbers[i].xi_alloccount;
61 }
62 if (error)
63 ci->error = error;
64
65 free(ireq);
66
67 ci->counters[agno] = nr;
68 }
69
70 /*
71 * Count all the inodes in a filesystem. Returns 0 or a positive error number.
72 */
73 int
74 scrub_count_all_inodes(
75 struct scrub_ctx *ctx,
76 uint64_t *count)
77 {
78 struct count_inodes *ci;
79 xfs_agnumber_t agno;
80 struct workqueue wq;
81 int ret, ret2;
82
83 ci = calloc(1, sizeof(struct count_inodes) +
84 (ctx->mnt.fsgeom.agcount * sizeof(uint64_t)));
85 if (!ci)
86 return errno;
87
88 ret = -workqueue_create(&wq, (struct xfs_mount *)ctx,
89 scrub_nproc_workqueue(ctx));
90 if (ret)
91 goto out_free;
92
93 for (agno = 0; agno < ctx->mnt.fsgeom.agcount && !ci->error; agno++) {
94 ret = -workqueue_add(&wq, count_ag_inodes, agno, ci);
95 if (ret)
96 break;
97 }
98
99 ret2 = -workqueue_terminate(&wq);
100 if (!ret && ret2)
101 ret = ret2;
102 workqueue_destroy(&wq);
103
104 if (ci->error) {
105 ret = ci->error;
106 goto out_free;
107 }
108
109 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++)
110 *count += ci->counters[agno];
111
112 out_free:
113 free(ci);
114 return ret;
115 }
116
117 /*
118 * Estimate the number of blocks and used inodes in the filesystem. Returns 0
119 * or a positive error number.
120 */
121 int
122 scrub_scan_estimate_blocks(
123 struct scrub_ctx *ctx,
124 unsigned long long *d_blocks,
125 unsigned long long *d_bfree,
126 unsigned long long *r_blocks,
127 unsigned long long *r_bfree,
128 unsigned long long *f_files_used)
129 {
130 struct xfs_fsop_counts fc;
131 int error;
132
133 /* Fetch the filesystem counters. */
134 error = ioctl(ctx->mnt.fd, XFS_IOC_FSCOUNTS, &fc);
135 if (error)
136 return errno;
137
138 *d_blocks = ctx->mnt.fsgeom.datablocks;
139 *d_bfree = fc.freedata;
140 *r_blocks = ctx->mnt.fsgeom.rtblocks;
141 *r_bfree = fc.freertx;
142 *f_files_used = fc.allocino - fc.freeino;
143
144 return 0;
145 }