Whamcloud - gitweb
LU-12355 llite: totalram_pages changed to atomic_long_t
[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 <libcfs/libcfs.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()
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(sizeof(union cfs_trace_data_union) *
64                                 num_possible_cpus(), GFP_KERNEL);
65                 if (cfs_trace_data[i] == NULL)
66                         goto out;
67
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] == NULL)
85                                 goto out;
86                 }
87
88         return 0;
89
90 out:
91         cfs_tracefile_fini_arch();
92         printk(KERN_ERR "lnet: Not enough memory\n");
93         return -ENOMEM;
94 }
95
96 void cfs_tracefile_fini_arch()
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                         if (cfs_trace_console_buffers[i][j] != NULL) {
104                                 kfree(cfs_trace_console_buffers[i][j]);
105                                 cfs_trace_console_buffers[i][j] = NULL;
106                         }
107
108         for (i = 0; cfs_trace_data[i] != NULL; i++) {
109                 kfree(cfs_trace_data[i]);
110                 cfs_trace_data[i] = NULL;
111         }
112 }
113
114 void cfs_tracefile_read_lock()
115 {
116         down_read(&cfs_tracefile_sem);
117 }
118
119 void cfs_tracefile_read_unlock()
120 {
121         up_read(&cfs_tracefile_sem);
122 }
123
124 void cfs_tracefile_write_lock()
125 {
126         down_write(&cfs_tracefile_sem);
127 }
128
129 void cfs_tracefile_write_unlock()
130 {
131         up_write(&cfs_tracefile_sem);
132 }
133
134 enum cfs_trace_buf_type cfs_trace_buf_idx_get()
135 {
136         if (in_irq())
137                 return CFS_TCD_TYPE_IRQ;
138         else if (in_softirq())
139                 return CFS_TCD_TYPE_SOFTIRQ;
140         else
141                 return CFS_TCD_TYPE_PROC;
142 }
143
144 /*
145  * The walking argument indicates the locking comes from all tcd types
146  * iterator and we must lock it and dissable local irqs to avoid deadlocks
147  * with other interrupt locks that might be happening. See LU-1311
148  * for details.
149  */
150 int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
151 __acquires(&tcd->tcd_lock)
152 {
153         __LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
154         if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
155                 spin_lock_irqsave(&tcd->tcd_lock, tcd->tcd_lock_flags);
156         else if (tcd->tcd_type == CFS_TCD_TYPE_SOFTIRQ)
157                 spin_lock_bh(&tcd->tcd_lock);
158         else if (unlikely(walking))
159                 spin_lock_irq(&tcd->tcd_lock);
160         else
161                 spin_lock(&tcd->tcd_lock);
162         return 1;
163 }
164
165 void cfs_trace_unlock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
166 __releases(&tcd->tcd_lock)
167 {
168         __LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
169         if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
170                 spin_unlock_irqrestore(&tcd->tcd_lock, tcd->tcd_lock_flags);
171         else if (tcd->tcd_type == CFS_TCD_TYPE_SOFTIRQ)
172                 spin_unlock_bh(&tcd->tcd_lock);
173         else if (unlikely(walking))
174                 spin_unlock_irq(&tcd->tcd_lock);
175         else
176                 spin_unlock(&tcd->tcd_lock);
177 }
178
179 int cfs_tcd_owns_tage(struct cfs_trace_cpu_data *tcd,
180                       struct cfs_trace_page *tage)
181 {
182         /*
183          * XXX nikita: do NOT call portals_debug_msg() (CDEBUG/ENTRY/EXIT)
184          * from here: this will lead to infinite recursion.
185          */
186         return tcd->tcd_cpu == tage->cpu;
187 }
188
189 void
190 cfs_set_ptldebug_header(struct ptldebug_header *header,
191                         struct libcfs_debug_msg_data *msgdata,
192                         unsigned long stack)
193 {
194         struct timespec64 ts;
195
196         ktime_get_real_ts64(&ts);
197
198         header->ph_subsys = msgdata->msg_subsys;
199         header->ph_mask = msgdata->msg_mask;
200         header->ph_cpu_id = smp_processor_id();
201         header->ph_type = cfs_trace_buf_idx_get();
202         /* y2038 safe since all user space treats this as unsigned, but
203          * will overflow in 2106
204          */
205         header->ph_sec = (u32)ts.tv_sec;
206         header->ph_usec = ts.tv_nsec / NSEC_PER_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
214 static char *
215 dbghdr_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
227 static char *
228 dbghdr_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
240 /**
241  * tty_write_msg - write a message to a certain tty, not just the console.
242  * @tty: the destination tty_struct
243  * @msg: the message to write
244  *
245  * tty_write_message is not exported, so write a same function for it
246  *
247  */
248 static void tty_write_msg(struct tty_struct *tty, const char *msg)
249 {
250         mutex_lock(&tty->atomic_write_lock);
251         tty_lock(tty);
252         if (tty->ops->write && tty->count > 0)
253                 tty->ops->write(tty, msg, strlen(msg));
254         tty_unlock(tty);
255         mutex_unlock(&tty->atomic_write_lock);
256         wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
257 }
258
259 static void cfs_tty_write_message(const char *prefix, const char *msg)
260 {
261         struct tty_struct *tty;
262
263         tty = get_current_tty();
264         if (!tty)
265                 return;
266
267         tty_write_msg(tty, prefix);
268         tty_write_msg(tty, ": ");
269         tty_write_msg(tty, msg);
270         tty_kref_put(tty);
271 }
272
273 void cfs_print_to_console(struct ptldebug_header *hdr, int mask,
274                           const char *buf, int len, const char *file,
275                           const char *fn)
276 {
277         char *prefix = "Lustre", *ptype = NULL;
278
279         if ((mask & D_EMERG) != 0) {
280                 prefix = dbghdr_to_err_string(hdr);
281                 ptype = KERN_EMERG;
282         } else if ((mask & D_ERROR) != 0) {
283                 prefix = dbghdr_to_err_string(hdr);
284                 ptype = KERN_ERR;
285         } else if ((mask & D_WARNING) != 0) {
286                 prefix = dbghdr_to_info_string(hdr);
287                 ptype = KERN_WARNING;
288         } else if ((mask & (D_CONSOLE | libcfs_printk)) != 0) {
289                 prefix = dbghdr_to_info_string(hdr);
290                 ptype = KERN_INFO;
291         }
292
293         if ((mask & D_TTY) != 0)
294                 cfs_tty_write_message(prefix, buf);
295
296         if ((mask & D_CONSOLE) != 0) {
297                 printk("%s%s: %.*s", ptype, prefix, len, buf);
298         } else {
299                 printk("%s%s: %d:%d:(%s:%d:%s()) %.*s", ptype, prefix,
300                        hdr->ph_pid, hdr->ph_extern_pid, file, hdr->ph_line_num,
301                        fn, len, buf);
302         }
303         return;
304 }
305
306 int cfs_trace_max_debug_mb(void)
307 {
308         int  total_mb = (cfs_totalram_pages() >> (20 - PAGE_SHIFT));
309
310         return MAX(512, (total_mb * 80)/100);
311 }