]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/frag.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
18 typedef struct extent
{
19 xfs_fileoff_t startoff
;
20 xfs_filblks_t blockcount
;
23 typedef struct extmap
{
28 #define EXTMAP_SIZE(n) \
29 (offsetof(extmap_t, ents) + (sizeof(extent_t) * (n)))
33 static uint64_t extcount_actual
;
34 static uint64_t extcount_ideal
;
42 typedef void (*scan_lbtree_f_t
)(struct xfs_btree_block
*block
,
47 typedef void (*scan_sbtree_f_t
)(struct xfs_btree_block
*block
,
51 static extmap_t
*extmap_alloc(xfs_extnum_t nex
);
52 static xfs_extnum_t
extmap_ideal(extmap_t
*extmap
);
53 static void extmap_set_ext(extmap_t
**extmapp
, xfs_fileoff_t o
,
55 static int frag_f(int argc
, char **argv
);
56 static int init(int argc
, char **argv
);
57 static void process_bmbt_reclist(xfs_bmbt_rec_t
*rp
, int numrecs
,
59 static void process_btinode(xfs_dinode_t
*dip
, extmap_t
**extmapp
,
61 static void process_exinode(xfs_dinode_t
*dip
, extmap_t
**extmapp
,
63 static void process_fork(xfs_dinode_t
*dip
, int whichfork
);
64 static void process_inode(xfs_agf_t
*agf
, xfs_agino_t agino
,
66 static void scan_ag(xfs_agnumber_t agno
);
67 static void scan_lbtree(xfs_fsblock_t root
, int nlevels
,
68 scan_lbtree_f_t func
, extmap_t
**extmapp
,
70 static void scan_sbtree(xfs_agf_t
*agf
, xfs_agblock_t root
,
71 int nlevels
, scan_sbtree_f_t func
,
73 static void scanfunc_bmap(struct xfs_btree_block
*block
, int level
,
74 extmap_t
**extmapp
, typnm_t btype
);
75 static void scanfunc_ino(struct xfs_btree_block
*block
, int level
,
78 static const cmdinfo_t frag_cmd
=
79 { "frag", NULL
, frag_f
, 0, -1, 0,
80 "[-a] [-d] [-f] [-l] [-q] [-R] [-r] [-v]",
81 "get file fragmentation data", NULL
};
91 extmap
= xmalloc(EXTMAP_SIZE(nex
));
104 for (ep
= &extmap
->ents
[0], rval
= 0;
105 ep
< &extmap
->ents
[extmap
->nents
];
107 if (ep
== &extmap
->ents
[0] ||
108 ep
->startoff
!= ep
[-1].startoff
+ ep
[-1].blockcount
)
124 if (extmap
->nents
== extmap
->naents
) {
126 extmap
= xrealloc(extmap
, EXTMAP_SIZE(extmap
->naents
));
129 ent
= &extmap
->ents
[extmap
->nents
];
138 add_command(&frag_cmd
);
142 * Get file fragmentation information.
152 if (!init(argc
, argv
))
154 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++)
157 answer
= (double)(extcount_actual
- extcount_ideal
) * 100.0 /
158 (double)extcount_actual
;
161 dbprintf(_("actual %llu, ideal %llu, fragmentation factor %.2f%%\n"),
162 extcount_actual
, extcount_ideal
, answer
);
163 dbprintf(_("Note, this number is largely meaningless.\n"));
164 answer
= (double)extcount_actual
/ (double)extcount_ideal
;
165 dbprintf(_("Files on this filesystem average %.2f extents per file\n"),
177 aflag
= dflag
= fflag
= lflag
= qflag
= Rflag
= rflag
= vflag
= 0;
179 while ((c
= getopt(argc
, argv
, "adflqRrv")) != EOF
) {
206 dbprintf(_("bad option for frag command\n"));
210 if (!aflag
&& !dflag
&& !fflag
&& !lflag
&& !qflag
&& !Rflag
&& !rflag
)
211 aflag
= dflag
= fflag
= lflag
= qflag
= Rflag
= rflag
= 1;
212 extcount_actual
= extcount_ideal
= 0;
217 process_bmbt_reclist(
228 for (i
= 0; i
< numrecs
; i
++, rp
++) {
229 convert_extent(rp
, &o
, &s
, &c
, &f
);
230 extmap_set_ext(extmapp
, (xfs_fileoff_t
)o
, (xfs_extlen_t
)c
);
240 xfs_bmdr_block_t
*dib
;
244 dib
= (xfs_bmdr_block_t
*)XFS_DFORK_PTR(dip
, whichfork
);
245 if (be16_to_cpu(dib
->bb_level
) == 0) {
246 xfs_bmbt_rec_t
*rp
= XFS_BMDR_REC_ADDR(dib
, 1);
247 process_bmbt_reclist(rp
, be16_to_cpu(dib
->bb_numrecs
), extmapp
);
250 pp
= XFS_BMDR_PTR_ADDR(dib
, 1,
251 libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip
, mp
, whichfork
), 0));
252 for (i
= 0; i
< be16_to_cpu(dib
->bb_numrecs
); i
++)
253 scan_lbtree(get_unaligned_be64(&pp
[i
]),
254 be16_to_cpu(dib
->bb_level
), scanfunc_bmap
, extmapp
,
255 whichfork
== XFS_DATA_FORK
? TYP_BMAPBTD
: TYP_BMAPBTA
);
266 rp
= (xfs_bmbt_rec_t
*)XFS_DFORK_PTR(dip
, whichfork
);
267 process_bmbt_reclist(rp
, XFS_DFORK_NEXTENTS(dip
, whichfork
), extmapp
);
278 nex
= XFS_DFORK_NEXTENTS(dip
, whichfork
);
281 extmap
= extmap_alloc(nex
);
282 switch (XFS_DFORK_FORMAT(dip
, whichfork
)) {
283 case XFS_DINODE_FMT_EXTENTS
:
284 process_exinode(dip
, &extmap
, whichfork
);
286 case XFS_DINODE_FMT_BTREE
:
287 process_btinode(dip
, &extmap
, whichfork
);
290 extcount_actual
+= extmap
->nents
;
291 extcount_ideal
+= extmap_ideal(extmap
);
307 ino
= XFS_AGINO_TO_INO(mp
, be32_to_cpu(agf
->agf_seqno
), agino
);
308 switch (be16_to_cpu(dip
->di_mode
) & S_IFMT
) {
313 if (!rflag
&& (be16_to_cpu(dip
->di_flags
) & XFS_DIFLAG_REALTIME
))
316 (ino
== mp
->m_sb
.sb_rbmino
||
317 ino
== mp
->m_sb
.sb_rsumino
))
320 (ino
== mp
->m_sb
.sb_uquotino
||
321 ino
== mp
->m_sb
.sb_gquotino
||
322 ino
== mp
->m_sb
.sb_pquotino
))
334 actual
= extcount_actual
;
335 ideal
= extcount_ideal
;
337 process_fork(dip
, XFS_DATA_FORK
);
338 skipa
= !aflag
|| !XFS_DFORK_Q(dip
);
340 process_fork(dip
, XFS_ATTR_FORK
);
341 if (vflag
&& (!skipd
|| !skipa
))
342 dbprintf(_("inode %lld actual %lld ideal %lld\n"),
343 ino
, extcount_actual
- actual
, extcount_ideal
- ideal
);
354 set_cur(&typtab
[TYP_AGF
],
355 XFS_AG_DADDR(mp
, agno
, XFS_AGF_DADDR(mp
)),
356 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
357 if ((agf
= iocur_top
->data
) == NULL
) {
358 dbprintf(_("can't read agf block for ag %u\n"), agno
);
363 set_cur(&typtab
[TYP_AGI
],
364 XFS_AG_DADDR(mp
, agno
, XFS_AGI_DADDR(mp
)),
365 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
366 if ((agi
= iocur_top
->data
) == NULL
) {
367 dbprintf(_("can't read agi block for ag %u\n"), agno
);
372 scan_sbtree(agf
, be32_to_cpu(agi
->agi_root
),
373 be32_to_cpu(agi
->agi_level
), scanfunc_ino
, TYP_INOBT
);
382 scan_lbtree_f_t func
,
387 set_cur(&typtab
[btype
], XFS_FSB_TO_DADDR(mp
, root
), blkbb
, DB_RING_IGN
,
389 if (iocur_top
->data
== NULL
) {
390 dbprintf(_("can't read btree block %u/%u\n"),
391 XFS_FSB_TO_AGNO(mp
, root
),
392 XFS_FSB_TO_AGBNO(mp
, root
));
395 (*func
)(iocur_top
->data
, nlevels
- 1, extmapp
, btype
);
404 scan_sbtree_f_t func
,
407 xfs_agnumber_t seqno
= be32_to_cpu(agf
->agf_seqno
);
410 set_cur(&typtab
[btype
], XFS_AGB_TO_DADDR(mp
, seqno
, root
),
411 blkbb
, DB_RING_IGN
, NULL
);
412 if (iocur_top
->data
== NULL
) {
413 dbprintf(_("can't read btree block %u/%u\n"), seqno
, root
);
416 (*func
)(iocur_top
->data
, nlevels
- 1, agf
);
422 struct xfs_btree_block
*block
,
432 nrecs
= be16_to_cpu(block
->bb_numrecs
);
435 if (nrecs
> mp
->m_bmap_dmxr
[0]) {
436 dbprintf(_("invalid numrecs (%u) in %s block\n"),
437 nrecs
, typtab
[btype
].name
);
440 rp
= XFS_BMBT_REC_ADDR(mp
, block
, 1);
441 process_bmbt_reclist(rp
, nrecs
, extmapp
);
445 if (nrecs
> mp
->m_bmap_dmxr
[1]) {
446 dbprintf(_("invalid numrecs (%u) in %s block\n"),
447 nrecs
, typtab
[btype
].name
);
450 pp
= XFS_BMBT_PTR_ADDR(mp
, block
, 1, mp
->m_bmap_dmxr
[0]);
451 for (i
= 0; i
< nrecs
; i
++)
452 scan_lbtree(be64_to_cpu(pp
[i
]), level
, scanfunc_bmap
, extmapp
,
458 struct xfs_btree_block
*block
,
463 xfs_agnumber_t seqno
= be32_to_cpu(agf
->agf_seqno
);
470 xfs_agblock_t end_agbno
;
471 struct xfs_dinode
*dip
;
476 if (xfs_sb_version_hassparseinodes(&mp
->m_sb
))
477 blks_per_buf
= mp
->m_blocks_per_cluster
;
479 blks_per_buf
= mp
->m_ialloc_blks
;
480 inodes_per_buf
= min(XFS_FSB_TO_INO(mp
, blks_per_buf
),
481 XFS_INODES_PER_CHUNK
);
484 rp
= XFS_INOBT_REC_ADDR(mp
, block
, 1);
485 for (i
= 0; i
< be16_to_cpu(block
->bb_numrecs
); i
++) {
486 agino
= be32_to_cpu(rp
[i
].ir_startino
);
487 agbno
= XFS_AGINO_TO_AGBNO(mp
, agino
);
488 off
= XFS_AGINO_TO_OFFSET(mp
, agino
);
489 end_agbno
= agbno
+ mp
->m_ialloc_blks
;
493 while (agbno
< end_agbno
&&
494 ioff
< XFS_INODES_PER_CHUNK
) {
495 if (xfs_inobt_is_sparse_disk(&rp
[i
], ioff
))
498 set_cur(&typtab
[TYP_INODE
],
499 XFS_AGB_TO_DADDR(mp
, seqno
, agbno
),
500 XFS_FSB_TO_BB(mp
, blks_per_buf
),
502 if (iocur_top
->data
== NULL
) {
503 dbprintf(_("can't read inode block %u/%u\n"),
508 for (j
= 0; j
< inodes_per_buf
; j
++) {
509 if (XFS_INOBT_IS_FREE_DISK(&rp
[i
], ioff
+ j
))
511 dip
= (xfs_dinode_t
*)((char *)iocur_top
->data
+
512 ((off
+ j
) << mp
->m_sb
.sb_inodelog
));
513 process_inode(agf
, agino
+ ioff
+ j
, dip
);
517 agbno
+= blks_per_buf
;
518 ioff
+= inodes_per_buf
;
524 pp
= XFS_INOBT_PTR_ADDR(mp
, block
, 1, mp
->m_inobt_mxr
[1]);
525 for (i
= 0; i
< be16_to_cpu(block
->bb_numrecs
); i
++)
526 scan_sbtree(agf
, be32_to_cpu(pp
[i
]), level
, scanfunc_ino
,