2 * Copyright (c) 2000-2001 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/
45 typedef struct extent
{
46 xfs_fileoff_t startoff
;
47 xfs_filblks_t blockcount
;
50 typedef struct extmap
{
55 #define EXTMAP_SIZE(n) \
56 (offsetof(extmap_t, ents) + (sizeof(extent_t) * (n)))
60 static __uint64_t extcount_actual
;
61 static __uint64_t extcount_ideal
;
69 typedef void (*scan_lbtree_f_t
)(xfs_btree_lblock_t
*block
,
74 typedef void (*scan_sbtree_f_t
)(xfs_btree_sblock_t
*block
,
78 static extmap_t
*extmap_alloc(xfs_extnum_t nex
);
79 static xfs_extnum_t
extmap_ideal(extmap_t
*extmap
);
80 static void extmap_set_ext(extmap_t
**extmapp
, xfs_fileoff_t o
,
82 static int frag_f(int argc
, char **argv
);
83 static int init(int argc
, char **argv
);
84 static void process_bmbt_reclist(xfs_bmbt_rec_32_t
*rp
, int numrecs
,
86 static void process_btinode(xfs_dinode_t
*dip
, extmap_t
**extmapp
,
88 static void process_exinode(xfs_dinode_t
*dip
, extmap_t
**extmapp
,
90 static void process_fork(xfs_dinode_t
*dip
, int whichfork
);
91 static void process_inode(xfs_agf_t
*agf
, xfs_agino_t agino
,
93 static void scan_ag(xfs_agnumber_t agno
);
94 static void scan_lbtree(xfs_fsblock_t root
, int nlevels
,
95 scan_lbtree_f_t func
, extmap_t
**extmapp
,
97 static void scan_sbtree(xfs_agf_t
*agf
, xfs_agblock_t root
,
98 int nlevels
, scan_sbtree_f_t func
,
100 static void scanfunc_bmap(xfs_btree_lblock_t
*ablock
, int level
,
101 extmap_t
**extmapp
, typnm_t btype
);
102 static void scanfunc_ino(xfs_btree_sblock_t
*ablock
, int level
,
105 static const cmdinfo_t frag_cmd
=
106 { "frag", NULL
, frag_f
, 0, -1, 0,
107 "[-a] [-d] [-f] [-l] [-r]",
108 "get file fragmentation data", NULL
};
118 extmap
= xmalloc(EXTMAP_SIZE(nex
));
119 extmap
->naents
= nex
;
131 for (ep
= &extmap
->ents
[0], rval
= 0;
132 ep
< &extmap
->ents
[extmap
->nents
];
134 if (ep
== &extmap
->ents
[0] ||
135 ep
->startoff
!= ep
[-1].startoff
+ ep
[-1].blockcount
)
151 if (extmap
->nents
== extmap
->naents
) {
153 extmap
= xrealloc(extmap
, EXTMAP_SIZE(extmap
->naents
));
156 ent
= &extmap
->ents
[extmap
->nents
];
165 add_command(&frag_cmd
);
169 * Get file fragmentation information.
179 if (!init(argc
, argv
))
181 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++)
184 answer
= (double)(extcount_actual
- extcount_ideal
) * 100.0 /
185 (double)extcount_actual
;
188 dbprintf("actual %llu, ideal %llu, fragmentation factor %.2f%%\n",
189 extcount_actual
, extcount_ideal
, answer
);
200 aflag
= dflag
= fflag
= lflag
= qflag
= Rflag
= rflag
= vflag
= 0;
202 while ((c
= getopt(argc
, argv
, "adflqRrv")) != EOF
) {
229 dbprintf("bad option for frag command\n");
233 if (!aflag
&& !dflag
&& !fflag
&& !lflag
&& !qflag
&& !Rflag
&& !rflag
)
234 aflag
= dflag
= fflag
= lflag
= qflag
= Rflag
= rflag
= 1;
235 extcount_actual
= extcount_ideal
= 0;
240 process_bmbt_reclist(
241 xfs_bmbt_rec_32_t
*rp
,
251 for (i
= 0; i
< numrecs
; i
++, rp
++) {
252 convert_extent((xfs_bmbt_rec_64_t
*)rp
, &o
, &s
, &c
, &f
);
253 extmap_set_ext(extmapp
, (xfs_fileoff_t
)o
, (xfs_extlen_t
)c
);
263 xfs_bmdr_block_t
*dib
;
266 xfs_bmbt_rec_32_t
*rp
;
268 dib
= (xfs_bmdr_block_t
*)XFS_DFORK_PTR(dip
, whichfork
);
269 if (INT_GET(dib
->bb_level
, ARCH_CONVERT
) == 0) {
270 rp
= (xfs_bmbt_rec_32_t
*)XFS_BTREE_REC_ADDR(
271 XFS_DFORK_SIZE(dip
, mp
, whichfork
),
273 XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip
, mp
,
276 process_bmbt_reclist(rp
, INT_GET(dib
->bb_numrecs
, ARCH_CONVERT
), extmapp
);
279 pp
= XFS_BTREE_PTR_ADDR(XFS_DFORK_SIZE(dip
, mp
, whichfork
),
281 XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip
, mp
, whichfork
),
283 for (i
= 0; i
< INT_GET(dib
->bb_numrecs
, ARCH_CONVERT
); i
++)
284 scan_lbtree((xfs_fsblock_t
)INT_GET(pp
[i
], ARCH_CONVERT
), INT_GET(dib
->bb_level
, ARCH_CONVERT
), scanfunc_bmap
,
286 whichfork
== XFS_DATA_FORK
? TYP_BMAPBTD
: TYP_BMAPBTA
);
295 xfs_bmbt_rec_32_t
*rp
;
297 rp
= (xfs_bmbt_rec_32_t
*)XFS_DFORK_PTR(dip
, whichfork
);
298 process_bmbt_reclist(rp
, XFS_DFORK_NEXTENTS(dip
, whichfork
), extmapp
);
309 nex
= XFS_DFORK_NEXTENTS(dip
, whichfork
);
312 extmap
= extmap_alloc(nex
);
313 switch (XFS_DFORK_FORMAT(dip
, whichfork
)) {
314 case XFS_DINODE_FMT_EXTENTS
:
315 process_exinode(dip
, &extmap
, whichfork
);
317 case XFS_DINODE_FMT_BTREE
:
318 process_btinode(dip
, &extmap
, whichfork
);
321 extcount_actual
+= extmap
->nents
;
322 extcount_ideal
+= extmap_ideal(extmap
);
333 xfs_dinode_core_t
*dic
;
340 ino
= XFS_AGINO_TO_INO(mp
, INT_GET(agf
->agf_seqno
, ARCH_CONVERT
), agino
);
341 switch (dic
->di_mode
& IFMT
) {
346 if (!rflag
&& (dic
->di_flags
& XFS_DIFLAG_REALTIME
))
349 (ino
== mp
->m_sb
.sb_rbmino
||
350 ino
== mp
->m_sb
.sb_rsumino
))
353 (ino
== mp
->m_sb
.sb_uquotino
||
354 ino
== mp
->m_sb
.sb_gquotino
))
366 actual
= extcount_actual
;
367 ideal
= extcount_ideal
;
369 process_fork(dip
, XFS_DATA_FORK
);
370 skipa
= !aflag
|| !XFS_DFORK_Q(dip
);
372 process_fork(dip
, XFS_ATTR_FORK
);
373 if (vflag
&& (!skipd
|| !skipa
))
374 dbprintf("inode %lld actual %lld ideal %lld\n",
375 ino
, extcount_actual
- actual
, extcount_ideal
- ideal
);
386 set_cur(&typtab
[TYP_AGF
],
387 XFS_AG_DADDR(mp
, agno
, XFS_AGF_DADDR(mp
)),
388 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
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
],
396 XFS_AG_DADDR(mp
, agno
, XFS_AGI_DADDR(mp
)),
397 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
398 if ((agi
= iocur_top
->data
) == NULL
) {
399 dbprintf("can't read agi block for ag %u\n", agno
);
405 INT_GET(agi
->agi_root
, ARCH_CONVERT
),
406 INT_GET(agi
->agi_level
, ARCH_CONVERT
),
407 scanfunc_ino
, TYP_INOBT
);
416 scan_lbtree_f_t func
,
421 set_cur(&typtab
[btype
], XFS_FSB_TO_DADDR(mp
, root
), blkbb
, DB_RING_IGN
,
423 if (iocur_top
->data
== NULL
) {
424 dbprintf("can't read btree block %u/%u\n",
425 XFS_FSB_TO_AGNO(mp
, root
),
426 XFS_FSB_TO_AGBNO(mp
, root
));
429 (*func
)(iocur_top
->data
, nlevels
- 1, extmapp
, btype
);
438 scan_sbtree_f_t func
,
441 xfs_agnumber_t seqno
= INT_GET(agf
->agf_seqno
, ARCH_CONVERT
);
444 set_cur(&typtab
[btype
], XFS_AGB_TO_DADDR(mp
, seqno
, root
),
445 blkbb
, DB_RING_IGN
, NULL
);
446 if (iocur_top
->data
== NULL
) {
447 dbprintf("can't read btree block %u/%u\n", seqno
, root
);
450 (*func
)(iocur_top
->data
, nlevels
- 1, agf
);
456 xfs_btree_lblock_t
*ablock
,
461 xfs_bmbt_block_t
*block
= (xfs_bmbt_block_t
*)ablock
;
464 xfs_bmbt_rec_32_t
*rp
;
467 rp
= (xfs_bmbt_rec_32_t
*)
468 XFS_BTREE_REC_ADDR(mp
->m_sb
.sb_blocksize
, xfs_bmbt
,
469 block
, 1, mp
->m_bmap_dmxr
[0]);
470 process_bmbt_reclist(rp
, INT_GET(block
->bb_numrecs
, ARCH_CONVERT
), extmapp
);
473 pp
= XFS_BTREE_PTR_ADDR(mp
->m_sb
.sb_blocksize
, xfs_bmbt
, block
, 1,
475 for (i
= 0; i
< INT_GET(block
->bb_numrecs
, ARCH_CONVERT
); i
++)
476 scan_lbtree(INT_GET(pp
[i
], ARCH_CONVERT
), level
, scanfunc_bmap
, extmapp
, btype
);
481 xfs_btree_sblock_t
*ablock
,
486 xfs_inobt_block_t
*block
= (xfs_inobt_block_t
*)ablock
;
487 xfs_agnumber_t seqno
= INT_GET(agf
->agf_seqno
, ARCH_CONVERT
);
495 rp
= XFS_BTREE_REC_ADDR(mp
->m_sb
.sb_blocksize
, xfs_inobt
, block
,
496 1, mp
->m_inobt_mxr
[0]);
497 for (i
= 0; i
< INT_GET(block
->bb_numrecs
, ARCH_CONVERT
); i
++) {
498 agino
= INT_GET(rp
[i
].ir_startino
, ARCH_CONVERT
);
499 off
= XFS_INO_TO_OFFSET(mp
, agino
);
501 set_cur(&typtab
[TYP_INODE
],
502 XFS_AGB_TO_DADDR(mp
, seqno
,
503 XFS_AGINO_TO_AGBNO(mp
, agino
)),
504 XFS_FSB_TO_BB(mp
, XFS_IALLOC_BLOCKS(mp
)),
506 if (iocur_top
->data
== NULL
) {
507 dbprintf("can't read inode block %u/%u\n",
508 seqno
, XFS_AGINO_TO_AGBNO(mp
, agino
));
511 for (j
= 0; j
< XFS_INODES_PER_CHUNK
; j
++) {
513 xfs_dinode_core_t tdic
;
515 dip
=(xfs_dinode_t
*)((char *)iocur_top
->data
+ ((off
+ j
) << mp
->m_sb
.sb_inodelog
));
517 /* convert the core, then copy it back into the inode */
518 libxfs_xlate_dinode_core( (xfs_caddr_t
)
519 &dip
->di_core
, &tdic
, 1, ARCH_CONVERT
);
520 memcpy(&dip
->di_core
, &tdic
, sizeof(xfs_dinode_core_t
));
522 if (XFS_INOBT_IS_FREE(&rp
[i
], j
, ARCH_CONVERT
))
524 process_inode(agf
, agino
+ j
,
525 (xfs_dinode_t
*)((char *)iocur_top
->data
+ ((off
+ j
) << mp
->m_sb
.sb_inodelog
)));
531 pp
= XFS_BTREE_PTR_ADDR(mp
->m_sb
.sb_blocksize
, xfs_inobt
, block
, 1,
533 for (i
= 0; i
< INT_GET(block
->bb_numrecs
, ARCH_CONVERT
); i
++)
534 scan_sbtree(agf
, INT_GET(pp
[i
], ARCH_CONVERT
), level
, scanfunc_ino
, TYP_INOBT
);