4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2013, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
31 * lustre/utils/lr_reader.c
33 * Author: Nathan Rutman <nathan@clusterfs.com>
35 /* Safely read the last_rcvd file from a device */
39 #endif /* HAVE_CONFIG_H */
54 #include <sys/types.h>
56 #include <sys/mount.h>
61 #include <asm/byteorder.h>
62 #include <linux/lustre/lustre_idl.h>
63 #include <linux/lustre/lustre_disk.h>
64 #include <linux/lustre/lustre_ver.h>
67 static struct option const long_opts[] = {
68 { .val = 'c', .name = "client", .has_arg = no_argument },
69 { .val = 'h', .name = "help", .has_arg = no_argument },
70 { .val = 'r', .name = "reply", .has_arg = no_argument },
71 { .val = 'R', .name = "reply_data", .has_arg = required_argument },
72 { .val = 'C', .name = "last_rcvd", .has_arg = required_argument },
81 n = read(fd, buf, sizeof(buf));
83 } while (n == sizeof(buf));
85 fprintf(stderr, "\n");
88 FILE *open_debugfs_file(char *filename, char *tmpdir, char *dev)
90 char log[] = "/tmp/run_command_logXXXXXX";
105 cmd = realloc(cmd, cmdsize);
107 fprintf(stderr, "%s: Unable to allocate cmd buffer\n",
112 n = snprintf(cmd, cmdsize,
113 "%s -c -R 'dump /%s %s/%s' %s > %s 2>&1",
114 DEBUGFS, filename, tmpdir, filename, dev, log);
117 } while (n > cmdsize);
122 fprintf(stderr, "%s: Unable to dump %s file\n",
127 snprintf(filepnm, sizeof(filepnm), "%s/%s", tmpdir, filename);
128 fp = fopen(filepnm, "r");
145 int print_last_rcvd(FILE *fp, int opt_client)
147 struct lr_server_data lsd = {};
151 /* read lr_server_data structure */
152 printf("%s:\n", LAST_RCVD);
153 n = fread(&lsd, 1, sizeof(lsd), fp);
154 if (n < sizeof(lsd)) {
155 fprintf(stderr, "%s: Short read (%d of %d)\n",
156 progname, n, (int)sizeof(lsd));
157 rc = ferror(fp) ? EIO : EINVAL;
160 /* swab structure fields of interest */
161 lsd.lsd_feature_compat = __le32_to_cpu(lsd.lsd_feature_compat);
162 lsd.lsd_feature_incompat = __le32_to_cpu(lsd.lsd_feature_incompat);
163 lsd.lsd_feature_rocompat = __le32_to_cpu(lsd.lsd_feature_rocompat);
164 lsd.lsd_last_transno = __le64_to_cpu(lsd.lsd_last_transno);
165 lsd.lsd_osd_index = __le32_to_cpu(lsd.lsd_osd_index);
166 lsd.lsd_mount_count = __le64_to_cpu(lsd.lsd_mount_count);
169 printf(" uuid: %.40s\n", lsd.lsd_uuid);
170 printf(" feature_compat: %#x\n", lsd.lsd_feature_compat);
171 printf(" feature_incompat: %#x\n", lsd.lsd_feature_incompat);
172 printf(" feature_rocompat: %#x\n", lsd.lsd_feature_rocompat);
173 printf(" last_transaction: %llu\n",
174 (unsigned long long)lsd.lsd_last_transno);
175 printf(" target_index: %u\n", lsd.lsd_osd_index);
176 printf(" mount_count: %llu\n",
177 (unsigned long long)lsd.lsd_mount_count);
179 if (!opt_client || rc)
182 /* read client information */
183 lsd.lsd_client_start = __le32_to_cpu(lsd.lsd_client_start);
184 lsd.lsd_client_size = __le16_to_cpu(lsd.lsd_client_size);
185 printf(" client_area_start: %u\n", lsd.lsd_client_start);
186 printf(" client_area_size: %hu\n", lsd.lsd_client_size);
188 /* seek to per-client data area */
189 rc = fseek(fp, lsd.lsd_client_start, SEEK_SET);
191 fprintf(stderr, "%s: seek failed. %s\n",
192 progname, strerror(errno));
196 /* walk throuh the per-client data area */
198 struct lsd_client_data lcd;
200 /* read a per-client data area */
201 n = fread(&lcd, 1, sizeof(lcd), fp);
202 if (n < sizeof(lcd)) {
205 fprintf(stderr, "%s: Short read (%d of %d)\n",
206 progname, n, (int)sizeof(lcd));
207 return ferror(fp) ? EIO : EINVAL;
210 if (lcd.lcd_uuid[0] == '\0')
213 /* swab structure fields */
214 lcd.lcd_last_transno =
215 __le64_to_cpu(lcd.lcd_last_transno);
216 lcd.lcd_last_xid = __le64_to_cpu(lcd.lcd_last_xid);
217 lcd.lcd_last_result = __le32_to_cpu(lcd.lcd_last_result);
218 lcd.lcd_last_data = __le32_to_cpu(lcd.lcd_last_data);
219 lcd.lcd_generation = __le32_to_cpu(lcd.lcd_generation);
221 /* display per-client data area */
222 printf("\n %.40s:\n", lcd.lcd_uuid);
223 printf(" generation: %u\n", lcd.lcd_generation);
224 printf(" last_transaction: %llu\n",
225 (unsigned long long)lcd.lcd_last_transno);
226 printf(" last_xid: %llu\n",
227 (unsigned long long)lcd.lcd_last_xid);
228 printf(" last_result: %u\n", lcd.lcd_last_result);
229 printf(" last_data: %u\n", lcd.lcd_last_data);
231 if (lcd.lcd_last_close_transno != 0 &&
232 lcd.lcd_last_close_xid != 0) {
233 lcd.lcd_last_close_transno =
234 __le64_to_cpu(lcd.lcd_last_close_transno);
235 lcd.lcd_last_close_xid =
236 __le64_to_cpu(lcd.lcd_last_close_xid);
237 lcd.lcd_last_close_result =
238 __le32_to_cpu(lcd.lcd_last_close_result);
239 lcd.lcd_last_close_data =
240 __le32_to_cpu(lcd.lcd_last_close_data);
241 printf(" last_close_transation: %llu\n",
242 (unsigned long long)lcd.lcd_last_close_transno);
243 printf(" last_close_xid: %llu\n",
244 (unsigned long long)lcd.lcd_last_close_xid);
245 printf(" last_close_result: %u\n",
246 lcd.lcd_last_close_result);
247 printf(" last_close_data: %u\n",
248 lcd.lcd_last_close_data);
255 int print_reply_data(FILE *fp)
257 struct lsd_reply_header lrh = {};
258 unsigned long long slot;
263 /* read reply_data header */
264 printf("\n%s:\n", REPLY_DATA);
265 n = fread(&lrh, 1, sizeof(lrh), fp);
266 if (n < sizeof(lrh)) {
267 fprintf(stderr, "%s: Short read (%d of %d)\n",
268 progname, n, (int)sizeof(lrh));
269 rc = ferror(fp) ? EIO : EINVAL;
273 lrh.lrh_magic = __le32_to_cpu(lrh.lrh_magic);
274 lrh.lrh_header_size = __le32_to_cpu(lrh.lrh_header_size);
275 lrh.lrh_reply_size = __le32_to_cpu(lrh.lrh_reply_size);
276 if (lrh.lrh_header_size != sizeof(struct lsd_reply_header)) {
278 "%s: invalid %s header: lrh_header_size=0x%08x expected 0x%08x\n",
279 progname, REPLY_DATA, lrh.lrh_header_size,
280 (unsigned int)sizeof(struct lsd_reply_header));
283 if (lrh.lrh_magic == LRH_MAGIC) {
284 if (lrh.lrh_reply_size != sizeof(struct lsd_reply_data)) {
286 "%s: invalid %s header: lrh_reply_size=0x%08x expected 0x%08x\n",
287 progname, REPLY_DATA, lrh.lrh_reply_size,
288 (unsigned int)sizeof(struct lsd_reply_data));
291 recsz = sizeof(struct lsd_reply_data);
293 } else if (lrh.lrh_magic == LRH_MAGIC_V1) {
294 if (lrh.lrh_reply_size != sizeof(struct lsd_reply_data_v1)) {
296 "%s: invalid %s header: lrh_reply_size=0x%08x expected 0x%08x\n",
297 progname, REPLY_DATA, lrh.lrh_reply_size,
298 (unsigned int)sizeof(struct lsd_reply_data));
301 recsz = sizeof(struct lsd_reply_data_v1);
305 "%s: invalid %s header: lrh_magic=0x%08x expected 0x%08x or 0x%08x\n",
306 progname, REPLY_DATA, lrh.lrh_magic, LRH_MAGIC,
313 fprintf(stderr, "lsd_reply_header:\n");
314 fprintf(stderr, "\tlrh_magic: 0x%08x\n", lrh.lrh_magic);
315 fprintf(stderr, "\tlrh_header_size: %u\n", lrh.lrh_header_size);
316 fprintf(stderr, "\tlrh_reply_size: %u\n", lrh.lrh_reply_size);
320 /* walk throuh the reply data */
321 for (slot = 0; ; slot++) {
322 struct lsd_reply_data lrd;
324 /* read a reply data */
325 n = fread(&lrd, 1, recsz, fp);
329 fprintf(stderr, "%s: Short read (%d of %d)\n",
330 progname, n, (int)sizeof(lrd));
331 return ferror(fp) ? EIO : EINVAL;
334 /* display reply data */
335 lrd.lrd_transno = __le64_to_cpu(lrd.lrd_transno);
336 lrd.lrd_xid = __le64_to_cpu(lrd.lrd_xid);
337 lrd.lrd_data = __le64_to_cpu(lrd.lrd_data);
338 lrd.lrd_result = __le32_to_cpu(lrd.lrd_result);
339 lrd.lrd_client_gen = __le32_to_cpu(lrd.lrd_client_gen);
341 if (lrh.lrh_magic == LRH_MAGIC)
342 lrd.lrd_batch_idx = __le32_to_cpu(lrd.lrd_batch_idx);
344 printf(" %lld:\n", slot);
345 printf(" client_generation: %u\n",
347 printf(" last_transaction: %lluu\n",
348 (unsigned long long)lrd.lrd_transno);
349 printf(" last_xid: %llu\n",
350 (unsigned long long)lrd.lrd_xid);
351 printf(" last_result: %u\n", lrd.lrd_result);
352 printf(" last_data: %llu\n\n",
353 (unsigned long long)lrd.lrd_data);
354 if (lrh.lrh_magic == LRH_MAGIC)
355 printf(" batch_idx: %u\n", lrd.lrd_batch_idx);
361 void display_usage(void)
363 printf("Usage: %s [OPTIONS] devicename\n", progname);
364 printf("Usage: %s [OPTIONS] -C <last_rcvd_file> -R <reply_data_file>\n",
366 printf("Read and print the last_rcvd/reply_data file from a device\n");
367 printf("(safe for mounted devices) or from a file\n");
368 printf("\t-c, --client, display client information\n");
369 printf("\t-h, --help, display this help and exit\n");
370 printf("\t-r, --reply, display reply data information\n");
371 printf("\t-C FILE, --last_rcvd=FILE, specify FILE as input for client information\n");
372 printf("\t-R FILE, --reply_data=FILE, specify FILE as input for reply information\n");
376 int main(int argc, char *const argv[])
378 char tmpdir[] = "/tmp/dirXXXXXX";
385 char *file_client = NULL;
386 char *file_reply = NULL;
389 progname = basename(argv[0]);
390 while ((c = getopt_long(argc, argv, "hcrC:R:", long_opts, NULL)) != -1) {
399 file_client = optarg;
411 if ((file_reply && file_client) ||
412 (!opt_reply && file_client) ||
413 (!opt_client && opt_reply && file_reply))
417 if (need_dev && !dev) {
422 /* Make a temporary directory to hold Lustre data files. */
423 if (need_dev && !mkdtemp(tmpdir)) {
424 fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
425 progname, tmpdir, strerror(errno));
429 if (file_client || dev) {
431 filep = fopen(file_client, "r");
433 filep = open_debugfs_file(LAST_RCVD, tmpdir, dev);
437 fprintf(stderr, "%s: Can't open %s: %s\n",
438 progname, LAST_RCVD, strerror(errno));
442 ret = print_last_rcvd(filep, opt_client);
451 filep = fopen(file_reply, "r");
453 filep = open_debugfs_file(REPLY_DATA, tmpdir, dev);
457 fprintf(stderr, "%s: Can't open %s: %s\n",
458 progname, LAST_RCVD, strerror(errno));
462 ret = print_reply_data(filep);