]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/fscounters.c
Merge branch 'libxfs-4.18-sync' into for-next
[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 "xfs_format.h"
13 #include "path.h"
14 #include "workqueue.h"
15 #include "xfs_scrub.h"
16 #include "common.h"
17 #include "fscounters.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 xfs_count_inodes {
28 bool moveon;
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 bool
37 xfs_count_inodes_range(
38 struct scrub_ctx *ctx,
39 const char *descr,
40 uint64_t first_ino,
41 uint64_t last_ino,
42 uint64_t *count)
43 {
44 struct xfs_fsop_bulkreq igrpreq = {0};
45 struct xfs_inogrp inogrp;
46 __u64 igrp_ino;
47 uint64_t nr = 0;
48 __s32 igrplen = 0;
49 int error;
50
51 ASSERT(!(first_ino & (XFS_INODES_PER_CHUNK - 1)));
52 ASSERT((last_ino & (XFS_INODES_PER_CHUNK - 1)));
53
54 igrpreq.lastip = &igrp_ino;
55 igrpreq.icount = 1;
56 igrpreq.ubuffer = &inogrp;
57 igrpreq.ocount = &igrplen;
58
59 igrp_ino = first_ino;
60 error = ioctl(ctx->mnt_fd, XFS_IOC_FSINUMBERS, &igrpreq);
61 while (!error && igrplen && inogrp.xi_startino < last_ino) {
62 nr += inogrp.xi_alloccount;
63 error = ioctl(ctx->mnt_fd, XFS_IOC_FSINUMBERS, &igrpreq);
64 }
65
66 if (error) {
67 str_errno(ctx, descr);
68 return false;
69 }
70
71 *count = nr;
72 return true;
73 }
74
75 /* Scan all the inodes in an AG. */
76 static void
77 xfs_count_ag_inodes(
78 struct workqueue *wq,
79 xfs_agnumber_t agno,
80 void *arg)
81 {
82 struct xfs_count_inodes *ci = arg;
83 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
84 char descr[DESCR_BUFSZ];
85 uint64_t ag_ino;
86 uint64_t next_ag_ino;
87 bool moveon;
88
89 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"),
90 major(ctx->fsinfo.fs_datadev),
91 minor(ctx->fsinfo.fs_datadev),
92 agno);
93
94 ag_ino = (__u64)agno << (ctx->inopblog + ctx->agblklog);
95 next_ag_ino = (__u64)(agno + 1) << (ctx->inopblog + ctx->agblklog);
96
97 moveon = xfs_count_inodes_range(ctx, descr, ag_ino, next_ag_ino - 1,
98 &ci->counters[agno]);
99 if (!moveon)
100 ci->moveon = false;
101 }
102
103 /* Count all the inodes in a filesystem. */
104 bool
105 xfs_count_all_inodes(
106 struct scrub_ctx *ctx,
107 uint64_t *count)
108 {
109 struct xfs_count_inodes *ci;
110 xfs_agnumber_t agno;
111 struct workqueue wq;
112 bool moveon;
113 int ret;
114
115 ci = calloc(1, sizeof(struct xfs_count_inodes) +
116 (ctx->geo.agcount * sizeof(uint64_t)));
117 if (!ci)
118 return false;
119 ci->moveon = true;
120
121 ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
122 scrub_nproc_workqueue(ctx));
123 if (ret) {
124 moveon = false;
125 str_info(ctx, ctx->mntpoint, _("Could not create workqueue."));
126 goto out_free;
127 }
128 for (agno = 0; agno < ctx->geo.agcount; agno++) {
129 ret = workqueue_add(&wq, xfs_count_ag_inodes, agno, ci);
130 if (ret) {
131 moveon = false;
132 str_info(ctx, ctx->mntpoint,
133 _("Could not queue AG %u icount work."), agno);
134 break;
135 }
136 }
137 workqueue_destroy(&wq);
138
139 for (agno = 0; agno < ctx->geo.agcount; agno++)
140 *count += ci->counters[agno];
141 moveon = ci->moveon;
142
143 out_free:
144 free(ci);
145 return moveon;
146 }
147
148 /* Estimate the number of blocks and inodes in the filesystem. */
149 bool
150 xfs_scan_estimate_blocks(
151 struct scrub_ctx *ctx,
152 unsigned long long *d_blocks,
153 unsigned long long *d_bfree,
154 unsigned long long *r_blocks,
155 unsigned long long *r_bfree,
156 unsigned long long *f_files,
157 unsigned long long *f_free)
158 {
159 struct xfs_fsop_counts fc;
160 struct xfs_fsop_resblks rb;
161 struct statvfs sfs;
162 int error;
163
164 /* Grab the fstatvfs counters, since it has to report accurately. */
165 error = fstatvfs(ctx->mnt_fd, &sfs);
166 if (error) {
167 str_errno(ctx, ctx->mntpoint);
168 return false;
169 }
170
171 /* Fetch the filesystem counters. */
172 error = ioctl(ctx->mnt_fd, XFS_IOC_FSCOUNTS, &fc);
173 if (error) {
174 str_errno(ctx, ctx->mntpoint);
175 return false;
176 }
177
178 /*
179 * XFS reserves some blocks to prevent hard ENOSPC, so add those
180 * blocks back to the free data counts.
181 */
182 error = ioctl(ctx->mnt_fd, XFS_IOC_GET_RESBLKS, &rb);
183 if (error)
184 str_errno(ctx, ctx->mntpoint);
185 sfs.f_bfree += rb.resblks_avail;
186
187 *d_blocks = sfs.f_blocks + (ctx->geo.logstart ? ctx->geo.logblocks : 0);
188 *d_bfree = sfs.f_bfree;
189 *r_blocks = ctx->geo.rtblocks;
190 *r_bfree = fc.freertx;
191 *f_files = sfs.f_files;
192 *f_free = sfs.f_ffree;
193
194 return true;
195 }