Whamcloud - gitweb
LU-15938 llog: llog_reader to detect more corruptions
[fs/lustre-release.git] / lustre / utils / llog_reader.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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31 /** \defgroup llog_reader Lustre Log Reader
32  *
33  * Interpret llogs used for storing configuration and changelog data
34  *
35  * @{
36  */
37
38 #include <errno.h>
39 #include <limits.h>
40 #include <stdbool.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/param.h>
47 #ifdef HAVE_ENDIAN_H
48 # include <endian.h>
49 #endif
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <sys/vfs.h>
53 #include <linux/magic.h>
54 #include <errno.h>
55 #include <time.h>
56 #include <linux/lnet/nidstr.h>
57 #include <linux/lustre/lustre_cfg.h>
58 #include <linux/lustre/lustre_fid.h>
59 #include <linux/lustre/lustre_ostid.h>
60 #include <linux/lustre/lustre_log_user.h>
61 #include <lustre/lustreapi.h>
62
63 static inline int ext2_test_bit(int nr, const void *addr)
64 {
65 #if __BYTE_ORDER == __BIG_ENDIAN
66         const unsigned char *tmp = addr;
67
68         return (tmp[nr >> 3] >> (nr & 7)) & 1;
69 #else
70         const unsigned long *tmp = addr;
71
72         return ((1UL << (nr & (__WORDSIZE - 1))) &
73                 ((tmp)[nr / __WORDSIZE])) != 0;
74 #endif
75 }
76
77 int llog_pack_buffer(int fd, struct llog_log_hdr **llog_buf,
78                      struct llog_rec_hdr ***recs, int *recs_number);
79
80 void print_llog_header(struct llog_log_hdr *llog_buf);
81 static void print_records(struct llog_rec_hdr **recs_buf,
82                           int rec_number, int is_ext);
83 void llog_unpack_buffer(int fd, struct llog_log_hdr *llog_buf,
84                         struct llog_rec_hdr **recs_buf);
85
86 #define CANCELLED 0x678
87
88 #define PTL_CMD_BASE 100
89 char *portals_command[17] = {
90         "REGISTER_PEER_FD",
91         "CLOSE_CONNECTION",
92         "REGISTER_MYNID",
93         "PUSH_CONNECTION",
94         "GET_CONN",
95         "DEL_PEER",
96         "ADD_PEER",
97         "GET_PEER",
98         "GET_TXDESC",
99         "ADD_ROUTE",
100         "DEL_ROUTE",
101         "GET_ROUTE",
102         "NOTIFY_ROUTER",
103         "ADD_INTERFACE",
104         "DEL_INTERFACE",
105         "GET_INTERFACE",
106         ""
107 };
108
109 int is_fstype_ext(int fd)
110 {
111         struct statfs st;
112         int rc;
113
114         rc = fstatfs(fd, &st);
115         if (rc < 0) {
116                 llapi_error(LLAPI_MSG_ERROR, rc, "Got statfs error.");
117                 return -errno;
118         }
119
120         return (st.f_type == EXT4_SUPER_MAGIC);
121 }
122
123 /**
124  * Attempt to display a path to the object (file) containing changelog entries,
125  * referred to by this changelog_catalog record.
126  *
127  * This path depends on the implementation of the OSD device; zfs-osd and
128  * ldiskfs-osd are different.
129  *
130  * Assumes that if the file system containing the changelog_catalog is
131  * ext{2,3,4}, the backend is ldiskfs-osd; otherwise it is either zfs-osd or at
132  * least names objects based on FID and the zfs-osd path (which includes the
133  * FID) will be sufficient.
134  *
135  * The Object ID stored in the record is also displayed untranslated.
136  */
137 #define OSD_OI_FID_NR         (1UL << 7)
138 static void print_log_path(struct llog_logid_rec *lid, int is_ext)
139 {
140         char object_path[255];
141         struct lu_fid fid_from_logid;
142
143         logid_to_fid(&lid->lid_id, &fid_from_logid);
144
145         if (is_ext)
146                 snprintf(object_path, sizeof(object_path),
147                          "O/%ju/d%u/%u", (uintmax_t)fid_from_logid.f_seq,
148                          fid_from_logid.f_oid % 32,
149                          fid_from_logid.f_oid);
150         else
151                 snprintf(object_path, sizeof(object_path),
152                          "oi.%ju/"DFID_NOBRACE,
153                          (uintmax_t)(fid_from_logid.f_seq &
154                                      (OSD_OI_FID_NR - 1)),
155                          PFID(&fid_from_logid));
156
157         printf("id="DFID":%x path=%s\n",
158                PFID(&lid->lid_id.lgl_oi.oi_fid), lid->lid_id.lgl_ogen,
159                object_path);
160 }
161
162 int main(int argc, char **argv)
163 {
164         int rc = 0;
165         int is_ext;
166         int fd, rec_number;
167         struct llog_log_hdr *llog_buf = NULL;
168         struct llog_rec_hdr **recs_buf = NULL;
169
170         setlinebuf(stdout);
171
172         if (argc != 2) {
173                 printf("Usage: llog_reader filename\n");
174                 return -1;
175         }
176
177         fd = open(argv[1], O_RDONLY);
178         if (fd < 0) {
179                 rc = -errno;
180                 llapi_error(LLAPI_MSG_ERROR, rc, "Could not open the file %s.",
181                             argv[1]);
182                 goto out;
183         }
184
185         is_ext = is_fstype_ext(fd);
186         if (is_ext < 0) {
187                 rc = is_ext;
188                 llapi_error(LLAPI_MSG_ERROR, -rc,
189                             "Unable to determine filesystem type for %s",
190                        argv[1]);
191                 goto out_fd;
192         }
193
194         rc = llog_pack_buffer(fd, &llog_buf, &recs_buf, &rec_number);
195         if (rc < 0) {
196                 llapi_error(LLAPI_MSG_ERROR, rc, "Could not pack buffer.");
197                 goto out_fd;
198         }
199
200         if (llog_buf)
201                 print_llog_header(llog_buf);
202         if (recs_buf)
203                 print_records(recs_buf, rec_number, is_ext);
204         llog_unpack_buffer(fd, llog_buf, recs_buf);
205
206 out_fd:
207         close(fd);
208 out:
209         return rc;
210 }
211
212 int llog_pack_buffer(int fd, struct llog_log_hdr **llog,
213                      struct llog_rec_hdr ***recs,
214                      int *recs_number)
215 {
216         int rc = 0, recs_num, rd = 0;
217         long long file_size;
218         struct stat st;
219         char *file_buf = NULL, *recs_buf = NULL;
220         struct llog_rec_hdr **recs_pr = NULL;
221         char *ptr = NULL;
222         int count, errors = 0;
223         int i, last_idx;
224
225         *recs = NULL;
226         *recs_number = 0;
227
228         rc = fstat(fd, &st);
229         if (rc < 0) {
230                 rc = -errno;
231                 llapi_error(LLAPI_MSG_ERROR, rc, "Got file stat error.");
232                 return rc;
233         }
234
235         file_size = st.st_size;
236         if (file_size < sizeof(**llog)) {
237                 llapi_error(LLAPI_MSG_ERROR, rc,
238                             "File too small for llog header: want=%zd got=%lld",
239                             sizeof(**llog), file_size);
240                 rc = -EIO;
241                 return rc;
242         }
243
244         file_buf = malloc(file_size);
245         if (!file_buf) {
246                 rc = -ENOMEM;
247                 llapi_error(LLAPI_MSG_ERROR, rc, "Memory Alloc for file_buf.");
248                 return rc;
249         }
250         *llog = (struct llog_log_hdr *)file_buf;
251
252         do {
253                 rc = read(fd, file_buf + rd, file_size - rd);
254                 if (rc > 0)
255                         rd += rc;
256         } while (rc > 0 && rd < file_size);
257
258         if (rd < file_size) {
259                 rc = rc < 0 ? -errno : -EIO;
260                 llapi_error(LLAPI_MSG_ERROR, rc,
261                             "Error reading llog header: need %zd, got %d",
262                             sizeof(**llog), rd);
263                 goto clear_file_buf;
264         }
265
266         count = __le32_to_cpu((*llog)->llh_count);
267         if (count < 0) {
268                 rc = -EINVAL;
269                 llapi_error(LLAPI_MSG_ERROR, rc,
270                             "corrupted llog: negative record number %d",
271                             count);
272                 goto clear_file_buf;
273         } else if (count == 0) {
274                 llapi_printf(LLAPI_MSG_NORMAL,
275                              "uninitialized llog: zero record number\n");
276                 goto clear_file_buf;
277         }
278
279         /* the llog header not countable here.*/
280         recs_num = count - 1;
281         if (recs_num == 0)
282                 goto clear_file_buf;
283
284         recs_buf = calloc(recs_num, sizeof(**recs_pr));
285         if (!recs_buf) {
286                 rc = -ENOMEM;
287                 llapi_error(LLAPI_MSG_ERROR, rc,
288                             "Error allocating %zd bytes for recs_buf",
289                             recs_num * sizeof(**recs_pr));
290                 goto clear_file_buf;
291         }
292         recs_pr = (struct llog_rec_hdr **)recs_buf;
293
294         ptr = file_buf + __le32_to_cpu((*llog)->llh_hdr.lrh_len);
295         i = 0;
296
297         last_idx = 0;
298         while (ptr < (file_buf + file_size)) {
299                 struct llog_rec_hdr *cur_rec;
300                 int idx;
301                 unsigned long offset;
302
303                 offset = (unsigned long)ptr - (unsigned long)file_buf;
304                 if (offset + sizeof(**recs_pr) > file_size) {
305                         printf("error: rec header is trimmed by EOF, last idx #%d offset %lu\n",
306                                last_idx, offset);
307                         errors++;
308                         break;
309                 }
310                 cur_rec = (struct llog_rec_hdr *)ptr;
311                 idx = __le32_to_cpu(cur_rec->lrh_index);
312                 if (cur_rec->lrh_len == 0 ||
313                     cur_rec->lrh_len > (*llog)->llh_hdr.lrh_len) {
314                         cur_rec->lrh_len = (*llog)->llh_hdr.lrh_len -
315                                 offset % (*llog)->llh_hdr.lrh_len;
316                         printf("off %lu skip %u to next chunk.\n", offset,
317                                cur_rec->lrh_len);
318                 } else if (ext2_test_bit(idx, LLOG_HDR_BITMAP(*llog))) {
319                         printf("rec #%d type=%x len=%u offset %lu\n", idx,
320                                cur_rec->lrh_type, cur_rec->lrh_len, offset);
321                         recs_pr[i] = cur_rec;
322                         i++;
323                 } else {
324                         cur_rec->lrh_id = CANCELLED;
325                         if (cur_rec->lrh_type == LLOG_PAD_MAGIC &&
326                            ((offset + cur_rec->lrh_len) & 0x7) != 0) {
327                                 printf("error: rec #%d wrong padding len=%u offset %lu to 0x%lx\n",
328                                        idx, cur_rec->lrh_len, offset,
329                                        offset + cur_rec->lrh_len);
330                                 errors++;
331                         }
332                         /* The header counts only set records */
333                 }
334
335                 while (++last_idx < idx) {
336                         printf("error: rec #%d is missing%s set in bitmap\n",
337                                last_idx,
338                                ext2_test_bit(last_idx, LLOG_HDR_BITMAP(*llog)) ?
339                                " but" : ", not");
340                         errors++;
341                 }
342                 /* index may decrease only when crosses index zero in catalog */
343                 if (last_idx > idx && idx != 1) {
344                         printf("error: rec #%d index is less than last #%d\n",
345                                idx, last_idx);
346                         errors++;
347                         last_idx = idx;
348                 }
349
350                 ptr += __le32_to_cpu(cur_rec->lrh_len);
351                 if ((ptr - file_buf) > file_size) {
352                         printf("error: rec #%d is trimmed by EOF, offset %lu\n",
353                                idx, offset);
354                         errors++;
355                         break;
356                 }
357         }
358
359         while (++last_idx < LLOG_HDR_BITMAP_SIZE((*llog))) {
360                 if (ext2_test_bit(last_idx, LLOG_HDR_BITMAP(*llog))) {
361                         printf("error: rec #%d is set in bitmap only\n",
362                                last_idx);
363                         errors++;
364                 }
365         }
366         if (i != recs_num)
367                 printf("error: header reports %d records but %d were found\n",
368                        recs_num, i);
369
370         /* don't set rc to output what was found */
371         if (errors)
372                 llapi_error(LLAPI_MSG_NO_ERRNO, 0,
373                             "The llog is corrupted, %d errors found", errors);
374
375         *recs = recs_pr;
376         /* don't try to output more recs than was found or allocated */
377         *recs_number = i > recs_num ? recs_num : i;
378
379         return 0;
380
381 clear_file_buf:
382         free(file_buf);
383         *llog = NULL;
384
385         return rc;
386 }
387
388 void llog_unpack_buffer(int fd, struct llog_log_hdr *llog_buf,
389                         struct llog_rec_hdr **recs_buf)
390 {
391         if (llog_buf)
392                 free(llog_buf);
393         if (recs_buf)
394                 free(recs_buf);
395 }
396
397 void print_llog_header(struct llog_log_hdr *llog_buf)
398 {
399         time_t t;
400         unsigned int lrh_len = __le32_to_cpu(llog_buf->llh_hdr.lrh_len);
401         struct llog_rec_tail *tail = ((struct llog_rec_tail *)((char *)llog_buf+
402                                  lrh_len - sizeof(llog_buf->llh_tail)));
403
404         printf("Header size : %u\t llh_size : %u\n", lrh_len,
405                __le32_to_cpu(llog_buf->llh_size));
406
407         t = __le64_to_cpu(llog_buf->llh_timestamp);
408         printf("Time : %s", ctime(&t));
409
410         printf("Number of records: %u\tcat_idx: %u\tlast_idx: %u\n",
411                __le32_to_cpu(llog_buf->llh_count)-1,
412                __le32_to_cpu(llog_buf->llh_cat_idx),
413                __le32_to_cpu(tail->lrt_index));
414
415         printf("Target uuid : %s\n",
416                (char *)(&llog_buf->llh_tgtuuid));
417
418         /* Add the other info you want to view here */
419
420         printf("-----------------------\n");
421 }
422
423 static void print_1_cfg(struct lustre_cfg *lcfg)
424 {
425         int i;
426
427         if (lcfg->lcfg_nid)
428                 printf("nid=%s(%#jx)  ", libcfs_nid2str(lcfg->lcfg_nid),
429                        (uintmax_t)lcfg->lcfg_nid);
430         if (lcfg->lcfg_nal)
431                 printf("nal=%d ", lcfg->lcfg_nal);
432         for (i = 0; i <  lcfg->lcfg_bufcount; i++)
433                 printf("%d:%.*s  ", i, lcfg->lcfg_buflens[i],
434                        (char *)lustre_cfg_buf(lcfg, i));
435 }
436
437 static char *lustre_cfg_string(struct lustre_cfg *lcfg, __u32 index)
438 {
439         char *s;
440
441         if (lcfg->lcfg_buflens[index] == 0)
442                 return NULL;
443
444         s = lustre_cfg_buf(lcfg, index);
445         if (!s)
446                 return NULL;
447
448         /*
449          * make sure it's NULL terminated, even if this kills a char
450          * of data. Try to use the padding first though.
451          */
452         if (s[lcfg->lcfg_buflens[index] - 1] != '\0') {
453                 size_t last = __ALIGN_KERNEL(lcfg->lcfg_buflens[index], 8) - 1;
454                 char lost;
455
456                 /* Use the smaller value */
457                 if (last > lcfg->lcfg_buflens[index])
458                         last = lcfg->lcfg_buflens[index];
459
460                 lost = s[last];
461                 s[last] = '\0';
462                 if (lost != '\0') {
463                         fprintf(stderr,
464                                 "Truncated buf %d to '%s' (lost '%c'...)\n",
465                                 index, s, lost);
466                 }
467         }
468         return s;
469 }
470
471 static void print_setup_cfg(struct lustre_cfg *lcfg)
472 {
473         struct lov_desc *desc;
474
475         if ((lcfg->lcfg_bufcount == 2) &&
476             (lcfg->lcfg_buflens[1] == sizeof(*desc))) {
477                 printf("lov_setup ");
478                 printf("0:%s  ", lustre_cfg_string(lcfg, 0));
479                 printf("1:(struct lov_desc)\n");
480                 desc = (struct lov_desc *)(lustre_cfg_string(lcfg, 1));
481                 printf("\t\tuuid=%s  ", (char *)desc->ld_uuid.uuid);
482                 printf("stripe:cnt=%u ", desc->ld_default_stripe_count);
483                 printf("size=%ju ", (uintmax_t)desc->ld_default_stripe_size);
484                 printf("offset=%ju ",
485                        (uintmax_t)desc->ld_default_stripe_offset);
486                 printf("pattern=%#x", desc->ld_pattern);
487         } else {
488                 printf("setup     ");
489                 print_1_cfg(lcfg);
490         }
491 }
492
493 void print_lustre_cfg(struct lustre_cfg *lcfg, int *skip)
494 {
495         enum lcfg_command_type cmd = __le32_to_cpu(lcfg->lcfg_command);
496
497         if (*skip > 0)
498                 printf("SKIP ");
499
500         switch (cmd) {
501         case(LCFG_ATTACH):{
502                 printf("attach    ");
503                 print_1_cfg(lcfg);
504                 break;
505         }
506         case(LCFG_SETUP):{
507                 print_setup_cfg(lcfg);
508                 break;
509         }
510         case(LCFG_DETACH):{
511                 printf("detach    ");
512                 print_1_cfg(lcfg);
513                 break;
514         }
515         case(LCFG_CLEANUP):{
516                 printf("cleanup   ");
517                 print_1_cfg(lcfg);
518                 break;
519         }
520         case(LCFG_ADD_UUID):{
521                 printf("add_uuid  ");
522                 print_1_cfg(lcfg);
523                 break;
524         }
525         case(LCFG_DEL_UUID):{
526                 printf("del_uuid  ");
527                 print_1_cfg(lcfg);
528                 break;
529         }
530         case(LCFG_ADD_CONN):{
531                 printf("add_conn  ");
532                 print_1_cfg(lcfg);
533                 break;
534         }
535         case(LCFG_DEL_CONN):{
536                 printf("del_conn  ");
537                 print_1_cfg(lcfg);
538                 break;
539         }
540         case(LCFG_LOV_ADD_OBD):{
541                 printf("lov_modify_tgts add ");
542                 print_1_cfg(lcfg);
543                 break;
544         }
545         case(LCFG_LOV_DEL_OBD):{
546                 printf("lov_modify_tgts del ");
547                 print_1_cfg(lcfg);
548                 break;
549         }
550         case(LCFG_ADD_MDC):{
551                 printf("modify_mdc_tgts add ");
552                 print_1_cfg(lcfg);
553                 break;
554         }
555         case(LCFG_DEL_MDC):{
556                 printf("modify_mdc_tgts del ");
557                 print_1_cfg(lcfg);
558                 break;
559         }
560         case(LCFG_MOUNTOPT):{
561                 printf("mount_option ");
562                 print_1_cfg(lcfg);
563                 break;
564         }
565         case(LCFG_DEL_MOUNTOPT):{
566                 printf("del_mount_option ");
567                 print_1_cfg(lcfg);
568                 break;
569         }
570         case(LCFG_SET_TIMEOUT):{
571                 printf("set_timeout=%d ", lcfg->lcfg_num);
572                 break;
573         }
574         case(LCFG_SET_LDLM_TIMEOUT):{
575                 printf("set_ldlm_timeout=%d ", lcfg->lcfg_num);
576                 break;
577         }
578         case(LCFG_SET_UPCALL):{
579                 printf("set_lustre_upcall ");
580                 print_1_cfg(lcfg);
581                 break;
582         }
583         case(LCFG_PARAM):{
584                 printf("param ");
585                 print_1_cfg(lcfg);
586                 break;
587         }
588         case(LCFG_SET_PARAM):{
589                 printf("set_param ");
590                 print_1_cfg(lcfg);
591                 break;
592         }
593         case(LCFG_SPTLRPC_CONF):{
594                 printf("sptlrpc_conf ");
595                 print_1_cfg(lcfg);
596                 break;
597         }
598         case(LCFG_MARKER):{
599                 struct cfg_marker *marker = lustre_cfg_buf(lcfg, 1);
600                 char createtime[26], canceltime[26] = "";
601                 time_t time_tmp;
602
603                 if (marker->cm_flags & CM_START &&
604                     marker->cm_flags & CM_SKIP) {
605                         printf("SKIP START ");
606                         (*skip)++;
607                 } else if (marker->cm_flags & CM_END) {
608                         printf("END   ");
609                         *skip = 0;
610                 }
611
612                 if (marker->cm_flags & CM_EXCLUDE) {
613                         if (marker->cm_flags & CM_START)
614                                 printf("EXCLUDE START ");
615                         else
616                                 printf("EXCLUDE END   ");
617                 }
618
619                 /*
620                  * Handle overflow of 32-bit time_t gracefully.
621                  * The copy to time_tmp is needed in any case to
622                  * keep the pointer happy, even on 64-bit systems.
623                  */
624                 time_tmp = marker->cm_createtime;
625                 if (time_tmp == marker->cm_createtime) {
626                         ctime_r(&time_tmp, createtime);
627                         createtime[strlen(createtime) - 1] = 0;
628                 } else {
629                         strcpy(createtime, "in the distant future");
630                 }
631
632                 if (marker->cm_canceltime) {
633                         /*
634                          * Like cm_createtime, we try to handle overflow of
635                          * 32-bit time_t gracefully. The copy to time_tmp
636                          * is also needed on 64-bit systems to keep the
637                          * pointer happy, see bug 16771
638                          */
639                         time_tmp = marker->cm_canceltime;
640                         if (time_tmp == marker->cm_canceltime) {
641                                 ctime_r(&time_tmp, canceltime);
642                                 canceltime[strlen(canceltime) - 1] = 0;
643                         } else {
644                                 strcpy(canceltime, "in the distant future");
645                         }
646                 }
647
648                 printf("marker %3d (flags=%#04x, v%d.%d.%d.%d) %-15s '%s' %s-%s",
649                        marker->cm_step, marker->cm_flags,
650                        OBD_OCD_VERSION_MAJOR(marker->cm_vers),
651                        OBD_OCD_VERSION_MINOR(marker->cm_vers),
652                        OBD_OCD_VERSION_PATCH(marker->cm_vers),
653                        OBD_OCD_VERSION_FIX(marker->cm_vers),
654                        marker->cm_tgtname, marker->cm_comment,
655                        createtime, canceltime);
656                 break;
657         }
658         case(LCFG_POOL_NEW):{
659                 printf("pool new ");
660                 print_1_cfg(lcfg);
661                 break;
662         }
663         case(LCFG_POOL_ADD):{
664                 printf("pool add ");
665                 print_1_cfg(lcfg);
666                 break;
667         }
668         case(LCFG_POOL_REM):{
669                 printf("pool remove ");
670                 print_1_cfg(lcfg);
671                 break;
672         }
673         case(LCFG_POOL_DEL):{
674                 printf("pool destroy ");
675                 print_1_cfg(lcfg);
676                 break;
677         }
678         default:
679                 printf("unsupported cmd_code = %x\n", cmd);
680         }
681         printf("\n");
682 }
683
684 static void print_hsm_action(struct llog_agent_req_rec *larr)
685 {
686         char buf[12];
687         int sz;
688
689         sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai);
690         printf("lrh=[type=%X len=%d idx=%d] fid="DFID" compound/cookie=%#llx/%#llx status=%s action=%s archive#=%d flags=%#llx create=%llu change=%llu extent=%#llx-%#llx gid=%#llx datalen=%d data=[%s]\n",
691                larr->arr_hdr.lrh_type,
692                larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index,
693                PFID(&larr->arr_hai.hai_fid),
694                (unsigned long long)larr->arr_compound_id,
695                (unsigned long long)larr->arr_hai.hai_cookie,
696                agent_req_status2name(larr->arr_status),
697                hsm_copytool_action2name(larr->arr_hai.hai_action),
698                larr->arr_archive_id,
699                (unsigned long long)larr->arr_flags,
700                (unsigned long long)larr->arr_req_create,
701                (unsigned long long)larr->arr_req_change,
702                (unsigned long long)larr->arr_hai.hai_extent.offset,
703                (unsigned long long)larr->arr_hai.hai_extent.length,
704                (unsigned long long)larr->arr_hai.hai_gid, sz,
705                hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf)));
706 }
707
708 void print_changelog_rec(struct llog_changelog_rec *rec)
709 {
710         time_t secs;
711         struct tm ts;
712
713         secs = __le64_to_cpu(rec->cr.cr_time) >> 30;
714         gmtime_r(&secs, &ts);
715         printf("changelog record id:0x%x index:%llu cr_flags:0x%x cr_type:%s(0x%x) date:'%02d:%02d:%02d.%09d %04d.%02d.%02d' target:"DFID,
716                __le32_to_cpu(rec->cr_hdr.lrh_id),
717                (unsigned long long)__le64_to_cpu(rec->cr.cr_index),
718                __le32_to_cpu(rec->cr.cr_flags),
719                changelog_type2str(__le32_to_cpu(rec->cr.cr_type)),
720                __le32_to_cpu(rec->cr.cr_type),
721                ts.tm_hour, ts.tm_min, ts.tm_sec,
722                (int)(__le64_to_cpu(rec->cr.cr_time) & ((1 << 30) - 1)),
723                ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
724                PFID(&rec->cr.cr_tfid));
725
726         if (rec->cr.cr_flags & CLF_JOBID) {
727                 struct changelog_ext_jobid *jid =
728                         changelog_rec_jobid(&rec->cr);
729
730                 if (jid->cr_jobid[0] != '\0')
731                         printf(" jobid:%s", jid->cr_jobid);
732         }
733
734         if (rec->cr.cr_flags & CLF_EXTRA_FLAGS) {
735                 struct changelog_ext_extra_flags *ef =
736                         changelog_rec_extra_flags(&rec->cr);
737
738                 printf(" cr_extra_flags:0x%llx",
739                        (unsigned long long)__le64_to_cpu(ef->cr_extra_flags));
740
741                 if (ef->cr_extra_flags & CLFE_UIDGID) {
742                         struct changelog_ext_uidgid *uidgid =
743                                 changelog_rec_uidgid(&rec->cr);
744
745                         printf(" user:%u:%u",
746                                __le32_to_cpu(uidgid->cr_uid),
747                                __le32_to_cpu(uidgid->cr_gid));
748                 }
749                 if (ef->cr_extra_flags & CLFE_NID) {
750                         struct changelog_ext_nid *nid =
751                                 changelog_rec_nid(&rec->cr);
752
753                         printf(" nid:%s",
754                                libcfs_nid2str(nid->cr_nid));
755                 }
756
757                 if (ef->cr_extra_flags & CLFE_OPEN) {
758                         struct changelog_ext_openmode *omd =
759                                 changelog_rec_openmode(&rec->cr);
760                         char mode[] = "---";
761
762                         /* exec mode must be exclusive */
763                         if (__le32_to_cpu(omd->cr_openflags) & MDS_FMODE_EXEC) {
764                                 mode[2] = 'x';
765                         } else {
766                                 if (__le32_to_cpu(omd->cr_openflags) &
767                                     MDS_FMODE_READ)
768                                         mode[0] = 'r';
769                                 if (__le32_to_cpu(omd->cr_openflags) &
770                            (MDS_FMODE_WRITE | MDS_OPEN_TRUNC | MDS_OPEN_APPEND))
771                                         mode[1] = 'w';
772                         }
773
774                         if (strcmp(mode, "---") != 0)
775                                 printf(" mode:%s", mode);
776                 }
777
778                 if (ef->cr_extra_flags & CLFE_XATTR) {
779                         struct changelog_ext_xattr *xattr =
780                                 changelog_rec_xattr(&rec->cr);
781
782                         if (xattr->cr_xattr[0] != '\0')
783                                 printf(" xattr:%s", xattr->cr_xattr);
784                 }
785         }
786
787         if (rec->cr.cr_namelen)
788                 printf(" parent:"DFID" name:%.*s", PFID(&rec->cr.cr_pfid),
789                        __le32_to_cpu(rec->cr.cr_namelen),
790                        changelog_rec_name(&rec->cr));
791
792         if (rec->cr.cr_flags & CLF_RENAME) {
793                 struct changelog_ext_rename *rnm =
794                         changelog_rec_rename(&rec->cr);
795
796                 if (!fid_is_zero(&rnm->cr_sfid))
797                         printf(" source_fid:"DFID" source_parent_fid:"DFID
798                                " %.*s",
799                                PFID(&rnm->cr_sfid),
800                                PFID(&rnm->cr_spfid),
801                                (int)__le32_to_cpu(
802                                        changelog_rec_snamelen(&rec->cr)),
803                                changelog_rec_sname(&rec->cr));
804         }
805         printf("\n");
806 }
807
808 static void lustre_swab_lu_fid(struct lu_fid *fid)
809 {
810         fid->f_seq = __swab64(fid->f_seq);
811         fid->f_oid = __swab32(fid->f_oid);
812         fid->f_ver = __swab32(fid->f_ver);
813 }
814
815 static inline size_t
816 update_op_size(unsigned int param_count)
817 {
818         return offsetof(struct update_op, uop_params_off[param_count]);
819 }
820
821
822 static inline struct update_op *
823 update_op_next_op(const struct update_op *uop)
824 {
825         return (struct update_op *)((char *)uop +
826                                 update_op_size(uop->uop_param_count));
827 }
828
829 static void lustre_swab_update_ops(struct update_ops *uops,
830                                    unsigned int op_count)
831 {
832         unsigned int i;
833         unsigned int j;
834
835         struct update_op *op =
836                (struct update_op *)((char *)&uops->uops_op[0]);
837
838         for (i = 0; i < op_count; i++, op = update_op_next_op(op)) {
839                 lustre_swab_lu_fid(&op->uop_fid);
840                 op->uop_type = __swab16(op->uop_type);
841                 op->uop_param_count = __swab16(op->uop_param_count);
842                 for (j = 0; j < op->uop_param_count; j++)
843                         op->uop_params_off[j] = __swab16(op->uop_params_off[j]);
844         }
845 }
846 static const char *update_op_str(__u16 opc)
847 {
848         static const char *opc_str[] = {
849                 [OUT_START] = "start",
850                 [OUT_CREATE] = "create",
851                 [OUT_DESTROY] = "destroy",
852                 [OUT_REF_ADD] = "ref_add",
853                 [OUT_REF_DEL] = "ref_del",
854                 [OUT_ATTR_SET] = "attr_set",
855                 [OUT_ATTR_GET] = "attr_get",
856                 [OUT_XATTR_SET] = "xattr_set",
857                 [OUT_XATTR_GET] = "xattr_get",
858                 [OUT_XATTR_LIST] = "xattr_list",
859                 [OUT_INDEX_LOOKUP] = "lookup",
860                 [OUT_INDEX_INSERT] = "insert",
861                 [OUT_INDEX_DELETE] = "delete",
862                 [OUT_WRITE] = "write",
863                 [OUT_XATTR_DEL] = "xattr_del",
864                 [OUT_PUNCH] = "punch",
865                 [OUT_READ] = "read",
866                 [OUT_NOOP] = "noop",
867         };
868
869         if (opc < (sizeof(opc_str) / sizeof((opc_str)[0])) &&
870             opc_str[opc] != NULL)
871                 return opc_str[opc];
872         else
873                 return "unknown";
874 }
875
876 char *buf2str(void *buf, unsigned int size)
877 {
878         const char *hex = "0123456789ABCDEF";
879         char *buf_c = buf;
880         static char string[128];
881         int i, j = 0;
882         bool format_hex = false;
883
884         if (size > 0 && buf_c[size - 1] == 0)
885                 size--;
886         for (i = 0; i < size; i++) {
887                 if (buf_c[i] >= 0x20 && buf_c[i] <= 0x7E) {
888                         string[j++] = buf_c[i];
889                         format_hex = false;
890                 } else if (j < sizeof(string) - 6) {
891                         if (!format_hex) {
892                                 string[j++] = '\\';
893                                 string[j++] = 'x';
894                                 format_hex = true;
895                         }
896                         string[j++] = hex[(buf_c[i] >> 4) & 0xF];
897                         string[j++] = hex[buf_c[i] & 0xF];
898                 } else {
899                         break;
900                 }
901                 if (j == sizeof(string) - 2)
902                         break;
903         }
904         string[j] = 0;
905         return string;
906 }
907
908 static inline size_t
909 object_update_param_size(const struct object_update_param *param)
910 {
911         return roundup(sizeof(*param) + param->oup_len, sizeof(__u64));
912 }
913
914 void print_update_rec(struct llog_update_record *lur)
915 {
916         struct update_records *rec = &lur->lur_update_rec;
917         unsigned int i, j, up_count, pm_count;
918         struct update_op *op;
919         struct object_update_param *pm;
920
921         up_count = __le32_to_cpu(rec->ur_update_count);
922         pm_count = __le32_to_cpu(rec->ur_param_count);
923         printf("updatelog record master_transno:%llu batchid:%llu flags:0x%x u_index:%d u_count:%d p_count:%d\n",
924                (unsigned long long)__le64_to_cpu(rec->ur_master_transno),
925                (unsigned long long)__le64_to_cpu(rec->ur_batchid),
926                __le32_to_cpu(rec->ur_flags),
927                __le32_to_cpu(rec->ur_index),
928                up_count,
929                pm_count);
930
931         op = (struct update_op *)((char *)&rec->ur_ops.uops_op[0] + 0);
932         if (op->uop_type != __le16_to_cpu(op->uop_type))
933                 lustre_swab_update_ops(&rec->ur_ops, up_count);
934
935         for (i = 0; i < up_count; i++, op = update_op_next_op(op)) {
936                 printf("\t"DFID" type:%s/%d params:%d ",
937                        PFID(&op->uop_fid), update_op_str(op->uop_type),
938                        op->uop_type, op->uop_param_count);
939                 for (j = 0; j < op->uop_param_count; j++)
940                         printf("p_%d:%d ", j, op->uop_params_off[j]);
941                 printf("\n");
942         }
943         pm = (struct object_update_param *) op;
944         for (i = 0; i < pm_count; i++) {
945                 printf("\tp_%d - %d/%s\n", i, pm->oup_len,
946                        buf2str(pm->oup_buf, pm->oup_len));
947                 pm = (struct object_update_param *)((char *)pm +
948                      object_update_param_size(pm));
949         }
950         printf("\n");
951
952 }
953
954 static void print_unlink_rec(struct llog_unlink_rec *lur)
955 {
956         printf("unlink record id:0x%x target %llx:%x:%x\n",
957                 __le32_to_cpu(lur->lur_hdr.lrh_id),
958                 (unsigned long long)__le64_to_cpu(lur->lur_oid),
959                 __le32_to_cpu(lur->lur_oseq),
960                 __le32_to_cpu(lur->lur_count));
961 }
962
963 static void print_unlink64_rec(struct llog_unlink64_rec *lur)
964 {
965         printf("unlink64 record id:0x%x target "DFID"\n",
966                 __le32_to_cpu(lur->lur_hdr.lrh_id),
967                 PFID(&lur->lur_fid));
968 }
969
970 static void print_setattr64_rec(struct llog_setattr64_rec *lsr)
971 {
972         printf("setattr64 record id:0x%x target "DFID" valid %llx uid %u:%u gid %u:%u\n",
973                 __le32_to_cpu(lsr->lsr_hdr.lrh_id),
974                 PFID(&lsr->lsr_oi.oi_fid),
975                 (unsigned long long)__le64_to_cpu(lsr->lsr_valid),
976                 __le32_to_cpu(lsr->lsr_uid_h),
977                 __le32_to_cpu(lsr->lsr_uid),
978                 __le32_to_cpu(lsr->lsr_gid_h),
979                 __le32_to_cpu(lsr->lsr_gid));
980 }
981
982 static void print_setattr64_rec_v2(struct llog_setattr64_rec_v2 *lsr)
983 {
984         printf("setattr64 v2 record id:0x%x target "DFID" valid %llx uid %u:%u gid %u:%u prj %u\n",
985                 __le32_to_cpu(lsr->lsr_hdr.lrh_id),
986                 PFID(&lsr->lsr_oi.oi_fid),
987                 (unsigned long long)__le64_to_cpu(lsr->lsr_valid),
988                 __le32_to_cpu(lsr->lsr_uid_h),
989                 __le32_to_cpu(lsr->lsr_uid),
990                 __le32_to_cpu(lsr->lsr_gid_h),
991                 __le32_to_cpu(lsr->lsr_gid),
992                 __le32_to_cpu(lsr->lsr_projid));
993 }
994
995
996 static void print_records(struct llog_rec_hdr **recs,
997                           int rec_number, int is_ext)
998 {
999         __u32 lopt;
1000         int i, skip = 0;
1001
1002         for (i = 0; i < rec_number; i++) {
1003                 if (!recs[i]) {
1004                         llapi_printf(LLAPI_MSG_NORMAL,
1005                                      "uninitialized llog record at index %d\n",
1006                                      i);
1007                         break;
1008                 }
1009                 printf("#%.2d (%.3d)", __le32_to_cpu(recs[i]->lrh_index),
1010                        __le32_to_cpu(recs[i]->lrh_len));
1011
1012                 lopt = __le32_to_cpu(recs[i]->lrh_type);
1013
1014                 if (recs[i]->lrh_id == CANCELLED)
1015                         printf("NOT SET ");
1016
1017                 switch (lopt) {
1018                 case OBD_CFG_REC:
1019                         print_lustre_cfg(
1020                                 (struct lustre_cfg *)((char *)(recs[i]) +
1021                                 sizeof(struct llog_rec_hdr)), &skip);
1022                         break;
1023                 case LLOG_PAD_MAGIC:
1024                         printf("padding\n");
1025                         break;
1026                 case LLOG_LOGID_MAGIC:
1027                         print_log_path((struct llog_logid_rec *)recs[i],
1028                                        is_ext);
1029                         break;
1030                 case HSM_AGENT_REC:
1031                         print_hsm_action((struct llog_agent_req_rec *)recs[i]);
1032                         break;
1033                 case CHANGELOG_REC:
1034                         print_changelog_rec((struct llog_changelog_rec *)
1035                                             recs[i]);
1036                         break;
1037                 case CHANGELOG_USER_REC:
1038                 case CHANGELOG_USER_REC2:
1039                         printf("changelog_user record id:0x%x\n",
1040                                __le32_to_cpu(recs[i]->lrh_id));
1041                         break;
1042                 case UPDATE_REC:
1043                         print_update_rec((struct llog_update_record *)recs[i]);
1044                         break;
1045                 case MDS_UNLINK_REC:
1046                         print_unlink_rec((struct llog_unlink_rec *)recs[i]);
1047                         break;
1048                 case MDS_UNLINK64_REC:
1049                         print_unlink64_rec((struct llog_unlink64_rec *)recs[i]);
1050                         break;
1051                 case MDS_SETATTR64_REC:
1052                         if (__le32_to_cpu(recs[i]->lrh_len) >
1053                                 sizeof(struct llog_setattr64_rec)) {
1054                                 print_setattr64_rec_v2(
1055                                   (struct llog_setattr64_rec_v2 *)recs[i]);
1056                         } else {
1057                                 print_setattr64_rec(
1058                                         (struct llog_setattr64_rec *)recs[i]);
1059                         }
1060                         break;
1061                 default:
1062                         printf("unknown type %x\n", lopt);
1063                         break;
1064                 }
1065         }
1066 }
1067
1068 /** @} llog_reader */