1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
19 " If the cursor points to a btree block, 'btdump' dumps the btree\n"
20 " downward from that block. If the cursor points to an inode,\n"
21 " the data fork btree root is selected by default. If the cursor\n"
22 " points to a directory or extended attribute btree node, the tree\n"
23 " will be printed downward from that block.\n"
26 " -a -- Display an inode's extended attribute fork btree.\n"
27 " -i -- Print internal btree nodes.\n"
44 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
47 v
= breakline(buf
, &c
);
55 struct xfs_btree_block
*block
,
59 return block
->bb_u
.l
.bb_rightsib
!= cpu_to_be64(NULLFSBLOCK
);
60 return block
->bb_u
.s
.bb_rightsib
!= cpu_to_be32(NULLAGBLOCK
);
68 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
69 xfs_daddr_t last_daddr
;
73 push_cur_and_set_type();
77 last_daddr
= iocur_top
->bb
;
78 dbprintf(_("%s level %u block %u daddr %llu\n"),
79 iocur_top
->typ
->name
, level
, nr
, last_daddr
);
81 ret
= eval("print keys");
84 ret
= eval("print ptrs");
86 ret
= eval("print recs");
90 if (btblock_has_rightsib(iocur_top
->data
, long_format
)) {
91 ret
= eval("addr rightsib");
96 } while (iocur_top
->bb
!= orig_daddr
&& iocur_top
->bb
!= last_daddr
);
105 bool dump_node_blocks
,
108 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
109 xfs_daddr_t last_daddr
;
113 push_cur_and_set_type();
115 cur_agno
= XFS_FSB_TO_AGNO(mp
, XFS_DADDR_TO_FSB(mp
, iocur_top
->bb
));
116 level
= xfs_btree_get_level(iocur_top
->data
);
118 last_daddr
= iocur_top
->bb
;
120 if (dump_node_blocks
) {
121 ret
= dump_btlevel(level
, long_format
);
125 ret
= eval("addr ptrs[1]");
127 ret
= dump_btlevel(level
, long_format
);
132 } while (level
>= 0 &&
133 iocur_top
->bb
!= orig_daddr
&&
134 iocur_top
->bb
!= last_daddr
);
141 static inline int dump_btree_short(bool dump_node_blocks
)
143 return dump_btree(dump_node_blocks
, false);
146 static inline int dump_btree_long(bool dump_node_blocks
)
148 return dump_btree(dump_node_blocks
, true);
153 bool dump_node_blocks
,
157 struct xfs_dinode
*dip
;
162 else if (xfs_sb_version_hascrc(&mp
->m_sb
))
167 dip
= iocur_top
->data
;
169 if (!dip
->di_anextents
||
170 dip
->di_aformat
!= XFS_DINODE_FMT_BTREE
) {
171 dbprintf(_("attr fork not in btree format\n"));
175 if (!dip
->di_nextents
||
176 dip
->di_format
!= XFS_DINODE_FMT_BTREE
) {
177 dbprintf(_("data fork not in btree format\n"));
182 push_cur_and_set_type();
184 if (dump_node_blocks
) {
185 ret
= eval("print %s.keys", prefix
);
188 ret
= eval("print %s.ptrs", prefix
);
193 ret
= eval("addr %s.ptrs[1]", prefix
);
197 ret
= dump_btree_long(dump_node_blocks
);
211 struct xfs_dir3_icleaf_hdr lhdr
;
212 struct xfs_da3_icnode_hdr nhdr
;
215 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
216 return nhdr
.forw
!= 0;
218 M_DIROPS(mp
)->leaf_hdr_from_disk(&lhdr
, block
);
219 return lhdr
.forw
!= 0;
226 struct xfs_dir3_icleaf_hdr lhdr
;
227 struct xfs_da3_icnode_hdr nhdr
;
229 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
230 case cpu_to_be16(XFS_DIR2_LEAF1_MAGIC
):
231 case cpu_to_be16(XFS_DIR2_LEAFN_MAGIC
):
232 M_DIROPS(mp
)->leaf_hdr_from_disk(&lhdr
, block
);
234 case cpu_to_be16(XFS_DA_NODE_MAGIC
):
235 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
246 struct xfs_dir3_icleaf_hdr lhdr
;
247 struct xfs_da3_icnode_hdr nhdr
;
249 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
250 case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC
):
251 case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC
):
252 M_DIROPS(mp
)->leaf_hdr_from_disk(&lhdr
, block
);
254 case cpu_to_be16(XFS_DA3_NODE_MAGIC
):
255 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
267 struct xfs_attr_leafblock lhdr
;
268 struct xfs_da3_icnode_hdr nhdr
;
271 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
272 return nhdr
.forw
!= 0;
274 xfs_attr3_leaf_hdr_to_disk(mp
->m_attr_geo
, &lhdr
, block
);
275 return lhdr
.hdr
.info
.forw
!= 0;
282 struct xfs_attr_leafblock lhdr
;
283 struct xfs_da3_icnode_hdr nhdr
;
285 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
286 case cpu_to_be16(XFS_ATTR_LEAF_MAGIC
):
287 xfs_attr3_leaf_hdr_to_disk(mp
->m_attr_geo
, &lhdr
, block
);
289 case cpu_to_be16(XFS_DA_NODE_MAGIC
):
290 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
301 struct xfs_attr_leafblock lhdr
;
302 struct xfs_da3_icnode_hdr nhdr
;
304 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
305 case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC
):
306 xfs_attr3_leaf_hdr_to_disk(mp
->m_attr_geo
, &lhdr
, block
);
308 case cpu_to_be16(XFS_DA3_NODE_MAGIC
):
309 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
316 struct dabprinter_ops
{
317 const char *print_node_entries
;
318 const char *print_leaf_entries
;
319 const char *go_node_forward
;
320 const char *go_leaf_forward
;
322 bool (*has_rightsib
)(void *, int);
323 int (*level
)(void *);
326 static struct dabprinter_ops attr_print
= {
327 .print_node_entries
= "btree",
328 .print_leaf_entries
= "entries nvlist",
329 .go_node_forward
= "hdr.info.forw",
330 .go_leaf_forward
= "hdr.info.forw",
331 .go_down
= "btree[0].before",
332 .has_rightsib
= attr_has_rightsib
,
336 static struct dabprinter_ops attr3_print
= {
337 .print_node_entries
= "btree",
338 .print_leaf_entries
= "entries nvlist",
339 .go_node_forward
= "hdr.info.hdr.forw",
340 .go_leaf_forward
= "hdr.info.hdr.forw",
341 .go_down
= "btree[0].before",
342 .has_rightsib
= attr_has_rightsib
,
343 .level
= attr3_level
,
346 static struct dabprinter_ops dir_print
= {
347 .print_node_entries
= "nbtree",
348 .print_leaf_entries
= "lents",
349 .go_node_forward
= "nhdr.info.hdr.forw",
350 .go_leaf_forward
= "lhdr.info.hdr.forw",
351 .go_down
= "nbtree[0].before",
352 .has_rightsib
= dir_has_rightsib
,
356 static struct dabprinter_ops dir3_print
= {
357 .print_node_entries
= "nbtree",
358 .print_leaf_entries
= "lents",
359 .go_node_forward
= "nhdr.info.forw",
360 .go_leaf_forward
= "lhdr.info.forw",
361 .go_down
= "nbtree[0].before",
362 .has_rightsib
= dir_has_rightsib
,
369 struct dabprinter_ops
*dbp
)
371 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
372 xfs_daddr_t last_daddr
;
376 push_cur_and_set_type();
380 last_daddr
= iocur_top
->bb
;
381 dbprintf(_("%s level %u block %u daddr %llu\n"),
382 iocur_top
->typ
->name
, level
, nr
, last_daddr
);
383 ret
= eval("print %s", level
> 0 ? dbp
->print_node_entries
:
384 dbp
->print_leaf_entries
);
387 if (dbp
->has_rightsib(iocur_top
->data
, level
)) {
388 ret
= eval("addr %s", level
> 0 ? dbp
->go_node_forward
:
389 dbp
->go_leaf_forward
);
394 } while (iocur_top
->bb
!= orig_daddr
&& iocur_top
->bb
!= last_daddr
);
403 bool dump_node_blocks
,
404 struct dabprinter_ops
*dbp
)
406 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
407 xfs_daddr_t last_daddr
;
411 push_cur_and_set_type();
413 cur_agno
= XFS_FSB_TO_AGNO(mp
, XFS_DADDR_TO_FSB(mp
, iocur_top
->bb
));
414 level
= dbp
->level(iocur_top
->data
);
416 printf(_("Current location is not part of a dir/attr btree.\n"));
421 last_daddr
= iocur_top
->bb
;
423 if (dump_node_blocks
) {
424 ret
= dump_dablevel(level
, dbp
);
428 ret
= eval("addr %s", dbp
->go_down
);
430 ret
= dump_dablevel(level
, dbp
);
435 } while (level
>= 0 &&
436 iocur_top
->bb
!= orig_daddr
&&
437 iocur_top
->bb
!= last_daddr
);
451 bool crc
= xfs_sb_version_hascrc(&mp
->m_sb
);
454 if (cur_typ
== NULL
) {
455 dbprintf(_("no current type\n"));
458 while ((c
= getopt(argc
, argv
, "ai")) != EOF
) {
467 dbprintf(_("bad option for btdump command\n"));
472 if (optind
!= argc
) {
473 dbprintf(_("bad options for btdump command\n"));
476 if (aflag
&& cur_typ
->typnm
!= TYP_INODE
) {
477 dbprintf(_("attrfork flag doesn't apply here\n"));
481 switch (cur_typ
->typnm
) {
488 return dump_btree_short(iflag
);
491 return dump_btree_long(iflag
);
493 return dump_inode(iflag
, aflag
);
495 return dump_dabtree(iflag
, crc
? &attr3_print
: &attr_print
);
497 return dump_dabtree(iflag
, crc
? &dir3_print
: &dir_print
);
499 dbprintf(_("type \"%s\" is not a btree type or inode\n"),
505 static const cmdinfo_t btdump_cmd
=
506 { "btdump", "b", btdump_f
, 0, 2, 0, "[-a] [-i]",
507 N_("dump btree"), btdump_help
};
512 add_command(&btdump_cmd
);