2 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
33 " If the cursor points to a btree block, 'btdump' dumps the btree\n"
34 " downward from that block. If the cursor points to an inode,\n"
35 " the data fork btree root is selected by default. If the cursor\n"
36 " points to a directory or extended attribute btree node, the tree\n"
37 " will be printed downward from that block.\n"
40 " -a -- Display an inode's extended attribute fork btree.\n"
41 " -i -- Print internal btree nodes.\n"
58 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
61 v
= breakline(buf
, &c
);
69 struct xfs_btree_block
*block
,
73 return block
->bb_u
.l
.bb_rightsib
!= cpu_to_be64(NULLFSBLOCK
);
74 return block
->bb_u
.s
.bb_rightsib
!= cpu_to_be32(NULLAGBLOCK
);
82 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
83 xfs_daddr_t last_daddr
;
87 push_cur_and_set_type();
91 last_daddr
= iocur_top
->bb
;
92 dbprintf(_("%s level %u block %u daddr %llu\n"),
93 iocur_top
->typ
->name
, level
, nr
, last_daddr
);
95 ret
= eval("print keys");
98 ret
= eval("print ptrs");
100 ret
= eval("print recs");
104 if (btblock_has_rightsib(iocur_top
->data
, long_format
)) {
105 ret
= eval("addr rightsib");
110 } while (iocur_top
->bb
!= orig_daddr
&& iocur_top
->bb
!= last_daddr
);
119 bool dump_node_blocks
,
122 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
123 xfs_daddr_t last_daddr
;
127 push_cur_and_set_type();
129 cur_agno
= XFS_FSB_TO_AGNO(mp
, XFS_DADDR_TO_FSB(mp
, iocur_top
->bb
));
130 level
= xfs_btree_get_level(iocur_top
->data
);
132 last_daddr
= iocur_top
->bb
;
134 if (dump_node_blocks
) {
135 ret
= dump_btlevel(level
, long_format
);
139 ret
= eval("addr ptrs[1]");
141 ret
= dump_btlevel(level
, long_format
);
146 } while (level
>= 0 &&
147 iocur_top
->bb
!= orig_daddr
&&
148 iocur_top
->bb
!= last_daddr
);
155 static inline int dump_btree_short(bool dump_node_blocks
)
157 return dump_btree(dump_node_blocks
, false);
160 static inline int dump_btree_long(bool dump_node_blocks
)
162 return dump_btree(dump_node_blocks
, true);
167 bool dump_node_blocks
,
171 struct xfs_dinode
*dip
;
176 else if (xfs_sb_version_hascrc(&mp
->m_sb
))
181 dip
= iocur_top
->data
;
183 if (!dip
->di_anextents
||
184 dip
->di_aformat
!= XFS_DINODE_FMT_BTREE
) {
185 dbprintf(_("attr fork not in btree format\n"));
189 if (!dip
->di_nextents
||
190 dip
->di_format
!= XFS_DINODE_FMT_BTREE
) {
191 dbprintf(_("data fork not in btree format\n"));
196 push_cur_and_set_type();
198 if (dump_node_blocks
) {
199 ret
= eval("print %s.keys", prefix
);
202 ret
= eval("print %s.ptrs", prefix
);
207 ret
= eval("addr %s.ptrs[1]", prefix
);
211 ret
= dump_btree_long(dump_node_blocks
);
225 struct xfs_dir3_icleaf_hdr lhdr
;
226 struct xfs_da3_icnode_hdr nhdr
;
229 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
230 return nhdr
.forw
!= 0;
232 M_DIROPS(mp
)->leaf_hdr_from_disk(&lhdr
, block
);
233 return lhdr
.forw
!= 0;
240 struct xfs_dir3_icleaf_hdr lhdr
;
241 struct xfs_da3_icnode_hdr nhdr
;
243 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
244 case cpu_to_be16(XFS_DIR2_LEAF1_MAGIC
):
245 case cpu_to_be16(XFS_DIR2_LEAFN_MAGIC
):
246 M_DIROPS(mp
)->leaf_hdr_from_disk(&lhdr
, block
);
248 case cpu_to_be16(XFS_DA_NODE_MAGIC
):
249 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
260 struct xfs_dir3_icleaf_hdr lhdr
;
261 struct xfs_da3_icnode_hdr nhdr
;
263 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
264 case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC
):
265 case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC
):
266 M_DIROPS(mp
)->leaf_hdr_from_disk(&lhdr
, block
);
268 case cpu_to_be16(XFS_DA3_NODE_MAGIC
):
269 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
281 struct xfs_attr_leafblock lhdr
;
282 struct xfs_da3_icnode_hdr nhdr
;
285 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
286 return nhdr
.forw
!= 0;
288 xfs_attr3_leaf_hdr_to_disk(mp
->m_attr_geo
, &lhdr
, block
);
289 return lhdr
.hdr
.info
.forw
!= 0;
296 struct xfs_attr_leafblock lhdr
;
297 struct xfs_da3_icnode_hdr nhdr
;
299 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
300 case cpu_to_be16(XFS_ATTR_LEAF_MAGIC
):
301 xfs_attr3_leaf_hdr_to_disk(mp
->m_attr_geo
, &lhdr
, block
);
303 case cpu_to_be16(XFS_DA_NODE_MAGIC
):
304 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
315 struct xfs_attr_leafblock lhdr
;
316 struct xfs_da3_icnode_hdr nhdr
;
318 switch (((struct xfs_da_intnode
*)block
)->hdr
.info
.magic
) {
319 case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC
):
320 xfs_attr3_leaf_hdr_to_disk(mp
->m_attr_geo
, &lhdr
, block
);
322 case cpu_to_be16(XFS_DA3_NODE_MAGIC
):
323 M_DIROPS(mp
)->node_hdr_from_disk(&nhdr
, block
);
330 struct dabprinter_ops
{
331 const char *print_node_entries
;
332 const char *print_leaf_entries
;
333 const char *go_node_forward
;
334 const char *go_leaf_forward
;
336 bool (*has_rightsib
)(void *, int);
337 int (*level
)(void *);
340 static struct dabprinter_ops attr_print
= {
341 .print_node_entries
= "btree",
342 .print_leaf_entries
= "entries nvlist",
343 .go_node_forward
= "hdr.info.forw",
344 .go_leaf_forward
= "hdr.info.forw",
345 .go_down
= "btree[0].before",
346 .has_rightsib
= attr_has_rightsib
,
350 static struct dabprinter_ops attr3_print
= {
351 .print_node_entries
= "btree",
352 .print_leaf_entries
= "entries nvlist",
353 .go_node_forward
= "hdr.info.hdr.forw",
354 .go_leaf_forward
= "hdr.info.hdr.forw",
355 .go_down
= "btree[0].before",
356 .has_rightsib
= attr_has_rightsib
,
357 .level
= attr3_level
,
360 static struct dabprinter_ops dir_print
= {
361 .print_node_entries
= "nbtree",
362 .print_leaf_entries
= "lents",
363 .go_node_forward
= "nhdr.info.hdr.forw",
364 .go_leaf_forward
= "lhdr.info.hdr.forw",
365 .go_down
= "nbtree[0].before",
366 .has_rightsib
= dir_has_rightsib
,
370 static struct dabprinter_ops dir3_print
= {
371 .print_node_entries
= "nbtree",
372 .print_leaf_entries
= "lents",
373 .go_node_forward
= "nhdr.info.forw",
374 .go_leaf_forward
= "lhdr.info.forw",
375 .go_down
= "nbtree[0].before",
376 .has_rightsib
= dir_has_rightsib
,
383 struct dabprinter_ops
*dbp
)
385 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
386 xfs_daddr_t last_daddr
;
390 push_cur_and_set_type();
394 last_daddr
= iocur_top
->bb
;
395 dbprintf(_("%s level %u block %u daddr %llu\n"),
396 iocur_top
->typ
->name
, level
, nr
, last_daddr
);
397 ret
= eval("print %s", level
> 0 ? dbp
->print_node_entries
:
398 dbp
->print_leaf_entries
);
401 if (dbp
->has_rightsib(iocur_top
->data
, level
)) {
402 ret
= eval("addr %s", level
> 0 ? dbp
->go_node_forward
:
403 dbp
->go_leaf_forward
);
408 } while (iocur_top
->bb
!= orig_daddr
&& iocur_top
->bb
!= last_daddr
);
417 bool dump_node_blocks
,
418 struct dabprinter_ops
*dbp
)
420 xfs_daddr_t orig_daddr
= iocur_top
->bb
;
421 xfs_daddr_t last_daddr
;
425 push_cur_and_set_type();
427 cur_agno
= XFS_FSB_TO_AGNO(mp
, XFS_DADDR_TO_FSB(mp
, iocur_top
->bb
));
428 level
= dbp
->level(iocur_top
->data
);
430 printf(_("Current location is not part of a dir/attr btree.\n"));
435 last_daddr
= iocur_top
->bb
;
437 if (dump_node_blocks
) {
438 ret
= dump_dablevel(level
, dbp
);
442 ret
= eval("addr %s", dbp
->go_down
);
444 ret
= dump_dablevel(level
, dbp
);
449 } while (level
>= 0 &&
450 iocur_top
->bb
!= orig_daddr
&&
451 iocur_top
->bb
!= last_daddr
);
465 bool crc
= xfs_sb_version_hascrc(&mp
->m_sb
);
468 if (cur_typ
== NULL
) {
469 dbprintf(_("no current type\n"));
472 while ((c
= getopt(argc
, argv
, "ai")) != EOF
) {
481 dbprintf(_("bad option for btdump command\n"));
486 if (optind
!= argc
) {
487 dbprintf(_("bad options for btdump command\n"));
490 if (aflag
&& cur_typ
->typnm
!= TYP_INODE
) {
491 dbprintf(_("attrfork flag doesn't apply here\n"));
495 switch (cur_typ
->typnm
) {
502 return dump_btree_short(iflag
);
505 return dump_btree_long(iflag
);
507 return dump_inode(iflag
, aflag
);
509 return dump_dabtree(iflag
, crc
? &attr3_print
: &attr_print
);
511 return dump_dabtree(iflag
, crc
? &dir3_print
: &dir_print
);
513 dbprintf(_("type \"%s\" is not a btree type or inode\n"),
519 static const cmdinfo_t btdump_cmd
=
520 { "btdump", "b", btdump_f
, 0, 2, 0, "[-a] [-i]",
521 N_("dump btree"), btdump_help
};
526 add_command(&btdump_cmd
);