]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/freesp.c
Update copyright dates (again)
[thirdparty/xfsprogs-dev.git] / db / freesp.c
1 /*
2 * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
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>
34 #include <getopt.h>
35 #include "command.h"
36 #include "data.h"
37 #include "freesp.h"
38 #include "io.h"
39 #include "type.h"
40 #include "output.h"
41 #include "mount.h"
42 #include "malloc.h"
43
44 typedef struct histent
45 {
46 int low;
47 int high;
48 long long count;
49 long long blocks;
50 } histent_t;
51
52 static void addhistent(int h);
53 static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno,
54 xfs_extlen_t len);
55 static int freesp_f(int argc, char **argv);
56 static void histinit(int maxlen);
57 static int init(int argc, char **argv);
58 static void printhist(void);
59 static void scan_ag(xfs_agnumber_t agno);
60 static void scanfunc_bno(xfs_btree_sblock_t *ablock, typnm_t typ, int level,
61 xfs_agf_t *agf);
62 static void scanfunc_cnt(xfs_btree_sblock_t *ablock, typnm_t typ, int level,
63 xfs_agf_t *agf);
64 static void scan_freelist(xfs_agf_t *agf);
65 static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ,
66 int nlevels,
67 void (*func)(xfs_btree_sblock_t *block, typnm_t typ,
68 int level, xfs_agf_t *agf));
69 static int usage(void);
70
71 static int agcount;
72 static xfs_agnumber_t *aglist;
73 static int countflag;
74 static int dumpflag;
75 static int equalsize;
76 static histent_t *hist;
77 static int histcount;
78 static int multsize;
79 static int seen1;
80 static int summaryflag;
81 static long long totblocks;
82 static long long totexts;
83
84 static const cmdinfo_t freesp_cmd =
85 { "freesp", NULL, freesp_f, 0, -1, 0,
86 "[-bcdfs] [-a agno]... [-e binsize] [-h h1]... [-m binmult]",
87 "summarize free space for filesystem", NULL };
88
89 static int
90 inaglist(
91 xfs_agnumber_t agno)
92 {
93 int i;
94
95 if (agcount == 0)
96 return 1;
97 for (i = 0; i < agcount; i++)
98 if (aglist[i] == agno)
99 return 1;
100 return 0;
101 }
102
103 /*
104 * Report on freespace usage in xfs filesystem.
105 */
106 static int
107 freesp_f(
108 int argc,
109 char **argv)
110 {
111 xfs_agnumber_t agno;
112
113 if (!init(argc, argv))
114 return 0;
115 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
116 if (inaglist(agno))
117 scan_ag(agno);
118 }
119 if (histcount)
120 printhist();
121 if (summaryflag) {
122 dbprintf("total free extents %lld\n", totexts);
123 dbprintf("total free blocks %lld\n", totblocks);
124 dbprintf("average free extent size %g\n",
125 (double)totblocks / (double)totexts);
126 }
127 if (aglist)
128 xfree(aglist);
129 if (hist)
130 xfree(hist);
131 return 0;
132 }
133
134 void
135 freesp_init(void)
136 {
137 add_command(&freesp_cmd);
138 }
139
140 static void
141 aglistadd(
142 char *a)
143 {
144 aglist = xrealloc(aglist, (agcount + 1) * sizeof(*aglist));
145 aglist[agcount] = (xfs_agnumber_t)atoi(a);
146 agcount++;
147 }
148
149 static int
150 init(
151 int argc,
152 char **argv)
153 {
154 int c;
155 int speced = 0;
156
157 agcount = countflag = dumpflag = equalsize = multsize = optind = 0;
158 histcount = seen1 = summaryflag = 0;
159 totblocks = totexts = 0;
160 aglist = NULL;
161 hist = NULL;
162 while ((c = getopt(argc, argv, "a:bcde:h:m:s")) != EOF) {
163 switch (c) {
164 case 'a':
165 aglistadd(optarg);
166 break;
167 case 'b':
168 if (speced)
169 return usage();
170 multsize = 2;
171 speced = 1;
172 break;
173 case 'c':
174 countflag = 1;
175 break;
176 case 'd':
177 dumpflag = 1;
178 break;
179 case 'e':
180 if (speced)
181 return usage();
182 equalsize = atoi(optarg);
183 speced = 1;
184 break;
185 case 'h':
186 if (speced && !histcount)
187 return usage();
188 addhistent(atoi(optarg));
189 speced = 1;
190 break;
191 case 'm':
192 if (speced)
193 return usage();
194 multsize = atoi(optarg);
195 speced = 1;
196 break;
197 case 's':
198 summaryflag = 1;
199 break;
200 case '?':
201 return usage();
202 }
203 }
204 if (optind != argc)
205 return usage();
206 if (!speced)
207 multsize = 2;
208 histinit((int)mp->m_sb.sb_agblocks);
209 return 1;
210 }
211
212 static int
213 usage(void)
214 {
215 dbprintf("freesp arguments: [-bcdfs] [-a agno] [-e binsize] [-h h1]... "
216 "[-m binmult]\n");
217 return 0;
218 }
219
220 static void
221 scan_ag(
222 xfs_agnumber_t agno)
223 {
224 xfs_agf_t *agf;
225
226 push_cur();
227 set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), 1,
228 DB_RING_IGN, NULL);
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
246 static void
247 scan_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],
259 XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR), 1,
260 DB_RING_IGN, NULL);
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;
268 if (++i == XFS_AGFL_SIZE)
269 i = 0;
270 }
271 pop_cur();
272 }
273
274 static void
275 scan_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 {
285 xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT);
286
287 push_cur();
288 set_cur(&typtab[typ], XFS_AGB_TO_DADDR(mp, seqno, root),
289 blkbb, DB_RING_IGN, NULL);
290 if (iocur_top->data == NULL) {
291 dbprintf("can't read btree block %u/%u\n", seqno, root);
292 return;
293 }
294 (*func)((xfs_btree_sblock_t *)iocur_top->data, typ, nlevels - 1, agf);
295 pop_cur();
296 }
297
298 /*ARGSUSED*/
299 static void
300 scanfunc_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),
316 INT_GET(rp[i].ar_startblock, ARCH_CONVERT), INT_GET(rp[i].ar_blockcount, ARCH_CONVERT));
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++)
322 scan_sbtree(agf, pp[i], typ, level, scanfunc_bno);
323 }
324
325 static void
326 scanfunc_cnt(
327 xfs_btree_sblock_t *ablock,
328 typnm_t typ,
329 int level,
330 xfs_agf_t *agf)
331 {
332 xfs_alloc_block_t *block = (xfs_alloc_block_t *)ablock;
333 int i;
334 xfs_alloc_ptr_t *pp;
335 xfs_alloc_rec_t *rp;
336
337 if (level == 0) {
338 rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block,
339 1, mp->m_alloc_mxr[0]);
340 for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++)
341 addtohist(INT_GET(agf->agf_seqno, ARCH_CONVERT),
342 INT_GET(rp[i].ar_startblock, ARCH_CONVERT), INT_GET(rp[i].ar_blockcount, ARCH_CONVERT));
343 return;
344 }
345 pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, 1,
346 mp->m_alloc_mxr[1]);
347 for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++)
348 scan_sbtree(agf, pp[i], typ, level, scanfunc_cnt);
349 }
350
351 static void
352 addhistent(
353 int h)
354 {
355 hist = xrealloc(hist, (histcount + 1) * sizeof(*hist));
356 if (h == 0)
357 h = 1;
358 hist[histcount].low = h;
359 hist[histcount].count = hist[histcount].blocks = 0;
360 histcount++;
361 if (h == 1)
362 seen1 = 1;
363 }
364
365 static void
366 addtohist(
367 xfs_agnumber_t agno,
368 xfs_agblock_t agbno,
369 xfs_extlen_t len)
370 {
371 int i;
372
373 if (dumpflag)
374 dbprintf("%8d %8d %8d\n", agno, agbno, len);
375 totexts++;
376 totblocks += len;
377 for (i = 0; i < histcount; i++) {
378 if (hist[i].high >= len) {
379 hist[i].count++;
380 hist[i].blocks += len;
381 break;
382 }
383 }
384 }
385
386 static int
387 hcmp(
388 const void *a,
389 const void *b)
390 {
391 return ((histent_t *)a)->low - ((histent_t *)b)->low;
392 }
393
394 static void
395 histinit(
396 int maxlen)
397 {
398 int i;
399
400 if (equalsize) {
401 for (i = 1; i < maxlen; i += equalsize)
402 addhistent(i);
403 } else if (multsize) {
404 for (i = 1; i < maxlen; i *= multsize)
405 addhistent(i);
406 } else {
407 if (!seen1)
408 addhistent(1);
409 qsort(hist, histcount, sizeof(*hist), hcmp);
410 }
411 for (i = 0; i < histcount; i++) {
412 if (i < histcount - 1)
413 hist[i].high = hist[i + 1].low - 1;
414 else
415 hist[i].high = maxlen;
416 }
417 }
418
419 static void
420 printhist(void)
421 {
422 int i;
423
424 dbprintf("%7s %7s %7s %7s %6s\n",
425 "from", "to", "extents", "blocks", "pct");
426 for (i = 0; i < histcount; i++) {
427 if (hist[i].count)
428 dbprintf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low,
429 hist[i].high, hist[i].count, hist[i].blocks,
430 hist[i].blocks * 100.0 / totblocks);
431 }
432 }