]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/freesp.c
43520481d5e038251f740167f37279f35d01dd89
[thirdparty/xfsprogs-dev.git] / db / freesp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include "command.h"
9 #include "freesp.h"
10 #include "io.h"
11 #include "type.h"
12 #include "output.h"
13 #include "init.h"
14 #include "malloc.h"
15 #include "libfrog/histogram.h"
16
17 static void addhistent(int h);
18 static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno,
19 xfs_extlen_t len);
20 static int freesp_f(int argc, char **argv);
21 static void histinit(int maxlen);
22 static int init(int argc, char **argv);
23 static void printhist(void);
24 static void scan_ag(xfs_agnumber_t agno);
25 static void scanfunc_bno(struct xfs_btree_block *block, typnm_t typ, int level,
26 xfs_agf_t *agf);
27 static void scanfunc_cnt(struct xfs_btree_block *block, typnm_t typ, int level,
28 xfs_agf_t *agf);
29 static void scan_freelist(xfs_agf_t *agf);
30 static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ,
31 int nlevels,
32 void (*func)(struct xfs_btree_block *block, typnm_t typ,
33 int level, xfs_agf_t *agf));
34 static int usage(void);
35
36 static int agcount;
37 static xfs_agnumber_t *aglist;
38 static int alignment;
39 static int countflag;
40 static int dumpflag;
41 static int equalsize;
42 static struct histogram freesp_hist;
43 static int multsize;
44 static int seen1;
45 static int summaryflag;
46
47 static const cmdinfo_t freesp_cmd =
48 { "freesp", NULL, freesp_f, 0, -1, 0,
49 "[-bcdfs] [-A alignment] [-a agno]... [-e binsize] [-h h1]... [-m binmult]",
50 "summarize free space for filesystem", NULL };
51
52 static int
53 inaglist(
54 xfs_agnumber_t agno)
55 {
56 int i;
57
58 if (agcount == 0)
59 return 1;
60 for (i = 0; i < agcount; i++)
61 if (aglist[i] == agno)
62 return 1;
63 return 0;
64 }
65
66 /*
67 * Report on freespace usage in xfs filesystem.
68 */
69 static int
70 freesp_f(
71 int argc,
72 char **argv)
73 {
74 xfs_agnumber_t agno;
75
76 if (!init(argc, argv))
77 return 0;
78
79 if (dumpflag)
80 dbprintf("%8s %8s %8s\n", "agno", "agbno", "len");
81
82 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
83 if (inaglist(agno))
84 scan_ag(agno);
85 }
86 if (hist_buckets(&freesp_hist))
87 printhist();
88 if (summaryflag) {
89 struct histogram_strings hstr = {
90 .sum = _("total free blocks"),
91 .observations = _("total free extents"),
92 .averages = _("average free extent size"),
93 };
94
95 hist_summarize(&freesp_hist, &hstr);
96 }
97 if (aglist)
98 xfree(aglist);
99 hist_free(&freesp_hist);
100 return 0;
101 }
102
103 void
104 freesp_init(void)
105 {
106 add_command(&freesp_cmd);
107 }
108
109 static void
110 aglistadd(
111 char *a)
112 {
113 aglist = xrealloc(aglist, (agcount + 1) * sizeof(*aglist));
114 aglist[agcount] = (xfs_agnumber_t)atoi(a);
115 agcount++;
116 }
117
118 static int
119 init(
120 int argc,
121 char **argv)
122 {
123 int c;
124 int speced = 0;
125
126 agcount = countflag = dumpflag = equalsize = multsize = optind = 0;
127 seen1 = summaryflag = 0;
128 aglist = NULL;
129
130 while ((c = getopt(argc, argv, "A:a:bcde:h:m:s")) != EOF) {
131 switch (c) {
132 case 'A':
133 alignment = atoi(optarg);
134 break;
135 case 'a':
136 aglistadd(optarg);
137 break;
138 case 'b':
139 if (speced)
140 return usage();
141 multsize = 2;
142 speced = 1;
143 break;
144 case 'c':
145 countflag = 1;
146 break;
147 case 'd':
148 dumpflag = 1;
149 break;
150 case 'e':
151 if (speced)
152 return usage();
153 equalsize = atoi(optarg);
154 speced = 1;
155 break;
156 case 'h':
157 if (speced && hist_buckets(&freesp_hist) == 0)
158 return usage();
159 addhistent(atoi(optarg));
160 speced = 1;
161 break;
162 case 'm':
163 if (speced)
164 return usage();
165 multsize = atoi(optarg);
166 speced = 1;
167 break;
168 case 's':
169 summaryflag = 1;
170 break;
171 default:
172 return usage();
173 }
174 }
175 if (optind != argc)
176 return usage();
177 if (!speced)
178 multsize = 2;
179 histinit((int)mp->m_sb.sb_agblocks);
180 return 1;
181 }
182
183 static int
184 usage(void)
185 {
186 dbprintf(_("freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... "
187 "[-m binmult]\n"));
188 return 0;
189 }
190
191 static void
192 scan_ag(
193 xfs_agnumber_t agno)
194 {
195 xfs_agf_t *agf;
196
197 push_cur();
198 set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
199 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
200 agf = iocur_top->data;
201 scan_freelist(agf);
202 if (countflag)
203 scan_sbtree(agf, be32_to_cpu(agf->agf_cnt_root),
204 TYP_CNTBT, be32_to_cpu(agf->agf_cnt_level),
205 scanfunc_cnt);
206 else
207 scan_sbtree(agf, be32_to_cpu(agf->agf_bno_root),
208 TYP_BNOBT, be32_to_cpu(agf->agf_bno_level),
209 scanfunc_bno);
210 pop_cur();
211 }
212
213 static int
214 scan_agfl(
215 struct xfs_mount *mp,
216 xfs_agblock_t bno,
217 void *priv)
218 {
219 addtohist(*(xfs_agnumber_t *)priv, bno, 1);
220 return 0;
221 }
222
223 static void
224 scan_freelist(
225 xfs_agf_t *agf)
226 {
227 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
228
229 if (be32_to_cpu(agf->agf_flcount) == 0)
230 return;
231 push_cur();
232 set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)),
233 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
234
235 /* verify agf values before proceeding */
236 if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) ||
237 be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) {
238 dbprintf(_("agf %d freelist blocks bad, skipping "
239 "freelist scan\n"), seqno);
240 pop_cur();
241 return;
242 }
243
244 libxfs_agfl_walk(mp, agf, iocur_top->bp, scan_agfl, &seqno);
245 pop_cur();
246 }
247
248 static void
249 scan_sbtree(
250 xfs_agf_t *agf,
251 xfs_agblock_t root,
252 typnm_t typ,
253 int nlevels,
254 void (*func)(struct xfs_btree_block *block,
255 typnm_t typ,
256 int level,
257 xfs_agf_t *agf))
258 {
259 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
260
261 push_cur();
262 set_cur(&typtab[typ], XFS_AGB_TO_DADDR(mp, seqno, root),
263 blkbb, DB_RING_IGN, NULL);
264 if (iocur_top->data == NULL) {
265 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
266 return;
267 }
268 (*func)(iocur_top->data, typ, nlevels - 1, agf);
269 pop_cur();
270 }
271
272 /*ARGSUSED*/
273 static void
274 scanfunc_bno(
275 struct xfs_btree_block *block,
276 typnm_t typ,
277 int level,
278 xfs_agf_t *agf)
279 {
280 int i;
281 xfs_alloc_ptr_t *pp;
282 xfs_alloc_rec_t *rp;
283
284 if (!(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC ||
285 be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC))
286 return;
287
288 if (level == 0) {
289 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
290 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
291 addtohist(be32_to_cpu(agf->agf_seqno),
292 be32_to_cpu(rp[i].ar_startblock),
293 be32_to_cpu(rp[i].ar_blockcount));
294 return;
295 }
296 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
297 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
298 scan_sbtree(agf, be32_to_cpu(pp[i]), typ, level, scanfunc_bno);
299 }
300
301 static void
302 scanfunc_cnt(
303 struct xfs_btree_block *block,
304 typnm_t typ,
305 int level,
306 xfs_agf_t *agf)
307 {
308 int i;
309 xfs_alloc_ptr_t *pp;
310 xfs_alloc_rec_t *rp;
311
312 if (!(be32_to_cpu(block->bb_magic) == XFS_ABTC_MAGIC ||
313 be32_to_cpu(block->bb_magic) == XFS_ABTC_CRC_MAGIC))
314 return;
315
316 if (level == 0) {
317 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
318 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
319 addtohist(be32_to_cpu(agf->agf_seqno),
320 be32_to_cpu(rp[i].ar_startblock),
321 be32_to_cpu(rp[i].ar_blockcount));
322 return;
323 }
324 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
325 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
326 scan_sbtree(agf, be32_to_cpu(pp[i]), typ, level, scanfunc_cnt);
327 }
328
329 static void
330 addhistent(
331 int h)
332 {
333 hist_add_bucket(&freesp_hist, h);
334 }
335
336 static void
337 addtohist(
338 xfs_agnumber_t agno,
339 xfs_agblock_t agbno,
340 xfs_extlen_t len)
341 {
342 if (alignment && (XFS_AGB_TO_FSB(mp,agno,agbno) % alignment))
343 return;
344
345 if (dumpflag)
346 dbprintf("%8d %8d %8d\n", agno, agbno, len);
347 hist_add(&freesp_hist, len);
348 }
349
350 static void
351 histinit(
352 int maxlen)
353 {
354 int i;
355
356 hist_init(&freesp_hist);
357 if (equalsize) {
358 for (i = 1; i < maxlen; i += equalsize)
359 addhistent(i);
360 } else if (multsize) {
361 for (i = 1; i < maxlen; i *= multsize)
362 addhistent(i);
363 } else {
364 if (!seen1)
365 addhistent(1);
366 }
367 hist_prepare(&freesp_hist, maxlen);
368 }
369
370 static void
371 printhist(void)
372 {
373 struct histogram_strings hstr = {
374 .sum = _("blocks"),
375 .observations = _("extents"),
376 };
377
378 hist_print(&freesp_hist, &hstr);
379 }