]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/freesp.c
libxfs: fix xfs_trans_alloc_empty namespace
[thirdparty/xfsprogs-dev.git] / db / freesp.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
dfc130f3 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
6b803e5a 19#include "libxfs.h"
2bd0ea18 20#include "command.h"
2bd0ea18
NS
21#include "freesp.h"
22#include "io.h"
23#include "type.h"
24#include "output.h"
4ca431fc 25#include "init.h"
2bd0ea18
NS
26#include "malloc.h"
27
28typedef struct histent
29{
30 int low;
31 int high;
32 long long count;
33 long long blocks;
34} histent_t;
35
36static void addhistent(int h);
37static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno,
38 xfs_extlen_t len);
39static int freesp_f(int argc, char **argv);
40static void histinit(int maxlen);
41static int init(int argc, char **argv);
42static void printhist(void);
43static void scan_ag(xfs_agnumber_t agno);
b3563c19 44static void scanfunc_bno(struct xfs_btree_block *block, typnm_t typ, int level,
2bd0ea18 45 xfs_agf_t *agf);
b3563c19 46static void scanfunc_cnt(struct xfs_btree_block *block, typnm_t typ, int level,
2bd0ea18
NS
47 xfs_agf_t *agf);
48static void scan_freelist(xfs_agf_t *agf);
49static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ,
50 int nlevels,
b3563c19 51 void (*func)(struct xfs_btree_block *block, typnm_t typ,
2bd0ea18
NS
52 int level, xfs_agf_t *agf));
53static int usage(void);
54
55static int agcount;
56static xfs_agnumber_t *aglist;
57static int countflag;
58static int dumpflag;
59static int equalsize;
60static histent_t *hist;
61static int histcount;
62static int multsize;
63static int seen1;
64static int summaryflag;
65static long long totblocks;
66static long long totexts;
67
68static const cmdinfo_t freesp_cmd =
69 { "freesp", NULL, freesp_f, 0, -1, 0,
dfc130f3 70 "[-bcdfs] [-a agno]... [-e binsize] [-h h1]... [-m binmult]",
2bd0ea18
NS
71 "summarize free space for filesystem", NULL };
72
73static int
74inaglist(
75 xfs_agnumber_t agno)
76{
77 int i;
78
79 if (agcount == 0)
80 return 1;
81 for (i = 0; i < agcount; i++)
82 if (aglist[i] == agno)
83 return 1;
84 return 0;
85}
86
87/*
88 * Report on freespace usage in xfs filesystem.
89 */
90static int
91freesp_f(
92 int argc,
93 char **argv)
94{
95 xfs_agnumber_t agno;
96
97 if (!init(argc, argv))
98 return 0;
982e5c7e
ES
99
100 if (dumpflag)
101 dbprintf("%8s %8s %8s\n", "agno", "agbno", "len");
102
2bd0ea18
NS
103 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
104 if (inaglist(agno))
105 scan_ag(agno);
106 }
107 if (histcount)
108 printhist();
109 if (summaryflag) {
9ee7055c
AM
110 dbprintf(_("total free extents %lld\n"), totexts);
111 dbprintf(_("total free blocks %lld\n"), totblocks);
112 dbprintf(_("average free extent size %g\n"),
2bd0ea18
NS
113 (double)totblocks / (double)totexts);
114 }
115 if (aglist)
116 xfree(aglist);
117 if (hist)
118 xfree(hist);
119 return 0;
120}
121
122void
123freesp_init(void)
124{
125 add_command(&freesp_cmd);
126}
127
128static void
129aglistadd(
130 char *a)
131{
132 aglist = xrealloc(aglist, (agcount + 1) * sizeof(*aglist));
133 aglist[agcount] = (xfs_agnumber_t)atoi(a);
134 agcount++;
135}
136
137static int
138init(
139 int argc,
140 char **argv)
141{
142 int c;
143 int speced = 0;
144
145 agcount = countflag = dumpflag = equalsize = multsize = optind = 0;
146 histcount = seen1 = summaryflag = 0;
147 totblocks = totexts = 0;
148 aglist = NULL;
149 hist = NULL;
150 while ((c = getopt(argc, argv, "a:bcde:h:m:s")) != EOF) {
151 switch (c) {
152 case 'a':
153 aglistadd(optarg);
154 break;
155 case 'b':
dfc130f3 156 if (speced)
2bd0ea18
NS
157 return usage();
158 multsize = 2;
159 speced = 1;
160 break;
161 case 'c':
162 countflag = 1;
163 break;
164 case 'd':
165 dumpflag = 1;
166 break;
167 case 'e':
168 if (speced)
169 return usage();
170 equalsize = atoi(optarg);
171 speced = 1;
172 break;
173 case 'h':
174 if (speced && !histcount)
175 return usage();
176 addhistent(atoi(optarg));
177 speced = 1;
178 break;
179 case 'm':
180 if (speced)
181 return usage();
182 multsize = atoi(optarg);
183 speced = 1;
184 break;
185 case 's':
186 summaryflag = 1;
187 break;
188 case '?':
189 return usage();
190 }
191 }
192 if (optind != argc)
193 return usage();
194 if (!speced)
195 multsize = 2;
196 histinit((int)mp->m_sb.sb_agblocks);
197 return 1;
198}
199
200static int
201usage(void)
202{
6fe93c03 203 dbprintf(_("freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... "
9ee7055c 204 "[-m binmult]\n"));
2bd0ea18
NS
205 return 0;
206}
207
208static void
209scan_ag(
210 xfs_agnumber_t agno)
211{
212 xfs_agf_t *agf;
213
214 push_cur();
5e656dbb
BN
215 set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
216 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18
NS
217 agf = iocur_top->data;
218 scan_freelist(agf);
219 if (countflag)
5e656dbb
BN
220 scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]),
221 TYP_CNTBT, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
2bd0ea18
NS
222 scanfunc_cnt);
223 else
5e656dbb
BN
224 scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]),
225 TYP_BNOBT, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
2bd0ea18
NS
226 scanfunc_bno);
227 pop_cur();
228}
229
230static void
231scan_freelist(
232 xfs_agf_t *agf)
233{
5e656dbb 234 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
235 xfs_agfl_t *agfl;
236 xfs_agblock_t bno;
237 int i;
84232448 238 __be32 *agfl_bno;
2bd0ea18 239
5e656dbb 240 if (be32_to_cpu(agf->agf_flcount) == 0)
2bd0ea18
NS
241 return;
242 push_cur();
5e656dbb
BN
243 set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)),
244 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18 245 agfl = iocur_top->data;
5e656dbb 246 i = be32_to_cpu(agf->agf_flfirst);
a529cc7f 247
84232448
DC
248 /* open coded XFS_BUF_TO_AGFL_BNO */
249 agfl_bno = xfs_sb_version_hascrc(&mp->m_sb) ? &agfl->agfl_bno[0]
250 : (__be32 *)agfl;
251
a529cc7f
ES
252 /* verify agf values before proceeding */
253 if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) ||
254 be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) {
255 dbprintf(_("agf %d freelist blocks bad, skipping "
256 "freelist scan\n"), i);
257 pop_cur();
258 return;
259 }
260
2bd0ea18 261 for (;;) {
84232448 262 bno = be32_to_cpu(agfl_bno[i]);
2bd0ea18 263 addtohist(seqno, bno, 1);
5e656dbb 264 if (i == be32_to_cpu(agf->agf_fllast))
2bd0ea18 265 break;
9440d84d 266 if (++i == XFS_AGFL_SIZE(mp))
2bd0ea18
NS
267 i = 0;
268 }
269 pop_cur();
270}
271
272static void
273scan_sbtree(
274 xfs_agf_t *agf,
275 xfs_agblock_t root,
276 typnm_t typ,
277 int nlevels,
b3563c19 278 void (*func)(struct xfs_btree_block *block,
2bd0ea18
NS
279 typnm_t typ,
280 int level,
281 xfs_agf_t *agf))
282{
5e656dbb 283 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
30b0c726 284
2bd0ea18 285 push_cur();
30b0c726 286 set_cur(&typtab[typ], XFS_AGB_TO_DADDR(mp, seqno, root),
2bd0ea18 287 blkbb, DB_RING_IGN, NULL);
30b0c726 288 if (iocur_top->data == NULL) {
9ee7055c 289 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
dfc130f3 290 return;
30b0c726 291 }
b3563c19 292 (*func)(iocur_top->data, typ, nlevels - 1, agf);
2bd0ea18
NS
293 pop_cur();
294}
295
296/*ARGSUSED*/
297static void
298scanfunc_bno(
b3563c19 299 struct xfs_btree_block *block,
2bd0ea18
NS
300 typnm_t typ,
301 int level,
302 xfs_agf_t *agf)
303{
2bd0ea18
NS
304 int i;
305 xfs_alloc_ptr_t *pp;
306 xfs_alloc_rec_t *rp;
307
c2907bd7
DC
308 if (!(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC ||
309 be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC))
65b04d8c
PW
310 return;
311
2bd0ea18 312 if (level == 0) {
b3563c19 313 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
5e656dbb
BN
314 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
315 addtohist(be32_to_cpu(agf->agf_seqno),
316 be32_to_cpu(rp[i].ar_startblock),
317 be32_to_cpu(rp[i].ar_blockcount));
2bd0ea18
NS
318 return;
319 }
b3563c19 320 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
321 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
322 scan_sbtree(agf, be32_to_cpu(pp[i]), typ, level, scanfunc_bno);
2bd0ea18
NS
323}
324
325static void
326scanfunc_cnt(
b3563c19 327 struct xfs_btree_block *block,
2bd0ea18
NS
328 typnm_t typ,
329 int level,
330 xfs_agf_t *agf)
331{
2bd0ea18
NS
332 int i;
333 xfs_alloc_ptr_t *pp;
334 xfs_alloc_rec_t *rp;
335
c2907bd7
DC
336 if (!(be32_to_cpu(block->bb_magic) == XFS_ABTC_MAGIC ||
337 be32_to_cpu(block->bb_magic) == XFS_ABTC_CRC_MAGIC))
65b04d8c
PW
338 return;
339
2bd0ea18 340 if (level == 0) {
b3563c19 341 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
5e656dbb
BN
342 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
343 addtohist(be32_to_cpu(agf->agf_seqno),
344 be32_to_cpu(rp[i].ar_startblock),
345 be32_to_cpu(rp[i].ar_blockcount));
2bd0ea18
NS
346 return;
347 }
b3563c19 348 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
349 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
350 scan_sbtree(agf, be32_to_cpu(pp[i]), typ, level, scanfunc_cnt);
2bd0ea18
NS
351}
352
353static void
354addhistent(
355 int h)
356{
357 hist = xrealloc(hist, (histcount + 1) * sizeof(*hist));
358 if (h == 0)
359 h = 1;
360 hist[histcount].low = h;
361 hist[histcount].count = hist[histcount].blocks = 0;
362 histcount++;
363 if (h == 1)
364 seen1 = 1;
365}
366
367static void
368addtohist(
369 xfs_agnumber_t agno,
370 xfs_agblock_t agbno,
371 xfs_extlen_t len)
372{
373 int i;
374
375 if (dumpflag)
376 dbprintf("%8d %8d %8d\n", agno, agbno, len);
377 totexts++;
378 totblocks += len;
379 for (i = 0; i < histcount; i++) {
380 if (hist[i].high >= len) {
381 hist[i].count++;
382 hist[i].blocks += len;
383 break;
384 }
385 }
386}
387
388static int
389hcmp(
390 const void *a,
391 const void *b)
392{
393 return ((histent_t *)a)->low - ((histent_t *)b)->low;
394}
395
396static void
397histinit(
398 int maxlen)
399{
400 int i;
401
402 if (equalsize) {
403 for (i = 1; i < maxlen; i += equalsize)
404 addhistent(i);
405 } else if (multsize) {
406 for (i = 1; i < maxlen; i *= multsize)
407 addhistent(i);
408 } else {
409 if (!seen1)
410 addhistent(1);
411 qsort(hist, histcount, sizeof(*hist), hcmp);
412 }
413 for (i = 0; i < histcount; i++) {
414 if (i < histcount - 1)
415 hist[i].high = hist[i + 1].low - 1;
416 else
417 hist[i].high = maxlen;
418 }
419}
420
421static void
422printhist(void)
423{
424 int i;
425
426 dbprintf("%7s %7s %7s %7s %6s\n",
9ee7055c 427 _("from"), _("to"), _("extents"), _("blocks"), _("pct"));
2bd0ea18
NS
428 for (i = 0; i < histcount; i++) {
429 if (hist[i].count)
430 dbprintf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
431 hist[i].high, hist[i].count, hist[i].blocks,
432 hist[i].blocks * 100.0 / totblocks);
433 }
434}