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