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