Whamcloud - gitweb
LU-8191 utils: remove unused, fix non-static functions
[fs/lustre-release.git] / lustre / utils / check_iam.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  *
24  * User-level tool to check iam files sanity.
25  *
26  * Author: Artem Blagodarenko <artem.blagodarenko@hpe.com>
27  */
28
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <endian.h>
35 #include <errno.h>
36
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>
42
43 static int verbose;
44 static bool print_records;
45
46 enum {
47         ROOT_NODE,
48         INDEX_NODE,
49         LEAF_NODE,
50         IDLE_NODE
51 };
52
53 struct node_info {
54         int referenced;
55         int recycled;
56         int node_type;
57 };
58
59 static void usage(char *str)
60 {
61         printf("Usage: %s [-hrv] iam_file\n", str);
62 }
63
64 struct iam_params {
65         char *filename;
66         int blocksize;
67         int fmt;
68         int keysize;
69         int recsize;
70         int ptrsize;
71         int indirect_levels;
72         int root_gap;
73         int node_gap;
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;
79         int rc;
80 };
81
82 static int check_idle_blocks(char *buf, struct iam_params *params)
83 {
84         struct iam_idle_head *idle;
85         int i;
86
87         idle = (struct iam_idle_head *)buf;
88
89         if (idle->iih_magic != __cpu_to_le16(IAM_IDLE_HEADER_MAGIC)) {
90                 printf("Wrong magic 0x%x\n", idle->iih_magic);
91                 return -1;
92         }
93
94         if (verbose) {
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));
98         }
99
100         for (i = 0; i < __le32_to_cpu(idle->iih_count); i++) {
101                 unsigned int blk = __le32_to_cpu(idle->iih_blks[i]);
102
103                 if (verbose)
104                         printf("%i, ", blk);
105                 if (blk >= params->blocks_count) {
106                         printf("Pointer to the idle block (%i) outside the file\n",
107                                blk);
108                         params->rc = -1;
109                 } else {
110                         if (params->node_info[blk].referenced && verbose)
111                                 printf("Reference to recycled node (%i)\n",
112                                        blk);
113                         params->node_info[blk].recycled = 1;
114                 }
115         }
116
117         if (verbose)
118                 printf("\n");
119
120         return 0;
121 }
122
123 static int check_entries(unsigned char *entries, size_t size, int count,
124                          struct iam_params *params, int block_type)
125 {
126         unsigned int ptr;
127         int i, j, rc;
128
129         for (i = 0; i < count; i++) {
130                 rc = 0;
131                 size -= (params->keysize + params->ptrsize);
132
133                 if (size < 0) {
134                         if (verbose)
135                                 printf("index outside of buffer\n");
136
137                         return -1;
138                 }
139
140                 if (block_type == INDEX_NODE) {
141
142                         if (verbose)
143                                 printf("key:");
144
145                         for (j = 0; j < params->keysize; j++, entries++)
146                                 if (verbose)
147                                         printf("%02x", *entries);
148
149                         ptr = __le32_to_cpu(*((__le32 *)entries));
150
151                         if (ptr >= params->blocks_count) {
152                                 params->rc = -1;
153                                 rc = -1;
154                         }
155                         if (verbose)
156                                 printf(", ptr: %u%s\n", ptr,
157                                        rc ? " wrong" : "");
158
159                         entries += params->ptrsize;
160
161                         if (rc)
162                                 continue;
163
164                         if (params->node_info[ptr].recycled && verbose) {
165                                 printf("Reference to recycled node (%u) from node %lu\n",
166                                         ptr, params->current_block);
167                         }
168                         params->node_info[ptr].referenced = 1;
169                 } else if (block_type == LEAF_NODE) {
170                         struct lu_fid fid;
171                         struct osd_inode_id *inode;
172
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;
176
177                         if (print_records)
178                                 printf(DFID" %u/%u\n", PFID(&fid),
179                                        __be32_to_cpu(inode->oii_ino),
180                                        __be32_to_cpu(inode->oii_gen));
181                 }
182
183         }
184
185         return 0;
186 }
187
188 static int check_leaf(char *buf, struct iam_params *params)
189 {
190         struct iam_leaf_head *leaf;
191         int counted_limit;
192         int leaf_count;
193
194         leaf = (struct iam_leaf_head *)buf;
195
196         params->node_info[params->current_block].node_type = LEAF_NODE;
197
198         counted_limit = node_limit(sizeof(struct iam_leaf_head),
199                                    params->blocksize,
200                                    params->keysize + params->recsize);
201         leaf_count = __le16_to_cpu(leaf->ill_count);
202
203         if (verbose)
204                 printf("Leaf block, count %i, limit %i\n", leaf_count,
205                        counted_limit);
206
207         if (leaf_count > counted_limit) {
208                 printf("More elements (%i) then limit (%i)\n", leaf_count,
209                         counted_limit);
210                 return -1;
211         }
212
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");
218                 return -1;
219         }
220
221         return 0;
222 }
223
224 static int check_index(char *buf, struct iam_params *params)
225 {
226         struct iam_index_head *index;
227         int counted_limit;
228         struct dx_countlimit *limit;
229         int limit_count;
230
231         index = (struct iam_index_head *)buf;
232         limit = &index->limit;
233
234         params->node_info[params->current_block].node_type = INDEX_NODE;
235
236         limit_count = __le16_to_cpu(limit->count);
237         if (verbose)
238                 printf("Index block, count %i, limit %i\n", limit_count,
239                        __le16_to_cpu(limit->limit));
240
241         counted_limit = node_limit(params->node_gap, params->blocksize,
242                                    params->keysize + params->ptrsize);
243
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);
247                 return -1;
248         }
249
250
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));
254                 return -1;
255         }
256
257          /* count - 1, because limit is entry itself */
258         if (check_entries(index->entries,
259                           params->blocksize - offsetof(struct iam_index_head,
260                                                        entries),
261                           limit_count - 1, params, INDEX_NODE)) {
262                 printf("Broken entries\n");
263                 return -1;
264         }
265
266         return 0;
267 }
268
269 static int check_root(char *buf, size_t size, struct iam_params *params)
270 {
271         struct iam_lfix_root *root;
272         unsigned int counted_limit;
273         int min;
274         struct dx_countlimit *limit;
275
276         if (verbose)
277                 printf("Root format ");
278
279         root = (struct iam_lfix_root *)buf;
280         if (root->ilr_magic == __cpu_to_le64(IAM_LFIX_ROOT_MAGIC)) {
281                 params->fmt = FMT_LFIX;
282                 if (verbose)
283                         printf("LFIX,");
284         } else if (root->ilr_magic == __cpu_to_le64(IAM_LVAR_ROOT_MAGIC)) {
285                 params->fmt = FMT_LVAR;
286                 if (verbose)
287                         printf("LVAR,");
288         } else {
289                 printf("Bad magic %llu\n", __le64_to_cpu(root->ilr_magic));
290                 params->rc = -1;
291         }
292
293         limit = &root->limit;
294
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;
299
300         params->node_info[0].referenced = 1; //self referance
301         params->node_info[0].node_type = ROOT_NODE;
302
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);
307                 params->rc = -1;
308         } else {
309                 params->node_info[params->idle_blocks].referenced = 1;
310                 params->node_info[params->idle_blocks].node_type = IDLE_NODE;
311         }
312
313         if (verbose) {
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);
318         }
319
320         if (params->ptrsize != 4 && params->ptrsize != 8) {
321                 printf("Invalid ptrsize (%i). Only 4 and 8 are supported\n",
322                        params->ptrsize);
323                 return -1;
324         }
325
326         if (params->keysize < 1 || params->recsize < 0) {
327                 printf("Too small key(%i) or recorod(%i)\n",
328                         params->keysize, params->recsize);
329                 return -1;
330         }
331
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)),
337                         params->blocksize);
338                 return -1;
339         }
340
341         counted_limit = root_limit(params->root_gap, params->node_gap,
342                                    params->blocksize,
343                                    params->keysize + params->ptrsize);
344
345
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);
349                 params->rc = -1;
350         }
351
352         min = (counted_limit < __le16_to_cpu(limit->limit)) ?
353                         counted_limit : __le16_to_cpu(limit->limit);
354
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));
359                 params->rc = -1;
360         }
361
362         min = (__le16_to_cpu(limit->count) < min) ?
363                         __le16_to_cpu(limit->count) : min;
364
365
366         if (verbose)
367                 printf("count %i, limit %i\n",
368                         __le16_to_cpu(root->limit.count),
369                         __le16_to_cpu(root->limit.limit));
370
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");
376                 return -1;
377         }
378
379         return 0;
380 }
381
382 static int check_block(char *buf, struct iam_params *params)
383 {
384         struct iam_leaf_head *head;
385
386         head = (struct iam_leaf_head *)buf;
387
388         if (verbose)
389                 printf("Block %lu,", params->current_block);
390
391         switch (head->ill_magic) {
392         case __cpu_to_le16(IAM_LEAF_HEADER_MAGIC):
393                         if (verbose)
394                                 printf("FIX leaf,");
395                         if (check_leaf(buf, params)) {
396                                 printf("Broken leaf block\n");
397                                 params->rc = -1;
398                         }
399                         break;
400         case __cpu_to_le16(IAM_LVAR_ROOT_MAGIC):
401                         if (verbose)
402                                 printf("LVAR leaf,");
403                         break;
404         case __cpu_to_le16(IAM_IDLE_HEADER_MAGIC):
405                         if (verbose)
406                                 printf("IDLE block");
407
408                         params->node_info[params->current_block].referenced = 1;
409
410                         if (check_idle_blocks(buf, params)) {
411                                 printf("Broken idle blocks\n");
412                                 params->rc = -1;
413                         }
414                         break;
415         default:
416                         if (check_index(buf, params)) {
417                                 printf("Broken index node\n");
418                                 params->rc = -1;
419                         }
420                         break;
421         }
422         if (verbose)
423                 printf("count %i\n", head->ill_count);
424
425         return 0;
426 }
427
428 static void print_node_type(int type)
429 {
430         switch (type) {
431         case ROOT_NODE:
432                         printf("ROOT\n");
433                         break;
434         case INDEX_NODE:
435                         printf("INDEX\n");
436                         break;
437         case LEAF_NODE:
438                         printf("LEAF\n");
439                         break;
440         case IDLE_NODE:
441                         printf("IDLE\n");
442                         break;
443         default:
444                         printf("UNKNOWN %i\n", type);
445                         break;
446         }
447 }
448 static int check_unconnected(struct iam_params *params)
449 {
450         unsigned long i;
451         int rc = 0;
452
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);
458                 }
459
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);
464                         rc = -1;
465                 }
466         }
467         return rc;
468 }
469 int main(int argc, char **argv)
470 {
471         struct iam_params params;
472         int rc = 0;
473         int opt;
474         void *buf;
475         int fd;
476         struct stat sb;
477
478         params.rc = 0;
479         print_records = false;
480         do {
481                 opt = getopt(argc, argv, "hvr");
482                 switch (opt) {
483                 case 'v':
484                                 verbose++;
485                                 break;
486                 case 'r':
487                                 print_records = true;
488                 case -1:
489                                 break;
490                 default:
491                                 fprintf(stderr, "Unable to parse options.");
492                 case 'h':
493                                 usage(argv[0]);
494                                 return 0;
495                 }
496         } while (opt != -1);
497
498         if (optind >= argc) {
499                 fprintf(stderr, "Expected filename after options\n");
500                 return -1;
501         }
502
503         params.filename = argv[optind];
504         params.blocksize = 4096;
505         params.current_block = 0;
506         params.root_gap = sizeof(struct iam_lfix_root);
507         params.node_gap = 0;
508
509         fd = open(params.filename, O_RDONLY);
510         if (fd < 0) {
511                 fprintf(stderr, "Can not open file %s, %s\n",
512                         params.filename, strerror(errno));
513                 return -1;
514         }
515
516         if (fstat(fd, &sb) == -1) {
517                 fprintf(stderr, "Error stat file.\n");
518                 close(fd);
519                 return -1;
520         }
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);
524
525         if (verbose)
526                 printf("Filesize %llu, blocks count %lu\n", params.file_size,
527                        params.blocks_count);
528         buf = malloc(params.blocksize);
529         if (buf == NULL) {
530                 fprintf(stderr, "Can't allocate buffer\n");
531                 close(fd);
532                 return -1;
533         }
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));
538
539         /* Read root block */
540         if (read(fd, buf, params.blocksize) < params.blocksize) {
541                 fprintf(stderr, "Can't read root block\n");
542                 params.rc = -1;
543                 goto err;
544         }
545
546         rc = check_root(buf, params.blocksize, &params);
547         if (rc) {
548                 printf("Root node is insane\n");
549                 goto err;
550         }
551
552         params.current_block++;
553
554         /* Read all another blocks */
555         while (read(fd, buf, params.blocksize)) {
556                 rc = check_block(buf, &params);
557                 if (rc) {
558                         printf("Node with offset 0x%lx in %s is broken\n",
559                                 params.current_block * params.blocksize,
560                                 params.filename);
561                         params.rc = rc;
562                 }
563                 params.current_block++;
564         }
565
566         rc = check_unconnected(&params);
567         if (rc)
568                 printf("There are unconnected nodes\n");
569 err:
570         if (!(rc ? rc : params.rc))
571                 printf("NO ERRORS\n");
572         else
573                 printf("FINISHED WITH ERRORS\n");
574
575         free(params.node_info);
576         free(buf);
577         close(fd);
578
579         return rc ?: params.rc;
580 }