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/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lustre/utils/lr_reader.c
34 * Author: Nathan Rutman <nathan@clusterfs.com>
36 /* Safely read the last_rcvd file from a device */
40 #endif /* HAVE_CONFIG_H */
55 #include <sys/types.h>
57 #include <sys/mount.h>
62 #include <asm/byteorder.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 },
73 /* Executes the command \a cmd and returns command status.
75 int run_command(char *cmd, size_t cmdsz)
77 char log[] = "/tmp/run_command_logXXXXXX";
80 if (strlen(cmd) + strlen(log) + 8 > cmdsz) {
81 fprintf(stderr, "Command buffer overflow: %.*s...\n",
89 strncat(cmd, " >", cmdsz);
90 strncat(cmd, log, cmdsz);
92 strncat(cmd, " 2>&1", cmdsz - strlen(cmd));
94 /* Can't use popen because we need the rv of the command */
101 while (fgets(buf, sizeof(buf), fp) != NULL) {
114 void display_usage(void)
116 printf("Usage: %s [OPTIONS] devicename\n", progname);
117 printf("Read and print the last_rcvd file from a device\n");
118 printf("(safe for mounted devices)\n");
119 printf("\t-c, --client, display client information\n");
120 printf("\t-h, --help, display this help and exit\n");
121 printf("\t-r, --reply, display reply data information\n");
125 int main(int argc, char *const argv[])
127 char tmpdir[] = "/tmp/dirXXXXXX";
129 char filepnm[128] = "";
131 struct lr_server_data lsd;
139 while ((c = getopt_long(argc, argv, "chr", long_opts, NULL)) != -1) {
159 /* Make a temporary directory to hold Lustre data files. */
160 if (!mkdtemp(tmpdir)) {
161 fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
162 progname, tmpdir, strerror(errno));
166 memset(cmd, 0, sizeof(cmd));
167 snprintf(cmd, sizeof(cmd),
168 "%s -c -R 'dump /%s %s/%s' %s",
169 DEBUGFS, LAST_RCVD, tmpdir, LAST_RCVD, dev);
171 ret = run_command(cmd, sizeof(cmd));
173 fprintf(stderr, "%s: Unable to dump %s file\n",
174 progname, LAST_RCVD);
178 snprintf(filepnm, 128, "%s/%s", tmpdir, LAST_RCVD);
179 filep = fopen(filepnm, "r");
181 fprintf(stderr, "%s: Unable to read old data\n",
188 /* read lr_server_data structure */
189 printf("%s:\n", LAST_RCVD);
190 ret = fread(&lsd, 1, sizeof(lsd), filep);
191 if (ret < sizeof(lsd)) {
192 fprintf(stderr, "%s: Short read (%d of %d)\n",
193 progname, ret, (int)sizeof(lsd));
194 ret = -ferror(filep);
199 /* swab structure fields of interest */
200 lsd.lsd_feature_compat = __le32_to_cpu(lsd.lsd_feature_compat);
201 lsd.lsd_feature_incompat = __le32_to_cpu(lsd.lsd_feature_incompat);
202 lsd.lsd_feature_rocompat = __le32_to_cpu(lsd.lsd_feature_rocompat);
203 lsd.lsd_last_transno = __le64_to_cpu(lsd.lsd_last_transno);
204 lsd.lsd_osd_index = __le32_to_cpu(lsd.lsd_osd_index);
205 lsd.lsd_mount_count = __le64_to_cpu(lsd.lsd_mount_count);
208 printf(" uuid: %.40s\n", lsd.lsd_uuid);
209 printf(" feature_compat: %#x\n", lsd.lsd_feature_compat);
210 printf(" feature_incompat: %#x\n", lsd.lsd_feature_incompat);
211 printf(" feature_rocompat: %#x\n", lsd.lsd_feature_rocompat);
212 printf(" last_transaction: %llu\n",
213 (unsigned long long)lsd.lsd_last_transno);
214 printf(" target_index: %u\n", lsd.lsd_osd_index);
215 printf(" mount_count: %llu\n",
216 (unsigned long long)lsd.lsd_mount_count);
218 /* read client information */
220 lsd.lsd_client_start = __le32_to_cpu(lsd.lsd_client_start);
221 lsd.lsd_client_size = __le16_to_cpu(lsd.lsd_client_size);
222 printf(" client_area_start: %u\n", lsd.lsd_client_start);
223 printf(" client_area_size: %hu\n", lsd.lsd_client_size);
225 /* seek to per-client data area */
226 ret = fseek(filep, lsd.lsd_client_start, SEEK_SET);
228 fprintf(stderr, "%s: seek failed. %s\n",
229 progname, strerror(errno));
234 /* walk throuh the per-client data area */
236 struct lsd_client_data lcd;
238 /* read a per-client data area */
239 ret = fread(&lcd, 1, sizeof(lcd), filep);
240 if (ret < sizeof(lcd)) {
243 fprintf(stderr, "%s: Short read (%d of %d)\n",
244 progname, ret, (int)sizeof(lcd));
245 ret = -ferror(filep);
249 if (lcd.lcd_uuid[0] == '\0')
252 /* swab structure fields */
253 lcd.lcd_last_transno =
254 __le64_to_cpu(lcd.lcd_last_transno);
255 lcd.lcd_last_xid = __le64_to_cpu(lcd.lcd_last_xid);
256 lcd.lcd_last_result = __le32_to_cpu(lcd.lcd_last_result);
257 lcd.lcd_last_data = __le32_to_cpu(lcd.lcd_last_data);
258 lcd.lcd_generation = __le32_to_cpu(lcd.lcd_generation);
260 /* display per-client data area */
261 printf("\n %.40s:\n", lcd.lcd_uuid);
262 printf(" generation: %u\n", lcd.lcd_generation);
263 printf(" last_transaction: %llu\n",
264 (unsigned long long)lcd.lcd_last_transno);
265 printf(" last_xid: %llu\n",
266 (unsigned long long)lcd.lcd_last_xid);
267 printf(" last_result: %u\n", lcd.lcd_last_result);
268 printf(" last_data: %u\n", lcd.lcd_last_data);
270 if (lcd.lcd_last_close_transno != 0 &&
271 lcd.lcd_last_close_xid != 0) {
272 lcd.lcd_last_close_transno =
273 __le64_to_cpu(lcd.lcd_last_close_transno);
274 lcd.lcd_last_close_xid =
275 __le64_to_cpu(lcd.lcd_last_close_xid);
276 lcd.lcd_last_close_result =
277 __le32_to_cpu(lcd.lcd_last_close_result);
278 lcd.lcd_last_close_data =
279 __le32_to_cpu(lcd.lcd_last_close_data);
280 printf(" last_close_transation: %llu\n",
281 (unsigned long long)lcd.lcd_last_close_transno);
282 printf(" last_close_xid: %llu\n",
283 (unsigned long long)lcd.lcd_last_close_xid);
284 printf(" last_close_result: %u\n",
285 lcd.lcd_last_close_result);
286 printf(" last_close_data: %u\n",
287 lcd.lcd_last_close_data);
294 /* read reply data information */
296 struct lsd_reply_header lrh;
297 struct lsd_reply_data lrd;
298 unsigned long long slot;
300 snprintf(cmd, sizeof(cmd),
301 "%s -c -R 'dump /%s %s/%s' %s",
302 DEBUGFS, REPLY_DATA, tmpdir, REPLY_DATA, dev);
304 ret = run_command(cmd, sizeof(cmd));
306 fprintf(stderr, "%s: Unable to dump %s file\n",
307 progname, REPLY_DATA);
311 snprintf(filepnm, sizeof(filepnm),
312 "%s/%s", tmpdir, REPLY_DATA);
313 filep = fopen(filepnm, "r");
315 fprintf(stderr, "%s: Unable to read reply data\n",
322 /* read reply_data header */
323 printf("\n%s:\n", REPLY_DATA);
324 ret = fread(&lrh, 1, sizeof(lrh), filep);
325 if (ret < sizeof(lrh)) {
326 fprintf(stderr, "%s: Short read (%d of %d)\n",
327 progname, ret, (int)sizeof(lrh));
328 ret = -ferror(filep);
334 lrh.lrh_magic = __le32_to_cpu(lrh.lrh_magic);
335 lrh.lrh_header_size = __le32_to_cpu(lrh.lrh_header_size);
336 lrh.lrh_reply_size = __le32_to_cpu(lrh.lrh_reply_size);
337 if (lrh.lrh_magic != LRH_MAGIC) {
338 fprintf(stderr, "%s: invalid %s header: "
339 "lrh_magic=%08x expected %08x\n",
340 progname, REPLY_DATA, lrh.lrh_magic, LRH_MAGIC);
343 if (lrh.lrh_header_size != sizeof(struct lsd_reply_header)) {
344 fprintf(stderr, "%s: invalid %s header: "
345 "lrh_header_size=%08x expected %08x\n",
346 progname, REPLY_DATA, lrh.lrh_header_size,
347 (unsigned int)sizeof(struct lsd_reply_header));
350 if (lrh.lrh_reply_size != sizeof(struct lsd_reply_data)) {
351 fprintf(stderr, "%s: invalid %s header: "
352 "lrh_reply_size=%08x expected %08x\n",
353 progname, REPLY_DATA, lrh.lrh_reply_size,
354 (unsigned int)sizeof(struct lsd_reply_data));
358 /* walk throuh the reply data */
359 for (slot = 0; ; slot++) {
360 /* read a reply data */
361 ret = fread(&lrd, 1, sizeof(lrd), filep);
362 if (ret < sizeof(lrd)) {
365 fprintf(stderr, "%s: Short read (%d of %d)\n",
366 progname, ret, (int)sizeof(lrd));
367 ret = -ferror(filep);
371 /* display reply data */
372 lrd.lrd_transno = __le64_to_cpu(lrd.lrd_transno);
373 lrd.lrd_xid = __le64_to_cpu(lrd.lrd_xid);
374 lrd.lrd_data = __le64_to_cpu(lrd.lrd_data);
375 lrd.lrd_result = __le32_to_cpu(lrd.lrd_result);
376 lrd.lrd_client_gen = __le32_to_cpu(lrd.lrd_client_gen);
378 printf(" %lld:\n", slot);
379 printf(" client_generation: %u\n",
381 printf(" last_transaction: %lluu\n",
382 (unsigned long long)lrd.lrd_transno);
383 printf(" last_xid: %llu\n",
384 (unsigned long long)lrd.lrd_xid);
385 printf(" last_result: %u\n", lrd.lrd_result);
386 printf(" last_data: %llu\n\n",
387 (unsigned long long)lrd.lrd_data);