linux/drivers/staging/lustre/lnet/libcfs/tracefile.h
<<
>>
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.gnu.org/licenses/gpl-2.0.html
  19 *
  20 * GPL HEADER END
  21 */
  22/*
  23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24 * Use is subject to license terms.
  25 *
  26 * Copyright (c) 2012, Intel Corporation.
  27 */
  28/*
  29 * This file is part of Lustre, http://www.lustre.org/
  30 * Lustre is a trademark of Sun Microsystems, Inc.
  31 */
  32
  33#ifndef __LIBCFS_TRACEFILE_H__
  34#define __LIBCFS_TRACEFILE_H__
  35
  36#include "../../include/linux/libcfs/libcfs.h"
  37
  38enum cfs_trace_buf_type {
  39        CFS_TCD_TYPE_PROC = 0,
  40        CFS_TCD_TYPE_SOFTIRQ,
  41        CFS_TCD_TYPE_IRQ,
  42        CFS_TCD_TYPE_MAX
  43};
  44
  45/* trace file lock routines */
  46
  47#define TRACEFILE_NAME_SIZE 1024
  48extern char      cfs_tracefile[TRACEFILE_NAME_SIZE];
  49extern long long cfs_tracefile_size;
  50
  51void libcfs_run_debug_log_upcall(char *file);
  52
  53int  cfs_tracefile_init_arch(void);
  54void cfs_tracefile_fini_arch(void);
  55
  56void cfs_tracefile_read_lock(void);
  57void cfs_tracefile_read_unlock(void);
  58void cfs_tracefile_write_lock(void);
  59void cfs_tracefile_write_unlock(void);
  60
  61int cfs_tracefile_dump_all_pages(char *filename);
  62void cfs_trace_debug_print(void);
  63void cfs_trace_flush_pages(void);
  64int cfs_trace_start_thread(void);
  65void cfs_trace_stop_thread(void);
  66int cfs_tracefile_init(int max_pages);
  67void cfs_tracefile_exit(void);
  68
  69int cfs_trace_copyin_string(char *knl_buffer, int knl_buffer_nob,
  70                            const char __user *usr_buffer, int usr_buffer_nob);
  71int cfs_trace_copyout_string(char __user *usr_buffer, int usr_buffer_nob,
  72                             const char *knl_str, char *append);
  73int cfs_trace_allocate_string_buffer(char **str, int nob);
  74int cfs_trace_dump_debug_buffer_usrstr(void __user *usr_str, int usr_str_nob);
  75int cfs_trace_daemon_command(char *str);
  76int cfs_trace_daemon_command_usrstr(void __user *usr_str, int usr_str_nob);
  77int cfs_trace_set_debug_mb(int mb);
  78int cfs_trace_get_debug_mb(void);
  79
  80void libcfs_debug_dumplog_internal(void *arg);
  81void libcfs_register_panic_notifier(void);
  82void libcfs_unregister_panic_notifier(void);
  83extern int  libcfs_panic_in_progress;
  84int cfs_trace_max_debug_mb(void);
  85
  86#define TCD_MAX_PAGES (5 << (20 - PAGE_SHIFT))
  87#define TCD_STOCK_PAGES (TCD_MAX_PAGES)
  88#define CFS_TRACEFILE_SIZE (500 << 20)
  89
  90#ifdef LUSTRE_TRACEFILE_PRIVATE
  91
  92/*
  93 * Private declare for tracefile
  94 */
  95#define TCD_MAX_PAGES (5 << (20 - PAGE_SHIFT))
  96#define TCD_STOCK_PAGES (TCD_MAX_PAGES)
  97
  98#define CFS_TRACEFILE_SIZE (500 << 20)
  99
 100/*
 101 * Size of a buffer for sprinting console messages if we can't get a page
 102 * from system
 103 */
 104#define CFS_TRACE_CONSOLE_BUFFER_SIZE   1024
 105
 106union cfs_trace_data_union {
 107        struct cfs_trace_cpu_data {
 108                /*
 109                 * Even though this structure is meant to be per-CPU, locking
 110                 * is needed because in some places the data may be accessed
 111                 * from other CPUs. This lock is directly used in trace_get_tcd
 112                 * and trace_put_tcd, which are called in libcfs_debug_vmsg2 and
 113                 * tcd_for_each_type_lock
 114                 */
 115                spinlock_t              tcd_lock;
 116                unsigned long      tcd_lock_flags;
 117
 118                /*
 119                 * pages with trace records not yet processed by tracefiled.
 120                 */
 121                struct list_head              tcd_pages;
 122                /* number of pages on ->tcd_pages */
 123                unsigned long      tcd_cur_pages;
 124
 125                /*
 126                 * pages with trace records already processed by
 127                 * tracefiled. These pages are kept in memory, so that some
 128                 * portion of log can be written in the event of LBUG. This
 129                 * list is maintained in LRU order.
 130                 *
 131                 * Pages are moved to ->tcd_daemon_pages by tracefiled()
 132                 * (put_pages_on_daemon_list()). LRU pages from this list are
 133                 * discarded when list grows too large.
 134                 */
 135                struct list_head              tcd_daemon_pages;
 136                /* number of pages on ->tcd_daemon_pages */
 137                unsigned long      tcd_cur_daemon_pages;
 138
 139                /*
 140                 * Maximal number of pages allowed on ->tcd_pages and
 141                 * ->tcd_daemon_pages each.
 142                 * Always TCD_MAX_PAGES * tcd_pages_factor / 100 in current
 143                 * implementation.
 144                 */
 145                unsigned long      tcd_max_pages;
 146
 147                /*
 148                 * preallocated pages to write trace records into. Pages from
 149                 * ->tcd_stock_pages are moved to ->tcd_pages by
 150                 * portals_debug_msg().
 151                 *
 152                 * This list is necessary, because on some platforms it's
 153                 * impossible to perform efficient atomic page allocation in a
 154                 * non-blockable context.
 155                 *
 156                 * Such platforms fill ->tcd_stock_pages "on occasion", when
 157                 * tracing code is entered in blockable context.
 158                 *
 159                 * trace_get_tage_try() tries to get a page from
 160                 * ->tcd_stock_pages first and resorts to atomic page
 161                 * allocation only if this queue is empty. ->tcd_stock_pages
 162                 * is replenished when tracing code is entered in blocking
 163                 * context (darwin-tracefile.c:trace_get_tcd()). We try to
 164                 * maintain TCD_STOCK_PAGES (40 by default) pages in this
 165                 * queue. Atomic allocation is only required if more than
 166                 * TCD_STOCK_PAGES pagesful are consumed by trace records all
 167                 * emitted in non-blocking contexts. Which is quite unlikely.
 168                 */
 169                struct list_head              tcd_stock_pages;
 170                /* number of pages on ->tcd_stock_pages */
 171                unsigned long      tcd_cur_stock_pages;
 172
 173                unsigned short    tcd_shutting_down;
 174                unsigned short    tcd_cpu;
 175                unsigned short    tcd_type;
 176                /* The factors to share debug memory. */
 177                unsigned short    tcd_pages_factor;
 178        } tcd;
 179        char __pad[L1_CACHE_ALIGN(sizeof(struct cfs_trace_cpu_data))];
 180};
 181
 182#define TCD_MAX_TYPES      8
 183extern union cfs_trace_data_union (*cfs_trace_data[TCD_MAX_TYPES])[NR_CPUS];
 184
 185#define cfs_tcd_for_each(tcd, i, j)                                    \
 186        for (i = 0; cfs_trace_data[i]; i++)                             \
 187                for (j = 0, ((tcd) = &(*cfs_trace_data[i])[j].tcd);     \
 188                     j < num_possible_cpus();                            \
 189                     j++, (tcd) = &(*cfs_trace_data[i])[j].tcd)
 190
 191#define cfs_tcd_for_each_type_lock(tcd, i, cpu)                    \
 192        for (i = 0; cfs_trace_data[i] &&                                \
 193             (tcd = &(*cfs_trace_data[i])[cpu].tcd) &&                  \
 194             cfs_trace_lock_tcd(tcd, 1); cfs_trace_unlock_tcd(tcd, 1), i++)
 195
 196void cfs_set_ptldebug_header(struct ptldebug_header *header,
 197                             struct libcfs_debug_msg_data *m,
 198                             unsigned long stack);
 199void cfs_print_to_console(struct ptldebug_header *hdr, int mask,
 200                          const char *buf, int len, const char *file,
 201                          const char *fn);
 202
 203int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking);
 204void cfs_trace_unlock_tcd(struct cfs_trace_cpu_data *tcd, int walking);
 205
 206extern char *cfs_trace_console_buffers[NR_CPUS][CFS_TCD_TYPE_MAX];
 207enum cfs_trace_buf_type cfs_trace_buf_idx_get(void);
 208
 209static inline char *
 210cfs_trace_get_console_buffer(void)
 211{
 212        unsigned int i = get_cpu();
 213        unsigned int j = cfs_trace_buf_idx_get();
 214
 215        return cfs_trace_console_buffers[i][j];
 216}
 217
 218static inline struct cfs_trace_cpu_data *
 219cfs_trace_get_tcd(void)
 220{
 221        struct cfs_trace_cpu_data *tcd =
 222                &(*cfs_trace_data[cfs_trace_buf_idx_get()])[get_cpu()].tcd;
 223
 224        cfs_trace_lock_tcd(tcd, 0);
 225
 226        return tcd;
 227}
 228
 229static inline void cfs_trace_put_tcd(struct cfs_trace_cpu_data *tcd)
 230{
 231        cfs_trace_unlock_tcd(tcd, 0);
 232
 233        put_cpu();
 234}
 235
 236int cfs_trace_refill_stock(struct cfs_trace_cpu_data *tcd, gfp_t gfp,
 237                           struct list_head *stock);
 238
 239void cfs_trace_assertion_failed(const char *str,
 240                                struct libcfs_debug_msg_data *m);
 241
 242/* ASSERTION that is safe to use within the debug system */
 243#define __LASSERT(cond)                                          \
 244do {                                                                \
 245        if (unlikely(!(cond))) {                                        \
 246                LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_EMERG, NULL);     \
 247                cfs_trace_assertion_failed("ASSERTION("#cond") failed", \
 248                                           &msgdata);              \
 249        }                                                              \
 250} while (0)
 251
 252#define __LASSERT_TAGE_INVARIANT(tage)                            \
 253do {                                                                \
 254        __LASSERT(tage);                                        \
 255        __LASSERT(tage->page);                            \
 256        __LASSERT(tage->used <= PAGE_SIZE);                      \
 257        __LASSERT(page_count(tage->page) > 0);                \
 258} while (0)
 259
 260#endif  /* LUSTRE_TRACEFILE_PRIVATE */
 261
 262#endif /* __LIBCFS_TRACEFILE_H__ */
 263