]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame_incremental - db/freesp.c
xfsprogs: Release v6.15.0
[thirdparty/xfsprogs-dev.git] / db / freesp.c
... / ...
CommitLineData
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
17static void addhistent(int h);
18static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno,
19 xfs_extlen_t len);
20static int freesp_f(int argc, char **argv);
21static void histinit(int maxlen);
22static int init(int argc, char **argv);
23static void printhist(void);
24static void scan_ag(xfs_agnumber_t agno);
25static void scanfunc_bno(struct xfs_btree_block *block, typnm_t typ, int level,
26 xfs_agf_t *agf);
27static void scanfunc_cnt(struct xfs_btree_block *block, typnm_t typ, int level,
28 xfs_agf_t *agf);
29static void scan_freelist(xfs_agf_t *agf);
30static 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));
34static int usage(void);
35
36static int agcount;
37static xfs_agnumber_t *aglist;
38static int alignment;
39static int countflag;
40static int dumpflag;
41static int equalsize;
42static struct histogram freesp_hist;
43static int multsize;
44static int seen1;
45static int summaryflag;
46
47static 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
52static int
53inaglist(
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 */
69static int
70freesp_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
103void
104freesp_init(void)
105{
106 add_command(&freesp_cmd);
107}
108
109static void
110aglistadd(
111 char *a)
112{
113 aglist = xrealloc(aglist, (agcount + 1) * sizeof(*aglist));
114 aglist[agcount] = (xfs_agnumber_t)atoi(a);
115 agcount++;
116}
117
118static int
119init(
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
183static int
184usage(void)
185{
186 dbprintf(_("freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... "
187 "[-m binmult]\n"));
188 return 0;
189}
190
191static void
192scan_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
213static int
214scan_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
223static void
224scan_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
248static void
249scan_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*/
273static void
274scanfunc_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
301static void
302scanfunc_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
329static void
330addhistent(
331 int h)
332{
333 hist_add_bucket(&freesp_hist, h);
334}
335
336static void
337addtohist(
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
350static void
351histinit(
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
370static void
371printhist(void)
372{
373 struct histogram_strings hstr = {
374 .sum = _("blocks"),
375 .observations = _("extents"),
376 };
377
378 hist_print(&freesp_hist, &hstr);
379}