linux/drivers/staging/lustre/lustre/libcfs/debug.c
<<
>>
Prefs
   1/*
   2 * GPL HEADER START
   3 *
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 only,
   8 * as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License version 2 for more details (a copy is included
  14 * in the LICENSE file that accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * version 2 along with this program; If not, see
  18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
  19 *
  20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  21 * CA 95054 USA or visit www.sun.com if you need additional information or
  22 * have any questions.
  23 *
  24 * GPL HEADER END
  25 */
  26/*
  27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  28 * Use is subject to license terms.
  29 *
  30 * Copyright (c) 2011, 2012, Intel Corporation.
  31 */
  32/*
  33 * This file is part of Lustre, http://www.lustre.org/
  34 * Lustre is a trademark of Sun Microsystems, Inc.
  35 *
  36 * libcfs/libcfs/debug.c
  37 *
  38 * Author: Phil Schwan <phil@clusterfs.com>
  39 *
  40 */
  41
  42# define DEBUG_SUBSYSTEM S_LNET
  43
  44#include <linux/libcfs/libcfs.h>
  45#include "tracefile.h"
  46
  47static char debug_file_name[1024];
  48
  49unsigned int libcfs_subsystem_debug = ~0;
  50CFS_MODULE_PARM(libcfs_subsystem_debug, "i", int, 0644,
  51                "Lustre kernel debug subsystem mask");
  52EXPORT_SYMBOL(libcfs_subsystem_debug);
  53
  54unsigned int libcfs_debug = (D_CANTMASK |
  55                             D_NETERROR | D_HA | D_CONFIG | D_IOCTL);
  56CFS_MODULE_PARM(libcfs_debug, "i", int, 0644,
  57                "Lustre kernel debug mask");
  58EXPORT_SYMBOL(libcfs_debug);
  59
  60unsigned int libcfs_debug_mb = 0;
  61CFS_MODULE_PARM(libcfs_debug_mb, "i", uint, 0644,
  62                "Total debug buffer size.");
  63EXPORT_SYMBOL(libcfs_debug_mb);
  64
  65unsigned int libcfs_printk = D_CANTMASK;
  66CFS_MODULE_PARM(libcfs_printk, "i", uint, 0644,
  67                "Lustre kernel debug console mask");
  68EXPORT_SYMBOL(libcfs_printk);
  69
  70unsigned int libcfs_console_ratelimit = 1;
  71CFS_MODULE_PARM(libcfs_console_ratelimit, "i", uint, 0644,
  72                "Lustre kernel debug console ratelimit (0 to disable)");
  73EXPORT_SYMBOL(libcfs_console_ratelimit);
  74
  75unsigned int libcfs_console_max_delay;
  76CFS_MODULE_PARM(libcfs_console_max_delay, "l", uint, 0644,
  77                "Lustre kernel debug console max delay (jiffies)");
  78EXPORT_SYMBOL(libcfs_console_max_delay);
  79
  80unsigned int libcfs_console_min_delay;
  81CFS_MODULE_PARM(libcfs_console_min_delay, "l", uint, 0644,
  82                "Lustre kernel debug console min delay (jiffies)");
  83EXPORT_SYMBOL(libcfs_console_min_delay);
  84
  85unsigned int libcfs_console_backoff = CDEBUG_DEFAULT_BACKOFF;
  86CFS_MODULE_PARM(libcfs_console_backoff, "i", uint, 0644,
  87                "Lustre kernel debug console backoff factor");
  88EXPORT_SYMBOL(libcfs_console_backoff);
  89
  90unsigned int libcfs_debug_binary = 1;
  91EXPORT_SYMBOL(libcfs_debug_binary);
  92
  93unsigned int libcfs_stack = 3 * THREAD_SIZE / 4;
  94EXPORT_SYMBOL(libcfs_stack);
  95
  96unsigned int portal_enter_debugger;
  97EXPORT_SYMBOL(portal_enter_debugger);
  98
  99unsigned int libcfs_catastrophe;
 100EXPORT_SYMBOL(libcfs_catastrophe);
 101
 102unsigned int libcfs_watchdog_ratelimit = 300;
 103EXPORT_SYMBOL(libcfs_watchdog_ratelimit);
 104
 105unsigned int libcfs_panic_on_lbug = 1;
 106CFS_MODULE_PARM(libcfs_panic_on_lbug, "i", uint, 0644,
 107                "Lustre kernel panic on LBUG");
 108EXPORT_SYMBOL(libcfs_panic_on_lbug);
 109
 110atomic_t libcfs_kmemory = ATOMIC_INIT(0);
 111EXPORT_SYMBOL(libcfs_kmemory);
 112
 113static wait_queue_head_t debug_ctlwq;
 114
 115char libcfs_debug_file_path_arr[PATH_MAX] = LIBCFS_DEBUG_FILE_PATH_DEFAULT;
 116
 117/* We need to pass a pointer here, but elsewhere this must be a const */
 118char *libcfs_debug_file_path;
 119CFS_MODULE_PARM(libcfs_debug_file_path, "s", charp, 0644,
 120                "Path for dumping debug logs, "
 121                "set 'NONE' to prevent log dumping");
 122
 123int libcfs_panic_in_progress;
 124
 125/* libcfs_debug_token2mask() expects the returned
 126 * string in lower-case */
 127const char *
 128libcfs_debug_subsys2str(int subsys)
 129{
 130        switch (1 << subsys) {
 131        default:
 132                return NULL;
 133        case S_UNDEFINED:
 134                return "undefined";
 135        case S_MDC:
 136                return "mdc";
 137        case S_MDS:
 138                return "mds";
 139        case S_OSC:
 140                return "osc";
 141        case S_OST:
 142                return "ost";
 143        case S_CLASS:
 144                return "class";
 145        case S_LOG:
 146                return "log";
 147        case S_LLITE:
 148                return "llite";
 149        case S_RPC:
 150                return "rpc";
 151        case S_LNET:
 152                return "lnet";
 153        case S_LND:
 154                return "lnd";
 155        case S_PINGER:
 156                return "pinger";
 157        case S_FILTER:
 158                return "filter";
 159        case S_ECHO:
 160                return "echo";
 161        case S_LDLM:
 162                return "ldlm";
 163        case S_LOV:
 164                return "lov";
 165        case S_LQUOTA:
 166                return "lquota";
 167        case S_OSD:
 168                return "osd";
 169        case S_LMV:
 170                return "lmv";
 171        case S_SEC:
 172                return "sec";
 173        case S_GSS:
 174                return "gss";
 175        case S_MGC:
 176                return "mgc";
 177        case S_MGS:
 178                return "mgs";
 179        case S_FID:
 180                return "fid";
 181        case S_FLD:
 182                return "fld";
 183        }
 184}
 185
 186/* libcfs_debug_token2mask() expects the returned
 187 * string in lower-case */
 188const char *
 189libcfs_debug_dbg2str(int debug)
 190{
 191        switch (1 << debug) {
 192        default:
 193                return NULL;
 194        case D_TRACE:
 195                return "trace";
 196        case D_INODE:
 197                return "inode";
 198        case D_SUPER:
 199                return "super";
 200        case D_EXT2:
 201                return "ext2";
 202        case D_MALLOC:
 203                return "malloc";
 204        case D_CACHE:
 205                return "cache";
 206        case D_INFO:
 207                return "info";
 208        case D_IOCTL:
 209                return "ioctl";
 210        case D_NETERROR:
 211                return "neterror";
 212        case D_NET:
 213                return "net";
 214        case D_WARNING:
 215                return "warning";
 216        case D_BUFFS:
 217                return "buffs";
 218        case D_OTHER:
 219                return "other";
 220        case D_DENTRY:
 221                return "dentry";
 222        case D_NETTRACE:
 223                return "nettrace";
 224        case D_PAGE:
 225                return "page";
 226        case D_DLMTRACE:
 227                return "dlmtrace";
 228        case D_ERROR:
 229                return "error";
 230        case D_EMERG:
 231                return "emerg";
 232        case D_HA:
 233                return "ha";
 234        case D_RPCTRACE:
 235                return "rpctrace";
 236        case D_VFSTRACE:
 237                return "vfstrace";
 238        case D_READA:
 239                return "reada";
 240        case D_MMAP:
 241                return "mmap";
 242        case D_CONFIG:
 243                return "config";
 244        case D_CONSOLE:
 245                return "console";
 246        case D_QUOTA:
 247                return "quota";
 248        case D_SEC:
 249                return "sec";
 250        case D_LFSCK:
 251                return "lfsck";
 252        }
 253}
 254
 255int
 256libcfs_debug_mask2str(char *str, int size, int mask, int is_subsys)
 257{
 258        const char *(*fn)(int bit) = is_subsys ? libcfs_debug_subsys2str :
 259                                                 libcfs_debug_dbg2str;
 260        int        len = 0;
 261        const char   *token;
 262        int        i;
 263
 264        if (mask == 0) {                        /* "0" */
 265                if (size > 0)
 266                        str[0] = '0';
 267                len = 1;
 268        } else {                                /* space-separated tokens */
 269                for (i = 0; i < 32; i++) {
 270                        if ((mask & (1 << i)) == 0)
 271                                continue;
 272
 273                        token = fn(i);
 274                        if (token == NULL)            /* unused bit */
 275                                continue;
 276
 277                        if (len > 0) {            /* separator? */
 278                                if (len < size)
 279                                        str[len] = ' ';
 280                                len++;
 281                        }
 282
 283                        while (*token != 0) {
 284                                if (len < size)
 285                                        str[len] = *token;
 286                                token++;
 287                                len++;
 288                        }
 289                }
 290        }
 291
 292        /* terminate 'str' */
 293        if (len < size)
 294                str[len] = 0;
 295        else
 296                str[size - 1] = 0;
 297
 298        return len;
 299}
 300
 301int
 302libcfs_debug_str2mask(int *mask, const char *str, int is_subsys)
 303{
 304        const char *(*fn)(int bit) = is_subsys ? libcfs_debug_subsys2str :
 305                                                 libcfs_debug_dbg2str;
 306        int      m = 0;
 307        int      matched;
 308        int      n;
 309        int      t;
 310
 311        /* Allow a number for backwards compatibility */
 312
 313        for (n = strlen(str); n > 0; n--)
 314                if (!isspace(str[n-1]))
 315                        break;
 316        matched = n;
 317
 318        if ((t = sscanf(str, "%i%n", &m, &matched)) >= 1 &&
 319            matched == n) {
 320                /* don't print warning for lctl set_param debug=0 or -1 */
 321                if (m != 0 && m != -1)
 322                        CWARN("You are trying to use a numerical value for the "
 323                              "mask - this will be deprecated in a future "
 324                              "release.\n");
 325                *mask = m;
 326                return 0;
 327        }
 328
 329        return cfs_str2mask(str, fn, mask, is_subsys ? 0 : D_CANTMASK,
 330                            0xffffffff);
 331}
 332
 333/**
 334 * Dump Lustre log to ::debug_file_path by calling tracefile_dump_all_pages()
 335 */
 336void libcfs_debug_dumplog_internal(void *arg)
 337{
 338        DECL_JOURNAL_DATA;
 339
 340        PUSH_JOURNAL;
 341
 342        if (strncmp(libcfs_debug_file_path_arr, "NONE", 4) != 0) {
 343                snprintf(debug_file_name, sizeof(debug_file_name) - 1,
 344                         "%s.%ld." LPLD, libcfs_debug_file_path_arr,
 345                         cfs_time_current_sec(), (long_ptr_t)arg);
 346                printk(KERN_ALERT "LustreError: dumping log to %s\n",
 347                       debug_file_name);
 348                cfs_tracefile_dump_all_pages(debug_file_name);
 349                libcfs_run_debug_log_upcall(debug_file_name);
 350        }
 351        POP_JOURNAL;
 352}
 353
 354int libcfs_debug_dumplog_thread(void *arg)
 355{
 356        libcfs_debug_dumplog_internal(arg);
 357        wake_up(&debug_ctlwq);
 358        return 0;
 359}
 360
 361void libcfs_debug_dumplog(void)
 362{
 363        wait_queue_t wait;
 364        task_t    *dumper;
 365        ENTRY;
 366
 367        /* we're being careful to ensure that the kernel thread is
 368         * able to set our state to running as it exits before we
 369         * get to schedule() */
 370        init_waitqueue_entry_current(&wait);
 371        set_current_state(TASK_INTERRUPTIBLE);
 372        add_wait_queue(&debug_ctlwq, &wait);
 373
 374        dumper = kthread_run(libcfs_debug_dumplog_thread,
 375                             (void *)(long)current_pid(),
 376                             "libcfs_debug_dumper");
 377        if (IS_ERR(dumper))
 378                printk(KERN_ERR "LustreError: cannot start log dump thread:"
 379                       " %ld\n", PTR_ERR(dumper));
 380        else
 381                waitq_wait(&wait, TASK_INTERRUPTIBLE);
 382
 383        /* be sure to teardown if cfs_create_thread() failed */
 384        remove_wait_queue(&debug_ctlwq, &wait);
 385        set_current_state(TASK_RUNNING);
 386}
 387EXPORT_SYMBOL(libcfs_debug_dumplog);
 388
 389int libcfs_debug_init(unsigned long bufsize)
 390{
 391        int    rc = 0;
 392        unsigned int max = libcfs_debug_mb;
 393
 394        init_waitqueue_head(&debug_ctlwq);
 395
 396        if (libcfs_console_max_delay <= 0 || /* not set by user or */
 397            libcfs_console_min_delay <= 0 || /* set to invalid values */
 398            libcfs_console_min_delay >= libcfs_console_max_delay) {
 399                libcfs_console_max_delay = CDEBUG_DEFAULT_MAX_DELAY;
 400                libcfs_console_min_delay = CDEBUG_DEFAULT_MIN_DELAY;
 401        }
 402
 403        if (libcfs_debug_file_path != NULL) {
 404                memset(libcfs_debug_file_path_arr, 0, PATH_MAX);
 405                strncpy(libcfs_debug_file_path_arr,
 406                        libcfs_debug_file_path, PATH_MAX-1);
 407        }
 408
 409        /* If libcfs_debug_mb is set to an invalid value or uninitialized
 410         * then just make the total buffers smp_num_cpus * TCD_MAX_PAGES */
 411        if (max > cfs_trace_max_debug_mb() || max < num_possible_cpus()) {
 412                max = TCD_MAX_PAGES;
 413        } else {
 414                max = (max / num_possible_cpus());
 415                max = (max << (20 - PAGE_CACHE_SHIFT));
 416        }
 417        rc = cfs_tracefile_init(max);
 418
 419        if (rc == 0)
 420                libcfs_register_panic_notifier();
 421
 422        return rc;
 423}
 424
 425int libcfs_debug_cleanup(void)
 426{
 427        libcfs_unregister_panic_notifier();
 428        cfs_tracefile_exit();
 429        return 0;
 430}
 431
 432int libcfs_debug_clear_buffer(void)
 433{
 434        cfs_trace_flush_pages();
 435        return 0;
 436}
 437
 438/* Debug markers, although printed by S_LNET
 439 * should not be be marked as such. */
 440#undef DEBUG_SUBSYSTEM
 441#define DEBUG_SUBSYSTEM S_UNDEFINED
 442int libcfs_debug_mark_buffer(const char *text)
 443{
 444        CDEBUG(D_TRACE,"***************************************************\n");
 445        LCONSOLE(D_WARNING, "DEBUG MARKER: %s\n", text);
 446        CDEBUG(D_TRACE,"***************************************************\n");
 447
 448        return 0;
 449}
 450#undef DEBUG_SUBSYSTEM
 451#define DEBUG_SUBSYSTEM S_LNET
 452
 453void libcfs_debug_set_level(unsigned int debug_level)
 454{
 455        printk(KERN_WARNING "Lustre: Setting portals debug level to %08x\n",
 456               debug_level);
 457        libcfs_debug = debug_level;
 458}
 459
 460EXPORT_SYMBOL(libcfs_debug_set_level);
 461
 462long libcfs_log_return(struct libcfs_debug_msg_data *msgdata, long rc)
 463{
 464        libcfs_debug_msg(msgdata, "Process leaving (rc=%lu : %ld : %lx)\n",
 465                         rc, rc, rc);
 466        return rc;
 467}
 468EXPORT_SYMBOL(libcfs_log_return);
 469
 470void libcfs_log_goto(struct libcfs_debug_msg_data *msgdata, const char *label,
 471                     long_ptr_t rc)
 472{
 473        libcfs_debug_msg(msgdata, "Process leaving via %s (rc=" LPLU " : " LPLD
 474                         " : " LPLX ")\n", label, (ulong_ptr_t)rc, rc, rc);
 475}
 476EXPORT_SYMBOL(libcfs_log_goto);
 477