Whamcloud - gitweb
LU-8551 test: Use mds1 rather than mds to operate on MDT0000
[fs/lustre-release.git] / lustre / utils / lr_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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2013, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/lr_reader.c
37  *
38  * Author: Nathan Rutman <nathan@clusterfs.com>
39  */
40  /* Safely read the last_rcvd file from a device */
41
42 #if HAVE_CONFIG_H
43 #  include "config.h"
44 #endif /* HAVE_CONFIG_H */
45
46 #ifndef _GNU_SOURCE
47 #define _GNU_SOURCE
48 #endif
49 #include <errno.h>
50 #include <limits.h>
51 #include <stdbool.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <fcntl.h>
56 #include <stdarg.h>
57 #include <mntent.h>
58
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <sys/mount.h>
62
63 #include <string.h>
64 #include <getopt.h>
65
66 #include <lustre_disk.h>
67 #include <lustre_ver.h>
68
69 char *progname;
70 static struct option const longopts[] = {
71         { "help", no_argument, 0, 'h' },
72         { "client", no_argument, 0, 'c' },
73         { "reply", no_argument, 0, 'r' },
74         { 0, 0, 0, 0}
75 };
76
77 /* Executes the command \a cmd and returns command status.
78  */
79 int run_command(char *cmd, size_t cmdsz)
80 {
81         char log[] = "/tmp/run_command_logXXXXXX";
82         int fd, rc;
83
84         if (strlen(cmd) + strlen(log) + 8 > cmdsz) {
85                 fprintf(stderr, "Command buffer overflow: %.*s...\n",
86                         (int)cmdsz, cmd);
87                 return -ENOMEM;
88         }
89
90         fd = mkstemp(log);
91         if (fd >= 0) {
92                 close(fd);
93                 strncat(cmd, " >", 2);
94                 strncat(cmd, log, strlen(log));
95         }
96         strncat(cmd, " 2>&1", 5);
97
98         /* Can't use popen because we need the rv of the command */
99         rc = system(cmd);
100         if (rc && fd >= 0) {
101                 char buf[128];
102                 FILE *fp;
103                 fp = fopen(log, "r");
104                 if (fp) {
105                         while (fgets(buf, sizeof(buf), fp) != NULL) {
106                                 if (rc)
107                                         printf("   %s", buf);
108                         }
109                         fclose(fp);
110                 }
111         }
112         if (fd >= 0)
113                 remove(log);
114         return rc;
115 }
116
117
118 void display_usage(void)
119 {
120         printf("Usage: %s [OPTIONS] devicename\n", progname);
121         printf("Read and print the last_rcvd file from a device\n");
122         printf("(safe for mounted devices)\n");
123         printf("\t-c, --client, display client information\n");
124         printf("\t-h, --help,   display this help and exit\n");
125         printf("\t-r, --reply,  display reply data information\n");
126 }
127
128
129 int main(int argc, char *const argv[])
130 {
131         char tmpdir[] = "/tmp/dirXXXXXX";
132         char cmd[128];
133         char filepnm[128] = "";
134         char *dev;
135         struct lr_server_data lsd;
136         FILE *filep = NULL;
137         int ret;
138         int c;
139         int opt_client = 0;
140         int opt_reply = 0;
141
142         progname = argv[0];
143         while ((c = getopt_long(argc, argv, "chr", longopts, NULL)) != -1) {
144                 switch (c) {
145                 case 'c':
146                         opt_client = 1;
147                         break;
148                 case 'r':
149                         opt_reply = 1;
150                         break;
151                 case 'h':
152                 default:
153                         display_usage();
154                         return -1;
155                 }
156         }
157         dev = argv[optind];
158         if (!dev) {
159                 display_usage();
160                 return -1;
161         }
162
163         /* Make a temporary directory to hold Lustre data files. */
164         if (!mkdtemp(tmpdir)) {
165                 fprintf(stderr, "%s: Can't create temporary directory %s: %s\n",
166                         progname, tmpdir, strerror(errno));
167                 return errno;
168         }
169
170         memset(cmd, 0, sizeof(cmd));
171         snprintf(cmd, sizeof(cmd),
172                 "%s -c -R 'dump /%s %s/%s' %s",
173                 DEBUGFS, LAST_RCVD, tmpdir, LAST_RCVD, dev);
174
175         ret = run_command(cmd, sizeof(cmd));
176         if (ret) {
177                 fprintf(stderr, "%s: Unable to dump %s file\n",
178                         progname, LAST_RCVD);
179                 goto out_rmdir;
180         }
181
182         snprintf(filepnm, 128, "%s/%s", tmpdir, LAST_RCVD);
183         filep = fopen(filepnm, "r");
184         if (!filep) {
185                 fprintf(stderr, "%s: Unable to read old data\n",
186                         progname);
187                 ret = -errno;
188                 goto out_rmdir;
189         }
190         unlink(filepnm);
191
192         /* read lr_server_data structure */
193         printf("%s:\n", LAST_RCVD);
194         ret = fread(&lsd, 1, sizeof(lsd), filep);
195         if (ret < sizeof(lsd)) {
196                 fprintf(stderr, "%s: Short read (%d of %d)\n",
197                         progname, ret, (int)sizeof(lsd));
198                 ret = -ferror(filep);
199                 if (ret)
200                         goto out_close;
201         }
202
203         /* swab structure fields of interest */
204         lsd.lsd_feature_compat = le32_to_cpu(lsd.lsd_feature_compat);
205         lsd.lsd_feature_incompat = le32_to_cpu(lsd.lsd_feature_incompat);
206         lsd.lsd_feature_rocompat = le32_to_cpu(lsd.lsd_feature_rocompat);
207         lsd.lsd_last_transno = le64_to_cpu(lsd.lsd_last_transno);
208         lsd.lsd_osd_index = le32_to_cpu(lsd.lsd_osd_index);
209         lsd.lsd_mount_count = le64_to_cpu(lsd.lsd_mount_count);
210
211         /* display */
212         printf("  uuid: %.40s\n", lsd.lsd_uuid);
213         printf("  feature_compat: %#x\n", lsd.lsd_feature_compat);
214         printf("  feature_incompat: %#x\n", lsd.lsd_feature_incompat);
215         printf("  feature_rocompat: %#x\n", lsd.lsd_feature_rocompat);
216         printf("  last_transaction: %llu\n", lsd.lsd_last_transno);
217         printf("  target_index: %u\n", lsd.lsd_osd_index);
218         printf("  mount_count: %llu\n", lsd.lsd_mount_count);
219
220         /* read client information */
221         if (opt_client) {
222                 lsd.lsd_client_start = le32_to_cpu(lsd.lsd_client_start);
223                 lsd.lsd_client_size = le16_to_cpu(lsd.lsd_client_size);
224                 printf("  client_area_start: %u\n", lsd.lsd_client_start);
225                 printf("  client_area_size: %hu\n", lsd.lsd_client_size);
226
227                 /* seek to per-client data area */
228                 ret = fseek(filep, lsd.lsd_client_start, SEEK_SET);
229                 if (ret) {
230                         fprintf(stderr, "%s: seek failed. %s\n",
231                                 progname, strerror(errno));
232                         ret = errno;
233                         goto out_close;
234                 }
235
236                 /* walk throuh the per-client data area */
237                 while (true) {
238                         struct lsd_client_data lcd;
239
240                         /* read a per-client data area */
241                         ret = fread(&lcd, 1, sizeof(lcd), filep);
242                         if (ret < sizeof(lcd)) {
243                                 if (feof(filep))
244                                         break;
245                                 fprintf(stderr, "%s: Short read (%d of %d)\n",
246                                         progname, ret, (int)sizeof(lcd));
247                                 ret = -ferror(filep);
248                                 goto out_close;
249                         }
250
251                         if (lcd.lcd_uuid[0] == '\0')
252                                 continue;
253
254                         /* swab structure fields */
255                         lcd.lcd_last_transno =
256                                         le64_to_cpu(lcd.lcd_last_transno);
257                         lcd.lcd_last_xid = le64_to_cpu(lcd.lcd_last_xid);
258                         lcd.lcd_last_result = le32_to_cpu(lcd.lcd_last_result);
259                         lcd.lcd_last_data = le32_to_cpu(lcd.lcd_last_data);
260                         lcd.lcd_generation = le32_to_cpu(lcd.lcd_generation);
261
262                         /* display per-client data area */
263                         printf("\n  %.40s:\n", lcd.lcd_uuid);
264                         printf("    generation: %u\n", lcd.lcd_generation);
265                         printf("    last_transaction: %llu\n",
266                                lcd.lcd_last_transno);
267                         printf("    last_xid: %llu\n", lcd.lcd_last_xid);
268                         printf("    last_result: %u\n", lcd.lcd_last_result);
269                         printf("    last_data: %u\n", lcd.lcd_last_data);
270
271                         if (lcd.lcd_last_close_transno != 0 &&
272                             lcd.lcd_last_close_xid != 0) {
273                                 lcd.lcd_last_close_transno =
274                                         le64_to_cpu(lcd.lcd_last_close_transno);
275                                 lcd.lcd_last_close_xid =
276                                         le64_to_cpu(lcd.lcd_last_close_xid);
277                                 lcd.lcd_last_close_result =
278                                         le32_to_cpu(lcd.lcd_last_close_result);
279                                 lcd.lcd_last_close_data =
280                                         le32_to_cpu(lcd.lcd_last_close_data);
281                                 printf("    last_close_transation: %llu\n",
282                                        lcd.lcd_last_close_transno);
283                                 printf("    last_close_xid: %llu\n",
284                                        lcd.lcd_last_close_xid);
285                                 printf("    last_close_result: %u\n",
286                                        lcd.lcd_last_close_result);
287                                 printf("    last_close_data: %u\n",
288                                        lcd.lcd_last_close_data);
289                         }
290                 }
291         }
292         fclose(filep);
293         filep = NULL;
294
295         /* read reply data information */
296         if (opt_reply) {
297                 struct lsd_reply_header lrh;
298                 struct lsd_reply_data lrd;
299                 unsigned long long slot;
300
301                 snprintf(cmd, sizeof(cmd),
302                          "%s -c -R 'dump /%s %s/%s' %s",
303                          DEBUGFS, REPLY_DATA, tmpdir, REPLY_DATA, dev);
304
305                 ret = run_command(cmd, sizeof(cmd));
306                 if (ret) {
307                         fprintf(stderr, "%s: Unable to dump %s file\n",
308                                 progname, REPLY_DATA);
309                         goto out_rmdir;
310                 }
311
312                 snprintf(filepnm, sizeof(filepnm),
313                          "%s/%s", tmpdir, REPLY_DATA);
314                 filep = fopen(filepnm, "r");
315                 if (!filep) {
316                         fprintf(stderr, "%s: Unable to read reply data\n",
317                                 progname);
318                         ret = -errno;
319                         goto out_rmdir;
320                 }
321                 unlink(filepnm);
322
323                 /* read reply_data header */
324                 printf("\n%s:\n", REPLY_DATA);
325                 ret = fread(&lrh, 1, sizeof(lrh), filep);
326                 if (ret < sizeof(lrh)) {
327                         fprintf(stderr, "%s: Short read (%d of %d)\n",
328                                 progname, ret, (int)sizeof(lrh));
329                         ret = -ferror(filep);
330                         if (ret)
331                                 goto out_close;
332                 }
333
334                 /* check header */
335                 lrh.lrh_magic = le32_to_cpu(lrh.lrh_magic);
336                 lrh.lrh_header_size = le32_to_cpu(lrh.lrh_header_size);
337                 lrh.lrh_reply_size = le32_to_cpu(lrh.lrh_reply_size);
338                 if (lrh.lrh_magic != LRH_MAGIC) {
339                         fprintf(stderr, "%s: invalid %s header: "
340                                 "lrh_magic=%08x expected %08x\n",
341                                 progname, REPLY_DATA, lrh.lrh_magic, LRH_MAGIC);
342                         goto out_close;
343                 }
344                 if (lrh.lrh_header_size != sizeof(struct lsd_reply_header)) {
345                         fprintf(stderr, "%s: invalid %s header: "
346                                 "lrh_header_size=%08x expected %08x\n",
347                                 progname, REPLY_DATA, lrh.lrh_header_size,
348                                 (unsigned int)sizeof(struct lsd_reply_header));
349                         goto out_close;
350                 }
351                 if (lrh.lrh_reply_size != sizeof(struct lsd_reply_data)) {
352                         fprintf(stderr, "%s: invalid %s header: "
353                                 "lrh_reply_size=%08x expected %08x\n",
354                                 progname, REPLY_DATA, lrh.lrh_reply_size,
355                                 (unsigned int)sizeof(struct lsd_reply_data));
356                         goto out_close;
357                 }
358
359                 /* walk throuh the reply data */
360                 for (slot = 0; ; slot++) {
361                         /* read a reply data */
362                         ret = fread(&lrd, 1, sizeof(lrd), filep);
363                         if (ret < sizeof(lrd)) {
364                                 if (feof(filep))
365                                         break;
366                                 fprintf(stderr, "%s: Short read (%d of %d)\n",
367                                         progname, ret, (int)sizeof(lrd));
368                                 ret = -ferror(filep);
369                                 goto out_close;
370                         }
371
372                         /* display reply data */
373                         lrd.lrd_transno = le64_to_cpu(lrd.lrd_transno);
374                         lrd.lrd_xid = le64_to_cpu(lrd.lrd_xid);
375                         lrd.lrd_data = le64_to_cpu(lrd.lrd_data);
376                         lrd.lrd_result = le32_to_cpu(lrd.lrd_result);
377                         lrd.lrd_client_gen = le32_to_cpu(lrd.lrd_client_gen);
378
379                         printf("  %lld:\n", slot);
380                         printf("    client_generation: %u\n",
381                                lrd.lrd_client_gen);
382                         printf("    last_transaction: %llu\n", lrd.lrd_transno);
383                         printf("    last_xid: %llu\n", lrd.lrd_xid);
384                         printf("    last_result: %u\n", lrd.lrd_result);
385                         printf("    last_data: %llu\n\n", lrd.lrd_data);
386                 }
387         }
388
389 out_close:
390         if (filep != NULL)
391                 fclose(filep);
392
393 out_rmdir:
394         rmdir(tmpdir);
395         return ret;
396 }