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