Whamcloud - gitweb
bz-13516
[fs/lustre-release.git] / lnet / libcfs / debug.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Phil Schwan <phil@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #ifndef EXPORT_SYMTAB
24 # define EXPORT_SYMTAB
25 #endif
26
27 # define DEBUG_SUBSYSTEM S_LNET
28
29 #include <stdarg.h>
30 #include <libcfs/kp30.h>
31 #include <libcfs/libcfs.h>
32 #include "tracefile.h"
33
34 static char debug_file_name[1024];
35
36 #ifdef __KERNEL__
37 unsigned int libcfs_subsystem_debug = ~0;
38 EXPORT_SYMBOL(libcfs_subsystem_debug);
39
40 unsigned int libcfs_debug = (D_EMERG | D_ERROR | D_WARNING | D_CONSOLE |
41                              D_NETERROR | D_HA | D_CONFIG | D_IOCTL);
42 EXPORT_SYMBOL(libcfs_debug);
43
44 unsigned int libcfs_printk;
45 EXPORT_SYMBOL(libcfs_printk);
46
47 unsigned int libcfs_console_ratelimit = 1;
48 EXPORT_SYMBOL(libcfs_console_ratelimit);
49
50 unsigned int libcfs_debug_binary = 1;
51 EXPORT_SYMBOL(libcfs_debug_binary);
52
53 unsigned int libcfs_stack;
54 EXPORT_SYMBOL(libcfs_stack);
55
56 unsigned int portal_enter_debugger;
57 EXPORT_SYMBOL(portal_enter_debugger);
58
59 unsigned int libcfs_catastrophe;
60 EXPORT_SYMBOL(libcfs_catastrophe);
61
62 unsigned int libcfs_panic_on_lbug = 0;
63 EXPORT_SYMBOL(libcfs_panic_on_lbug);
64
65 atomic_t libcfs_kmemory = ATOMIC_INIT(0);
66 EXPORT_SYMBOL(libcfs_kmemory);
67
68 static cfs_waitq_t debug_ctlwq;
69
70 #ifdef __arch_um__
71 char debug_file_path[1024] = "/r/tmp/lustre-log";
72 #else
73 char debug_file_path[1024] = "/tmp/lustre-log";
74 #endif
75
76 int libcfs_panic_in_progress;
77
78 /* libcfs_debug_token2mask() expects the returned
79  * string in lower-case */
80 const char *
81 libcfs_debug_subsys2str(int subsys)
82 {
83         switch (subsys) {
84         default:
85                 return NULL;
86         case S_UNDEFINED:
87                 return "undefined";
88         case S_MDC:
89                 return "mdc";
90         case S_MDS:
91                 return "mds";
92         case S_OSC:
93                 return "osc";
94         case S_OST:
95                 return "ost";
96         case S_CLASS:
97                 return "class";
98         case S_LOG:
99                 return "log";
100         case S_LLITE:
101                 return "llite";
102         case S_RPC:
103                 return "rpc";
104         case S_LNET:
105                 return "lnet";
106         case S_LND:
107                 return "lnd";
108         case S_PINGER:
109                 return "pinger";
110         case S_FILTER:
111                 return "filter";
112         case S_ECHO:
113                 return "echo";
114         case S_LDLM:
115                 return "ldlm";
116         case S_LOV:
117                 return "lov";
118         case S_LMV:
119                 return "lmv";
120         case S_SEC:
121                 return "sec";
122         case S_GSS:
123                 return "gss";
124         case S_MGC:
125                 return "mgc";
126         case S_MGS:
127                 return "mgs";
128         case S_FID:
129                 return "fid";
130         case S_FLD:
131                 return "fld";
132         }
133 }
134
135 /* libcfs_debug_token2mask() expects the returned
136  * string in lower-case */
137 const char *
138 libcfs_debug_dbg2str(int debug)
139 {
140         switch (debug) {
141         default:
142                 return NULL;
143         case D_TRACE:
144                 return "trace";
145         case D_INODE:
146                 return "inode";
147         case D_SUPER:
148                 return "super";
149         case D_EXT2:
150                 return "ext2";
151         case D_MALLOC:
152                 return "malloc";
153         case D_CACHE:
154                 return "cache";
155         case D_INFO:
156                 return "info";
157         case D_IOCTL:
158                 return "ioctl";
159         case D_NETERROR:
160                 return "neterror";
161         case D_NET:
162                 return "net";
163         case D_WARNING:
164                 return "warning";
165         case D_BUFFS:
166                 return "buffs";
167         case D_OTHER:
168                 return "other";
169         case D_DENTRY:
170                 return "dentry";
171         case D_NETTRACE:
172                 return "nettrace";
173         case D_PAGE:
174                 return "page";
175         case D_DLMTRACE:
176                 return "dlmtrace";
177         case D_ERROR:
178                 return "error";
179         case D_EMERG:
180                 return "emerg";
181         case D_HA:
182                 return "ha";
183         case D_RPCTRACE:
184                 return "rpctrace";
185         case D_VFSTRACE:
186                 return "vfstrace";
187         case D_READA:
188                 return "reada";
189         case D_MMAP:
190                 return "mmap";
191         case D_CONFIG:
192                 return "config";
193         case D_CONSOLE:
194                 return "console";
195         case D_QUOTA:
196                 return "quota";
197         case D_SEC:
198                 return "sec";
199         }
200 }
201
202 int
203 libcfs_debug_mask2str(char *str, int size, int mask, int is_subsys)
204 {
205         const char *(*fn)(int bit) = is_subsys ? libcfs_debug_subsys2str :
206                                                  libcfs_debug_dbg2str;
207         int           len = 0;
208         const char   *token;
209         int           bit;
210         int           i;
211
212         if (mask == 0) {                        /* "0" */
213                 if (size > 0)
214                         str[0] = '0';
215                 len = 1;
216         } else {                                /* space-separated tokens */
217                 for (i = 0; i < 32; i++) {
218                         bit = 1 << i;
219
220                         if ((mask & bit) == 0)
221                                 continue;
222
223                         token = fn(bit);
224                         if (token == NULL)              /* unused bit */
225                                 continue;
226
227                         if (len > 0) {                  /* separator? */
228                                 if (len < size)
229                                         str[len] = ' ';
230                                 len++;
231                         }
232
233                         while (*token != 0) {
234                                 if (len < size)
235                                         str[len] = *token;
236                                 token++;
237                                 len++;
238                         }
239                 }
240         }
241
242         /* terminate 'str' */
243         if (len < size)
244                 str[len] = 0;
245         else
246                 str[size - 1] = 0;
247
248         return len;
249 }
250
251 int
252 libcfs_debug_token2mask(int *mask, const char *str, int len, int is_subsys)
253 {
254         const char *(*fn)(int bit) = is_subsys ? libcfs_debug_subsys2str :
255                                                  libcfs_debug_dbg2str;
256         int           i;
257         int           j;
258         int           bit;
259         const char   *token;
260
261         /* match against known tokens */
262         for (i = 0; i < 32; i++) {
263                 bit = 1 << i;
264
265                 token = fn(bit);
266                 if (token == NULL)              /* unused? */
267                         continue;
268
269                 /* strcasecmp */
270                 for (j = 0; ; j++) {
271                         if (j == len) {         /* end of token */
272                                 if (token[j] == 0) {
273                                         *mask = bit;
274                                         return 0;
275                                 }
276                                 break;
277                         }
278
279                         if (token[j] == 0)
280                                 break;
281
282                         if (str[j] == token[j])
283                                 continue;
284
285                         if (str[j] < 'A' || 'Z' < str[j])
286                                 break;
287
288                         if (str[j] - 'A' + 'a' != token[j])
289                                 break;
290                 }
291         }
292
293         return -EINVAL;                         /* no match */
294 }
295
296 int
297 libcfs_debug_str2mask(int *mask, const char *str, int is_subsys)
298 {
299         int         m = 0;
300         char        op = 0;
301         int         matched;
302         int         n;
303         int         t;
304
305         /* Allow a number for backwards compatibility */
306
307         for (n = strlen(str); n > 0; n--)
308                 if (!isspace(str[n-1]))
309                         break;
310         matched = n;
311
312         if ((t = sscanf(str, "%i%n", &m, &matched)) >= 1 &&
313             matched == n) {
314                 *mask = m;
315                 return 0;
316         }
317
318         /* <str> must be a list of debug tokens or numbers separated by
319          * whitespace and optionally an operator ('+' or '-').  If an operator
320          * appears first in <str>, '*mask' is used as the starting point
321          * (relative), otherwise 0 is used (absolute).  An operator applies to
322          * all following tokens up to the next operator. */
323
324         matched = 0;
325         while (*str != 0) {
326                 while (isspace(*str)) /* skip whitespace */
327                         str++;
328
329                 if (*str == 0)
330                         break;
331
332                 if (*str == '+' || *str == '-') {
333                         op = *str++;
334
335                         /* op on first token == relative */
336                         if (!matched)
337                                 m = *mask;
338
339                         while (isspace(*str)) /* skip whitespace */
340                                 str++;
341
342                         if (*str == 0)          /* trailing op */
343                                 return -EINVAL;
344                 }
345
346                 /* find token length */
347                 for (n = 0; str[n] != 0 && !isspace(str[n]); n++);
348
349                 /* match token */
350                 if (libcfs_debug_token2mask(&t, str, n, is_subsys) != 0)
351                         return -EINVAL;
352
353                 matched = 1;
354                 if (op == '-')
355                         m &= ~t;
356                 else
357                         m |= t;
358
359                 str += n;
360         }
361
362         if (!matched)
363                 return -EINVAL;
364
365         *mask = m;
366         return 0;
367 }
368
369 void libcfs_debug_dumplog_internal(void *arg)
370 {
371         CFS_DECL_JOURNAL_DATA;
372
373         CFS_PUSH_JOURNAL;
374
375         snprintf(debug_file_name, sizeof(debug_file_path) - 1, "%s.%ld.%ld",
376                  debug_file_path, cfs_time_current_sec(), (long)arg);
377         printk(KERN_ALERT "LustreError: dumping log to %s\n", debug_file_name);
378         tracefile_dump_all_pages(debug_file_name);
379
380         CFS_POP_JOURNAL;
381 }
382
383 int libcfs_debug_dumplog_thread(void *arg)
384 {
385         cfs_daemonize("");
386         libcfs_debug_dumplog_internal(arg);
387         cfs_waitq_signal(&debug_ctlwq);
388         return 0;
389 }
390
391 void libcfs_debug_dumplog(void)
392 {
393         int            rc;
394         cfs_waitlink_t wait;
395         ENTRY;
396
397         /* we're being careful to ensure that the kernel thread is
398          * able to set our state to running as it exits before we
399          * get to schedule() */
400         cfs_waitlink_init(&wait);
401         set_current_state(TASK_INTERRUPTIBLE);
402         cfs_waitq_add(&debug_ctlwq, &wait);
403
404         rc = cfs_kernel_thread(libcfs_debug_dumplog_thread,
405                                (void *)(long)cfs_curproc_pid(),
406                                CLONE_VM | CLONE_FS | CLONE_FILES);
407         if (rc < 0)
408                 printk(KERN_ERR "LustreError: cannot start log dump thread: "
409                        "%d\n", rc);
410         else
411                 cfs_waitq_wait(&wait, CFS_TASK_INTERRUPTIBLE);
412
413         /* be sure to teardown if kernel_thread() failed */
414         cfs_waitq_del(&debug_ctlwq, &wait);
415         set_current_state(TASK_RUNNING);
416 }
417
418 int libcfs_debug_init(unsigned long bufsize)
419 {
420         int    rc;
421
422         cfs_waitq_init(&debug_ctlwq);
423         rc = tracefile_init();
424
425         if (rc == 0)
426                 libcfs_register_panic_notifier();
427
428         return rc;
429 }
430
431 int libcfs_debug_cleanup(void)
432 {
433         libcfs_unregister_panic_notifier();
434         tracefile_exit();
435         return 0;
436 }
437
438 int libcfs_debug_clear_buffer(void)
439 {
440         trace_flush_pages();
441         return 0;
442 }
443
444 /* Debug markers, although printed by S_LNET
445  * should not be be marked as such. */
446 #undef DEBUG_SUBSYSTEM
447 #define DEBUG_SUBSYSTEM S_UNDEFINED
448 int libcfs_debug_mark_buffer(char *text)
449 {
450         CDEBUG(D_TRACE,"***************************************************\n");
451         CDEBUG(D_WARNING, "DEBUG MARKER: %s\n", text);
452         CDEBUG(D_TRACE,"***************************************************\n");
453
454         return 0;
455 }
456 #undef DEBUG_SUBSYSTEM
457 #define DEBUG_SUBSYSTEM S_LNET
458
459 void libcfs_debug_set_level(unsigned int debug_level)
460 {
461         printk(KERN_WARNING "Lustre: Setting portals debug level to %08x\n",
462                debug_level);
463         libcfs_debug = debug_level;
464 }
465
466 EXPORT_SYMBOL(libcfs_debug_dumplog);
467 EXPORT_SYMBOL(libcfs_debug_set_level);
468
469
470 #else /* !__KERNEL__ */
471
472 #include <libcfs/libcfs.h>
473
474 #ifdef HAVE_CATAMOUNT_DATA_H
475 #include <catamount/data.h>
476 #include <catamount/lputs.h>
477
478 static char source_nid[16];
479 /* 0 indicates no messages to console, 1 is errors, > 1 is all debug messages */
480 static int toconsole = 1;
481 unsigned int libcfs_console_ratelimit = 1;
482 #else /* !HAVE_CATAMOUNT_DATA_H */
483 #ifdef HAVE_NETDB_H
484 #include <sys/utsname.h>
485 #endif /* HAVE_NETDB_H */
486 struct utsname *tmp_utsname;
487 static char source_nid[sizeof(tmp_utsname->nodename)];
488 #endif /* HAVE_CATAMOUNT_DATA_H */
489
490 static int source_pid;
491 int smp_processor_id = 1;
492 char debug_file_path[1024];
493 FILE *debug_file_fd;
494
495 int portals_do_debug_dumplog(void *arg)
496 {
497         printf("Look in %s\n", debug_file_name);
498         return 0;
499 }
500
501
502 void portals_debug_print(void)
503 {
504         return;
505 }
506
507
508 void libcfs_debug_dumplog(void)
509 {
510         printf("Look in %s\n", debug_file_name);
511         return;
512 }
513
514 int libcfs_debug_init(unsigned long bufsize)
515 {
516         char *debug_mask = NULL;
517         char *debug_subsys = NULL;
518         char *debug_filename;
519
520 #ifdef HAVE_CATAMOUNT_DATA_H
521         char *debug_console = NULL;
522         char *debug_ratelimit = NULL;
523
524         snprintf(source_nid, sizeof(source_nid) - 1, "%u", _my_pnid);
525         source_pid = _my_pid;
526
527         debug_console = getenv("LIBLUSTRE_DEBUG_CONSOLE");
528         if (debug_console != NULL) {
529                 toconsole = strtoul(debug_console, NULL, 0);
530                 CDEBUG(D_INFO, "set liblustre toconsole to %u\n", toconsole);
531         }
532         debug_ratelimit = getenv("LIBLUSTRE_DEBUG_CONSOLE_RATELIMIT");
533         if (debug_ratelimit != NULL) {
534                 libcfs_console_ratelimit = strtoul(debug_ratelimit, NULL, 0);
535                 CDEBUG(D_INFO, "set liblustre console ratelimit to %u\n", libcfs_console_ratelimit);
536         }
537 #else
538         struct utsname myname;
539
540         if (uname(&myname) == 0)
541                 strcpy(source_nid, myname.nodename);
542         source_pid = getpid();
543 #endif
544         /* debug masks */
545         debug_mask = getenv("LIBLUSTRE_DEBUG_MASK");
546         if (debug_mask)
547                 libcfs_debug = (unsigned int) strtol(debug_mask, NULL, 0);
548
549         debug_subsys = getenv("LIBLUSTRE_DEBUG_SUBSYS");
550         if (debug_subsys)
551                 libcfs_subsystem_debug =
552                                 (unsigned int) strtol(debug_subsys, NULL, 0);
553
554         debug_filename = getenv("LIBLUSTRE_DEBUG_BASE");
555         if (debug_filename)
556                 strncpy(debug_file_path,debug_filename,sizeof(debug_file_path));
557
558         debug_filename = getenv("LIBLUSTRE_DEBUG_FILE");
559         if (debug_filename)
560                 strncpy(debug_file_name,debug_filename,sizeof(debug_file_path));
561
562         if (debug_file_name[0] == '\0' && debug_file_path[0] != '\0')
563                 snprintf(debug_file_name, sizeof(debug_file_name) - 1,
564                          "%s-%s-%lu.log", debug_file_path, source_nid, time(0));
565
566         if (strcmp(debug_file_name, "stdout") == 0 ||
567             strcmp(debug_file_name, "-") == 0) {
568                 debug_file_fd = stdout;
569         } else if (strcmp(debug_file_name, "stderr") == 0) {
570                 debug_file_fd = stderr;
571         } else if (debug_file_name[0] != '\0') {
572                 debug_file_fd = fopen(debug_file_name, "w");
573                 if (debug_file_fd == NULL)
574                         fprintf(stderr, "%s: unable to open '%s': %s\n",
575                                 source_nid, debug_file_name, strerror(errno));
576         }
577
578         if (debug_file_fd == NULL)
579                 debug_file_fd = stdout;
580
581         return 0;
582 }
583
584 int libcfs_debug_cleanup(void)
585 {
586         if (debug_file_fd != stdout && debug_file_fd != stderr)
587                 fclose(debug_file_fd);
588         return 0;
589 }
590
591 int libcfs_debug_clear_buffer(void)
592 {
593         return 0;
594 }
595
596 int libcfs_debug_mark_buffer(char *text)
597 {
598
599         fprintf(debug_file_fd, "*******************************************************************************\n");
600         fprintf(debug_file_fd, "DEBUG MARKER: %s\n", text);
601         fprintf(debug_file_fd, "*******************************************************************************\n");
602
603         return 0;
604 }
605
606 #ifdef HAVE_CATAMOUNT_DATA_H
607 #define CATAMOUNT_MAXLINE (256-4)
608 void catamount_printline(char *buf, size_t size)
609 {
610     char *pos = buf;
611     int prsize = size;
612
613     while (prsize > 0){
614         lputs(pos);
615         pos += CATAMOUNT_MAXLINE;
616         prsize -= CATAMOUNT_MAXLINE;
617     }
618 }
619 #endif
620
621 int
622 libcfs_debug_vmsg2(cfs_debug_limit_state_t *cdls,
623                    int subsys, int mask,
624                    const char *file, const char *fn, const int line,
625                    const char *format1, va_list args,
626                    const char *format2, ...)
627 {
628         struct timeval tv;
629         int            nob;
630         int            remain;
631         va_list        ap;
632         char           buf[PAGE_SIZE]; /* size 4096 used for compatimble with linux,
633                                         * where message can`t be exceed PAGE_SIZE */
634         int            console = 0;
635         char *prefix = "Lustre";
636
637 #ifdef HAVE_CATAMOUNT_DATA_H
638         /* toconsole == 0 - all messages to debug_file_fd
639          * toconsole == 1 - warnings to console, all to debug_file_fd
640          * toconsole >  1 - all debug to console */
641         if ( ((mask & D_CANTMASK) &&
642              (toconsole == 1)) || (toconsole > 1)) {
643                 console = 1;
644         }
645 #endif
646
647         if ((!console) && (!debug_file_fd)) {
648                 return 0;
649         }
650
651         if (mask & (D_EMERG | D_ERROR))
652                prefix = "LustreError";
653
654         nob = snprintf(buf, sizeof(buf), "%s: %u-%s:(%s:%d:%s()): ", prefix,
655                        source_pid, source_nid, file, line, fn);
656
657         remain = sizeof(buf) - nob;
658         if (format1) {
659                 nob += vsnprintf(&buf[nob], remain, format1, args);
660         }
661
662         remain = sizeof(buf) - nob;
663         if ((format2) && (remain > 0)) {
664                 va_start(ap, format2);
665                 nob += vsnprintf(&buf[nob], remain, format2, ap);
666                 va_end(ap);
667         }
668
669 #ifdef HAVE_CATAMOUNT_DATA_H
670         if (console) {
671                 /* check rate limit for console */
672                 if (cdls != NULL) {
673                         cfs_time_t t = cdls->cdls_next +
674                                        cfs_time_seconds(CDEBUG_MAX_LIMIT + 10);
675                         cfs_duration_t  dmax = cfs_time_seconds(CDEBUG_MAX_LIMIT);
676
677                         if (libcfs_console_ratelimit &&
678                                 cdls->cdls_next != 0 &&     /* not first time ever */
679                                 !cfs_time_after(cfs_time_current(), cdls->cdls_next)) {
680
681                                 /* skipping a console message */
682                                 cdls->cdls_count++;
683                                 goto out_file;
684                         }
685
686                         if (cfs_time_after(cfs_time_current(), t)) {
687                                 /* last timeout was a long time ago */
688                                 cdls->cdls_delay /= 8;
689                         } else {
690                                 cdls->cdls_delay *= 2;
691
692                                 if (cdls->cdls_delay < CFS_TICK)
693                                         cdls->cdls_delay = CFS_TICK;
694                                 else if (cdls->cdls_delay > dmax)
695                                         cdls->cdls_delay = dmax;
696                         }
697
698                         /* ensure cdls_next is never zero after it's been seen */
699                         cdls->cdls_next = (cfs_time_current() + cdls->cdls_delay) | 1;
700                 }
701
702                 if (cdls != NULL && cdls->cdls_count != 0) {
703                         char buf2[100];
704
705                         nob = snprintf(buf2, sizeof(buf2),
706                                        "Skipped %d previous similar message%s\n",
707                                        cdls->cdls_count, (cdls->cdls_count > 1) ? "s" : "");
708
709                         catamount_printline(buf2, nob);
710                         cdls->cdls_count = 0;
711                         goto out_file;
712                 }
713                 catamount_printline(buf, nob);
714        }
715 out_file:
716         /* return on toconsole > 1, as we don't want the user getting
717         * spammed by the debug data */
718         if (toconsole > 1)
719                 return 0;
720 #endif
721         if (debug_file_fd == NULL)
722                 return 0;
723
724         gettimeofday(&tv, NULL);
725
726         fprintf(debug_file_fd, "%lu.%06lu:%u:%s:(%s:%d:%s()): %s",
727                 tv.tv_sec, tv.tv_usec, source_pid, source_nid,
728                 file, line, fn, buf);
729
730         return 0;
731 }
732
733 void
734 libcfs_assertion_failed(const char *expr, const char *file, const char *func,
735                         const int line)
736 {
737         libcfs_debug_msg(NULL, 0, D_EMERG, file, func, line,
738                          "ASSERTION(%s) failed\n", expr);
739         abort();
740 }
741
742 #endif /* __KERNEL__ */