4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
24 * User-level tool to check iam files sanity.
26 * Author: Artem Blagodarenko <artem.blagodarenko@hpe.com>
37 #include <sys/types.h>
38 #include <linux/lustre/lustre_user.h>
39 #include <linux/lustre/lustre_fid.h>
40 #include <asm/byteorder.h>
41 #include <lustre/libiam.h>
44 static bool print_records;
59 static void usage(char *str)
61 printf("Usage: %s [-hrv] iam_file\n", str);
74 unsigned long idle_blocks;
75 unsigned long current_block;
76 unsigned long long file_size;
77 unsigned long blocks_count;
78 struct node_info *node_info;
82 static int check_idle_blocks(char *buf, struct iam_params *params)
84 struct iam_idle_head *idle;
87 idle = (struct iam_idle_head *)buf;
89 if (idle->iih_magic != __cpu_to_le16(IAM_IDLE_HEADER_MAGIC)) {
90 printf("Wrong magic 0x%x\n", idle->iih_magic);
95 printf(", %i blocks, next table in block %i, idle blocks: ",
96 __le16_to_cpu(idle->iih_count),
97 __le32_to_cpu(idle->iih_next));
100 for (i = 0; i < __le32_to_cpu(idle->iih_count); i++) {
101 unsigned int blk = __le32_to_cpu(idle->iih_blks[i]);
105 if (blk >= params->blocks_count) {
106 printf("Pointer to the idle block (%i) outside the file\n",
110 if (params->node_info[blk].referenced && verbose)
111 printf("Reference to recycled node (%i)\n",
113 params->node_info[blk].recycled = 1;
123 static int check_entries(unsigned char *entries, size_t size, int count,
124 struct iam_params *params, int block_type)
129 for (i = 0; i < count; i++) {
131 size -= (params->keysize + params->ptrsize);
135 printf("index outside of buffer\n");
140 if (block_type == INDEX_NODE) {
145 for (j = 0; j < params->keysize; j++, entries++)
147 printf("%02x", *entries);
149 ptr = __le32_to_cpu(*((__le32 *)entries));
151 if (ptr >= params->blocks_count) {
156 printf(", ptr: %u%s\n", ptr,
159 entries += params->ptrsize;
164 if (params->node_info[ptr].recycled && verbose) {
165 printf("Reference to recycled node (%u) from node %lu\n",
166 ptr, params->current_block);
168 params->node_info[ptr].referenced = 1;
169 } else if (block_type == LEAF_NODE) {
171 struct osd_inode_id *inode;
173 fid_be_to_cpu(&fid, (struct lu_fid *)entries);
174 inode = (struct osd_inode_id *)(entries + sizeof(fid));
175 entries += params->keysize + params->recsize;
178 printf(DFID" %u/%u\n", PFID(&fid),
179 __be32_to_cpu(inode->oii_ino),
180 __be32_to_cpu(inode->oii_gen));
188 static int check_leaf(char *buf, struct iam_params *params)
190 struct iam_leaf_head *leaf;
194 leaf = (struct iam_leaf_head *)buf;
196 params->node_info[params->current_block].node_type = LEAF_NODE;
198 counted_limit = node_limit(sizeof(struct iam_leaf_head),
200 params->keysize + params->recsize);
201 leaf_count = __le16_to_cpu(leaf->ill_count);
204 printf("Leaf block, count %i, limit %i\n", leaf_count,
207 if (leaf_count > counted_limit) {
208 printf("More elements (%i) then limit (%i)\n", leaf_count,
213 if (check_entries((unsigned char *)(buf + sizeof(struct iam_leaf_head)),
214 params->blocksize - sizeof(struct iam_leaf_head),
215 counted_limit < leaf_count ?
216 counted_limit : leaf_count, params, LEAF_NODE)) {
217 printf("Broken entries\n");
224 static int check_index(char *buf, struct iam_params *params)
226 struct iam_index_head *index;
228 struct dx_countlimit *limit;
231 index = (struct iam_index_head *)buf;
232 limit = &index->limit;
234 params->node_info[params->current_block].node_type = INDEX_NODE;
236 limit_count = __le16_to_cpu(limit->count);
238 printf("Index block, count %i, limit %i\n", limit_count,
239 __le16_to_cpu(limit->limit));
241 counted_limit = node_limit(params->node_gap, params->blocksize,
242 params->keysize + params->ptrsize);
244 if (__le16_to_cpu(limit->limit) != counted_limit) {
245 fprintf(stderr, "Wrong limit %i, counted limit %i\n",
246 __le16_to_cpu(limit->limit), counted_limit);
251 if (limit_count > __le16_to_cpu(limit->limit)) {
252 printf("More elements (%i) then limit (%i)\n", limit_count,
253 __le16_to_cpu(limit->limit));
257 /* count - 1, because limit is entry itself */
258 if (check_entries(index->entries,
259 params->blocksize - offsetof(struct iam_index_head,
261 limit_count - 1, params, INDEX_NODE)) {
262 printf("Broken entries\n");
269 static int check_root(char *buf, size_t size, struct iam_params *params)
271 struct iam_lfix_root *root;
272 unsigned int counted_limit;
274 struct dx_countlimit *limit;
277 printf("Root format ");
279 root = (struct iam_lfix_root *)buf;
280 if (root->ilr_magic == __cpu_to_le64(IAM_LFIX_ROOT_MAGIC)) {
281 params->fmt = FMT_LFIX;
284 } else if (root->ilr_magic == __cpu_to_le64(IAM_LVAR_ROOT_MAGIC)) {
285 params->fmt = FMT_LVAR;
289 printf("Bad magic %llu\n", __le64_to_cpu(root->ilr_magic));
293 limit = &root->limit;
295 params->keysize = __le16_to_cpu(root->ilr_keysize);
296 params->recsize = __le16_to_cpu(root->ilr_recsize);
297 params->ptrsize = __le16_to_cpu(root->ilr_ptrsize);
298 params->indirect_levels = root->ilr_indirect_levels;
300 params->node_info[0].referenced = 1; //self referance
301 params->node_info[0].node_type = ROOT_NODE;
303 params->idle_blocks = __le32_to_cpu(root->idle_blocks);
304 if (params->idle_blocks >= params->blocks_count) {
305 printf("Idle blocks number (%lu) is out of blocks range (%lu)\n",
306 params->idle_blocks, params->blocks_count);
309 params->node_info[params->idle_blocks].referenced = 1;
310 params->node_info[params->idle_blocks].node_type = IDLE_NODE;
314 printf("Idle blocks block number %lu\n", params->idle_blocks);
315 printf("keysize %i, recsize %i, ptrsize %i, indirect_levels %i\n",
316 params->keysize, params->recsize, params->ptrsize,
317 params->indirect_levels);
320 if (params->ptrsize != 4 && params->ptrsize != 8) {
321 printf("Invalid ptrsize (%i). Only 4 and 8 are supported\n",
326 if (params->keysize < 1 || params->recsize < 0) {
327 printf("Too small key(%i) or recorod(%i)\n",
328 params->keysize, params->recsize);
332 if ((params->keysize + params->recsize +
333 (int)sizeof(struct iam_leaf_head)) > (params->blocksize / 3)) {
334 printf("Too large record + key or too small block, %i, %i\n",
335 (params->keysize + params->recsize +
336 (int)sizeof(struct iam_leaf_head)),
341 counted_limit = root_limit(params->root_gap, params->node_gap,
343 params->keysize + params->ptrsize);
346 if (__le16_to_cpu(limit->limit) != counted_limit) {
347 fprintf(stderr, "Wrong limit %i, counted limit %i\n",
348 __le16_to_cpu(limit->limit), counted_limit);
352 min = (counted_limit < __le16_to_cpu(limit->limit)) ?
353 counted_limit : __le16_to_cpu(limit->limit);
355 if (__le16_to_cpu(limit->count) > __le16_to_cpu(limit->limit)) {
356 printf("More elements (%i) then limit (%i)\n",
357 __le16_to_cpu(root->limit.count),
358 __le16_to_cpu(root->limit.limit));
362 min = (__le16_to_cpu(limit->count) < min) ?
363 __le16_to_cpu(limit->count) : min;
367 printf("count %i, limit %i\n",
368 __le16_to_cpu(root->limit.count),
369 __le16_to_cpu(root->limit.limit));
371 /* cound - 1, because limit is entry itself */
372 if (check_entries(root->entries,
373 size - offsetof(struct iam_lfix_root, entries),
374 min - 1, params, INDEX_NODE)) {
375 printf("Broken entries\n");
382 static int check_block(char *buf, struct iam_params *params)
384 struct iam_leaf_head *head;
386 head = (struct iam_leaf_head *)buf;
389 printf("Block %lu,", params->current_block);
391 switch (head->ill_magic) {
392 case __cpu_to_le16(IAM_LEAF_HEADER_MAGIC):
395 if (check_leaf(buf, params)) {
396 printf("Broken leaf block\n");
400 case __cpu_to_le16(IAM_LVAR_ROOT_MAGIC):
402 printf("LVAR leaf,");
404 case __cpu_to_le16(IAM_IDLE_HEADER_MAGIC):
406 printf("IDLE block");
408 params->node_info[params->current_block].referenced = 1;
410 if (check_idle_blocks(buf, params)) {
411 printf("Broken idle blocks\n");
416 if (check_index(buf, params)) {
417 printf("Broken index node\n");
423 printf("count %i\n", head->ill_count);
428 static void print_node_type(int type)
444 printf("UNKNOWN %i\n", type);
448 static int check_unconnected(struct iam_params *params)
453 for (i = 0; i < params->blocks_count; i++) {
454 if (params->node_info[i].referenced &&
455 params->node_info[i].recycled) {
456 printf("Node %lu referenced and recycled. FAIL, ", i);
457 print_node_type(params->node_info[i].node_type);
460 if (!params->node_info[i].referenced &&
461 !params->node_info[i].recycled) {
462 printf("Unconnected node %lu. FAIL, ", i);
463 print_node_type(params->node_info[i].node_type);
469 int main(int argc, char **argv)
471 struct iam_params params;
479 print_records = false;
481 opt = getopt(argc, argv, "hvr");
487 print_records = true;
491 fprintf(stderr, "Unable to parse options.");
498 if (optind >= argc) {
499 fprintf(stderr, "Expected filename after options\n");
503 params.filename = argv[optind];
504 params.blocksize = 4096;
505 params.current_block = 0;
506 params.root_gap = sizeof(struct iam_lfix_root);
509 fd = open(params.filename, O_RDONLY);
511 fprintf(stderr, "Can not open file %s, %s\n",
512 params.filename, strerror(errno));
516 if (fstat(fd, &sb) == -1) {
517 fprintf(stderr, "Error stat file.\n");
521 params.file_size = (unsigned long long)sb.st_size;
522 params.blocks_count = params.file_size / params.blocksize +
523 ((params.file_size % params.blocksize) ? 1 : 0);
526 printf("Filesize %llu, blocks count %lu\n", params.file_size,
527 params.blocks_count);
528 buf = malloc(params.blocksize);
530 fprintf(stderr, "Can't allocate buffer\n");
534 params.node_info = malloc(params.blocks_count *
535 sizeof(struct node_info));
536 memset(params.node_info, 0,
537 params.blocks_count * sizeof(struct node_info));
539 /* Read root block */
540 if (read(fd, buf, params.blocksize) < params.blocksize) {
541 fprintf(stderr, "Can't read root block\n");
546 rc = check_root(buf, params.blocksize, ¶ms);
548 printf("Root node is insane\n");
552 params.current_block++;
554 /* Read all another blocks */
555 while (read(fd, buf, params.blocksize)) {
556 rc = check_block(buf, ¶ms);
558 printf("Node with offset 0x%lx in %s is broken\n",
559 params.current_block * params.blocksize,
563 params.current_block++;
566 rc = check_unconnected(¶ms);
568 printf("There are unconnected nodes\n");
570 if (!(rc ? rc : params.rc))
571 printf("NO ERRORS\n");
573 printf("FINISHED WITH ERRORS\n");
575 free(params.node_info);
579 return rc ?: params.rc;