]>
Commit | Line | Data |
---|---|---|
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. */ | |
28 | struct 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 | */ | |
37 | static bool | |
23ea9841 | 38 | xfs_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 | 50 | if (!ireq) { |
e98616ba | 51 | str_liberror(ctx, ENOMEM, _("allocating inumbers request")); |
b94a69ac DW |
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. */ | |
75 | static void | |
76 | xfs_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. */ | |
97 | bool | |
98 | xfs_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; | |
71296cf8 | 105 | bool moveon = true; |
604dd334 DW |
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 | } | |
71296cf8 DW |
129 | |
130 | ret = workqueue_terminate(&wq); | |
131 | if (ret) { | |
132 | moveon = false; | |
133 | str_liberror(ctx, ret, _("finishing icount work")); | |
134 | } | |
604dd334 DW |
135 | workqueue_destroy(&wq); |
136 | ||
71296cf8 DW |
137 | if (!moveon) |
138 | goto out_free; | |
139 | ||
3f9efb2e | 140 | for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) |
604dd334 DW |
141 | *count += ci->counters[agno]; |
142 | moveon = ci->moveon; | |
143 | ||
144 | out_free: | |
145 | free(ci); | |
146 | return moveon; | |
147 | } | |
148 | ||
149 | /* Estimate the number of blocks and inodes in the filesystem. */ | |
150 | bool | |
151 | xfs_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 | } |