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