]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/freesp.c
xfsprogs: simplify internal includes
[thirdparty/xfsprogs-dev.git] / db / freesp.c
1 /*
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #include "libxfs.h"
20 #include "command.h"
21 #include "freesp.h"
22 #include "io.h"
23 #include "type.h"
24 #include "output.h"
25 #include "init.h"
26 #include "malloc.h"
27
28 typedef struct histent
29 {
30 int low;
31 int high;
32 long long count;
33 long long blocks;
34 } histent_t;
35
36 static void addhistent(int h);
37 static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno,
38 xfs_extlen_t len);
39 static int freesp_f(int argc, char **argv);
40 static void histinit(int maxlen);
41 static int init(int argc, char **argv);
42 static void printhist(void);
43 static void scan_ag(xfs_agnumber_t agno);
44 static void scanfunc_bno(struct xfs_btree_block *block, typnm_t typ, int level,
45 xfs_agf_t *agf);
46 static void scanfunc_cnt(struct xfs_btree_block *block, typnm_t typ, int level,
47 xfs_agf_t *agf);
48 static void scan_freelist(xfs_agf_t *agf);
49 static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ,
50 int nlevels,
51 void (*func)(struct xfs_btree_block *block, typnm_t typ,
52 int level, xfs_agf_t *agf));
53 static int usage(void);
54
55 static int agcount;
56 static xfs_agnumber_t *aglist;
57 static int countflag;
58 static int dumpflag;
59 static int equalsize;
60 static histent_t *hist;
61 static int histcount;
62 static int multsize;
63 static int seen1;
64 static int summaryflag;
65 static long long totblocks;
66 static long long totexts;
67
68 static const cmdinfo_t freesp_cmd =
69 { "freesp", NULL, freesp_f, 0, -1, 0,
70 "[-bcdfs] [-a agno]... [-e binsize] [-h h1]... [-m binmult]",
71 "summarize free space for filesystem", NULL };
72
73 static int
74 inaglist(
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 */
90 static int
91 freesp_f(
92 int argc,
93 char **argv)
94 {
95 xfs_agnumber_t agno;
96
97 if (!init(argc, argv))
98 return 0;
99
100 if (dumpflag)
101 dbprintf("%8s %8s %8s\n", "agno", "agbno", "len");
102
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) {
110 dbprintf(_("total free extents %lld\n"), totexts);
111 dbprintf(_("total free blocks %lld\n"), totblocks);
112 dbprintf(_("average free extent size %g\n"),
113 (double)totblocks / (double)totexts);
114 }
115 if (aglist)
116 xfree(aglist);
117 if (hist)
118 xfree(hist);
119 return 0;
120 }
121
122 void
123 freesp_init(void)
124 {
125 add_command(&freesp_cmd);
126 }
127
128 static void
129 aglistadd(
130 char *a)
131 {
132 aglist = xrealloc(aglist, (agcount + 1) * sizeof(*aglist));
133 aglist[agcount] = (xfs_agnumber_t)atoi(a);
134 agcount++;
135 }
136
137 static int
138 init(
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':
156 if (speced)
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
200 static int
201 usage(void)
202 {
203 dbprintf(_("freesp arguments: [-bcds] [-a agno] [-e binsize] [-h h1]... "
204 "[-m binmult]\n"));
205 return 0;
206 }
207
208 static void
209 scan_ag(
210 xfs_agnumber_t agno)
211 {
212 xfs_agf_t *agf;
213
214 push_cur();
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);
217 agf = iocur_top->data;
218 scan_freelist(agf);
219 if (countflag)
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]),
222 scanfunc_cnt);
223 else
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]),
226 scanfunc_bno);
227 pop_cur();
228 }
229
230 static void
231 scan_freelist(
232 xfs_agf_t *agf)
233 {
234 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
235 xfs_agfl_t *agfl;
236 xfs_agblock_t bno;
237 int i;
238 __be32 *agfl_bno;
239
240 if (be32_to_cpu(agf->agf_flcount) == 0)
241 return;
242 push_cur();
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);
245 agfl = iocur_top->data;
246 i = be32_to_cpu(agf->agf_flfirst);
247
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
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
261 for (;;) {
262 bno = be32_to_cpu(agfl_bno[i]);
263 addtohist(seqno, bno, 1);
264 if (i == be32_to_cpu(agf->agf_fllast))
265 break;
266 if (++i == XFS_AGFL_SIZE(mp))
267 i = 0;
268 }
269 pop_cur();
270 }
271
272 static void
273 scan_sbtree(
274 xfs_agf_t *agf,
275 xfs_agblock_t root,
276 typnm_t typ,
277 int nlevels,
278 void (*func)(struct xfs_btree_block *block,
279 typnm_t typ,
280 int level,
281 xfs_agf_t *agf))
282 {
283 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
284
285 push_cur();
286 set_cur(&typtab[typ], XFS_AGB_TO_DADDR(mp, seqno, root),
287 blkbb, DB_RING_IGN, NULL);
288 if (iocur_top->data == NULL) {
289 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
290 return;
291 }
292 (*func)(iocur_top->data, typ, nlevels - 1, agf);
293 pop_cur();
294 }
295
296 /*ARGSUSED*/
297 static void
298 scanfunc_bno(
299 struct xfs_btree_block *block,
300 typnm_t typ,
301 int level,
302 xfs_agf_t *agf)
303 {
304 int i;
305 xfs_alloc_ptr_t *pp;
306 xfs_alloc_rec_t *rp;
307
308 if (!(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC ||
309 be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC))
310 return;
311
312 if (level == 0) {
313 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
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));
318 return;
319 }
320 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
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);
323 }
324
325 static void
326 scanfunc_cnt(
327 struct xfs_btree_block *block,
328 typnm_t typ,
329 int level,
330 xfs_agf_t *agf)
331 {
332 int i;
333 xfs_alloc_ptr_t *pp;
334 xfs_alloc_rec_t *rp;
335
336 if (!(be32_to_cpu(block->bb_magic) == XFS_ABTC_MAGIC ||
337 be32_to_cpu(block->bb_magic) == XFS_ABTC_CRC_MAGIC))
338 return;
339
340 if (level == 0) {
341 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
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));
346 return;
347 }
348 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
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);
351 }
352
353 static void
354 addhistent(
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
367 static void
368 addtohist(
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
388 static int
389 hcmp(
390 const void *a,
391 const void *b)
392 {
393 return ((histent_t *)a)->low - ((histent_t *)b)->low;
394 }
395
396 static void
397 histinit(
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
421 static void
422 printhist(void)
423 {
424 int i;
425
426 dbprintf("%7s %7s %7s %7s %6s\n",
427 _("from"), _("to"), _("extents"), _("blocks"), _("pct"));
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 }