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