2 * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Some code is based on work previously done by Marcus Overhagen.
5 * This file may be used under the terms of the MIT License.
10 #include "BlockAllocator.h"
11 #include "BPlusTree.h"
19 static unsigned char tupel
[5];
21 tupel
[0] = 0xff & (id
>> 24);
22 tupel
[1] = 0xff & (id
>> 16);
23 tupel
[2] = 0xff & (id
>> 8);
24 tupel
[3] = 0xff & (id
);
26 for (int16 i
= 0;i
< 4;i
++) {
27 if (tupel
[i
] < ' ' || tupel
[i
] > 128)
36 dump_block_run(const char* prefix
, const block_run
& run
)
38 kprintf("%s(%d, %d, %d)\n", prefix
, (int)run
.allocation_group
, run
.start
,
44 dump_super_block(const disk_super_block
* superBlock
)
46 kprintf("disk_super_block:\n");
47 kprintf(" name = %s\n", superBlock
->name
);
48 kprintf(" magic1 = %#08x (%s) %s\n", (int)superBlock
->Magic1(),
49 get_tupel(superBlock
->magic1
),
50 (superBlock
->magic1
== SUPER_BLOCK_MAGIC1
? "valid" : "INVALID"));
51 kprintf(" fs_byte_order = %#08x (%s)\n", (int)superBlock
->fs_byte_order
,
52 get_tupel(superBlock
->fs_byte_order
));
53 kprintf(" block_size = %u\n", (unsigned)superBlock
->BlockSize());
54 kprintf(" block_shift = %u\n", (unsigned)superBlock
->BlockShift());
55 kprintf(" num_blocks = %" B_PRIdOFF
"\n", superBlock
->NumBlocks());
56 kprintf(" used_blocks = %" B_PRIdOFF
"\n", superBlock
->UsedBlocks());
57 kprintf(" inode_size = %u\n", (unsigned)superBlock
->InodeSize());
58 kprintf(" magic2 = %#08x (%s) %s\n", (int)superBlock
->Magic2(),
59 get_tupel(superBlock
->magic2
),
60 (superBlock
->magic2
== (int)SUPER_BLOCK_MAGIC2
? "valid" : "INVALID"));
61 kprintf(" blocks_per_ag = %u\n",
62 (unsigned)superBlock
->BlocksPerAllocationGroup());
63 kprintf(" ag_shift = %u (%ld bytes)\n",
64 (unsigned)superBlock
->AllocationGroupShift(),
65 1L << superBlock
->AllocationGroupShift());
66 kprintf(" num_ags = %u\n", (unsigned)superBlock
->AllocationGroups());
67 kprintf(" flags = %#08x (%s)\n", (int)superBlock
->Flags(),
68 get_tupel(superBlock
->Flags()));
69 dump_block_run(" log_blocks = ", superBlock
->log_blocks
);
70 kprintf(" log_start = %" B_PRIdOFF
"\n", superBlock
->LogStart());
71 kprintf(" log_end = %" B_PRIdOFF
"\n", superBlock
->LogEnd());
72 kprintf(" magic3 = %#08x (%s) %s\n", (int)superBlock
->Magic3(),
73 get_tupel(superBlock
->magic3
),
74 (superBlock
->magic3
== SUPER_BLOCK_MAGIC3
? "valid" : "INVALID"));
75 dump_block_run(" root_dir = ", superBlock
->root_dir
);
76 dump_block_run(" indices = ", superBlock
->indices
);
81 dump_data_stream(const data_stream
* stream
)
83 kprintf("data_stream:\n");
84 for (int i
= 0; i
< NUM_DIRECT_BLOCKS
; i
++) {
85 if (!stream
->direct
[i
].IsZero()) {
86 kprintf(" direct[%02d] = ", i
);
87 dump_block_run("", stream
->direct
[i
]);
90 kprintf(" max_direct_range = %" B_PRIdOFF
"\n",
91 stream
->MaxDirectRange());
93 if (!stream
->indirect
.IsZero())
94 dump_block_run(" indirect = ", stream
->indirect
);
96 kprintf(" max_indirect_range = %" B_PRIdOFF
"\n",
97 stream
->MaxIndirectRange());
99 if (!stream
->double_indirect
.IsZero()) {
100 dump_block_run(" double_indirect = ",
101 stream
->double_indirect
);
104 kprintf(" max_double_indirect_range = %" B_PRIdOFF
"\n",
105 stream
->MaxDoubleIndirectRange());
106 kprintf(" size = %" B_PRIdOFF
"\n", stream
->Size());
111 dump_inode(const bfs_inode
* inode
)
114 kprintf(" magic1 = %08x (%s) %s\n", (int)inode
->Magic1(),
115 get_tupel(inode
->magic1
),
116 (inode
->magic1
== INODE_MAGIC1
? "valid" : "INVALID"));
117 dump_block_run( " inode_num = ", inode
->inode_num
);
118 kprintf(" uid = %u\n", (unsigned)inode
->UserID());
119 kprintf(" gid = %u\n", (unsigned)inode
->GroupID());
120 kprintf(" mode = %08x\n", (int)inode
->Mode());
121 kprintf(" flags = %08x\n", (int)inode
->Flags());
122 kprintf(" create_time = %" B_PRIx64
" (%" B_PRIdTIME
".%u)\n",
123 inode
->CreateTime(), bfs_inode::ToSecs(inode
->CreateTime()),
124 (unsigned)bfs_inode::ToNsecs(inode
->CreateTime()));
125 kprintf(" last_modified_time = %" B_PRIx64
" (%" B_PRIdTIME
".%u)\n",
126 inode
->LastModifiedTime(), bfs_inode::ToSecs(inode
->LastModifiedTime()),
127 (unsigned)bfs_inode::ToNsecs(inode
->LastModifiedTime()));
128 kprintf(" status_change_time = %" B_PRIx64
" (%" B_PRIdTIME
".%u)\n",
129 inode
->StatusChangeTime(), bfs_inode::ToSecs(inode
->StatusChangeTime()),
130 (unsigned)bfs_inode::ToNsecs(inode
->StatusChangeTime()));
131 dump_block_run( " parent = ", inode
->parent
);
132 dump_block_run( " attributes = ", inode
->attributes
);
133 kprintf(" type = %u\n", (unsigned)inode
->Type());
134 kprintf(" inode_size = %u\n", (unsigned)inode
->InodeSize());
135 kprintf(" short_symlink = %s\n",
136 S_ISLNK(inode
->Mode()) && (inode
->Flags() & INODE_LONG_SYMLINK
) == 0
137 ? inode
->short_symlink
: "-");
138 dump_data_stream(&(inode
->data
));
139 kprintf(" --\n pad[0] = %08x\n", (int)inode
->pad
[0]);
140 kprintf(" pad[1] = %08x\n", (int)inode
->pad
[1]);
145 dump_bplustree_header(const bplustree_header
* header
)
147 kprintf("bplustree_header:\n");
148 kprintf(" magic = %#08x (%s) %s\n", (int)header
->Magic(),
149 get_tupel(header
->magic
),
150 (header
->magic
== BPLUSTREE_MAGIC
? "valid" : "INVALID"));
151 kprintf(" node_size = %u\n", (unsigned)header
->NodeSize());
152 kprintf(" max_number_of_levels = %u\n",
153 (unsigned)header
->MaxNumberOfLevels());
154 kprintf(" data_type = %u\n", (unsigned)header
->DataType());
155 kprintf(" root_node_pointer = %" B_PRIdOFF
"\n", header
->RootNode());
156 kprintf(" free_node_pointer = %" B_PRIdOFF
"\n", header
->FreeNode());
157 kprintf(" maximum_size = %" B_PRIdOFF
"\n", header
->MaximumSize());
161 #define DUMPED_BLOCK_SIZE 16
164 dump_block(const char* buffer
,int size
)
166 for (int i
= 0; i
< size
;) {
169 for (; i
< start
+ DUMPED_BLOCK_SIZE
; i
++) {
176 kprintf("%02x", *(unsigned char *)(buffer
+ i
));
180 for (i
= start
; i
< start
+ DUMPED_BLOCK_SIZE
; i
++) {
182 char c
= *(buffer
+ i
);
197 dump_bplustree_node(const bplustree_node
* node
, const bplustree_header
* header
,
200 kprintf("bplustree_node:\n");
201 kprintf(" left_link = %" B_PRId64
"\n", node
->left_link
);
202 kprintf(" right_link = %" B_PRId64
"\n", node
->right_link
);
203 kprintf(" overflow_link = %" B_PRId64
"\n", node
->overflow_link
);
204 kprintf(" all_key_count = %u\n", node
->all_key_count
);
205 kprintf(" all_key_length = %u\n", node
->all_key_length
);
210 if (node
->all_key_count
> node
->all_key_length
211 || uint32(node
->all_key_count
* 10) > (uint32
)header
->node_size
212 || node
->all_key_count
== 0) {
214 dump_block((char *)node
, header
->node_size
/*, sizeof(off_t)*/);
219 for (int32 i
= 0;i
< node
->all_key_count
;i
++) {
221 char buffer
[256], *key
= (char *)node
->KeyAt(i
, &length
);
222 if (length
> 255 || length
== 0) {
223 kprintf(" %2d. Invalid length (%u)!!\n", (int)i
, length
);
224 dump_block((char *)node
, header
->node_size
/*, sizeof(off_t)*/);
227 memcpy(buffer
, key
, length
);
228 buffer
[length
] = '\0';
230 off_t
* value
= node
->Values() + i
;
231 if ((addr_t
)value
< (addr_t
)node
232 || (addr_t
)value
> (addr_t
)node
+ header
->node_size
)
233 kprintf(" %2d. Invalid Offset!!\n", (int)i
);
235 kprintf(" %2d. ", (int)i
);
236 if (header
->data_type
== BPLUSTREE_STRING_TYPE
)
237 kprintf("\"%s\"", buffer
);
238 else if (header
->data_type
== BPLUSTREE_INT32_TYPE
) {
239 kprintf("int32 = %d (0x%x)", (int)*(int32
*)&buffer
,
240 (int)*(int32
*)&buffer
);
241 } else if (header
->data_type
== BPLUSTREE_UINT32_TYPE
) {
242 kprintf("uint32 = %u (0x%x)", (unsigned)*(uint32
*)&buffer
,
243 (unsigned)*(uint32
*)&buffer
);
244 } else if (header
->data_type
== BPLUSTREE_INT64_TYPE
) {
245 kprintf("int64 = %" B_PRId64
" (%#" B_PRIx64
")",
246 *(int64
*)&buffer
, *(int64
*)&buffer
);
250 off_t offset
= *value
& 0x3fffffffffffffffLL
;
251 kprintf(" (%d bytes) -> %" B_PRIdOFF
, length
, offset
);
252 if (volume
!= NULL
) {
253 block_run run
= volume
->ToBlockRun(offset
);
254 kprintf(" (%d, %d)", (int)run
.allocation_group
, run
.start
);
256 if (bplustree_node::LinkType(*value
)
257 == BPLUSTREE_DUPLICATE_FRAGMENT
) {
258 kprintf(" (duplicate fragment %" B_PRIdOFF
")\n",
260 } else if (bplustree_node::LinkType(*value
)
261 == BPLUSTREE_DUPLICATE_NODE
) {
262 kprintf(" (duplicate node)\n");
270 // #pragma mark - debugger commands
273 #ifdef BFS_DEBUGGER_COMMANDS
277 dump_inode(int argc
, char** argv
)
280 if (argc
>= 3 && !strcmp(argv
[1], "-b"))
283 if (argc
!= 2 + (block
? 1 : 0) || !strcmp(argv
[1], "--help")) {
284 kprintf("usage: bfsinode [-b] <ptr-to-inode>\n"
285 " -b the address is regarded as pointer to a block instead of one "
290 addr_t address
= parse_expression(argv
[argc
- 1]);
293 node
= (bfs_inode
*)address
;
295 Inode
* inode
= (Inode
*)address
;
297 kprintf("INODE %p\n", inode
);
298 kprintf(" rw lock: %p\n", &inode
->Lock());
299 kprintf(" tree: %p\n", inode
->Tree());
300 kprintf(" file cache: %p\n", inode
->FileCache());
301 kprintf(" file map: %p\n", inode
->Map());
302 kprintf(" old size: %" B_PRIdOFF
"\n", inode
->OldSize());
303 kprintf(" old last modified: %" B_PRIdOFF
"\n",
304 inode
->OldLastModified());
306 node
= &inode
->Node();
315 dump_volume(int argc
, char** argv
)
317 if (argc
< 2 || !strcmp(argv
[1], "--help")) {
318 kprintf("usage: bfs <ptr-to-volume> [<block-run>]\n"
319 "Dumps a BFS volume - <block-run> is given, it is converted to a "
320 "block offset instead (and vice versa).\n");
324 Volume
* volume
= (Volume
*)parse_expression(argv
[1]);
327 // convert block_runs/offsets
328 for (int i
= 2; i
< argc
; i
++) {
330 if (strchr(arg
, '.') != NULL
|| strchr(arg
, ',') != NULL
) {
331 // block_run to offset
333 run
.allocation_group
= HOST_ENDIAN_TO_BFS_INT32(
334 strtoul(arg
, &arg
, 0));
335 run
.start
= HOST_ENDIAN_TO_BFS_INT16(strtoul(arg
+ 1, NULL
, 0));
338 kprintf("%" B_PRId32
".%u -> block %" B_PRIdOFF
", bitmap block"
339 " %" B_PRId32
"\n", run
.AllocationGroup(), run
.Start(),
340 volume
->ToBlock(run
),
341 volume
->SuperBlock().BlocksPerAllocationGroup()
342 * run
.AllocationGroup() + 1);
344 // offset to block_run
345 off_t offset
= parse_expression(arg
);
346 block_run run
= volume
->ToBlockRun(offset
);
348 kprintf("block %" B_PRIdOFF
" -> %" B_PRId32
".%u, bitmap block"
349 " %" B_PRId32
"\n", offset
, run
.AllocationGroup(),
350 run
.Start(), volume
->SuperBlock().BlocksPerAllocationGroup()
351 * run
.AllocationGroup() + 1);
357 kprintf("id: %" B_PRId32
"\n", volume
->ID());
358 kprintf("block cache: %p\n", volume
->BlockCache());
359 kprintf("journal: %p\n", volume
->GetJournal(0));
360 kprintf("allocator: %p\n", &volume
->Allocator());
361 kprintf("root node: %p\n", volume
->RootNode());
362 kprintf("indices node: %p\n\n", volume
->IndicesNode());
364 dump_super_block(&volume
->SuperBlock());
366 set_debug_variable("_cache", (addr_t
)volume
->BlockCache());
367 set_debug_variable("_root", (addr_t
)volume
->RootNode());
368 set_debug_variable("_indices", (addr_t
)volume
->IndicesNode());
375 dump_block_run_array(int argc
, char** argv
)
377 if (argc
< 2 || !strcmp(argv
[1], "--help")) {
378 kprintf("usage: %s <ptr-to-array> [number-of-runs] [block-size] "
379 "[start-offset] [search-offset]\n", argv
[0]);
383 const block_run
* runs
= (const block_run
*)parse_expression(argv
[1]);
386 count
= parse_expression(argv
[2]);
388 uint32 blockSize
= 0;
390 blockSize
= parse_expression(argv
[3]);
394 offset
= parse_expression(argv
[4]);
396 off_t searchOffset
= 0;
398 searchOffset
= parse_expression(argv
[5]);
400 for (uint32 i
= 0; i
< count
; i
++) {
402 dprintf("[%3" B_PRIu32
"] %10" B_PRIdOFF
" ", i
, offset
);
404 dprintf("[%3" B_PRIu32
"] ", i
);
406 uint32 size
= runs
[i
].Length() * blockSize
;
407 if (searchOffset
!= 0 && searchOffset
>= offset
408 && searchOffset
< offset
+ size
)
411 dump_block_run("", runs
[i
]);
421 dump_bplustree_node(int argc
, char** argv
)
423 if (argc
< 2 || argc
> 4 || !strcmp(argv
[1], "--help")) {
424 kprintf("usage: %s <ptr-to-node> [ptr-to-header] [ptr-to-volume]\n",
429 bplustree_node
* node
= (bplustree_node
*)parse_expression(argv
[1]);
430 bplustree_header
* header
= NULL
;
431 Volume
* volume
= NULL
;
434 header
= (bplustree_header
*)parse_expression(argv
[2]);
436 volume
= (Volume
*)parse_expression(argv
[3]);
438 dump_bplustree_node(node
, header
, volume
);
445 dump_bplustree_header(int argc
, char** argv
)
447 if (argc
!= 2 || !strcmp(argv
[1], "--help")) {
448 kprintf("usage: %s <ptr-to-header>\n", argv
[0]);
452 bplustree_header
* header
= (bplustree_header
*)parse_expression(argv
[1]);
453 dump_bplustree_header(header
);
460 remove_debugger_commands()
462 remove_debugger_command("bfs_inode", dump_inode
);
463 remove_debugger_command("bfs_allocator", dump_block_allocator
);
465 remove_debugger_command("bfs_allocator_blocks",
466 dump_block_allocator_blocks
);
468 remove_debugger_command("bfs_journal", dump_journal
);
469 remove_debugger_command("bfs_btree_header", dump_bplustree_header
);
470 remove_debugger_command("bfs_btree_node", dump_bplustree_node
);
471 remove_debugger_command("bfs", dump_volume
);
472 remove_debugger_command("bfs_block_runs", dump_block_run_array
);
477 add_debugger_commands()
479 add_debugger_command("bfs_inode", dump_inode
, "dump an Inode object");
480 add_debugger_command("bfs_allocator", dump_block_allocator
,
481 "dump a BFS block allocator");
483 add_debugger_command("bfs_allocator_blocks", dump_block_allocator_blocks
,
484 "dump a BFS block allocator actions that affected a certain block");
486 add_debugger_command("bfs_journal", dump_journal
,
487 "dump the journal log entries");
488 add_debugger_command("bfs_btree_header", dump_bplustree_header
,
489 "dump a BFS B+tree header");
490 add_debugger_command("bfs_btree_node", dump_bplustree_node
,
491 "dump a BFS B+tree node");
492 add_debugger_command("bfs", dump_volume
, "dump a BFS volume");
493 add_debugger_command("bfs_block_runs", dump_block_run_array
,
494 "dump a block run array");
498 #endif // BFS_DEBUGGER_COMMANDS