Whamcloud - gitweb
LU-6142 libcfs: Fix style issues for linux-tracefile.c
[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 static char *
212 dbghdr_to_err_string(struct ptldebug_header *hdr)
213 {
214         switch (hdr->ph_subsys) {
215         case S_LND:
216         case S_LNET:
217                 return "LNetError";
218         default:
219                 return "LustreError";
220         }
221 }
222
223 static char *
224 dbghdr_to_info_string(struct ptldebug_header *hdr)
225 {
226         switch (hdr->ph_subsys) {
227         case S_LND:
228         case S_LNET:
229                 return "LNet";
230         default:
231                 return "Lustre";
232         }
233 }
234
235 /**
236  * tty_write_msg - write a message to a certain tty, not just the console.
237  * @tty: the destination tty_struct
238  * @msg: the message to write
239  *
240  * tty_write_message is not exported, so write a same function for it
241  *
242  */
243 static void tty_write_msg(struct tty_struct *tty, const char *msg)
244 {
245         mutex_lock(&tty->atomic_write_lock);
246         tty_lock(tty);
247         if (tty->ops->write && tty->count > 0)
248                 tty->ops->write(tty, msg, strlen(msg));
249         tty_unlock(tty);
250         mutex_unlock(&tty->atomic_write_lock);
251         wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
252 }
253
254 static void cfs_tty_write_message(const char *prefix, const char *msg)
255 {
256         struct tty_struct *tty;
257
258         tty = get_current_tty();
259         if (!tty)
260                 return;
261
262         tty_write_msg(tty, prefix);
263         tty_write_msg(tty, ": ");
264         tty_write_msg(tty, msg);
265         tty_kref_put(tty);
266 }
267
268 void cfs_print_to_console(struct ptldebug_header *hdr, int mask,
269                           const char *buf, int len, const char *file,
270                           const char *fn)
271 {
272         char *prefix = "Lustre", *ptype = NULL;
273
274         if (mask & D_EMERG) {
275                 prefix = dbghdr_to_err_string(hdr);
276                 ptype = KERN_EMERG;
277         } else if (mask & D_ERROR) {
278                 prefix = dbghdr_to_err_string(hdr);
279                 ptype = KERN_ERR;
280         } else if (mask & D_WARNING) {
281                 prefix = dbghdr_to_info_string(hdr);
282                 ptype = KERN_WARNING;
283         } else if (mask & (D_CONSOLE | libcfs_printk)) {
284                 prefix = dbghdr_to_info_string(hdr);
285                 ptype = KERN_INFO;
286         }
287
288         if (mask & D_TTY)
289                 cfs_tty_write_message(prefix, buf);
290
291         if (mask & D_CONSOLE) {
292                 pr_info("%s%s: %.*s", ptype, prefix, len, buf);
293         } else {
294                 pr_info("%s%s: %d:%d:(%s:%d:%s()) %.*s", ptype, prefix,
295                         hdr->ph_pid, hdr->ph_extern_pid, file,
296                         hdr->ph_line_num, fn, len, buf);
297         }
298 }
299
300 int cfs_trace_max_debug_mb(void)
301 {
302         int total_mb = (cfs_totalram_pages() >> (20 - PAGE_SHIFT));
303
304         return max(512, (total_mb * 80) / 100);
305 }