]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - spaceman/freesp.c
xfs_spaceman: remove typedef usage
[thirdparty/xfsprogs-dev.git] / spaceman / freesp.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
cccf6abc
DC
2/*
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * Copyright (c) 2012 Red Hat, Inc.
5 * Copyright (c) 2017 Oracle.
6 * All Rights Reserved.
cccf6abc
DC
7 */
8
9#include "libxfs.h"
10#include <linux/fiemap.h>
11#include "command.h"
12#include "init.h"
42b4c8e8 13#include "libfrog/paths.h"
cccf6abc
DC
14#include "space.h"
15#include "input.h"
16
10cfd61e 17struct histent
cccf6abc
DC
18{
19 long long low;
20 long long high;
21 long long count;
22 long long blocks;
10cfd61e 23};
cccf6abc
DC
24
25static int agcount;
26static xfs_agnumber_t *aglist;
10cfd61e 27static struct histent *hist;
cccf6abc
DC
28static int dumpflag;
29static long long equalsize;
30static long long multsize;
31static int histcount;
32static int seen1;
33static int summaryflag;
f77f9908 34static int gflag;
cccf6abc
DC
35static bool rtflag;
36static long long totblocks;
37static long long totexts;
38
39static cmdinfo_t freesp_cmd;
40
41static void
42addhistent(
43 long long h)
44{
45 if (histcount == INT_MAX) {
46 printf(_("Too many histogram buckets.\n"));
47 return;
48 }
49 hist = realloc(hist, (histcount + 1) * sizeof(*hist));
50 if (h == 0)
51 h = 1;
52 hist[histcount].low = h;
53 hist[histcount].count = hist[histcount].blocks = 0;
54 histcount++;
55 if (h == 1)
56 seen1 = 1;
57}
58
59static void
60addtohist(
61 xfs_agnumber_t agno,
62 xfs_agblock_t agbno,
63 off64_t len)
64{
65 long i;
66
67 if (dumpflag)
68 printf("%8d %8d %8"PRId64"\n", agno, agbno, len);
69 totexts++;
70 totblocks += len;
71 for (i = 0; i < histcount; i++) {
72 if (hist[i].high >= len) {
73 hist[i].count++;
74 hist[i].blocks += len;
75 break;
76 }
77 }
78}
79
80static int
81hcmp(
82 const void *a,
83 const void *b)
84{
10cfd61e 85 return ((struct histent *)a)->low - ((struct histent *)b)->low;
cccf6abc
DC
86}
87
88static void
89histinit(
90 long long maxlen)
91{
92 long long i;
93
94 if (equalsize) {
95 for (i = 1; i < maxlen; i += equalsize)
96 addhistent(i);
97 } else if (multsize) {
98 for (i = 1; i < maxlen; i *= multsize)
99 addhistent(i);
100 } else {
101 if (!seen1)
102 addhistent(1);
103 qsort(hist, histcount, sizeof(*hist), hcmp);
104 }
105 for (i = 0; i < histcount; i++) {
106 if (i < histcount - 1)
107 hist[i].high = hist[i + 1].low - 1;
108 else
109 hist[i].high = maxlen;
110 }
111}
112
113static void
114printhist(void)
115{
116 int i;
117
118 printf("%7s %7s %7s %7s %6s\n",
119 _("from"), _("to"), _("extents"), _("blocks"), _("pct"));
120 for (i = 0; i < histcount; i++) {
121 if (hist[i].count)
122 printf("%7lld %7lld %7lld %7lld %6.2f\n", hist[i].low,
123 hist[i].high, hist[i].count, hist[i].blocks,
124 hist[i].blocks * 100.0 / totblocks);
125 }
126}
127
128static int
129inaglist(
130 xfs_agnumber_t agno)
131{
132 int i;
133
134 if (agcount == 0)
135 return 1;
136 for (i = 0; i < agcount; i++)
137 if (aglist[i] == agno)
138 return 1;
139 return 0;
140}
141
142#define NR_EXTENTS 128
143
144static void
145scan_ag(
146 xfs_agnumber_t agno)
147{
148 struct fsmap_head *fsmap;
149 struct fsmap *extent;
150 struct fsmap *l, *h;
151 struct fsmap *p;
152 off64_t blocksize = file->geom.blocksize;
153 off64_t bperag;
154 off64_t aglen;
155 xfs_agblock_t agbno;
f77f9908
DW
156 unsigned long long freeblks = 0;
157 unsigned long long freeexts = 0;
cccf6abc
DC
158 int ret;
159 int i;
160
161 bperag = (off64_t)file->geom.agblocks * blocksize;
162
163 fsmap = malloc(fsmap_sizeof(NR_EXTENTS));
164 if (!fsmap) {
165 fprintf(stderr, _("%s: fsmap malloc failed.\n"), progname);
166 exitcode = 1;
167 return;
168 }
169
170 memset(fsmap, 0, sizeof(*fsmap));
171 fsmap->fmh_count = NR_EXTENTS;
172 l = fsmap->fmh_keys;
173 h = fsmap->fmh_keys + 1;
174 if (agno != NULLAGNUMBER) {
175 l->fmr_physical = agno * bperag;
176 h->fmr_physical = ((agno + 1) * bperag) - 1;
177 l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
178 } else {
179 l->fmr_physical = 0;
180 h->fmr_physical = ULLONG_MAX;
181 l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
182 }
183 h->fmr_owner = ULLONG_MAX;
184 h->fmr_flags = UINT_MAX;
185 h->fmr_offset = ULLONG_MAX;
186
187 while (true) {
188 ret = ioctl(file->fd, FS_IOC_GETFSMAP, fsmap);
189 if (ret < 0) {
190 fprintf(stderr, _("%s: FS_IOC_GETFSMAP [\"%s\"]: %s\n"),
191 progname, file->name, strerror(errno));
192 free(fsmap);
193 exitcode = 1;
194 return;
195 }
196
197 /* No more extents to map, exit */
198 if (!fsmap->fmh_entries)
199 break;
200
201 for (i = 0, extent = fsmap->fmh_recs;
202 i < fsmap->fmh_entries;
203 i++, extent++) {
204 if (!(extent->fmr_flags & FMR_OF_SPECIAL_OWNER) ||
205 extent->fmr_owner != XFS_FMR_OWN_FREE)
206 continue;
207 agbno = (extent->fmr_physical - (bperag * agno)) /
208 blocksize;
209 aglen = extent->fmr_length / blocksize;
f77f9908
DW
210 freeblks += aglen;
211 freeexts++;
cccf6abc
DC
212
213 addtohist(agno, agbno, aglen);
214 }
215
216 p = &fsmap->fmh_recs[fsmap->fmh_entries - 1];
217 if (p->fmr_flags & FMR_OF_LAST)
218 break;
219 fsmap_advance(fsmap);
220 }
f77f9908
DW
221
222 if (gflag) {
223 if (agno == NULLAGNUMBER)
224 printf(_(" rtdev %10llu %10llu\n"), freeexts,
225 freeblks);
226 else
227 printf(_("%10u %10llu %10llu\n"), agno, freeexts,
228 freeblks);
229 }
e177680d 230 free(fsmap);
cccf6abc 231}
e177680d 232
cccf6abc
DC
233static void
234aglistadd(
235 char *a)
236{
237 xfs_agnumber_t x;
238
239 aglist = realloc(aglist, (agcount + 1) * sizeof(*aglist));
240 x = cvt_u32(a, 0);
241 if (errno) {
242 printf(_("Unrecognized AG number: %s\n"), a);
243 return;
244 }
245 aglist[agcount] = x;
246 agcount++;
247}
248
249static int
250init(
251 int argc,
252 char **argv)
253{
254 long long x;
255 int c;
256 int speced = 0; /* only one of -b -e -h or -m */
257
f77f9908 258 agcount = dumpflag = equalsize = multsize = optind = gflag = 0;
cccf6abc
DC
259 histcount = seen1 = summaryflag = 0;
260 totblocks = totexts = 0;
261 aglist = NULL;
262 hist = NULL;
263 rtflag = false;
264
f77f9908 265 while ((c = getopt(argc, argv, "a:bde:gh:m:rs")) != EOF) {
cccf6abc
DC
266 switch (c) {
267 case 'a':
268 aglistadd(optarg);
269 break;
270 case 'b':
271 if (speced)
272 goto many_spec;
273 multsize = 2;
274 speced = 1;
275 break;
276 case 'd':
277 dumpflag = 1;
278 break;
279 case 'e':
280 if (speced)
281 goto many_spec;
282 equalsize = cvt_s64(optarg, 0);
283 if (errno)
284 return command_usage(&freesp_cmd);
285 speced = 1;
286 break;
f77f9908
DW
287 case 'g':
288 histcount = 0;
289 gflag++;
290 break;
cccf6abc
DC
291 case 'h':
292 if (speced && !histcount)
293 goto many_spec;
294 /* addhistent increments histcount */
295 x = cvt_s64(optarg, 0);
296 if (errno)
297 return command_usage(&freesp_cmd);
298 addhistent(x);
299 speced = 1;
300 break;
301 case 'm':
302 if (speced)
303 goto many_spec;
304 multsize = cvt_s64(optarg, 0);
305 if (errno)
306 return command_usage(&freesp_cmd);
307 speced = 1;
308 break;
309 case 'r':
310 rtflag = true;
311 break;
312 case 's':
313 summaryflag = 1;
314 break;
315 case '?':
316 default:
317 return command_usage(&freesp_cmd);
318 }
319 }
320 if (optind != argc)
321 return 0;
322 if (!speced)
323 multsize = 2;
324 histinit(file->geom.agblocks);
325 return 1;
326many_spec:
327 return command_usage(&freesp_cmd);
328}
329
330/*
331 * Report on freespace usage in xfs filesystem.
332 */
333static int
334freesp_f(
335 int argc,
336 char **argv)
337{
338 xfs_agnumber_t agno;
339
340 if (!init(argc, argv))
341 return 0;
f77f9908
DW
342 if (gflag)
343 printf(_(" AG extents blocks\n"));
cccf6abc
DC
344 if (rtflag)
345 scan_ag(NULLAGNUMBER);
346 for (agno = 0; !rtflag && agno < file->geom.agcount; agno++) {
347 if (inaglist(agno))
348 scan_ag(agno);
349 }
f77f9908 350 if (histcount && !gflag)
cccf6abc
DC
351 printhist();
352 if (summaryflag) {
353 printf(_("total free extents %lld\n"), totexts);
354 printf(_("total free blocks %lld\n"), totblocks);
355 printf(_("average free extent size %g\n"),
356 (double)totblocks / (double)totexts);
357 }
358 if (aglist)
359 free(aglist);
360 if (hist)
361 free(hist);
362 return 0;
363}
364
365static void
366freesp_help(void)
367{
368 printf(_(
369"\n"
370"Examine filesystem free space\n"
371"\n"
372" -a agno -- Scan only the given AG agno.\n"
373" -b -- binary histogram bin size\n"
374" -d -- debug output\n"
375" -e bsize -- Use fixed histogram bin size of bsize\n"
f77f9908 376" -g -- Print only a per-AG summary.\n"
cccf6abc
DC
377" -h hbsz -- Use custom histogram bin size of h1.\n"
378" Multiple specifications are allowed.\n"
379" -m bmult -- Use histogram bin size multiplier of bmult.\n"
380" -r -- Display realtime device free space information.\n"
381" -s -- Emit freespace summary information.\n"
382"\n"
383"Only one of -b, -e, -h, or -m may be specified.\n"
384"\n"));
385
386}
387
388void
389freesp_init(void)
390{
391 freesp_cmd.name = "freesp";
392 freesp_cmd.altname = "fsp";
393 freesp_cmd.cfunc = freesp_f;
394 freesp_cmd.argmin = 0;
395 freesp_cmd.argmax = -1;
f77f9908 396 freesp_cmd.args = "[-dgrs] [-a agno]... [ -b | -e bsize | -h h1... | -m bmult ]";
cccf6abc
DC
397 freesp_cmd.flags = CMD_FLAG_ONESHOT;
398 freesp_cmd.oneline = _("Examine filesystem free space");
399 freesp_cmd.help = freesp_help;
400
401 add_command(&freesp_cmd);
402}
403