]>
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 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. */ | |
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; | |
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 | ||
135 | out_free: | |
136 | free(ci); | |
137 | return moveon; | |
138 | } | |
139 | ||
140 | /* Estimate the number of blocks and inodes in the filesystem. */ | |
141 | bool | |
142 | xfs_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 | } |