Whamcloud - gitweb
5e6b18b31453b8321b1bf3aadfe61ef9419cd36d
[fs/lustre-release.git] / libcfs / libcfs / linux-tracefile.c
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 #define DEBUG_SUBSYSTEM S_LNET
34 #define LUSTRE_TRACEFILE_PRIVATE
35
36 #include <linux/slab.h>
37 #include <linux/tty.h>
38 #include <linux/poll.h>
39 #include <linux/mm.h>
40 #include "tracefile.h"
41
42 /* percents to share the total debug memory for each type */
43 static unsigned int pages_factor[CFS_TCD_TYPE_MAX] = {
44         80,  /* 80% pages for CFS_TCD_TYPE_PROC */
45         10,  /* 10% pages for CFS_TCD_TYPE_SOFTIRQ */
46         10   /* 10% pages for CFS_TCD_TYPE_IRQ */
47 };
48
49 char *cfs_trace_console_buffers[NR_CPUS][CFS_TCD_TYPE_MAX];
50
51 int cfs_tracefile_init_arch(void)
52 {
53         int i;
54         int j;
55         struct cfs_trace_cpu_data *tcd;
56
57         /* initialize trace_data */
58         memset(cfs_trace_data, 0, sizeof(cfs_trace_data));
59         for (i = 0; i < CFS_TCD_TYPE_MAX; i++) {
60                 cfs_trace_data[i] =
61                         kmalloc_array(num_possible_cpus(),
62                                       sizeof(union cfs_trace_data_union),
63                                       GFP_KERNEL);
64                 if (!cfs_trace_data[i])
65                         goto out;
66         }
67
68         /* arch related info initialized */
69         cfs_tcd_for_each(tcd, i, j) {
70                 spin_lock_init(&tcd->tcd_lock);
71                 tcd->tcd_pages_factor = pages_factor[i];
72                 tcd->tcd_type = i;
73                 tcd->tcd_cpu = j;
74         }
75
76         for (i = 0; i < num_possible_cpus(); i++)
77                 for (j = 0; j < 3; j++) {
78                         cfs_trace_console_buffers[i][j] =
79                                 kmalloc(CFS_TRACE_CONSOLE_BUFFER_SIZE,
80                                         GFP_KERNEL);
81
82                         if (!cfs_trace_console_buffers[i][j])
83                                 goto out;
84                 }
85
86         return 0;
87
88 out:
89         cfs_tracefile_fini_arch();
90         pr_err("lnet: Not enough memory\n");
91         return -ENOMEM;
92 }
93
94 void cfs_tracefile_fini_arch(void)
95 {
96         int i;
97         int j;
98
99         for (i = 0; i < num_possible_cpus(); i++)
100                 for (j = 0; j < 3; j++) {
101                         kfree(cfs_trace_console_buffers[i][j]);
102                         cfs_trace_console_buffers[i][j] = NULL;
103                 }
104
105         for (i = 0; cfs_trace_data[i]; i++) {
106                 kfree(cfs_trace_data[i]);
107                 cfs_trace_data[i] = NULL;
108         }
109 }
110
111 enum cfs_trace_buf_type cfs_trace_buf_idx_get(void)
112 {
113         if (in_irq())
114                 return CFS_TCD_TYPE_IRQ;
115         if (in_softirq())
116                 return CFS_TCD_TYPE_SOFTIRQ;
117         return CFS_TCD_TYPE_PROC;
118 }
119
120 /*
121  * The walking argument indicates the locking comes from all tcd types
122  * iterator and we must lock it and dissable local irqs to avoid deadlocks
123  * with other interrupt locks that might be happening. See LU-1311
124  * for details.
125  */
126 int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
127         __acquires(&tcd->tcd_lock)
128 {
129         __LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
130         if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
131                 spin_lock_irqsave(&tcd->tcd_lock, tcd->tcd_lock_flags);
132         else if (tcd->tcd_type == CFS_TCD_TYPE_SOFTIRQ)
133                 spin_lock_bh(&tcd->tcd_lock);
134         else if (unlikely(walking))
135                 spin_lock_irq(&tcd->tcd_lock);
136         else
137                 spin_lock(&tcd->tcd_lock);
138         return 1;
139 }
140
141 void cfs_trace_unlock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
142         __releases(&tcd->tcd_lock)
143 {
144         __LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
145         if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
146                 spin_unlock_irqrestore(&tcd->tcd_lock, tcd->tcd_lock_flags);
147         else if (tcd->tcd_type == CFS_TCD_TYPE_SOFTIRQ)
148                 spin_unlock_bh(&tcd->tcd_lock);
149         else if (unlikely(walking))
150                 spin_unlock_irq(&tcd->tcd_lock);
151         else
152                 spin_unlock(&tcd->tcd_lock);
153 }
154
155 int cfs_tcd_owns_tage(struct cfs_trace_cpu_data *tcd,
156                       struct cfs_trace_page *tage)
157 {
158         /*
159          * XXX nikita: do NOT call portals_debug_msg() (CDEBUG/ENTRY/EXIT)
160          * from here: this will lead to infinite recursion.
161          */
162         return tcd->tcd_cpu == tage->cpu;
163 }
164
165 void
166 cfs_set_ptldebug_header(struct ptldebug_header *header,
167                         struct libcfs_debug_msg_data *msgdata,
168                         unsigned long stack)
169 {
170         struct timespec64 ts;
171
172         ktime_get_real_ts64(&ts);
173
174         header->ph_subsys = msgdata->msg_subsys;
175         header->ph_mask = msgdata->msg_mask;
176         header->ph_cpu_id = smp_processor_id();
177         header->ph_type = cfs_trace_buf_idx_get();
178         /* y2038 safe since all user space treats this as unsigned, but
179          * will overflow in 2106
180          */
181         header->ph_sec = (u32)ts.tv_sec;
182         header->ph_usec = ts.tv_nsec / NSEC_PER_USEC;
183         header->ph_stack = stack;
184         header->ph_pid = current->pid;
185         header->ph_line_num = msgdata->msg_line;
186         header->ph_extern_pid = 0;
187 }
188
189 /**
190  * tty_write_msg - write a message to a certain tty, not just the console.
191  * @tty: the destination tty_struct
192  * @msg: the message to write
193  *
194  * tty_write_message is not exported, so write a same function for it
195  *
196  */
197 static void tty_write_msg(struct tty_struct *tty, const char *msg)
198 {
199         mutex_lock(&tty->atomic_write_lock);
200         tty_lock(tty);
201         if (tty->ops->write && tty->count > 0)
202                 tty->ops->write(tty, msg, strlen(msg));
203         tty_unlock(tty);
204         mutex_unlock(&tty->atomic_write_lock);
205         wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
206 }
207
208 static void cfs_tty_write_message(const char *prefix, int mask, const char *msg)
209 {
210         struct tty_struct *tty;
211
212         tty = get_current_tty();
213         if (!tty)
214                 return;
215
216         tty_write_msg(tty, prefix);
217         if ((mask & D_EMERG) || (mask & D_ERROR))
218                 tty_write_msg(tty, "Error");
219         tty_write_msg(tty, ": ");
220         tty_write_msg(tty, msg);
221         tty_kref_put(tty);
222 }
223
224 void cfs_print_to_console(struct ptldebug_header *hdr, int mask,
225                           const char *buf, int len, const char *file,
226                           const char *fn)
227 {
228         char *prefix = "Lustre";
229
230         if (hdr->ph_subsys == S_LND || hdr->ph_subsys == S_LNET)
231                 prefix = "LNet";
232
233         if (mask & D_CONSOLE) {
234                 if (mask & D_EMERG)
235                         pr_emerg("%sError: %.*s", prefix, len, buf);
236                 else if (mask & D_ERROR)
237                         pr_err("%sError: %.*s", prefix, len, buf);
238                 else if (mask & D_WARNING)
239                         pr_warn("%s: %.*s", prefix, len, buf);
240                 else if (mask & libcfs_printk)
241                         pr_info("%s: %.*s", prefix, len, buf);
242         } else {
243                 if (mask & D_EMERG)
244                         pr_emerg("%sError: %d:%d:(%s:%d:%s()) %.*s", prefix,
245                                  hdr->ph_pid, hdr->ph_extern_pid, file,
246                                  hdr->ph_line_num, fn, len, buf);
247                 else if (mask & D_ERROR)
248                         pr_err("%sError: %d:%d:(%s:%d:%s()) %.*s", prefix,
249                                hdr->ph_pid, hdr->ph_extern_pid, file,
250                                hdr->ph_line_num, fn, len, buf);
251                 else if (mask & D_WARNING)
252                         pr_warn("%s: %d:%d:(%s:%d:%s()) %.*s", prefix,
253                                 hdr->ph_pid, hdr->ph_extern_pid, file,
254                                 hdr->ph_line_num, fn, len, buf);
255                         else if (mask & (D_CONSOLE | libcfs_printk))
256                                 pr_info("%s: %.*s", prefix, len, buf);
257         }
258
259         if (mask & D_TTY)
260                 cfs_tty_write_message(prefix, mask, buf);
261 }