2
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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.
23
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24
* Mountain View, CA 94043, or:
28
* For further information regarding this notice, see:
30
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
46
typedef struct extent {
47
xfs_fileoff_t startoff;
48
xfs_filblks_t blockcount;
51
typedef struct extmap {
56
#define EXTMAP_SIZE(n) \
57
(offsetof(extmap_t, ents) + (sizeof(extent_t) * (n)))
61
static __uint64_t extcount_actual;
62
static __uint64_t extcount_ideal;
70
typedef void (*scan_lbtree_f_t)(xfs_btree_lblock_t *block,
75
typedef void (*scan_sbtree_f_t)(xfs_btree_sblock_t *block,
79
static extmap_t *extmap_alloc(xfs_extnum_t nex);
80
static xfs_extnum_t extmap_ideal(extmap_t *extmap);
81
static void extmap_set_ext(extmap_t **extmapp, xfs_fileoff_t o,
83
static int frag_f(int argc, char **argv);
84
static int init(int argc, char **argv);
85
static void process_bmbt_reclist(xfs_bmbt_rec_32_t *rp, int numrecs,
87
static void process_btinode(xfs_dinode_t *dip, extmap_t **extmapp,
89
static void process_exinode(xfs_dinode_t *dip, extmap_t **extmapp,
91
static void process_fork(xfs_dinode_t *dip, int whichfork);
92
static void process_inode(xfs_agf_t *agf, xfs_agino_t agino,
94
static void scan_ag(xfs_agnumber_t agno);
95
static void scan_lbtree(xfs_fsblock_t root, int nlevels,
96
scan_lbtree_f_t func, extmap_t **extmapp,
98
static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root,
99
int nlevels, scan_sbtree_f_t func,
101
static void scanfunc_bmap(xfs_btree_lblock_t *ablock, int level,
102
extmap_t **extmapp, typnm_t btype);
103
static void scanfunc_ino(xfs_btree_sblock_t *ablock, int level,
106
static const cmdinfo_t frag_cmd =
107
{ "frag", NULL, frag_f, 0, -1, 0,
108
"[-a] [-d] [-f] [-l] [-r]",
109
"get file fragmentation data", NULL };
119
extmap = xmalloc(EXTMAP_SIZE(nex));
120
extmap->naents = nex;
132
for (ep = &extmap->ents[0], rval = 0;
133
ep < &extmap->ents[extmap->nents];
135
if (ep == &extmap->ents[0] ||
136
ep->startoff != ep[-1].startoff + ep[-1].blockcount)
152
if (extmap->nents == extmap->naents) {
154
extmap = xrealloc(extmap, EXTMAP_SIZE(extmap->naents));
157
ent = &extmap->ents[extmap->nents];
166
add_command(&frag_cmd);
170
* Get file fragmentation information.
180
if (!init(argc, argv))
182
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
185
answer = (double)(extcount_actual - extcount_ideal) * 100.0 /
186
(double)extcount_actual;
189
dbprintf("actual %llu, ideal %llu, fragmentation factor %.2f%%\n",
190
extcount_actual, extcount_ideal, answer);
201
aflag = dflag = fflag = lflag = qflag = Rflag = rflag = vflag = 0;
203
while ((c = getopt(argc, argv, "adflqRrv")) != EOF) {
230
dbprintf("bad option for frag command\n");
234
if (!aflag && !dflag && !fflag && !lflag && !qflag && !Rflag && !rflag)
235
aflag = dflag = fflag = lflag = qflag = Rflag = rflag = 1;
236
extcount_actual = extcount_ideal = 0;
241
process_bmbt_reclist(
242
xfs_bmbt_rec_32_t *rp,
252
for (i = 0; i < numrecs; i++, rp++) {
253
convert_extent((xfs_bmbt_rec_64_t *)rp, &o, &s, &c, &f);
254
extmap_set_ext(extmapp, (xfs_fileoff_t)o, (xfs_extlen_t)c);
264
xfs_bmdr_block_t *dib;
267
xfs_bmbt_rec_32_t *rp;
269
dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
270
if (INT_GET(dib->bb_level, ARCH_CONVERT) == 0) {
271
rp = (xfs_bmbt_rec_32_t *)XFS_BTREE_REC_ADDR(
272
XFS_DFORK_SIZE(dip, mp, whichfork),
274
XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip, mp,
277
process_bmbt_reclist(rp, INT_GET(dib->bb_numrecs, ARCH_CONVERT), extmapp);
280
pp = XFS_BTREE_PTR_ADDR(XFS_DFORK_SIZE(dip, mp, whichfork),
282
XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip, mp, whichfork),
284
for (i = 0; i < INT_GET(dib->bb_numrecs, ARCH_CONVERT); i++)
285
scan_lbtree((xfs_fsblock_t)INT_GET(pp[i], ARCH_CONVERT), INT_GET(dib->bb_level, ARCH_CONVERT), scanfunc_bmap,
287
whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA);
296
xfs_bmbt_rec_32_t *rp;
298
rp = (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR(dip, whichfork);
299
process_bmbt_reclist(rp, XFS_DFORK_NEXTENTS(dip, whichfork), extmapp);
310
nex = XFS_DFORK_NEXTENTS(dip, whichfork);
313
extmap = extmap_alloc(nex);
314
switch (XFS_DFORK_FORMAT(dip, whichfork)) {
315
case XFS_DINODE_FMT_EXTENTS:
316
process_exinode(dip, &extmap, whichfork);
318
case XFS_DINODE_FMT_BTREE:
319
process_btinode(dip, &extmap, whichfork);
322
extcount_actual += extmap->nents;
323
extcount_ideal += extmap_ideal(extmap);
334
xfs_dinode_core_t *dic;
341
ino = XFS_AGINO_TO_INO(mp, INT_GET(agf->agf_seqno, ARCH_CONVERT), agino);
342
switch (dic->di_mode & IFMT) {
347
if (!rflag && (dic->di_flags & XFS_DIFLAG_REALTIME))
350
(ino == mp->m_sb.sb_rbmino ||
351
ino == mp->m_sb.sb_rsumino))
354
(ino == mp->m_sb.sb_uquotino ||
355
ino == mp->m_sb.sb_gquotino))
367
actual = extcount_actual;
368
ideal = extcount_ideal;
370
process_fork(dip, XFS_DATA_FORK);
371
skipa = !aflag || !XFS_DFORK_Q(dip);
373
process_fork(dip, XFS_ATTR_FORK);
374
if (vflag && (!skipd || !skipa))
375
dbprintf("inode %lld actual %lld ideal %lld\n",
376
ino, extcount_actual - actual, extcount_ideal - ideal);
387
set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), 1,
389
if ((agf = iocur_top->data) == NULL) {
390
dbprintf("can't read agf block for ag %u\n", agno);
395
set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), 1,
397
if ((agi = iocur_top->data) == NULL) {
398
dbprintf("can't read agi block for ag %u\n", agno);
404
INT_GET(agi->agi_root, ARCH_CONVERT),
405
INT_GET(agi->agi_level, ARCH_CONVERT),
406
scanfunc_ino, TYP_INOBT);
415
scan_lbtree_f_t func,
420
set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN,
422
if (iocur_top->data == NULL) {
423
dbprintf("can't read btree block %u/%u\n",
424
XFS_FSB_TO_AGNO(mp, root),
425
XFS_FSB_TO_AGBNO(mp, root));
428
(*func)(iocur_top->data, nlevels - 1, extmapp, btype);
437
scan_sbtree_f_t func,
440
xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT);
443
set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, seqno, root),
444
blkbb, DB_RING_IGN, NULL);
445
if (iocur_top->data == NULL) {
446
dbprintf("can't read btree block %u/%u\n", seqno, root);
449
(*func)(iocur_top->data, nlevels - 1, agf);
455
xfs_btree_lblock_t *ablock,
460
xfs_bmbt_block_t *block = (xfs_bmbt_block_t *)ablock;
463
xfs_bmbt_rec_32_t *rp;
466
rp = (xfs_bmbt_rec_32_t *)
467
XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt,
468
block, 1, mp->m_bmap_dmxr[0]);
469
process_bmbt_reclist(rp, INT_GET(block->bb_numrecs, ARCH_CONVERT), extmapp);
472
pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, 1,
474
for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++)
475
scan_lbtree(INT_GET(pp[i], ARCH_CONVERT), level, scanfunc_bmap, extmapp, btype);
480
xfs_btree_sblock_t *ablock,
485
xfs_inobt_block_t *block = (xfs_inobt_block_t *)ablock;
486
xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT);
494
rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block,
495
1, mp->m_inobt_mxr[0]);
496
for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) {
497
agino = INT_GET(rp[i].ir_startino, ARCH_CONVERT);
498
off = XFS_INO_TO_OFFSET(mp, agino);
500
set_cur(&typtab[TYP_INODE],
501
XFS_AGB_TO_DADDR(mp, seqno,
502
XFS_AGINO_TO_AGBNO(mp, agino)),
503
(int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)),
505
if (iocur_top->data == NULL) {
506
dbprintf("can't read inode block %u/%u\n",
507
seqno, XFS_AGINO_TO_AGBNO(mp, agino));
510
for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
512
xfs_dinode_core_t tdic;
514
dip=(xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog));
516
/* convert the core, then copy it back into the inode */
517
libxfs_xlate_dinode_core( (xfs_caddr_t)
518
&dip->di_core, &tdic, 1, ARCH_CONVERT );
519
memcpy(&dip->di_core, &tdic, sizeof(xfs_dinode_core_t));
521
if (XFS_INOBT_IS_FREE(&rp[i], j, ARCH_CONVERT))
523
process_inode(agf, agino + j,
524
(xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)));
530
pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, 1,
532
for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++)
533
scan_sbtree(agf, INT_GET(pp[i], ARCH_CONVERT), level, scanfunc_ino, TYP_INOBT);