linux/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.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) 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
  37#define DEBUG_SUBSYSTEM S_LNET
  38#define LUSTRE_TRACEFILE_PRIVATE
  39
  40#include "../../../include/linux/libcfs/libcfs.h"
  41#include "../tracefile.h"
  42
  43/* percents to share the total debug memory for each type */
  44static unsigned int pages_factor[CFS_TCD_TYPE_MAX] = {
  45        80,  /* 80% pages for CFS_TCD_TYPE_PROC */
  46        10,  /* 10% pages for CFS_TCD_TYPE_SOFTIRQ */
  47        10   /* 10% pages for CFS_TCD_TYPE_IRQ */
  48};
  49
  50char *cfs_trace_console_buffers[NR_CPUS][CFS_TCD_TYPE_MAX];
  51
  52struct rw_semaphore cfs_tracefile_sem;
  53
  54int cfs_tracefile_init_arch(void)
  55{
  56        int    i;
  57        int    j;
  58        struct cfs_trace_cpu_data *tcd;
  59
  60        init_rwsem(&cfs_tracefile_sem);
  61
  62        /* initialize trace_data */
  63        memset(cfs_trace_data, 0, sizeof(cfs_trace_data));
  64        for (i = 0; i < CFS_TCD_TYPE_MAX; i++) {
  65                cfs_trace_data[i] =
  66                        kmalloc(sizeof(union cfs_trace_data_union) *
  67                                num_possible_cpus(), GFP_KERNEL);
  68                if (cfs_trace_data[i] == NULL)
  69                        goto out;
  70
  71        }
  72
  73        /* arch related info initialized */
  74        cfs_tcd_for_each(tcd, i, j) {
  75                spin_lock_init(&tcd->tcd_lock);
  76                tcd->tcd_pages_factor = pages_factor[i];
  77                tcd->tcd_type = i;
  78                tcd->tcd_cpu = j;
  79        }
  80
  81        for (i = 0; i < num_possible_cpus(); i++)
  82                for (j = 0; j < 3; j++) {
  83                        cfs_trace_console_buffers[i][j] =
  84                                kmalloc(CFS_TRACE_CONSOLE_BUFFER_SIZE,
  85                                        GFP_KERNEL);
  86
  87                        if (cfs_trace_console_buffers[i][j] == NULL)
  88                                goto out;
  89                }
  90
  91        return 0;
  92
  93out:
  94        cfs_tracefile_fini_arch();
  95        printk(KERN_ERR "lnet: Not enough memory\n");
  96        return -ENOMEM;
  97}
  98
  99void cfs_tracefile_fini_arch(void)
 100{
 101        int    i;
 102        int    j;
 103
 104        for (i = 0; i < num_possible_cpus(); i++)
 105                for (j = 0; j < 3; j++)
 106                        if (cfs_trace_console_buffers[i][j] != NULL) {
 107                                kfree(cfs_trace_console_buffers[i][j]);
 108                                cfs_trace_console_buffers[i][j] = NULL;
 109                        }
 110
 111        for (i = 0; cfs_trace_data[i] != NULL; i++) {
 112                kfree(cfs_trace_data[i]);
 113                cfs_trace_data[i] = NULL;
 114        }
 115}
 116
 117void cfs_tracefile_read_lock(void)
 118{
 119        down_read(&cfs_tracefile_sem);
 120}
 121
 122void cfs_tracefile_read_unlock(void)
 123{
 124        up_read(&cfs_tracefile_sem);
 125}
 126
 127void cfs_tracefile_write_lock(void)
 128{
 129        down_write(&cfs_tracefile_sem);
 130}
 131
 132void cfs_tracefile_write_unlock(void)
 133{
 134        up_write(&cfs_tracefile_sem);
 135}
 136
 137cfs_trace_buf_type_t cfs_trace_buf_idx_get(void)
 138{
 139        if (in_irq())
 140                return CFS_TCD_TYPE_IRQ;
 141        else if (in_softirq())
 142                return CFS_TCD_TYPE_SOFTIRQ;
 143        else
 144                return CFS_TCD_TYPE_PROC;
 145}
 146
 147/*
 148 * The walking argument indicates the locking comes from all tcd types
 149 * iterator and we must lock it and dissable local irqs to avoid deadlocks
 150 * with other interrupt locks that might be happening. See LU-1311
 151 * for details.
 152 */
 153int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
 154        __acquires(&tcd->tc_lock)
 155{
 156        __LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
 157        if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
 158                spin_lock_irqsave(&tcd->tcd_lock, tcd->tcd_lock_flags);
 159        else if (tcd->tcd_type == CFS_TCD_TYPE_SOFTIRQ)
 160                spin_lock_bh(&tcd->tcd_lock);
 161        else if (unlikely(walking))
 162                spin_lock_irq(&tcd->tcd_lock);
 163        else
 164                spin_lock(&tcd->tcd_lock);
 165        return 1;
 166}
 167
 168void cfs_trace_unlock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
 169        __releases(&tcd->tcd_lock)
 170{
 171        __LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
 172        if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
 173                spin_unlock_irqrestore(&tcd->tcd_lock, tcd->tcd_lock_flags);
 174        else if (tcd->tcd_type == CFS_TCD_TYPE_SOFTIRQ)
 175                spin_unlock_bh(&tcd->tcd_lock);
 176        else if (unlikely(walking))
 177                spin_unlock_irq(&tcd->tcd_lock);
 178        else
 179                spin_unlock(&tcd->tcd_lock);
 180}
 181
 182int cfs_tcd_owns_tage(struct cfs_trace_cpu_data *tcd,
 183                      struct cfs_trace_page *tage)
 184{
 185        /*
 186         * XXX nikita: do NOT call portals_debug_msg() (CDEBUG/ENTRY/EXIT)
 187         * from here: this will lead to infinite recursion.
 188         */
 189        return tcd->tcd_cpu == tage->cpu;
 190}
 191
 192void
 193cfs_set_ptldebug_header(struct ptldebug_header *header,
 194                        struct libcfs_debug_msg_data *msgdata,
 195                        unsigned long stack)
 196{
 197        struct timeval tv;
 198
 199        do_gettimeofday(&tv);
 200
 201        header->ph_subsys = msgdata->msg_subsys;
 202        header->ph_mask = msgdata->msg_mask;
 203        header->ph_cpu_id = smp_processor_id();
 204        header->ph_type = cfs_trace_buf_idx_get();
 205        header->ph_sec = (__u32)tv.tv_sec;
 206        header->ph_usec = tv.tv_usec;
 207        header->ph_stack = stack;
 208        header->ph_pid = current->pid;
 209        header->ph_line_num = msgdata->msg_line;
 210        header->ph_extern_pid = 0;
 211        return;
 212}
 213
 214static char *
 215dbghdr_to_err_string(struct ptldebug_header *hdr)
 216{
 217        switch (hdr->ph_subsys) {
 218
 219                case S_LND:
 220                case S_LNET:
 221                        return "LNetError";
 222                default:
 223                        return "LustreError";
 224        }
 225}
 226
 227static char *
 228dbghdr_to_info_string(struct ptldebug_header *hdr)
 229{
 230        switch (hdr->ph_subsys) {
 231
 232                case S_LND:
 233                case S_LNET:
 234                        return "LNet";
 235                default:
 236                        return "Lustre";
 237        }
 238}
 239
 240void cfs_print_to_console(struct ptldebug_header *hdr, int mask,
 241                          const char *buf, int len, const char *file,
 242                          const char *fn)
 243{
 244        char *prefix = "Lustre", *ptype = NULL;
 245
 246        if ((mask & D_EMERG) != 0) {
 247                prefix = dbghdr_to_err_string(hdr);
 248                ptype = KERN_EMERG;
 249        } else if ((mask & D_ERROR) != 0) {
 250                prefix = dbghdr_to_err_string(hdr);
 251                ptype = KERN_ERR;
 252        } else if ((mask & D_WARNING) != 0) {
 253                prefix = dbghdr_to_info_string(hdr);
 254                ptype = KERN_WARNING;
 255        } else if ((mask & (D_CONSOLE | libcfs_printk)) != 0) {
 256                prefix = dbghdr_to_info_string(hdr);
 257                ptype = KERN_INFO;
 258        }
 259
 260        if ((mask & D_CONSOLE) != 0) {
 261                printk("%s%s: %.*s", ptype, prefix, len, buf);
 262        } else {
 263                printk("%s%s: %d:%d:(%s:%d:%s()) %.*s", ptype, prefix,
 264                       hdr->ph_pid, hdr->ph_extern_pid, file, hdr->ph_line_num,
 265                       fn, len, buf);
 266        }
 267        return;
 268}
 269
 270int cfs_trace_max_debug_mb(void)
 271{
 272        int  total_mb = (totalram_pages >> (20 - PAGE_SHIFT));
 273
 274        return max(512, (total_mb * 80)/100);
 275}
 276