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