Whamcloud - gitweb
87028187ca8daabc6a0625c961f738c46ca0b7f3
[fs/lustre-release.git] / lnet / utils / debug.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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, 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  * lnet/utils/debug.c
37  * Some day I'll split all of this functionality into a cfs_debug module
38  * of its own. That day is not today.
39  */
40
41 #define __USE_FILE_OFFSET64
42 #ifndef _GNU_SOURCE
43 #define  _GNU_SOURCE
44 #endif
45
46 #include <libcfs/libcfsutil.h>
47 #include <lnet/lnetctl.h>
48
49
50 static char rawbuf[8192];
51 static char *buf = rawbuf;
52 static int max = 8192;
53 /*static int g_pfd = -1;*/
54 static int subsystem_mask = ~0;
55 static int debug_mask = ~0;
56
57 #define MAX_MARK_SIZE 256
58
59 static const char *libcfs_debug_subsystems[] = LIBCFS_DEBUG_SUBSYS_NAMES;
60 static const char *libcfs_debug_masks[] = LIBCFS_DEBUG_MASKS_NAMES;
61
62 #ifdef __linux__
63
64 #define DAEMON_CTL_NAME         "/proc/sys/lnet/daemon_file"
65 #define SUBSYS_DEBUG_CTL_NAME   "/proc/sys/lnet/subsystem_debug"
66 #define DEBUG_CTL_NAME          "/proc/sys/lnet/debug"
67 #define DUMP_KERNEL_CTL_NAME    "/proc/sys/lnet/dump_kernel"
68
69 static int
70 dbg_open_ctlhandle(const char *str)
71 {
72         int fd;
73         fd = open(str, O_WRONLY);
74         if (fd < 0) {
75                 fprintf(stderr, "open %s failed: %s\n", str,
76                         strerror(errno));
77                 return -1;
78         }
79         return fd;
80 }
81
82 static void
83 dbg_close_ctlhandle(int fd)
84 {
85         close(fd);
86 }
87
88 static int
89 dbg_write_cmd(int fd, char *str, int len)
90 {
91         int    rc  = write(fd, str, len);
92
93         return (rc == len ? 0 : 1);
94 }
95
96 #else
97 #error - Unknown sysctl convention.
98 #endif
99
100 static int do_debug_mask(char *name, int enable)
101 {
102         int found = 0, i;
103
104         for (i = 0; libcfs_debug_subsystems[i] != NULL; i++) {
105                 if (strcasecmp(name, libcfs_debug_subsystems[i]) == 0 ||
106                     strcasecmp(name, "all_subs") == 0) {
107                         printf("%s output from subsystem \"%s\"\n",
108                                 enable ? "Enabling" : "Disabling",
109                                 libcfs_debug_subsystems[i]);
110                         if (enable)
111                                 subsystem_mask |= (1 << i);
112                         else
113                                 subsystem_mask &= ~(1 << i);
114                         found = 1;
115                 }
116         }
117         for (i = 0; libcfs_debug_masks[i] != NULL; i++) {
118                 if (strcasecmp(name, libcfs_debug_masks[i]) == 0 ||
119                     strcasecmp(name, "all_types") == 0) {
120                         printf("%s output of type \"%s\"\n",
121                                 enable ? "Enabling" : "Disabling",
122                                 libcfs_debug_masks[i]);
123                         if (enable)
124                                 debug_mask |= (1 << i);
125                         else
126                                 debug_mask &= ~(1 << i);
127                         found = 1;
128                 }
129         }
130
131         return found;
132 }
133
134 int dbg_initialize(int argc, char **argv)
135 {
136         return 0;
137 }
138
139 int jt_dbg_filter(int argc, char **argv)
140 {
141         int   i;
142
143         if (argc < 2) {
144                 fprintf(stderr, "usage: %s <subsystem ID or debug mask>\n",
145                         argv[0]);
146                 return 0;
147         }
148
149         for (i = 1; i < argc; i++)
150                 if (!do_debug_mask(argv[i], 0))
151                         fprintf(stderr, "Unknown subsystem or debug type: %s\n",
152                                 argv[i]);
153         return 0;
154 }
155
156 int jt_dbg_show(int argc, char **argv)
157 {
158         int    i;
159
160         if (argc < 2) {
161                 fprintf(stderr, "usage: %s <subsystem ID or debug mask>\n",
162                         argv[0]);
163                 return 0;
164         }
165
166         for (i = 1; i < argc; i++)
167                 if (!do_debug_mask(argv[i], 1))
168                         fprintf(stderr, "Unknown subsystem or debug type: %s\n",
169                                 argv[i]);
170
171         return 0;
172 }
173
174 static int applymask(char* procpath, int value)
175 {
176         int rc;
177         char buf[64];
178         int len = snprintf(buf, 64, "%d", value);
179
180         int fd = dbg_open_ctlhandle(procpath);
181         if (fd == -1) {
182                 fprintf(stderr, "Unable to open %s: %s\n",
183                         procpath, strerror(errno));
184                 return fd;
185         }
186         rc = dbg_write_cmd(fd, buf, len+1);
187         if (rc != 0) {
188                 fprintf(stderr, "Write to %s failed: %s\n",
189                         procpath, strerror(errno));
190         }
191
192         dbg_close_ctlhandle(fd);
193
194         return rc;
195 }
196
197 static void applymask_all(unsigned int subs_mask, unsigned int debug_mask)
198 {
199         if (!dump_filename) {
200                 applymask(SUBSYS_DEBUG_CTL_NAME, subs_mask);
201                 applymask(DEBUG_CTL_NAME, debug_mask);
202         } else {
203                 struct libcfs_debug_ioctl_data data;
204
205                 data.hdr.ioc_len = sizeof(data);
206                 data.hdr.ioc_version = 0;
207                 data.subs = subs_mask;
208                 data.debug = debug_mask;
209
210                 dump(OBD_DEV_ID, LIBCFS_IOC_DEBUG_MASK, &data);
211         }
212         printf("Applied subsystem_debug=%d, debug=%d to /proc/sys/lnet\n",
213                subs_mask, debug_mask);
214 }
215
216 int jt_dbg_list(int argc, char **argv)
217 {
218         int i;
219
220         if (argc != 2) {
221                 fprintf(stderr, "usage: %s <subs || types>\n", argv[0]);
222                 return 0;
223         }
224
225         if (strcasecmp(argv[1], "subs") == 0) {
226                 printf("Subsystems: all_subs");
227                 for (i = 0; libcfs_debug_subsystems[i] != NULL; i++)
228                         if (libcfs_debug_subsystems[i][0])
229                                 printf(", %s", libcfs_debug_subsystems[i]);
230                 printf("\n");
231         } else if (strcasecmp(argv[1], "types") == 0) {
232                 printf("Types: all_types");
233                 for (i = 0; libcfs_debug_masks[i] != NULL; i++)
234                         printf(", %s", libcfs_debug_masks[i]);
235                 printf("\n");
236         } else if (strcasecmp(argv[1], "applymasks") == 0) {
237                 applymask_all(subsystem_mask, debug_mask);
238         }
239         return 0;
240 }
241
242 /* all strings nul-terminated; only the struct and hdr need to be freed */
243 struct dbg_line {
244         struct ptldebug_header *hdr;
245         char *file;
246         char *fn;
247         char *text;
248 };
249
250 static int cmp_rec(const void *p1, const void *p2)
251 {
252         struct dbg_line *d1 = *(struct dbg_line **)p1;
253         struct dbg_line *d2 = *(struct dbg_line **)p2;
254
255         if (d1->hdr->ph_sec < d2->hdr->ph_sec)
256                 return -1;
257         if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
258             d1->hdr->ph_usec < d2->hdr->ph_usec)
259                 return -1;
260         if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
261             d1->hdr->ph_usec == d2->hdr->ph_usec)
262                 return 0;
263         return 1;
264 }
265
266 static void print_rec(struct dbg_line ***linevp, int used, int fdout)
267 {
268         struct dbg_line **linev = *linevp;
269         int i;
270
271         qsort(linev, used, sizeof(struct dbg_line *), cmp_rec);
272         for (i = 0; i < used; i++) {
273                 struct dbg_line *line = linev[i];
274                 struct ptldebug_header *hdr = line->hdr;
275                 char out[4097];
276                 char *buf = out;
277                 int bytes;
278                 ssize_t bytes_written;
279
280                 bytes = sprintf(out, "%08x:%08x:%u.%u%s:%u.%06llu:%u:%u:%u:(%s:%u:%s()) %s",
281                                 hdr->ph_subsys, hdr->ph_mask,
282                                 hdr->ph_cpu_id, hdr->ph_type,
283                                 hdr->ph_flags & PH_FLAG_FIRST_RECORD ? "F" : "",
284                                 hdr->ph_sec, (unsigned long long)hdr->ph_usec,
285                                 hdr->ph_stack, hdr->ph_pid, hdr->ph_extern_pid,
286                                 line->file, hdr->ph_line_num, line->fn, line->text);
287                 while (bytes > 0) {
288                         bytes_written = write(fdout, buf, bytes);
289                         if (bytes_written <= 0)
290                                 break;
291                         bytes -= bytes_written;
292                         buf += bytes_written;
293                 }
294                 free(line->hdr);
295                 free(line);
296         }
297         free(linev);
298         *linevp = NULL;
299 }
300
301 static int add_rec(struct dbg_line *line, struct dbg_line ***linevp, int *lenp,
302                    int used)
303 {
304         struct dbg_line **linev = *linevp;
305
306         if (used == *lenp) {
307                 int nlen = *lenp + 4096;
308                 int nsize = nlen * sizeof(struct dbg_line *);
309
310                 linev = realloc(*linevp, nsize);
311                 if (!linev)
312                         return -ENOMEM;
313
314                 *linevp = linev;
315                 *lenp = nlen;
316         }
317         linev[used] = line;
318
319         return 0;
320 }
321   
322 static void dump_hdr(unsigned long long offset, struct ptldebug_header *hdr)
323 {
324         fprintf(stderr, "badly-formed record at offset = %llu\n", offset);
325         fprintf(stderr, "  len = %u\n", hdr->ph_len);
326         fprintf(stderr, "  flags = %x\n", hdr->ph_flags);
327         fprintf(stderr, "  subsystem = %x\n", hdr->ph_subsys);
328         fprintf(stderr, "  mask = %x\n", hdr->ph_mask);
329         fprintf(stderr, "  cpu_id = %u\n", hdr->ph_cpu_id);
330         fprintf(stderr, "  type = %u\n", hdr->ph_type);
331         fprintf(stderr, "  seconds = %u\n", hdr->ph_sec);
332         fprintf(stderr, "  microseconds = %lu\n", (long)hdr->ph_usec);
333         fprintf(stderr, "  stack = %u\n", hdr->ph_stack);
334         fprintf(stderr, "  pid = %u\n", hdr->ph_pid);
335         fprintf(stderr, "  host pid = %u\n", hdr->ph_extern_pid);
336         fprintf(stderr, "  line number = %u\n", hdr->ph_line_num);
337 }
338  
339 #define HDR_SIZE sizeof(*hdr)
340  
341 static int parse_buffer(int fdin, int fdout)
342 {
343         struct dbg_line *line;
344         struct ptldebug_header *hdr;
345         char buf[4097], *ptr;
346         unsigned long dropped = 0, kept = 0, bad = 0;
347         struct dbg_line **linev = NULL;
348         int linev_len = 0;
349         int rc;
350  
351         hdr = (void *)buf;
352   
353         while (1) {
354                 int first_bad = 1;
355                 int count;
356  
357                 count = HDR_SIZE;
358                 ptr = buf;
359         readhdr:
360                 rc = read(fdin, ptr, count);
361                 if (rc <= 0)
362                          goto print;
363   
364                 ptr += rc;
365                 count -= rc;
366                 if (count > 0)
367                         goto readhdr;
368                 
369                 if (hdr->ph_len > 4094 ||       /* is this header bogus? */
370                     hdr->ph_type >= libcfs_tcd_type_max() ||
371                     hdr->ph_stack > 65536 ||
372                     hdr->ph_sec < (1 << 30) ||
373                     hdr->ph_usec > 1000000000 ||
374                     hdr->ph_line_num > 65536) {
375                         if (first_bad)
376                                 dump_hdr(lseek(fdin, 0, SEEK_CUR), hdr);
377                         bad += first_bad;
378                         first_bad = 0;
379  
380                         /* try to restart on next line */
381                         while (count < HDR_SIZE && buf[count] != '\n')
382                                 count++;
383                         if (buf[count] == '\n')
384                                 count++; /* move past '\n' */
385                         if (HDR_SIZE - count > 0) {
386                                 int left = HDR_SIZE - count;
387
388                                 memmove(buf, buf + count, left);
389                                 ptr = buf + left;
390
391                                 goto readhdr;
392                         }
393
394                         continue;
395                 }
396   
397                 if (hdr->ph_len == 0)
398                         continue;
399
400                 count = hdr->ph_len - HDR_SIZE;
401         readmore:
402                 rc = read(fdin, ptr, count);
403                 if (rc <= 0)
404                         break;
405   
406                 ptr += rc;
407                 count -= rc;
408                 if (count > 0)
409                         goto readmore;
410  
411                 first_bad = 1;
412
413                 if ((hdr->ph_subsys && !(subsystem_mask & hdr->ph_subsys)) ||
414                     (hdr->ph_mask && !(debug_mask & hdr->ph_mask))) {
415                         dropped++;
416                         continue;
417                 }
418   
419         retry_alloc:
420                 line = malloc(sizeof(*line));
421                 if (line == NULL) {
422                          if (linev) {
423                                 fprintf(stderr, "error: line malloc(%u): "
424                                         "printing accumulated records\n",
425                                         (unsigned int)sizeof(*line));
426                                 print_rec(&linev, kept, fdout);
427
428                                 goto retry_alloc;
429                         }
430                         fprintf(stderr, "error: line malloc(%u): exiting\n",
431                                 (unsigned int)sizeof(*line));
432                         break;
433                 }
434
435                 line->hdr = malloc(hdr->ph_len + 1);
436                 if (line->hdr == NULL) {
437                         free(line);
438                         if (linev) {
439                                 fprintf(stderr, "error: hdr malloc(%u): "
440                                         "printing accumulated records\n",
441                                         hdr->ph_len + 1);
442                                 print_rec(&linev, kept, fdout);
443  
444                                 goto retry_alloc;
445                         }
446                         fprintf(stderr, "error: hdr malloc(%u): exiting\n",
447                                         hdr->ph_len + 1);
448                         break;
449                 }
450   
451                 ptr = (void *)line->hdr;
452                 memcpy(line->hdr, buf, hdr->ph_len);
453                 ptr[hdr->ph_len] = '\0';
454
455                 ptr += sizeof(*hdr);
456                 line->file = ptr;
457                 ptr += strlen(line->file) + 1;
458                 line->fn = ptr;
459                 ptr += strlen(line->fn) + 1;
460                 line->text = ptr;
461  
462         retry_add:
463                 if (add_rec(line, &linev, &linev_len, kept) < 0) {
464                         if (linev) {
465                                 fprintf(stderr, "error: add_rec[%u] failed; "
466                                         "print accumulated records\n",
467                                         linev_len);
468                                 print_rec(&linev, kept, fdout);
469
470                                 goto retry_add;
471                         }
472                         fprintf(stderr, "error: add_rec[0] failed; exiting\n");
473                         break;
474                 }
475                 kept++;
476         }
477
478 print:
479         if (linev)
480                 print_rec(&linev, kept, fdout);
481
482         printf("Debug log: %lu lines, %lu kept, %lu dropped, %lu bad.\n",
483                 dropped + kept + bad, kept, dropped, bad);
484
485         return 0;
486 }
487
488 int jt_dbg_debug_kernel(int argc, char **argv)
489 {
490         struct stat st;
491         char filename[PATH_MAX];
492         int raw = 0;
493         int save_errno;
494         int fdin;
495         int fdout;
496         int rc;
497
498         if (argc > 3) {
499                 fprintf(stderr, "usage: %s [file] [raw]\n", argv[0]);
500                 return 0;
501         }
502
503         if (argc > 2) {
504                 raw = atoi(argv[2]);
505         } else if (argc > 1 && (argv[1][0] == '0' || argv[1][0] == '1')) {
506                 raw = atoi(argv[1]);
507                 argc--;
508         }
509
510         /* If we are dumping raw (which means no conversion step to ASCII)
511          * then dump directly to any supplied filename, otherwise this is
512          * just a temp file and we dump to the real file at convert time. */
513         if (argc > 1 && raw) {
514                 if (strlen(argv[1]) >= sizeof(filename)) {
515                         fprintf(stderr, "File name too long: %s\n", argv[1]);
516                         return 1;
517                 }
518                 strncpy(filename, argv[1], sizeof(filename));
519         } else {
520                 if (snprintf(filename, sizeof(filename), "%s"CFS_TIME_T".%u",
521                              LIBCFS_DEBUG_FILE_PATH_DEFAULT, time(NULL),
522                              getpid())
523                     >= sizeof(filename)) {
524                         fprintf(stderr, "File name too long\n");
525                         return 1;
526                 }
527         }
528
529         if (stat(filename, &st) == 0 && S_ISREG(st.st_mode))
530                 unlink(filename);
531
532         fdin = dbg_open_ctlhandle(DUMP_KERNEL_CTL_NAME);
533         if (fdin < 0) {
534                 fprintf(stderr, "open(dump_kernel) failed: %s\n",
535                         strerror(errno));
536                 return 1;
537         }
538
539         rc = dbg_write_cmd(fdin, filename, strlen(filename));
540         save_errno = errno;
541         dbg_close_ctlhandle(fdin);
542         if (rc != 0) {
543                 fprintf(stderr, "write(%s) failed: %s\n", filename,
544                         strerror(save_errno));
545                 return 1;
546         }
547
548         if (raw)
549                 return 0;
550
551         fdin = open(filename, O_RDONLY);
552         if (fdin < 0) {
553                 if (errno == ENOENT) /* no dump file created */
554                         return 0;
555                 fprintf(stderr, "fopen(%s) failed: %s\n", filename,
556                         strerror(errno));
557                 return 1;
558         }
559         if (argc > 1) {
560                 fdout = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC,
561                              S_IRUSR | S_IWUSR);
562                 if (fdout < 0) {
563                         fprintf(stderr, "fopen(%s) failed: %s\n", argv[1],
564                                 strerror(errno));
565                         close(fdin);
566                         return 1;
567                 }
568         } else {
569                 fdout = fileno(stdout);
570         }
571
572         rc = parse_buffer(fdin, fdout);
573         close(fdin);
574         if (argc > 1)
575                 close(fdout);
576         if (rc) {
577                 fprintf(stderr, "parse_buffer failed; leaving tmp file %s "
578                         "behind.\n", filename);
579         } else {
580                 rc = unlink(filename);
581                 if (rc)
582                         fprintf(stderr, "dumped successfully, but couldn't "
583                                 "unlink tmp file %s: %s\n", filename,
584                                 strerror(errno));
585         }
586
587         return rc;
588 }
589
590 int jt_dbg_debug_file(int argc, char **argv)
591 {
592         int    fdin;
593         int    fdout;
594         int    rc;
595
596         if (argc > 3 || argc < 2) {
597                 fprintf(stderr, "usage: %s <input> [output]\n", argv[0]);
598                 return 0;
599         }
600
601         fdin = open(argv[1], O_RDONLY | O_LARGEFILE);
602         if (fdin < 0) {
603                 fprintf(stderr, "open(%s) failed: %s\n", argv[1],
604                         strerror(errno));
605                 return 1;
606         }
607         if (argc > 2) {
608                 fdout = open(argv[2],
609                              O_CREAT | O_TRUNC | O_WRONLY | O_LARGEFILE,
610                              0600);
611                 if (fdout < 0) {
612                         fprintf(stderr, "open(%s) failed: %s\n", argv[2],
613                                 strerror(errno));
614                         close(fdin);
615                         return 1;
616                 }
617         } else {
618                 fdout = fileno(stdout);
619         }
620
621         rc = parse_buffer(fdin, fdout);
622
623         close(fdin);
624         if (fdout != fileno(stdout))
625                 close(fdout);
626
627         return rc;
628 }
629
630 const char debug_daemon_usage[] = "usage: %s {start file [MB]|stop}\n";
631
632 int jt_dbg_debug_daemon(int argc, char **argv)
633 {
634         int  rc;
635         int  fd;
636
637         if (argc <= 1) {
638                 fprintf(stderr, debug_daemon_usage, argv[0]);
639                 return 1;
640         }
641
642         fd = dbg_open_ctlhandle(DAEMON_CTL_NAME);
643         if (fd < 0)
644                 return -1;
645
646         rc = -1;
647         if (strcasecmp(argv[1], "start") == 0) {
648              if (argc < 3 || argc > 4 ||
649                     (argc == 4 && strlen(argv[3]) > 5)) {
650                         fprintf(stderr, debug_daemon_usage, argv[0]);
651                         goto out;
652                 }
653                 if (argc == 4) {
654                         char       buf[12];
655                         const long min_size = 10;
656                         const long max_size = 20480;
657                         long       size;
658                         char      *end;
659
660                         size = strtoul(argv[3], &end, 0);
661                         if (size < min_size ||
662                             size > max_size ||
663                             *end != 0) {
664                                 fprintf(stderr, "size %s invalid, must be in "
665                                         "the range %ld-%ld MB\n", argv[3],
666                                         min_size, max_size);
667                                 goto out;
668                         }
669                         snprintf(buf, sizeof(buf), "size=%ld", size);
670                         rc = dbg_write_cmd(fd, buf, strlen(buf));
671
672                         if (rc != 0) {
673                                 fprintf(stderr, "set %s failed: %s\n",
674                                         buf, strerror(errno));
675                                 goto out;
676                         }
677                 }
678
679                 rc = dbg_write_cmd(fd, argv[2], strlen(argv[2]));
680                 if (rc != 0) {
681                         fprintf(stderr, "start debug_daemon on %s failed: %s\n",
682                                 argv[2], strerror(errno));
683                         goto out;
684                 }
685                 rc = 0;
686                 goto out;
687         }
688         if (strcasecmp(argv[1], "stop") == 0) {
689                 rc = dbg_write_cmd(fd, "stop", 4);
690                 if (rc != 0) {
691                         fprintf(stderr, "stopping debug_daemon failed: %s\n",
692                                 strerror(errno));
693                         goto out;
694                 }
695
696                 rc = 0;
697                 goto out;
698         }
699
700         fprintf(stderr, debug_daemon_usage, argv[0]);
701         rc = -1;
702 out:
703         dbg_close_ctlhandle(fd);
704         return rc;
705 }
706
707 int jt_dbg_clear_debug_buf(int argc, char **argv)
708 {
709         int rc;
710         struct libcfs_ioctl_data data;
711
712         if (argc != 1) {
713                 fprintf(stderr, "usage: %s\n", argv[0]);
714                 return 0;
715         }
716
717         memset(&data, 0, sizeof(data));
718         if (libcfs_ioctl_pack(&data, &buf, max) != 0) {
719                 fprintf(stderr, "libcfs_ioctl_pack failed.\n");
720                 return -1;
721         }
722
723         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CLEAR_DEBUG, buf);
724         if (rc) {
725                 fprintf(stderr, "IOC_LIBCFS_CLEAR_DEBUG failed: %s\n",
726                         strerror(errno));
727                 return -1;
728         }
729         return 0;
730 }
731
732 int jt_dbg_mark_debug_buf(int argc, char **argv)
733 {
734         static char scratch[MAX_MARK_SIZE] = "";
735         struct libcfs_ioctl_data data = { 0 };
736         char *text;
737         int rc;
738
739         if (argc > 1) {
740                 int count, max_size = sizeof(scratch) - 1;
741
742                 strncpy(scratch, argv[1], max_size);
743                 max_size -= strlen(argv[1]);
744                 for (count = 2; (count < argc) && (max_size > 1); count++) {
745                         strncat(scratch, " ", max_size);
746                         max_size -= 1;
747                         strncat(scratch, argv[count], max_size);
748                         max_size -= strlen(argv[count]);
749                 }
750                 scratch[sizeof(scratch) - 1] = '\0';
751                 text = scratch;
752         } else {
753                 time_t now = time(NULL);
754                 text = ctime(&now);
755         }
756
757         data.ioc_inllen1 = strlen(text) + 1;
758         data.ioc_inlbuf1 = text;
759         if (libcfs_ioctl_pack(&data, &buf, max) != 0) {
760                 fprintf(stderr, "libcfs_ioctl_pack failed.\n");
761                 return -1;
762         }
763
764         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_MARK_DEBUG, buf);
765         if (rc) {
766                 fprintf(stderr, "IOC_LIBCFS_MARK_DEBUG failed: %s\n",
767                         strerror(errno));
768                 return -1;
769         }
770         return 0;
771 }
772
773 static struct mod_paths {
774         char *name, *path;
775 } mod_paths[] = {
776         { "libcfs", "libcfs/libcfs" },
777         { "lnet", "lnet/lnet" },
778         { "kmxlnd", "lnet/klnds/mxlnd" },
779         { "ko2iblnd", "lnet/klnds/o2iblnd" },
780         { "kgnilnd", "lnet/klnds/gnilnd"},
781         { "kqswlnd", "lnet/klnds/qswlnd" },
782         { "kralnd", "lnet/klnds/ralnd" },
783         { "ksocklnd", "lnet/klnds/socklnd" },
784         { "ktdilnd", "lnet/klnds/tdilnd" },
785         { "obdclass", "lustre/obdclass" },
786         { "llog_test", "lustre/obdclass" },
787         { "ptlrpc_gss", "lustre/ptlrpc/gss" },
788         { "ptlrpc", "lustre/ptlrpc" },
789         { "gks", "lustre/sec/gks" },
790         { "gkc", "lustre/sec/gks" },
791         { "ost", "lustre/ost" },
792         { "osc", "lustre/osc" },
793         { "mds", "lustre/mds" },
794         { "mdc", "lustre/mdc" },
795         { "lustre", "lustre/llite" },
796         { "llite_lloop", "lustre/llite" },
797         { "ldiskfs", "ldiskfs" },
798         { "obdecho", "lustre/obdecho" },
799         { "ldlm", "lustre/ldlm" },
800         { "obdfilter", "lustre/obdfilter" },
801         { "lov", "lustre/lov" },
802         { "lmv", "lustre/lmv" },
803         { "lquota", "lustre/quota" },
804         { "mgs", "lustre/mgs" },
805         { "mgc", "lustre/mgc" },
806         { "mdt", "lustre/mdt" },
807         { "mdd", "lustre/mdd" },
808         { "osd", "lustre/osd" },
809         { "cmm", "lustre/cmm" },
810         {"fid", "lustre/fid"},
811         {"fld", "lustre/fld"},
812         {"lod", "lustre/lod"},
813         {"osp", "lustre/osp"},
814         { "lfsck", "lustre/lfsck" },
815         {NULL, NULL}
816 };
817
818 int jt_dbg_modules(int argc, char **argv)
819 {
820         struct mod_paths *mp;
821         char *path = "";
822         const char *proc = "/proc/modules";
823         char modname[128], buf[4096];
824         unsigned long modaddr;
825         FILE *file;
826
827         if (argc >= 2)
828                 path = argv[1];
829         if (argc > 3) {
830                 printf("%s [path] [kernel]\n", argv[0]);
831                 return 0;
832         }
833
834         file = fopen(proc, "r");
835         if (!file) {
836                 printf("failed open %s: %s\n", proc, strerror(errno));
837                 return 0;
838         }
839
840         while (fgets(buf, sizeof(buf), file) != NULL) {
841                 if (sscanf(buf, "%s %*s %*s %*s %*s %lx", modname, &modaddr) == 2) {
842                         for (mp = mod_paths; mp->name != NULL; mp++) {
843                                 if (!strcmp(mp->name, modname))
844                                         break;
845                         }
846                         if (mp->name) {
847                                 printf("add-symbol-file %s%s%s/%s.o 0x%0lx\n",
848                                         path, path[0] ? "/" : "",
849                                         mp->path, mp->name, modaddr);
850                         }
851                 }
852         }
853
854         fclose(file);
855         return 0;
856 }
857
858 int jt_dbg_panic(int argc, char **argv)
859 {
860         int rc;
861         struct libcfs_ioctl_data data;
862
863         if (argc != 1) {
864                 fprintf(stderr, "usage: %s\n", argv[0]);
865                 return 0;
866         }
867
868         memset(&data, 0, sizeof(data));
869         if (libcfs_ioctl_pack(&data, &buf, max) != 0) {
870                 fprintf(stderr, "libcfs_ioctl_pack failed.\n");
871                 return -1;
872         }
873
874         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_PANIC, buf);
875         if (rc) {
876                 fprintf(stderr, "IOC_LIBCFS_PANIC failed: %s\n",
877                         strerror(errno));
878                 return -1;
879         }
880         return 0;
881 }