*
* 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2013, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <lustre_disk.h>
#include <lustre_ver.h>
-int run_command(char *cmd)
+char *progname;
+static struct option const longopts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "client", no_argument, 0, 'c' },
+ { "reply", no_argument, 0, 'r' },
+ { 0, 0, 0, 0}
+};
+
+/* Executes the command \a cmd and returns command status.
+ */
+int run_command(char *cmd, size_t cmdsz)
{
- char log[] = "/tmp/mkfs_logXXXXXX";
- int fd, rc;
-
-
- if ((fd = mkstemp(log)) >= 0) {
- close(fd);
- strcat(cmd, " >");
- strcat(cmd, log);
- }
- strcat(cmd, " 2>&1");
-
- /* Can't use popen because we need the rv of the command */
- rc = system(cmd);
- if (rc && fd >= 0) {
- char buf[128];
- FILE *fp;
- fp = fopen(log, "r");
- if (fp) {
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- if (rc)
- printf(" %s", buf);
- }
- fclose(fp);
- }
- }
- if (fd >= 0)
- remove(log);
- return rc;
-}
+ char log[] = "/tmp/run_command_logXXXXXX";
+ int fd, rc;
+
+ if (strlen(cmd) + strlen(log) + 8 > cmdsz) {
+ fprintf(stderr, "Command buffer overflow: %.*s...\n",
+ (int)cmdsz, cmd);
+ return -ENOMEM;
+ }
+ fd = mkstemp(log);
+ if (fd >= 0) {
+ close(fd);
+ strncat(cmd, " >", 2);
+ strncat(cmd, log, strlen(log));
+ }
+ strncat(cmd, " 2>&1", 5);
+
+ /* Can't use popen because we need the rv of the command */
+ rc = system(cmd);
+ if (rc && fd >= 0) {
+ char buf[128];
+ FILE *fp;
+ fp = fopen(log, "r");
+ if (fp) {
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if (rc)
+ printf(" %s", buf);
+ }
+ fclose(fp);
+ }
+ }
+ if (fd >= 0)
+ remove(log);
+ return rc;
+}
+
+
+void display_usage(void)
+{
+ printf("Usage: %s [OPTIONS] devicename\n", progname);
+ printf("Read and print the last_rcvd file from a device\n");
+ printf("(safe for mounted devices)\n");
+ printf("\t-c, --client, display client information\n");
+ printf("\t-h, --help, display this help and exit\n");
+ printf("\t-r, --reply, display reply data information\n");
+}
int main(int argc, char *const argv[])
{
- char tmpdir[] = "/tmp/dirXXXXXX";
- char cmd[128];
- char filepnm[128];
- char *progname, *dev;
- struct lr_server_data lsd;
- FILE *filep;
- int ret;
-
- if ((argc < 2) || (argv[argc - 1][0] == '-')) {
- printf("Usage: %s devicename\n", argv[0]);
- printf("Read and print the last_rcvd file from a device\n");
- printf("(safe for mounted devices)\n");
- return EINVAL;
- }
-
- progname = argv[0];
- dev = argv[argc - 1];
-
- /* Make a temporary directory to hold Lustre data files. */
- if (!mkdtemp(tmpdir)) {
- fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
- progname, tmpdir, strerror(errno));
- return errno;
- }
-
- memset(cmd, 0, sizeof(cmd));
+ char tmpdir[] = "/tmp/dirXXXXXX";
+ char cmd[128];
+ char filepnm[128] = "";
+ char *dev;
+ struct lr_server_data lsd;
+ FILE *filep = NULL;
+ int ret;
+ int c;
+ int opt_client = 0;
+ int opt_reply = 0;
+
+ progname = argv[0];
+ while ((c = getopt_long(argc, argv, "chr", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'c':
+ opt_client = 1;
+ break;
+ case 'r':
+ opt_reply = 1;
+ break;
+ case 'h':
+ default:
+ display_usage();
+ return -1;
+ }
+ }
+ dev = argv[optind];
+ if (!dev) {
+ display_usage();
+ return -1;
+ }
+
+ /* Make a temporary directory to hold Lustre data files. */
+ if (!mkdtemp(tmpdir)) {
+ fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
+ progname, tmpdir, strerror(errno));
+ return errno;
+ }
+
+ memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd),
- "%s -c -R 'dump /%s %s/%s' %s",
- DEBUGFS, LAST_RCVD, tmpdir, LAST_RCVD, dev);
-
- ret = run_command(cmd);
- if (ret) {
- fprintf(stderr, "%s: Unable to dump %s file\n",
- progname, LAST_RCVD);
- goto out_rmdir;
- }
-
- sprintf(filepnm, "%s/%s", tmpdir, LAST_RCVD);
- filep = fopen(filepnm, "r");
- if (!filep) {
- fprintf(stderr, "%s: Unable to read old data\n",
- progname);
- ret = -errno;
- goto out_rmdir;
- }
-
- printf("Reading %s\n", LAST_RCVD);
- ret = fread(&lsd, 1, sizeof(lsd), filep);
- if (ret < sizeof(lsd)) {
- fprintf(stderr, "%s: Short read (%d of %d)\n",
- progname, ret, (int)sizeof(lsd));
- ret = -ferror(filep);
- if (ret)
- goto out_close;
- }
-
- #if 0
- __u8 lsd_uuid[40]; /* server UUID */
- __u64 lsd_last_transno; /* last completed transaction ID */
- __u64 lsd_compat14; /* reserved - compat with old last_rcvd */
- __u64 lsd_mount_count; /* incarnation number */
- __u32 lsd_feature_compat; /* compatible feature flags */
- __u32 lsd_feature_rocompat;/* read-only compatible feature flags */
- __u32 lsd_feature_incompat;/* incompatible feature flags */
- __u32 lsd_server_size; /* size of server data area */
- __u32 lsd_client_start; /* start of per-client data area */
- __u16 lsd_client_size; /* size of per-client data area */
- __u16 lsd_subdir_count; /* number of subdirectories for objects */
- __u64 lsd_catalog_oid; /* recovery catalog object id */
- __u32 lsd_catalog_ogen; /* recovery catalog inode generation */
- __u8 lsd_peeruuid[40]; /* UUID of MDS associated with this OST */
- __u32 lsd_ost_index; /* index number of OST in LOV */
- __u32 lsd_mdt_index; /* index number of MDT in LMV */
- __u8 lsd_padding[LR_SERVER_SIZE - 148];
- #endif
-
- printf("UUID %s\n", lsd.lsd_uuid);
- printf("Feature compat=%#x\n", lsd.lsd_feature_compat);
- printf("Feature incompat=%#x\n", lsd.lsd_feature_incompat);
- printf("Feature rocompat=%#x\n", lsd.lsd_feature_rocompat);
- printf("Last transaction %llu\n", (long long)lsd.lsd_last_transno);
- printf("ost index %u\n", lsd.lsd_ost_index);
- printf("mdt index %u\n", lsd.lsd_mdt_index);
-
- if ((lsd.lsd_feature_compat & OBD_COMPAT_OST) ||
- (lsd.lsd_feature_incompat & OBD_INCOMPAT_OST)) {
- printf("OST, index %d\n", lsd.lsd_ost_index);
- } else if ((lsd.lsd_feature_compat & OBD_COMPAT_MDT) ||
- (lsd.lsd_feature_incompat & OBD_INCOMPAT_MDT)) {
- /* We must co-locate so mgs can see old logs.
- If user doesn't want this, they can copy the old
- logs manually and re-tunefs. */
- printf("MDS, index %d\n", lsd.lsd_mdt_index);
- } else {
- /* If neither is set, we're pre-1.4.6, make a guess. */
- /* Construct debugfs command line. */
- memset(cmd, 0, sizeof(cmd));
- sprintf(cmd,
- "%s -c -R 'rdump /%s %s' %s",
- DEBUGFS, MDT_LOGS_DIR, tmpdir, dev);
-
- run_command(cmd);
-
- sprintf(filepnm, "%s/%s", tmpdir, MDT_LOGS_DIR);
- if (lsd.lsd_ost_index > 0) {
- printf("non-flagged OST, index %d\n",
- lsd.lsd_ost_index);
- } else {
- /* If there's a LOGS dir, it's an MDT */
- if ((ret = access(filepnm, F_OK)) == 0) {
- /* Old MDT's are always index 0
- (pre CMD) */
- printf("non-flagged MDS, index 0\n");
- } else {
- printf("non-flagged OST, index unknown\n");
- }
- }
- }
-
-out_close:
- fclose(filep);
+ "%s -c -R 'dump /%s %s/%s' %s",
+ DEBUGFS, LAST_RCVD, tmpdir, LAST_RCVD, dev);
+
+ ret = run_command(cmd, sizeof(cmd));
+ if (ret) {
+ fprintf(stderr, "%s: Unable to dump %s file\n",
+ progname, LAST_RCVD);
+ goto out_rmdir;
+ }
+
+ snprintf(filepnm, 128, "%s/%s", tmpdir, LAST_RCVD);
+ filep = fopen(filepnm, "r");
+ if (!filep) {
+ fprintf(stderr, "%s: Unable to read old data\n",
+ progname);
+ ret = -errno;
+ goto out_rmdir;
+ }
+ unlink(filepnm);
+
+ /* read lr_server_data structure */
+ printf("%s:\n", LAST_RCVD);
+ ret = fread(&lsd, 1, sizeof(lsd), filep);
+ if (ret < sizeof(lsd)) {
+ fprintf(stderr, "%s: Short read (%d of %d)\n",
+ progname, ret, (int)sizeof(lsd));
+ ret = -ferror(filep);
+ if (ret)
+ goto out_close;
+ }
+
+ /* swab structure fields of interest */
+ lsd.lsd_feature_compat = __le32_to_cpu(lsd.lsd_feature_compat);
+ lsd.lsd_feature_incompat = __le32_to_cpu(lsd.lsd_feature_incompat);
+ lsd.lsd_feature_rocompat = __le32_to_cpu(lsd.lsd_feature_rocompat);
+ lsd.lsd_last_transno = __le64_to_cpu(lsd.lsd_last_transno);
+ lsd.lsd_osd_index = __le32_to_cpu(lsd.lsd_osd_index);
+ lsd.lsd_mount_count = __le64_to_cpu(lsd.lsd_mount_count);
+
+ /* display */
+ printf(" uuid: %.40s\n", lsd.lsd_uuid);
+ printf(" feature_compat: %#x\n", lsd.lsd_feature_compat);
+ printf(" feature_incompat: %#x\n", lsd.lsd_feature_incompat);
+ printf(" feature_rocompat: %#x\n", lsd.lsd_feature_rocompat);
+ printf(" last_transaction: %llu\n", lsd.lsd_last_transno);
+ printf(" target_index: %u\n", lsd.lsd_osd_index);
+ printf(" mount_count: %llu\n", lsd.lsd_mount_count);
+
+ /* read client information */
+ if (opt_client) {
+ lsd.lsd_client_start = __le32_to_cpu(lsd.lsd_client_start);
+ lsd.lsd_client_size = __le16_to_cpu(lsd.lsd_client_size);
+ printf(" client_area_start: %u\n", lsd.lsd_client_start);
+ printf(" client_area_size: %hu\n", lsd.lsd_client_size);
+
+ /* seek to per-client data area */
+ ret = fseek(filep, lsd.lsd_client_start, SEEK_SET);
+ if (ret) {
+ fprintf(stderr, "%s: seek failed. %s\n",
+ progname, strerror(errno));
+ ret = errno;
+ goto out_close;
+ }
+
+ /* walk throuh the per-client data area */
+ while (true) {
+ struct lsd_client_data lcd;
+
+ /* read a per-client data area */
+ ret = fread(&lcd, 1, sizeof(lcd), filep);
+ if (ret < sizeof(lcd)) {
+ if (feof(filep))
+ break;
+ fprintf(stderr, "%s: Short read (%d of %d)\n",
+ progname, ret, (int)sizeof(lcd));
+ ret = -ferror(filep);
+ goto out_close;
+ }
+
+ if (lcd.lcd_uuid[0] == '\0')
+ continue;
+
+ /* swab structure fields */
+ lcd.lcd_last_transno =
+ __le64_to_cpu(lcd.lcd_last_transno);
+ lcd.lcd_last_xid = __le64_to_cpu(lcd.lcd_last_xid);
+ lcd.lcd_last_result = __le32_to_cpu(lcd.lcd_last_result);
+ lcd.lcd_last_data = __le32_to_cpu(lcd.lcd_last_data);
+ lcd.lcd_generation = __le32_to_cpu(lcd.lcd_generation);
+
+ /* display per-client data area */
+ printf("\n %.40s:\n", lcd.lcd_uuid);
+ printf(" generation: %u\n", lcd.lcd_generation);
+ printf(" last_transaction: %llu\n",
+ lcd.lcd_last_transno);
+ printf(" last_xid: %llu\n", lcd.lcd_last_xid);
+ printf(" last_result: %u\n", lcd.lcd_last_result);
+ printf(" last_data: %u\n", lcd.lcd_last_data);
+
+ if (lcd.lcd_last_close_transno != 0 &&
+ lcd.lcd_last_close_xid != 0) {
+ lcd.lcd_last_close_transno =
+ __le64_to_cpu(lcd.lcd_last_close_transno);
+ lcd.lcd_last_close_xid =
+ __le64_to_cpu(lcd.lcd_last_close_xid);
+ lcd.lcd_last_close_result =
+ __le32_to_cpu(lcd.lcd_last_close_result);
+ lcd.lcd_last_close_data =
+ __le32_to_cpu(lcd.lcd_last_close_data);
+ printf(" last_close_transation: %llu\n",
+ lcd.lcd_last_close_transno);
+ printf(" last_close_xid: %llu\n",
+ lcd.lcd_last_close_xid);
+ printf(" last_close_result: %u\n",
+ lcd.lcd_last_close_result);
+ printf(" last_close_data: %u\n",
+ lcd.lcd_last_close_data);
+ }
+ }
+ }
+ fclose(filep);
+ filep = NULL;
+
+ /* read reply data information */
+ if (opt_reply) {
+ struct lsd_reply_header lrh;
+ struct lsd_reply_data lrd;
+ unsigned long long slot;
+
+ snprintf(cmd, sizeof(cmd),
+ "%s -c -R 'dump /%s %s/%s' %s",
+ DEBUGFS, REPLY_DATA, tmpdir, REPLY_DATA, dev);
+
+ ret = run_command(cmd, sizeof(cmd));
+ if (ret) {
+ fprintf(stderr, "%s: Unable to dump %s file\n",
+ progname, REPLY_DATA);
+ goto out_rmdir;
+ }
+
+ snprintf(filepnm, sizeof(filepnm),
+ "%s/%s", tmpdir, REPLY_DATA);
+ filep = fopen(filepnm, "r");
+ if (!filep) {
+ fprintf(stderr, "%s: Unable to read reply data\n",
+ progname);
+ ret = -errno;
+ goto out_rmdir;
+ }
+ unlink(filepnm);
+
+ /* read reply_data header */
+ printf("\n%s:\n", REPLY_DATA);
+ ret = fread(&lrh, 1, sizeof(lrh), filep);
+ if (ret < sizeof(lrh)) {
+ fprintf(stderr, "%s: Short read (%d of %d)\n",
+ progname, ret, (int)sizeof(lrh));
+ ret = -ferror(filep);
+ if (ret)
+ goto out_close;
+ }
+
+ /* check header */
+ lrh.lrh_magic = __le32_to_cpu(lrh.lrh_magic);
+ lrh.lrh_header_size = __le32_to_cpu(lrh.lrh_header_size);
+ lrh.lrh_reply_size = __le32_to_cpu(lrh.lrh_reply_size);
+ if (lrh.lrh_magic != LRH_MAGIC) {
+ fprintf(stderr, "%s: invalid %s header: "
+ "lrh_magic=%08x expected %08x\n",
+ progname, REPLY_DATA, lrh.lrh_magic, LRH_MAGIC);
+ goto out_close;
+ }
+ if (lrh.lrh_header_size != sizeof(struct lsd_reply_header)) {
+ fprintf(stderr, "%s: invalid %s header: "
+ "lrh_header_size=%08x expected %08x\n",
+ progname, REPLY_DATA, lrh.lrh_header_size,
+ (unsigned int)sizeof(struct lsd_reply_header));
+ goto out_close;
+ }
+ if (lrh.lrh_reply_size != sizeof(struct lsd_reply_data)) {
+ fprintf(stderr, "%s: invalid %s header: "
+ "lrh_reply_size=%08x expected %08x\n",
+ progname, REPLY_DATA, lrh.lrh_reply_size,
+ (unsigned int)sizeof(struct lsd_reply_data));
+ goto out_close;
+ }
+
+ /* walk throuh the reply data */
+ for (slot = 0; ; slot++) {
+ /* read a reply data */
+ ret = fread(&lrd, 1, sizeof(lrd), filep);
+ if (ret < sizeof(lrd)) {
+ if (feof(filep))
+ break;
+ fprintf(stderr, "%s: Short read (%d of %d)\n",
+ progname, ret, (int)sizeof(lrd));
+ ret = -ferror(filep);
+ goto out_close;
+ }
+
+ /* display reply data */
+ lrd.lrd_transno = __le64_to_cpu(lrd.lrd_transno);
+ lrd.lrd_xid = __le64_to_cpu(lrd.lrd_xid);
+ lrd.lrd_data = __le64_to_cpu(lrd.lrd_data);
+ lrd.lrd_result = __le32_to_cpu(lrd.lrd_result);
+ lrd.lrd_client_gen = __le32_to_cpu(lrd.lrd_client_gen);
+
+ printf(" %lld:\n", slot);
+ printf(" client_generation: %u\n",
+ lrd.lrd_client_gen);
+ printf(" last_transaction: %llu\n", lrd.lrd_transno);
+ printf(" last_xid: %llu\n", lrd.lrd_xid);
+ printf(" last_result: %u\n", lrd.lrd_result);
+ printf(" last_data: %llu\n\n", lrd.lrd_data);
+ }
+ }
+
+out_close:
+ if (filep != NULL)
+ fclose(filep);
out_rmdir:
- memset(cmd, 0, sizeof(cmd));
- sprintf(cmd, "rm -rf %s", tmpdir);
- run_command(cmd);
- return ret;
+ rmdir(tmpdir);
+ return ret;
}