X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Futils%2Fllog_reader.c;h=01e59de320d24a4c00cb46877975ac7ddda7fb68;hp=d1fd956a3c95f8384f560372984a68dcac0637d3;hb=3f3a241498be7e043df7e416da7fc8722a559498;hpb=665e36b780faa2144cecccd29a0d8a8196a76903 diff --git a/lustre/utils/llog_reader.c b/lustre/utils/llog_reader.c index d1fd956..01e59de 100644 --- a/lustre/utils/llog_reader.c +++ b/lustre/utils/llog_reader.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -17,39 +15,69 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, 2017, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ * Lustre is a trademark of Sun Microsystems, Inc. */ - /* Interpret configuration llogs */ - +/** \defgroup llog_reader Lustre Log Reader + * + * Interpret llogs used for storing configuration and changelog data + * + * @{ + */ +#include +#include +#include #include +#include +#include #include #include +#ifdef HAVE_ENDIAN_H +# include +#endif +#include #include - +#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include + +static inline int ext2_test_bit(int nr, const void *addr) +{ +#if __BYTE_ORDER == __BIG_ENDIAN + const unsigned char *tmp = addr; + return (tmp[nr >> 3] >> (nr & 7)) & 1; +#else + const unsigned long *tmp = addr; + return ((1UL << (nr & (__WORDSIZE - 1))) & + ((tmp)[nr / __WORDSIZE])) != 0; +#endif +} int llog_pack_buffer(int fd, struct llog_log_hdr **llog_buf, struct llog_rec_hdr ***recs, int *recs_number); void print_llog_header(struct llog_log_hdr *llog_buf); -void print_records(struct llog_rec_hdr **recs_buf,int rec_number); +static void print_records(struct llog_rec_hdr **recs_buf, + int rec_number, int is_ext); void llog_unpack_buffer(int fd, struct llog_log_hdr *llog_buf, struct llog_rec_hdr **recs_buf); @@ -77,159 +105,278 @@ char* portals_command[17]= "" }; -int main(int argc, char **argv) +int is_fstype_ext(int fd) { - int rc = 0; - int fd, rec_number; - struct llog_log_hdr *llog_buf = NULL; - struct llog_rec_hdr **recs_buf = NULL; - - setlinebuf(stdout); + struct statfs st; + int rc; - if(argc != 2 ){ - printf("Usage: llog_reader filename\n"); - return -1; - } - - fd = open(argv[1],O_RDONLY); - if (fd < 0){ - printf("Could not open the file %s\n", argv[1]); - goto out; - } - rc = llog_pack_buffer(fd, &llog_buf, &recs_buf, &rec_number); - if (rc < 0) { - printf("Could not pack buffer; rc=%d\n", rc); - goto out_fd; - } + rc = fstatfs(fd, &st); + if (rc < 0) { + llapi_error(LLAPI_MSG_ERROR, rc, "Got statfs error."); + return -errno; + } - print_llog_header(llog_buf); - print_records(recs_buf,rec_number); - llog_unpack_buffer(fd,llog_buf,recs_buf); -out_fd: - close(fd); -out: - return rc; + return (st.f_type == EXT4_SUPER_MAGIC); } - -int llog_pack_buffer(int fd, struct llog_log_hdr **llog, - struct llog_rec_hdr ***recs, - int *recs_number) +/** + * Attempt to display a path to the object (file) containing changelog entries, + * referred to by this changelog_catalog record. + * + * This path depends on the implementation of the OSD device; zfs-osd and + * ldiskfs-osd are different. + * + * Assumes that if the file system containing the changelog_catalog is + * ext{2,3,4}, the backend is ldiskfs-osd; otherwise it is either zfs-osd or at + * least names objects based on FID and the zfs-osd path (which includes the + * FID) will be sufficient. + * + * The Object ID stored in the record is also displayed untranslated. + */ +#define OSD_OI_FID_NR (1UL << 7) +static void print_log_path(struct llog_logid_rec *lid, int is_ext) { - int rc = 0, recs_num,rd; - off_t file_size; - struct stat st; - char *file_buf=NULL, *recs_buf=NULL; - struct llog_rec_hdr **recs_pr=NULL; - char *ptr=NULL; - int i; - - rc = fstat(fd,&st); - if (rc < 0){ - printf("Get file stat error.\n"); - goto out; - } - file_size = st.st_size; - - file_buf = malloc(file_size); - if (file_buf == NULL){ - printf("Memory Alloc for file_buf error.\n"); - rc = -ENOMEM; - goto out; - } - *llog = (struct llog_log_hdr*)file_buf; - - rd = read(fd,file_buf,file_size); - if (rd < file_size){ - printf("Read file error.\n"); - rc = -EIO; /*FIXME*/ - goto clear_file_buf; - } - /* the llog header not countable here.*/ - recs_num = le32_to_cpu((*llog)->llh_count)-1; + char object_path[255]; + struct lu_fid fid_from_logid; + + logid_to_fid(&lid->lid_id, &fid_from_logid); + + if (is_ext) + snprintf(object_path, sizeof(object_path), + "O/%ju/d%u/%u", (uintmax_t)fid_from_logid.f_seq, + fid_from_logid.f_oid % 32, + fid_from_logid.f_oid); + else + snprintf(object_path, sizeof(object_path), + "oi.%ju/"DFID_NOBRACE, + (uintmax_t)(fid_from_logid.f_seq & (OSD_OI_FID_NR - 1)), + PFID(&fid_from_logid)); + + printf("id="DFID":%x path=%s\n", + PFID(&lid->lid_id.lgl_oi.oi_fid), lid->lid_id.lgl_ogen, + object_path); +} - recs_buf = malloc(recs_num * sizeof(struct llog_rec_hdr *)); - if (recs_buf == NULL){ - printf("Memory Alloc for recs_buf error.\n"); - rc = -ENOMEM; - goto clear_file_buf; - } - recs_pr = (struct llog_rec_hdr **)recs_buf; +int main(int argc, char **argv) +{ + int rc = 0; + int is_ext; + int fd, rec_number; + struct llog_log_hdr *llog_buf = NULL; + struct llog_rec_hdr **recs_buf = NULL; + + setlinebuf(stdout); + + if (argc != 2) { + printf("Usage: llog_reader filename\n"); + return -1; + } + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "Could not open the file %s.", + argv[1]); + goto out; + } + + is_ext = is_fstype_ext(fd); + if (is_ext < 0) { + rc = is_ext; + llapi_error(LLAPI_MSG_ERROR, -rc, + "Unable to determine filesystem type for %s", + argv[1]); + goto out_fd; + } + + rc = llog_pack_buffer(fd, &llog_buf, &recs_buf, &rec_number); + if (rc < 0) { + llapi_error(LLAPI_MSG_ERROR, rc, "Could not pack buffer."); + goto out_fd; + } + + if (llog_buf != NULL) + print_llog_header(llog_buf); + if (recs_buf != NULL) + print_records(recs_buf, rec_number, is_ext); + llog_unpack_buffer(fd, llog_buf, recs_buf); - ptr = file_buf + le32_to_cpu((*llog)->llh_hdr.lrh_len); - i = 0; +out_fd: + close(fd); +out: + return rc; +} - while (i < recs_num){ - struct llog_rec_hdr *cur_rec = (struct llog_rec_hdr*)ptr; - int idx = le32_to_cpu(cur_rec->lrh_index); - recs_pr[i] = cur_rec; - if (ext2_test_bit(idx, (*llog)->llh_bitmap)) { - if (le32_to_cpu(cur_rec->lrh_type) != OBD_CFG_REC) - printf("rec #%d type=%x len=%u\n", idx, - cur_rec->lrh_type, cur_rec->lrh_len); - } else { - printf("Bit %d of %d not set\n", idx, recs_num); - cur_rec->padding = CANCELLED; - /* The header counts only set records */ - i--; - } - - ptr += le32_to_cpu(cur_rec->lrh_len); - if ((ptr - file_buf) > file_size) { - printf("The log is corrupt (too big at %d)\n", i); - rc = -EINVAL; - goto clear_recs_buf; - } - i++; - } - *recs = recs_pr; - *recs_number = recs_num; +int llog_pack_buffer(int fd, struct llog_log_hdr **llog, + struct llog_rec_hdr ***recs, + int *recs_number) +{ + int rc = 0, recs_num, rd = 0; + long long file_size; + struct stat st; + char *file_buf = NULL, *recs_buf = NULL; + struct llog_rec_hdr **recs_pr = NULL; + char *ptr = NULL; + int count; + int i; + + rc = fstat(fd, &st); + if (rc < 0) { + rc = -errno; + llapi_error(LLAPI_MSG_ERROR, rc, "Got file stat error."); + goto out; + } + + file_size = st.st_size; + if (file_size < sizeof(**llog)) { + llapi_error(LLAPI_MSG_ERROR, rc, + "File too small for llog header: want=%zd got=%lld", + sizeof(**llog), file_size); + rc = -EIO; + goto out; + } + + file_buf = malloc(file_size); + if (file_buf == NULL) { + rc = -ENOMEM; + llapi_error(LLAPI_MSG_ERROR, rc, "Memory Alloc for file_buf."); + goto out; + } + *llog = (struct llog_log_hdr *)file_buf; + + do { + rc = read(fd, file_buf + rd, file_size - rd); + if (rc > 0) + rd += rc; + } while (rc > 0 && rd < file_size); + + if (rd < file_size) { + rc = rc < 0 ? -errno : -EIO; + llapi_error(LLAPI_MSG_ERROR, rc, + "Error reading llog header: need %zd, got %d", + sizeof(**llog), rd); + goto clear_file_buf; + } + + count = __le32_to_cpu((*llog)->llh_count); + if (count < 0) { + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, + "corrupted llog: negative record number %d", + count); + goto clear_file_buf; + } else if (count == 0) { + llapi_printf(LLAPI_MSG_NORMAL, + "uninitialized llog: zero record number\n"); + *recs_number = 0; + goto clear_file_buf; + } + /* the llog header not countable here.*/ + recs_num = count - 1; + + recs_buf = calloc(recs_num, sizeof(**recs_pr)); + if (recs_buf == NULL) { + rc = -ENOMEM; + llapi_error(LLAPI_MSG_ERROR, rc, + "Error allocating %zd bytes for recs_buf", + recs_num * sizeof(**recs_pr)); + goto clear_file_buf; + } + recs_pr = (struct llog_rec_hdr **)recs_buf; + + ptr = file_buf + __le32_to_cpu((*llog)->llh_hdr.lrh_len); + i = 0; + + while (ptr < (file_buf + file_size)) { + struct llog_rec_hdr *cur_rec; + int idx; + unsigned long offset; + + if (ptr + sizeof(**recs_pr) > file_buf + file_size) { + rc = -EINVAL; + llapi_error(LLAPI_MSG_ERROR, rc, + "The log is corrupt (too big at %d)", i); + goto clear_recs_buf; + } + + cur_rec = (struct llog_rec_hdr *)ptr; + idx = __le32_to_cpu(cur_rec->lrh_index); + recs_pr[i] = cur_rec; + offset = (unsigned long)ptr - (unsigned long)file_buf; + if (cur_rec->lrh_len == 0 || + cur_rec->lrh_len > (*llog)->llh_hdr.lrh_len) { + cur_rec->lrh_len = (*llog)->llh_hdr.lrh_len - + offset % (*llog)->llh_hdr.lrh_len; + printf("off %lu skip %u to next chunk.\n", offset, + cur_rec->lrh_len); + i--; + } else if (ext2_test_bit(idx, LLOG_HDR_BITMAP(*llog))) { + printf("rec #%d type=%x len=%u offset %lu\n", idx, + cur_rec->lrh_type, cur_rec->lrh_len, offset); + } else { + printf("Bit %d of %d not set\n", idx, recs_num); + cur_rec->lrh_id = CANCELLED; + /* The header counts only set records */ + i--; + } + + ptr += __le32_to_cpu(cur_rec->lrh_len); + if ((ptr - file_buf) > file_size) { + printf("The log is corrupt (too big at %d)\n", i); + rc = -EINVAL; + goto clear_recs_buf; + } + i++; + } + + *recs = recs_pr; + *recs_number = recs_num; out: - return rc; + return rc; clear_recs_buf: - free(recs_buf); + free(recs_buf); clear_file_buf: - free(file_buf); + free(file_buf); - *llog=NULL; - goto out; + *llog = NULL; + goto out; } void llog_unpack_buffer(int fd, struct llog_log_hdr *llog_buf, - struct llog_rec_hdr **recs_buf) + struct llog_rec_hdr **recs_buf) { - free(llog_buf); - free(recs_buf); - return; + if (llog_buf != NULL) + free(llog_buf); + if (recs_buf != NULL) + free(recs_buf); } void print_llog_header(struct llog_log_hdr *llog_buf) { - time_t t; + time_t t; - printf("Header size : %u\n", - le32_to_cpu(llog_buf->llh_hdr.lrh_len)); + printf("Header size : %u\n", + __le32_to_cpu(llog_buf->llh_hdr.lrh_len)); - t = le64_to_cpu(llog_buf->llh_timestamp); - printf("Time : %s", ctime(&t)); + t = __le64_to_cpu(llog_buf->llh_timestamp); + printf("Time : %s", ctime(&t)); - printf("Number of records: %u\n", - le32_to_cpu(llog_buf->llh_count)-1); + printf("Number of records: %u\n", + __le32_to_cpu(llog_buf->llh_count)-1); - printf("Target uuid : %s \n", - (char *)(&llog_buf->llh_tgtuuid)); + printf("Target uuid : %s\n", + (char *)(&llog_buf->llh_tgtuuid)); - /* Add the other info you want to view here */ + /* Add the other info you want to view here */ - printf("-----------------------\n"); - return; + printf("-----------------------\n"); } static void print_1_cfg(struct lustre_cfg *lcfg) @@ -237,16 +384,47 @@ static void print_1_cfg(struct lustre_cfg *lcfg) int i; if (lcfg->lcfg_nid) - printf("nid=%s("LPX64") ", libcfs_nid2str(lcfg->lcfg_nid), - lcfg->lcfg_nid); + printf("nid=%s(%#jx) ", libcfs_nid2str(lcfg->lcfg_nid), + (uintmax_t)lcfg->lcfg_nid); if (lcfg->lcfg_nal) printf("nal=%d ", lcfg->lcfg_nal); for (i = 0; i < lcfg->lcfg_bufcount; i++) printf("%d:%.*s ", i, lcfg->lcfg_buflens[i], (char*)lustre_cfg_buf(lcfg, i)); - return; } +static char *lustre_cfg_string(struct lustre_cfg *lcfg, __u32 index) +{ + char *s; + + if (lcfg->lcfg_buflens[index] == 0) + return NULL; + + s = lustre_cfg_buf(lcfg, index); + if (s == NULL) + return NULL; + + /* + * make sure it's NULL terminated, even if this kills a char + * of data. Try to use the padding first though. + */ + if (s[lcfg->lcfg_buflens[index] - 1] != '\0') { + size_t last = __ALIGN_KERNEL(lcfg->lcfg_buflens[index], 8) - 1; + char lost; + + /* Use the smaller value */ + if (last > lcfg->lcfg_buflens[index]) + last = lcfg->lcfg_buflens[index]; + + lost = s[last]; + s[last] = '\0'; + if (lost != '\0') { + fprintf(stderr, "Truncated buf %d to '%s' (lost '%c'...)\n", + index, s, lost); + } + } + return s; +} static void print_setup_cfg(struct lustre_cfg *lcfg) { @@ -260,20 +438,19 @@ static void print_setup_cfg(struct lustre_cfg *lcfg) desc = (struct lov_desc*)(lustre_cfg_string(lcfg, 1)); printf("\t\tuuid=%s ", (char*)desc->ld_uuid.uuid); printf("stripe:cnt=%u ", desc->ld_default_stripe_count); - printf("size="LPU64" ", desc->ld_default_stripe_size); - printf("offset="LPU64" ", desc->ld_default_stripe_offset); + printf("size=%ju ", (uintmax_t)desc->ld_default_stripe_size); + printf("offset=%ju ", + (uintmax_t)desc->ld_default_stripe_offset); printf("pattern=%#x", desc->ld_pattern); } else { printf("setup "); print_1_cfg(lcfg); } - - return; } void print_lustre_cfg(struct lustre_cfg *lcfg, int *skip) { - enum lcfg_command_type cmd = le32_to_cpu(lcfg->lcfg_command); + enum lcfg_command_type cmd = __le32_to_cpu(lcfg->lcfg_command); if (*skip > 0) printf("SKIP "); @@ -350,7 +527,10 @@ void print_lustre_cfg(struct lustre_cfg *lcfg, int *skip) } case(LCFG_SET_TIMEOUT):{ printf("set_timeout=%d ", lcfg->lcfg_num); - print_1_cfg(lcfg); + break; + } + case(LCFG_SET_LDLM_TIMEOUT):{ + printf("set_ldlm_timeout=%d ", lcfg->lcfg_num); break; } case(LCFG_SET_UPCALL):{ @@ -358,36 +538,67 @@ void print_lustre_cfg(struct lustre_cfg *lcfg, int *skip) print_1_cfg(lcfg); break; } - case(LCFG_PARAM):{ - printf("param "); + case(LCFG_PARAM):{ + printf("param "); + print_1_cfg(lcfg); + break; + } + case(LCFG_SET_PARAM):{ + printf("set_param "); + print_1_cfg(lcfg); + break; + } + case(LCFG_SPTLRPC_CONF):{ + printf("sptlrpc_conf "); print_1_cfg(lcfg); break; } case(LCFG_MARKER):{ struct cfg_marker *marker = lustre_cfg_buf(lcfg, 1); char createtime[26], canceltime[26] = ""; + time_t time_tmp; + + if (marker->cm_flags & CM_START && + marker->cm_flags & CM_SKIP) { + printf("SKIP START "); + (*skip)++; + } else if (marker->cm_flags & CM_END) { + printf( "END "); + *skip = 0; + } + + if (marker->cm_flags & CM_EXCLUDE) { + if (marker->cm_flags & CM_START) + printf("EXCLUDE START "); + else + printf("EXCLUDE END "); + } + + /* Handle overflow of 32-bit time_t gracefully. + * The copy to time_tmp is needed in any case to + * keep the pointer happy, even on 64-bit systems. */ + time_tmp = marker->cm_createtime; + if (time_tmp == marker->cm_createtime) { + ctime_r(&time_tmp, createtime); + createtime[strlen(createtime) - 1] = 0; + } else { + strcpy(createtime, "in the distant future"); + } - if (marker->cm_flags & CM_SKIP) { - if (marker->cm_flags & CM_START) { - printf("SKIP START "); - (*skip)++; + if (marker->cm_canceltime) { + /* Like cm_createtime, we try to handle overflow of + * 32-bit time_t gracefully. The copy to time_tmp + * is also needed on 64-bit systems to keep the + * pointer happy, see bug 16771 */ + time_tmp = marker->cm_canceltime; + if (time_tmp == marker->cm_canceltime) { + ctime_r(&time_tmp, canceltime); + canceltime[strlen(canceltime) - 1] = 0; } else { - printf( "END "); - *skip = 0; + strcpy(canceltime, "in the distant future"); } } - if (marker->cm_flags & CM_EXCLUDE) { - if (marker->cm_flags & CM_START) - printf("EXCLUDE START "); - else - printf("EXCLUDE END "); - } - ctime_r(&marker->cm_createtime, createtime); - createtime[strlen(createtime) - 1] = 0; - if (marker->cm_canceltime) { - ctime_r(&marker->cm_canceltime, canceltime); - canceltime[strlen(canceltime) - 1] = 0; - } + printf("marker %3d (flags=%#04x, v%d.%d.%d.%d) %-15s '%s' %s-%s", marker->cm_step, marker->cm_flags, OBD_OCD_VERSION_MAJOR(marker->cm_vers), @@ -422,31 +633,189 @@ void print_lustre_cfg(struct lustre_cfg *lcfg, int *skip) printf("unsupported cmd_code = %x\n",cmd); } printf("\n"); - return; } -void print_records(struct llog_rec_hdr **recs, int rec_number) +static void print_hsm_action(struct llog_agent_req_rec *larr) { - __u32 lopt; - int i, skip = 0; - - for(i = 0; i < rec_number; i++) { - printf("#%.2d (%.3d)", le32_to_cpu(recs[i]->lrh_index), - le32_to_cpu(recs[i]->lrh_len)); - - lopt = le32_to_cpu(recs[i]->lrh_type); - - if (recs[i]->padding == CANCELLED) - printf("NOT SET "); - - if (lopt == OBD_CFG_REC) { - struct lustre_cfg *lcfg; - lcfg = (struct lustre_cfg *)((char*)(recs[i]) + - sizeof(struct llog_rec_hdr)); - print_lustre_cfg(lcfg, &skip); - } else if (lopt == LLOG_PAD_MAGIC) { - printf("padding\n"); - } else - printf("unknown type %x\n", lopt); - } + char buf[12]; + int sz; + + sz = larr->arr_hai.hai_len - sizeof(larr->arr_hai); + printf("lrh=[type=%X len=%d idx=%d] fid="DFID + " compound/cookie=%#jx/%#jx" + " status=%s action=%s archive#=%d flags=%#jx" + " create=%ju change=%ju" + " extent=%#jx-%#jx gid=%#jx datalen=%d" + " data=[%s]\n", + larr->arr_hdr.lrh_type, + larr->arr_hdr.lrh_len, larr->arr_hdr.lrh_index, + PFID(&larr->arr_hai.hai_fid), + (uintmax_t)larr->arr_compound_id, + (uintmax_t)larr->arr_hai.hai_cookie, + agent_req_status2name(larr->arr_status), + hsm_copytool_action2name(larr->arr_hai.hai_action), + larr->arr_archive_id, + (uintmax_t)larr->arr_flags, + (uintmax_t)larr->arr_req_create, + (uintmax_t)larr->arr_req_change, + (uintmax_t)larr->arr_hai.hai_extent.offset, + (uintmax_t)larr->arr_hai.hai_extent.length, + (uintmax_t)larr->arr_hai.hai_gid, sz, + hai_dump_data_field(&larr->arr_hai, buf, sizeof(buf))); +} + +void print_changelog_rec(struct llog_changelog_rec *rec) +{ + time_t secs; + struct tm ts; + + secs = __le64_to_cpu(rec->cr.cr_time) >> 30; + gmtime_r(&secs, &ts); + 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, __le32_to_cpu(rec->cr_hdr.lrh_id), + __le64_to_cpu(rec->cr.cr_index), + __le32_to_cpu(rec->cr.cr_flags), + changelog_type2str(__le32_to_cpu(rec->cr.cr_type)), + __le32_to_cpu(rec->cr.cr_type), + ts.tm_hour, ts.tm_min, ts.tm_sec, + (int)(__le64_to_cpu(rec->cr.cr_time) & ((1 << 30) - 1)), + ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, + PFID(&rec->cr.cr_tfid)); + + if (rec->cr.cr_flags & CLF_JOBID) { + struct changelog_ext_jobid *jid = + changelog_rec_jobid(&rec->cr); + + if (jid->cr_jobid[0] != '\0') + printf(" jobid:%s", jid->cr_jobid); + } + + if (rec->cr.cr_flags & CLF_EXTRA_FLAGS) { + struct changelog_ext_extra_flags *ef = + changelog_rec_extra_flags(&rec->cr); + + printf(" cr_extra_flags:0x%llx", + __le64_to_cpu(ef->cr_extra_flags)); + + if (ef->cr_extra_flags & CLFE_UIDGID) { + struct changelog_ext_uidgid *uidgid = + changelog_rec_uidgid(&rec->cr); + + printf(" user:%u:%u", + __le32_to_cpu(uidgid->cr_uid), + __le32_to_cpu(uidgid->cr_gid)); + } + if (ef->cr_extra_flags & CLFE_NID) { + struct changelog_ext_nid *nid = + changelog_rec_nid(&rec->cr); + + printf(" nid:%s", + libcfs_nid2str(nid->cr_nid)); + } + + if (ef->cr_extra_flags & CLFE_OPEN) { + struct changelog_ext_openmode *omd = + changelog_rec_openmode(&rec->cr); + char mode[] = "---"; + + /* exec mode must be exclusive */ + if (__le32_to_cpu(omd->cr_openflags) & MDS_FMODE_EXEC) { + mode[2] = 'x'; + } else { + if (__le32_to_cpu(omd->cr_openflags) & + MDS_FMODE_READ) + mode[0] = 'r'; + if (__le32_to_cpu(omd->cr_openflags) & + (MDS_FMODE_WRITE | MDS_OPEN_TRUNC | MDS_OPEN_APPEND)) + mode[1] = 'w'; + } + + if (strcmp(mode, "---") != 0) + printf(" mode:%s", mode); + + } + + if (ef->cr_extra_flags & CLFE_XATTR) { + struct changelog_ext_xattr *xattr = + changelog_rec_xattr(&rec->cr); + + if (xattr->cr_xattr[0] != '\0') + printf(" xattr:%s", xattr->cr_xattr); + } + } + + if (rec->cr.cr_namelen) + printf(" parent:"DFID" name:%.*s", PFID(&rec->cr.cr_pfid), + __le32_to_cpu(rec->cr.cr_namelen), + changelog_rec_name(&rec->cr)); + + if (rec->cr.cr_flags & CLF_RENAME) { + struct changelog_ext_rename *rnm = + changelog_rec_rename(&rec->cr); + + if (!fid_is_zero(&rnm->cr_sfid)) + printf(" source_fid:"DFID" source_parent_fid:"DFID + " %.*s", + PFID(&rnm->cr_sfid), + PFID(&rnm->cr_spfid), + (int)__le32_to_cpu( + changelog_rec_snamelen(&rec->cr)), + changelog_rec_sname(&rec->cr)); + } + printf("\n"); } + +static void print_records(struct llog_rec_hdr **recs, + int rec_number, int is_ext) +{ + __u32 lopt; + int i, skip = 0; + + for (i = 0; i < rec_number; i++) { + if (recs[i] == NULL) { + llapi_printf(LLAPI_MSG_NORMAL, + "uninitialized llog record at index %d\n", + i); + break; + } + printf("#%.2d (%.3d)", __le32_to_cpu(recs[i]->lrh_index), + __le32_to_cpu(recs[i]->lrh_len)); + + lopt = __le32_to_cpu(recs[i]->lrh_type); + + if (recs[i]->lrh_id == CANCELLED) + printf("NOT SET "); + + switch (lopt) { + case OBD_CFG_REC: + print_lustre_cfg( + (struct lustre_cfg *)((char *)(recs[i]) + + sizeof(struct llog_rec_hdr)), &skip); + break; + case LLOG_PAD_MAGIC: + printf("padding\n"); + break; + case LLOG_LOGID_MAGIC: + print_log_path((struct llog_logid_rec *)recs[i], + is_ext); + break; + case HSM_AGENT_REC: + print_hsm_action((struct llog_agent_req_rec *)recs[i]); + break; + case CHANGELOG_REC: + print_changelog_rec((struct llog_changelog_rec *) + recs[i]); + break; + case CHANGELOG_USER_REC: + printf("changelog_user record id:0x%x\n", + __le32_to_cpu(recs[i]->lrh_id)); + break; + default: + printf("unknown type %x\n", lopt); + break; + } + } +} + +/** @} llog_reader */