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