Whamcloud - gitweb
1fb38cfbe09fc7c2ab95f576fdf92c06c989160f
[fs/lustre-release.git] / lnet / libcfs / linux / linux-tracefile.c
1 #define DEBUG_SUBSYSTEM S_LNET
2 #define LUSTRE_TRACEFILE_PRIVATE
3
4 #include <libcfs/libcfs.h>
5 #include <libcfs/kp30.h>
6 #include "tracefile.h"
7
8 #ifndef get_cpu
9 #define get_cpu() smp_processor_id()
10 #define put_cpu() do { } while (0)
11 #endif
12
13 extern union trace_data_union trace_data[NR_CPUS];
14 extern char *tracefile;
15 extern long long tracefile_size;
16
17 char *trace_console_buffers[NR_CPUS][3];
18
19 struct rw_semaphore tracefile_sem;
20
21 int tracefile_init_arch()
22 {
23         int    i;
24         int    j;
25
26         init_rwsem(&tracefile_sem);
27
28         for (i = 0; i < NR_CPUS; i++)
29                 for (j = 0; j < 3; j++) {
30                         trace_console_buffers[i][j] =
31                                 kmalloc(TRACE_CONSOLE_BUFFER_SIZE,
32                                         GFP_KERNEL);
33
34                         if (trace_console_buffers[i][j] == NULL) {
35                                 tracefile_fini_arch();
36                                 printk(KERN_ERR
37                                        "Can't allocate "
38                                        "console message buffer\n");
39                                 return -ENOMEM;
40                         }
41                 }
42
43         return 0;
44 }
45
46 void tracefile_fini_arch()
47 {
48         int    i;
49         int    j;
50
51         for (i = 0; i < NR_CPUS; i++)
52                 for (j = 0; j < 3; j++)
53                         if (trace_console_buffers[i][j] != NULL) {
54                                 kfree(trace_console_buffers[i][j]);
55                                 trace_console_buffers[i][j] = NULL;
56                         }
57 }
58
59 void tracefile_read_lock()
60 {
61         down_read(&tracefile_sem);
62 }
63
64 void tracefile_read_unlock()
65 {
66         up_read(&tracefile_sem);
67 }
68
69 void tracefile_write_lock()
70 {
71         down_write(&tracefile_sem);
72 }
73
74 void tracefile_write_unlock()
75 {
76         up_write(&tracefile_sem);
77 }
78
79 char *
80 trace_get_console_buffer(void)
81 {
82         int  cpu = get_cpu();
83         int  idx;
84
85         if (in_irq()) {
86                 idx = 0;
87         } else if (in_softirq()) {
88                 idx = 1;
89         } else {
90                 idx = 2;
91         }
92
93         return trace_console_buffers[cpu][idx];
94 }
95
96 void
97 trace_put_console_buffer(char *buffer)
98 {
99         put_cpu();
100 }
101
102 struct trace_cpu_data *
103 trace_get_tcd(void)
104 {
105         int cpu;
106
107         if (in_interrupt()) /* no logging in IRQ context */
108                 return NULL;
109
110         cpu = get_cpu();
111         return &trace_data[cpu].tcd;
112 }
113
114 void
115 trace_put_tcd (struct trace_cpu_data *tcd)
116 {
117         __LASSERT (!in_interrupt());
118         put_cpu();
119 }
120
121 int tcd_owns_tage(struct trace_cpu_data *tcd, struct trace_page *tage)
122 {
123         /*
124          * XXX nikita: do NOT call portals_debug_msg() (CDEBUG/ENTRY/EXIT)
125          * from here: this will lead to infinite recursion.
126          */
127         return tcd->tcd_cpu == tage->cpu;
128 }
129
130 void
131 set_ptldebug_header(struct ptldebug_header *header, int subsys, int mask,
132                     const int line, unsigned long stack)
133 {
134         struct timeval tv;
135
136         do_gettimeofday(&tv);
137
138         header->ph_subsys = subsys;
139         header->ph_mask = mask;
140         header->ph_cpu_id = smp_processor_id();
141         header->ph_sec = (__u32)tv.tv_sec;
142         header->ph_usec = tv.tv_usec;
143         header->ph_stack = stack;
144         header->ph_pid = current->pid;
145         header->ph_line_num = line;
146 #if defined(__arch_um__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20))
147         header->ph_extern_pid = current->thread.extern_pid;
148 #elif defined(__arch_um__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
149         header->ph_extern_pid = current->thread.mode.tt.extern_pid;
150 #else
151         header->ph_extern_pid = 0;
152 #endif
153         return;
154 }
155
156 void print_to_console(struct ptldebug_header *hdr, int mask, const char *buf,
157                              int len, const char *file, const char *fn)
158 {
159         char *prefix = "Lustre", *ptype = NULL;
160
161         if ((mask & D_EMERG) != 0) {
162                 prefix = "LustreError";
163                 ptype = KERN_EMERG;
164         } else if ((mask & D_ERROR) != 0) {
165                 prefix = "LustreError";
166                 ptype = KERN_ERR;
167         } else if ((mask & D_WARNING) != 0) {
168                 prefix = "Lustre";
169                 ptype = KERN_WARNING;
170         } else if ((mask & libcfs_printk) != 0 || (mask & D_CONSOLE)) {
171                 prefix = "Lustre";
172                 ptype = KERN_INFO;
173         }
174
175         if ((mask & D_CONSOLE) != 0) {
176                 printk("%s%s: %.*s", ptype, prefix, len, buf);
177         } else {
178                 printk("%s%s: %d:%d:(%s:%d:%s()) %.*s", ptype, prefix, hdr->ph_pid,
179                        hdr->ph_extern_pid, file, hdr->ph_line_num, fn, len, buf);
180         }
181         return;
182 }
183
184 int trace_write_daemon_file(struct file *file, const char *buffer,
185                             unsigned long count, void *data)
186 {
187         char *name;
188         unsigned long off;
189         int rc;
190
191         name = kmalloc(count + 1, GFP_KERNEL);
192         if (name == NULL)
193                 return -ENOMEM;
194
195         if (copy_from_user(name, buffer, count)) {
196                 rc = -EFAULT;
197                 goto out;
198         }
199
200         /* be nice and strip out trailing '\n' */
201         for (off = count ; off > 2 && isspace(name[off - 1]); off--)
202                 ;
203
204         name[off] = '\0';
205
206         tracefile_write_lock();
207         if (strcmp(name, "stop") == 0) {
208                 tracefile = NULL;
209                 trace_stop_thread();
210                 goto out_sem;
211         } else if (strncmp(name, "size=", 5) == 0) {
212                 tracefile_size = simple_strtoul(name + 5, NULL, 0);
213                 if (tracefile_size < 10 || tracefile_size > 20480)
214                         tracefile_size = TRACEFILE_SIZE;
215                 else
216                         tracefile_size <<= 20;
217                 goto out_sem;
218         }
219
220         if (name[0] != '/') {
221                 rc = -EINVAL;
222                 goto out_sem;
223         }
224
225         if (tracefile != NULL)
226                 kfree(tracefile);
227
228         tracefile = name;
229         name = NULL;
230         printk(KERN_INFO "Lustre: debug daemon will attempt to start writing "
231                "to %s (%lukB max)\n", tracefile, (long)(tracefile_size >> 10));
232
233         trace_start_thread();
234 out_sem:
235         tracefile_write_unlock();
236 out:
237         kfree(name);
238         return count;
239 }
240
241 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
242                            int *eof, void *data)
243 {
244         int rc;
245
246         tracefile_read_lock();
247         rc = snprintf(page, count, "%s", tracefile);
248         tracefile_read_unlock();
249
250         return rc;
251 }
252
253 int trace_write_debug_mb(struct file *file, const char *buffer,
254                          unsigned long count, void *data)
255 {
256         char string[32];
257         int i;
258         unsigned max;
259
260         if (count >= sizeof(string)) {
261                 printk(KERN_ERR "Lustre: value too large (length %lu bytes)\n",
262                        count);
263                 return -EOVERFLOW;
264         }
265
266         if (copy_from_user(string, buffer, count))
267                 return -EFAULT;
268
269         max = simple_strtoul(string, NULL, 0);
270         if (max == 0)
271                 return -EINVAL;
272
273         if (max > (num_physpages >> (20 - 2 - CFS_PAGE_SHIFT)) / 5 || max >= 512) {
274                 printk(KERN_ERR "Lustre: Refusing to set debug buffer size to "
275                        "%dMB, which is more than 80%% of available RAM (%lu)\n",
276                        max, (num_physpages >> (20 - 2 - CFS_PAGE_SHIFT)) / 5);
277                 return -EINVAL;
278         }
279
280         max /= smp_num_cpus;
281
282         for (i = 0; i < NR_CPUS; i++) {
283                 struct trace_cpu_data *tcd;
284                 tcd = &trace_data[i].tcd;
285                 tcd->tcd_max_pages = max << (20 - CFS_PAGE_SHIFT);
286         }
287         return count;
288 }
289
290 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
291                                         int *eof, void *data)
292 {
293         struct trace_cpu_data *tcd;
294         int rc;
295
296         tcd = trace_get_tcd();
297         __LASSERT (tcd != NULL);
298
299         rc = snprintf(page, count, "%lu\n",
300                       (tcd->tcd_max_pages >> (20 - CFS_PAGE_SHIFT)) * smp_num_cpus);
301
302         trace_put_tcd(tcd);
303         return rc;
304 }
305
306 void
307 trace_call_on_all_cpus(void (*fn)(void *arg), void *arg)
308 {
309         cpumask_t cpus_allowed = current->cpus_allowed;
310         /* use cpus_allowed to quiet 2.4 UP kernel warning only */
311         cpumask_t m = cpus_allowed;
312         int       cpu;
313
314         /* Run the given routine on every CPU in thread context */
315         for (cpu = 0; cpu < NR_CPUS; cpu++) {
316                 if (!cpu_online(cpu))
317                         continue;
318
319                 cpus_clear(m);
320                 cpu_set(cpu, m);
321                 set_cpus_allowed(current, m);
322
323                 fn(arg);
324
325                 set_cpus_allowed(current, cpus_allowed);
326         }
327 }