]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/frag.c
2 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
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.
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.
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
30 typedef struct extent
{
31 xfs_fileoff_t startoff
;
32 xfs_filblks_t blockcount
;
35 typedef struct extmap
{
40 #define EXTMAP_SIZE(n) \
41 (offsetof(extmap_t, ents) + (sizeof(extent_t) * (n)))
45 static uint64_t extcount_actual
;
46 static uint64_t extcount_ideal
;
54 typedef void (*scan_lbtree_f_t
)(struct xfs_btree_block
*block
,
59 typedef void (*scan_sbtree_f_t
)(struct xfs_btree_block
*block
,
63 static extmap_t
*extmap_alloc(xfs_extnum_t nex
);
64 static xfs_extnum_t
extmap_ideal(extmap_t
*extmap
);
65 static void extmap_set_ext(extmap_t
**extmapp
, xfs_fileoff_t o
,
67 static int frag_f(int argc
, char **argv
);
68 static int init(int argc
, char **argv
);
69 static void process_bmbt_reclist(xfs_bmbt_rec_t
*rp
, int numrecs
,
71 static void process_btinode(xfs_dinode_t
*dip
, extmap_t
**extmapp
,
73 static void process_exinode(xfs_dinode_t
*dip
, extmap_t
**extmapp
,
75 static void process_fork(xfs_dinode_t
*dip
, int whichfork
);
76 static void process_inode(xfs_agf_t
*agf
, xfs_agino_t agino
,
78 static void scan_ag(xfs_agnumber_t agno
);
79 static void scan_lbtree(xfs_fsblock_t root
, int nlevels
,
80 scan_lbtree_f_t func
, extmap_t
**extmapp
,
82 static void scan_sbtree(xfs_agf_t
*agf
, xfs_agblock_t root
,
83 int nlevels
, scan_sbtree_f_t func
,
85 static void scanfunc_bmap(struct xfs_btree_block
*block
, int level
,
86 extmap_t
**extmapp
, typnm_t btype
);
87 static void scanfunc_ino(struct xfs_btree_block
*block
, int level
,
90 static const cmdinfo_t frag_cmd
=
91 { "frag", NULL
, frag_f
, 0, -1, 0,
92 "[-a] [-d] [-f] [-l] [-q] [-R] [-r] [-v]",
93 "get file fragmentation data", NULL
};
103 extmap
= xmalloc(EXTMAP_SIZE(nex
));
104 extmap
->naents
= nex
;
116 for (ep
= &extmap
->ents
[0], rval
= 0;
117 ep
< &extmap
->ents
[extmap
->nents
];
119 if (ep
== &extmap
->ents
[0] ||
120 ep
->startoff
!= ep
[-1].startoff
+ ep
[-1].blockcount
)
136 if (extmap
->nents
== extmap
->naents
) {
138 extmap
= xrealloc(extmap
, EXTMAP_SIZE(extmap
->naents
));
141 ent
= &extmap
->ents
[extmap
->nents
];
150 add_command(&frag_cmd
);
154 * Get file fragmentation information.
164 if (!init(argc
, argv
))
166 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++)
169 answer
= (double)(extcount_actual
- extcount_ideal
) * 100.0 /
170 (double)extcount_actual
;
173 dbprintf(_("actual %llu, ideal %llu, fragmentation factor %.2f%%\n"),
174 extcount_actual
, extcount_ideal
, answer
);
175 dbprintf(_("Note, this number is largely meaningless.\n"));
176 answer
= (double)extcount_actual
/ (double)extcount_ideal
;
177 dbprintf(_("Files on this filesystem average %.2f extents per file\n"),
189 aflag
= dflag
= fflag
= lflag
= qflag
= Rflag
= rflag
= vflag
= 0;
191 while ((c
= getopt(argc
, argv
, "adflqRrv")) != EOF
) {
218 dbprintf(_("bad option for frag command\n"));
222 if (!aflag
&& !dflag
&& !fflag
&& !lflag
&& !qflag
&& !Rflag
&& !rflag
)
223 aflag
= dflag
= fflag
= lflag
= qflag
= Rflag
= rflag
= 1;
224 extcount_actual
= extcount_ideal
= 0;
229 process_bmbt_reclist(
240 for (i
= 0; i
< numrecs
; i
++, rp
++) {
241 convert_extent(rp
, &o
, &s
, &c
, &f
);
242 extmap_set_ext(extmapp
, (xfs_fileoff_t
)o
, (xfs_extlen_t
)c
);
252 xfs_bmdr_block_t
*dib
;
256 dib
= (xfs_bmdr_block_t
*)XFS_DFORK_PTR(dip
, whichfork
);
257 if (be16_to_cpu(dib
->bb_level
) == 0) {
258 xfs_bmbt_rec_t
*rp
= XFS_BMDR_REC_ADDR(dib
, 1);
259 process_bmbt_reclist(rp
, be16_to_cpu(dib
->bb_numrecs
), extmapp
);
262 pp
= XFS_BMDR_PTR_ADDR(dib
, 1,
263 libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip
, mp
, whichfork
), 0));
264 for (i
= 0; i
< be16_to_cpu(dib
->bb_numrecs
); i
++)
265 scan_lbtree(get_unaligned_be64(&pp
[i
]),
266 be16_to_cpu(dib
->bb_level
), scanfunc_bmap
, extmapp
,
267 whichfork
== XFS_DATA_FORK
? TYP_BMAPBTD
: TYP_BMAPBTA
);
278 rp
= (xfs_bmbt_rec_t
*)XFS_DFORK_PTR(dip
, whichfork
);
279 process_bmbt_reclist(rp
, XFS_DFORK_NEXTENTS(dip
, whichfork
), extmapp
);
290 nex
= XFS_DFORK_NEXTENTS(dip
, whichfork
);
293 extmap
= extmap_alloc(nex
);
294 switch (XFS_DFORK_FORMAT(dip
, whichfork
)) {
295 case XFS_DINODE_FMT_EXTENTS
:
296 process_exinode(dip
, &extmap
, whichfork
);
298 case XFS_DINODE_FMT_BTREE
:
299 process_btinode(dip
, &extmap
, whichfork
);
302 extcount_actual
+= extmap
->nents
;
303 extcount_ideal
+= extmap_ideal(extmap
);
319 ino
= XFS_AGINO_TO_INO(mp
, be32_to_cpu(agf
->agf_seqno
), agino
);
320 switch (be16_to_cpu(dip
->di_mode
) & S_IFMT
) {
325 if (!rflag
&& (be16_to_cpu(dip
->di_flags
) & XFS_DIFLAG_REALTIME
))
328 (ino
== mp
->m_sb
.sb_rbmino
||
329 ino
== mp
->m_sb
.sb_rsumino
))
332 (ino
== mp
->m_sb
.sb_uquotino
||
333 ino
== mp
->m_sb
.sb_gquotino
||
334 ino
== mp
->m_sb
.sb_pquotino
))
346 actual
= extcount_actual
;
347 ideal
= extcount_ideal
;
349 process_fork(dip
, XFS_DATA_FORK
);
350 skipa
= !aflag
|| !XFS_DFORK_Q(dip
);
352 process_fork(dip
, XFS_ATTR_FORK
);
353 if (vflag
&& (!skipd
|| !skipa
))
354 dbprintf(_("inode %lld actual %lld ideal %lld\n"),
355 ino
, extcount_actual
- actual
, extcount_ideal
- ideal
);
366 set_cur(&typtab
[TYP_AGF
],
367 XFS_AG_DADDR(mp
, agno
, XFS_AGF_DADDR(mp
)),
368 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
369 if ((agf
= iocur_top
->data
) == NULL
) {
370 dbprintf(_("can't read agf block for ag %u\n"), agno
);
375 set_cur(&typtab
[TYP_AGI
],
376 XFS_AG_DADDR(mp
, agno
, XFS_AGI_DADDR(mp
)),
377 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
378 if ((agi
= iocur_top
->data
) == NULL
) {
379 dbprintf(_("can't read agi block for ag %u\n"), agno
);
384 scan_sbtree(agf
, be32_to_cpu(agi
->agi_root
),
385 be32_to_cpu(agi
->agi_level
), scanfunc_ino
, TYP_INOBT
);
394 scan_lbtree_f_t func
,
399 set_cur(&typtab
[btype
], XFS_FSB_TO_DADDR(mp
, root
), blkbb
, DB_RING_IGN
,
401 if (iocur_top
->data
== NULL
) {
402 dbprintf(_("can't read btree block %u/%u\n"),
403 XFS_FSB_TO_AGNO(mp
, root
),
404 XFS_FSB_TO_AGBNO(mp
, root
));
407 (*func
)(iocur_top
->data
, nlevels
- 1, extmapp
, btype
);
416 scan_sbtree_f_t func
,
419 xfs_agnumber_t seqno
= be32_to_cpu(agf
->agf_seqno
);
422 set_cur(&typtab
[btype
], XFS_AGB_TO_DADDR(mp
, seqno
, root
),
423 blkbb
, DB_RING_IGN
, NULL
);
424 if (iocur_top
->data
== NULL
) {
425 dbprintf(_("can't read btree block %u/%u\n"), seqno
, root
);
428 (*func
)(iocur_top
->data
, nlevels
- 1, agf
);
434 struct xfs_btree_block
*block
,
444 nrecs
= be16_to_cpu(block
->bb_numrecs
);
447 if (nrecs
> mp
->m_bmap_dmxr
[0]) {
448 dbprintf(_("invalid numrecs (%u) in %s block\n"),
449 nrecs
, typtab
[btype
].name
);
452 rp
= XFS_BMBT_REC_ADDR(mp
, block
, 1);
453 process_bmbt_reclist(rp
, nrecs
, extmapp
);
457 if (nrecs
> mp
->m_bmap_dmxr
[1]) {
458 dbprintf(_("invalid numrecs (%u) in %s block\n"),
459 nrecs
, typtab
[btype
].name
);
462 pp
= XFS_BMBT_PTR_ADDR(mp
, block
, 1, mp
->m_bmap_dmxr
[0]);
463 for (i
= 0; i
< nrecs
; i
++)
464 scan_lbtree(be64_to_cpu(pp
[i
]), level
, scanfunc_bmap
, extmapp
,
470 struct xfs_btree_block
*block
,
475 xfs_agnumber_t seqno
= be32_to_cpu(agf
->agf_seqno
);
483 rp
= XFS_INOBT_REC_ADDR(mp
, block
, 1);
484 for (i
= 0; i
< be16_to_cpu(block
->bb_numrecs
); i
++) {
485 agino
= be32_to_cpu(rp
[i
].ir_startino
);
486 off
= XFS_INO_TO_OFFSET(mp
, agino
);
488 set_cur(&typtab
[TYP_INODE
],
489 XFS_AGB_TO_DADDR(mp
, seqno
,
490 XFS_AGINO_TO_AGBNO(mp
, agino
)),
491 XFS_FSB_TO_BB(mp
, mp
->m_ialloc_blks
),
493 if (iocur_top
->data
== NULL
) {
494 dbprintf(_("can't read inode block %u/%u\n"),
495 seqno
, XFS_AGINO_TO_AGBNO(mp
, agino
));
498 for (j
= 0; j
< XFS_INODES_PER_CHUNK
; j
++) {
499 if (XFS_INOBT_IS_FREE_DISK(&rp
[i
], j
))
501 process_inode(agf
, agino
+ j
, (xfs_dinode_t
*)
502 ((char *)iocur_top
->data
+
503 ((off
+ j
) << mp
->m_sb
.sb_inodelog
)));
509 pp
= XFS_INOBT_PTR_ADDR(mp
, block
, 1, mp
->m_inobt_mxr
[1]);
510 for (i
= 0; i
< be16_to_cpu(block
->bb_numrecs
); i
++)
511 scan_sbtree(agf
, be32_to_cpu(pp
[i
]), level
, scanfunc_ino
,