Whamcloud - gitweb
Landing b_hd_newconfig on HEAD
[fs/lustre-release.git] / lnet / libcfs / darwin / darwin-tracefile.c
1
2 #define DEBUG_SUBSYSTEM S_LNET
3 #define LUSTRE_TRACEFILE_PRIVATE
4 #include <libcfs/libcfs.h>
5 #include <libcfs/kp30.h>
6 #include "tracefile.h"
7
8 /*
9  * We can't support smp tracefile currently.
10  * Everything is put on one cpu.
11  */
12
13 #define M_TCD_MAX_PAGES (128 * 1280)
14 extern union trace_data_union trace_data[NR_CPUS];
15 extern char *tracefile;
16 extern long long tracefile_size;
17 extern int trace_start_thread(void);
18 extern void trace_stop_thread(void);
19
20 long max_debug_mb = M_TCD_MAX_PAGES;
21 static long max_permit_mb = (64 * 1024);
22
23 spinlock_t trace_cpu_serializer;
24
25 /*
26  * thread currently executing tracefile code or NULL if none does. Used to
27  * detect recursive calls to libcfs_debug_msg().
28  */
29 static thread_t trace_owner = NULL;
30
31 extern int get_preemption_level(void);
32 extern atomic_t tage_allocated;
33
34 struct rw_semaphore tracefile_sem;
35
36 int tracefile_init_arch() {
37     init_rwsem(&tracefile_sem);
38 #error "Todo: initialise per-cpu console buffers"
39     return 0;
40 }
41
42 void tracefile_fini_arch() {
43 }
44
45 void tracefile_read_lock() {
46     down_read(&tracefile_sem);
47 }
48
49 void tracefile_read_unlock() {
50     up_read(&tracefile_sem);
51 }
52
53 void tracefile_write_lock() {
54     down_write(&tracefile_sem);
55 }
56
57 void tracefile_write_unlock() {
58     up_write(&tracefile_sem);
59 }
60
61 char *trace_get_console_buffer(void)
62 {
63 #error "todo: return a per-cpu/interrupt console buffer and disable pre-emption"
64 }
65
66 void trace_put_console_buffer(char *buffer)
67 {
68 #error "todo: re-enable pre-emption"
69 }
70
71 struct trace_cpu_data *trace_get_tcd(void)
72 {
73         struct trace_cpu_data *tcd;
74         int nr_pages;
75         struct list_head pages;
76
77         /*
78          * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
79          * from here: this will lead to infinite recursion.
80          */
81
82         /*
83          * debugging check for recursive call to libcfs_debug_msg()
84          */
85         if (trace_owner == current_thread()) {
86                 /*
87                  * Cannot assert here.
88                  */
89                 printk(KERN_EMERG "recursive call to %s", __FUNCTION__);
90                 /*
91                  * "The death of God left the angels in a strange position."
92                  */
93                 cfs_enter_debugger();
94         }
95         tcd = &trace_data[0].tcd;
96         CFS_INIT_LIST_HEAD(&pages);
97         if (get_preemption_level() == 0)
98                 nr_pages = trace_refill_stock(tcd, CFS_ALLOC_STD, &pages);
99         else
100                 nr_pages = 0;
101         spin_lock(&trace_cpu_serializer);
102         trace_owner = current_thread();
103         tcd->tcd_cur_stock_pages += nr_pages;
104         list_splice(&pages, &tcd->tcd_stock_pages);
105         return tcd;
106 }
107
108 extern void raw_page_death_row_clean(void);
109
110 void __trace_put_tcd(struct trace_cpu_data *tcd)
111 {
112         /*
113          * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
114          * from here: this will lead to infinite recursion.
115          */
116         LASSERT(trace_owner == current_thread());
117         trace_owner = NULL;
118         spin_unlock(&trace_cpu_serializer);
119         if (get_preemption_level() == 0)
120                 /* purge all pending pages */
121                 raw_page_death_row_clean();
122 }
123
124 int tcd_owns_tage(struct trace_cpu_data *tcd, struct trace_page *tage)
125 {
126         /*
127          * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
128          * from here: this will lead to infinite recursion.
129          */
130         /* XNU has global tcd, and all pages are owned by it */
131         return 1;
132 }
133
134 void
135 set_ptldebug_header(struct ptldebug_header *header, int subsys, int mask,
136                     const int line, unsigned long stack)
137 {
138         struct timeval tv;
139         
140         /*
141          * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
142          * from here: this will lead to infinite recursion.
143          */
144         do_gettimeofday(&tv);
145         header->ph_subsys = subsys;
146         header->ph_mask = mask;
147         header->ph_cpu_id = smp_processor_id();
148         header->ph_sec = (__u32)tv.tv_sec;
149         header->ph_usec = tv.tv_usec;
150         header->ph_stack = stack;
151         header->ph_pid = cfs_curproc_pid();
152         header->ph_line_num = line;
153         header->ph_extern_pid = (__u32)current_thread();
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 = KERN_INFO;
160
161         /*
162          * XXX nikita: do NOT call libcfs_debug_msg() (CDEBUG/ENTRY/EXIT)
163          * from here: this will lead to infinite recursion.
164          */
165         if ((mask & D_EMERG) != 0) {
166                 prefix = "LustreError";
167                 ptype = KERN_EMERG;
168         } else if ((mask & D_ERROR) != 0) {
169                 prefix = "LustreError";
170                 ptype = KERN_ERR;
171         } else if ((mask & D_WARNING) != 0) {
172                 prefix = "Lustre";
173                 ptype = KERN_WARNING;
174         } else if ((mask & libcfs_printk) != 0 || (mask & D_CONSOLE)) {
175                 prefix = "Lustre";
176                 ptype = KERN_INFO;
177         }
178
179         if ((mask & D_CONSOLE) != 0) {
180                 printk("%s%s: %.*s", ptype, prefix, len, buf);
181         } else {
182                 printk("%s%s: %d:%d:(%s:%d:%s()) %*s",
183                        ptype, prefix, hdr->ph_pid, hdr->ph_extern_pid,
184                        file, hdr->ph_line_num, fn, len, buf);
185         }
186 }
187
188 /*
189  * Sysctl handle of libcfs
190  */
191 #define MAX_TRACEFILE_PATH_LEN  256
192 int cfs_trace_daemon SYSCTL_HANDLER_ARGS
193 {
194         int error = 0;
195         char *name = NULL;
196
197         if (req->newptr == USER_ADDR_NULL) {
198                 /* a read */
199                 if (tracefile)
200                         error = sysctl_handle_string(oidp, tracefile, 0, req);
201                 else
202                         error = sysctl_handle_string(oidp, "NA", 0, req);
203
204                 return error;
205         }
206         
207         /* now hanle write requests */
208         MALLOC(name, char *, MAX_TRACEFILE_PATH_LEN + 1, M_TEMP, M_WAITOK | M_ZERO);
209         if (name == NULL)
210                 return -ENOMEM;
211         name[0] = '\0';
212         tracefile_write_lock();
213         error = sysctl_handle_string(oidp, name, MAX_TRACEFILE_PATH_LEN + 1, req);
214         if (!error) {
215                 if (strcmp(name, "stop") == 0) {
216                         /* stop tracefile daemon */
217                         tracefile = NULL;
218                         trace_stop_thread();
219                         goto out;
220                 }else if (strncmp(name, "size=", 5) == 0) {
221                         tracefile_size = simple_strtoul(name + 5, NULL, 0);
222                         if (tracefile_size < 10 || tracefile_size > 20480)
223                                 tracefile_size = TRACEFILE_SIZE;
224                         else
225                                 tracefile_size <<= 20;
226                         goto out;
227
228                 }
229                 if (name[0] != '/') {
230                         error = -EINVAL;
231                         goto out;
232                 }
233                 if (tracefile != NULL)
234                         cfs_free(tracefile);
235                 tracefile = name;
236                 name = NULL;
237                 trace_start_thread();
238         } else {
239                 /* Something was wrong with the write request */
240                 printf("sysctl debug daemon failed: %d.\n", error);
241                 goto out;
242         }
243 out:
244         if (name != NULL)
245                 FREE(name, M_TEMP);
246         tracefile_write_unlock();
247         return error;
248 }
249 #undef MAX_TRACEFILE_PATH_LEN
250
251
252 int cfs_debug_mb SYSCTL_HANDLER_ARGS
253 {
254         int i;
255         int error = 0;
256
257         error = sysctl_handle_long(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
258         if (!error && req->newptr != USER_ADDR_NULL) {
259                 /* We have a new value stored in the standard location */
260                 if (max_debug_mb <= 0)
261                         return -EINVAL;
262                 if (max_debug_mb > max_permit_mb) {
263                         printf("sysctl debug_mb is too big: %d.\n", max_debug_mb);
264                         return 0;
265                 }
266                 for (i = 0; i < NR_CPUS; i++) {
267                         struct trace_cpu_data *tcd;
268                         tcd = &trace_data[i].tcd;
269                         tcd->tcd_max_pages = max_debug_mb;
270                 }
271         } else if (req->newptr != USER_ADDR_NULL) {
272                 /* Something was wrong with the write request */
273                 printf ("sysctl debug_mb fault: %d.\n", error);
274         }
275
276         return error;
277 }
278
279 void
280 trace_call_on_all_cpus(void (*fn)(void *arg), void *arg)
281 {
282 #error "tbd"
283 }