Whamcloud - gitweb
land v0.9.1 on HEAD, in preparation for a 1.0.x branch
[fs/lustre-release.git] / lnet / libcfs / lwt.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2003 Cluster File Systems, Inc.
5  *   Author: Eric Barton <eeb@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #ifndef EXPORT_SYMTAB
24 # define EXPORT_SYMTAB
25 #endif
26
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/kmod.h>
30 #include <linux/kernel.h>
31 #include <linux/kernel.h>
32 #include <linux/mm.h>
33 #include <linux/string.h>
34 #include <linux/stat.h>
35 #include <linux/errno.h>
36 #include <linux/smp_lock.h>
37 #include <linux/unistd.h>
38 #include <linux/interrupt.h>
39 #include <asm/system.h>
40 #include <asm/uaccess.h>
41
42 #define DEBUG_SUBSYSTEM S_PORTALS
43
44 #include <linux/kp30.h>
45
46 #if LWT_SUPPORT
47
48 #define LWT_MEMORY              (1<<20)         /* 1Mb of trace memory */
49 #define LWT_MAX_CPUS             4
50
51 int         lwt_enabled;
52 int         lwt_pages_per_cpu;
53 lwt_cpu_t   lwt_cpus[LWT_MAX_CPUS];
54
55 /* NB only root is allowed to retrieve LWT info; it's an open door into the
56  * kernel... */
57
58 int
59 lwt_lookup_string (int *size, char *knl_ptr,
60                    char *user_ptr, int user_size)
61 {
62         int   maxsize = 128;
63         
64         /* knl_ptr was retrieved from an LWT snapshot and the caller wants to
65          * turn it into a string.  NB we can crash with an access violation
66          * trying to determine the string length, so we're trusting our
67          * caller... */
68
69         if (!capable(CAP_SYS_ADMIN))
70                 return (-EPERM);
71
72         if (user_size > 0 && 
73             maxsize > user_size)
74                 maxsize = user_size;
75
76         *size = strnlen (knl_ptr, maxsize - 1) + 1;
77         
78         if (user_ptr != NULL) {
79                 if (user_size < 4)
80                         return (-EINVAL);
81                 
82                 if (copy_to_user (user_ptr, knl_ptr, *size))
83                         return (-EFAULT);
84
85                 /* Did I truncate the string?  */
86                 if (knl_ptr[*size - 1] != 0)
87                         copy_to_user (user_ptr + *size - 4, "...", 4);
88         }
89
90         return (0);
91 }
92
93 int
94 lwt_control (int enable, int clear)
95 {
96         lwt_page_t  *p;
97         int          i;
98         int          j;
99
100         if (!capable(CAP_SYS_ADMIN))
101                 return (-EPERM);
102
103         if (clear)
104                 for (i = 0; i < num_online_cpus(); i++) {
105                         p = lwt_cpus[i].lwtc_current_page;
106
107                         for (j = 0; j < lwt_pages_per_cpu; j++) {
108                                 memset (p->lwtp_events, 0, PAGE_SIZE);
109
110                                 p = list_entry (p->lwtp_list.next,
111                                                 lwt_page_t, lwtp_list);
112                         }
113         }
114
115         lwt_enabled = enable;
116         mb();
117         if (!enable) {
118                 /* give people some time to stop adding traces */
119                 schedule_timeout(10);
120         }
121
122         return (0);
123 }
124
125 int
126 lwt_snapshot (int *ncpu, int *total_size, void *user_ptr, int user_size)
127 {
128         const int    events_per_page = PAGE_SIZE / sizeof(lwt_event_t);
129         const int    bytes_per_page = events_per_page * sizeof(lwt_event_t);
130         lwt_page_t  *p;
131         int          i;
132         int          j;
133
134         if (!capable(CAP_SYS_ADMIN))
135                 return (-EPERM);
136
137         *ncpu = num_online_cpus();
138         *total_size = num_online_cpus() * lwt_pages_per_cpu * bytes_per_page;
139
140         if (user_ptr == NULL)
141                 return (0);
142
143         for (i = 0; i < num_online_cpus(); i++) {
144                 p = lwt_cpus[i].lwtc_current_page;
145                 
146                 for (j = 0; j < lwt_pages_per_cpu; j++) {
147                         if (copy_to_user(user_ptr, p->lwtp_events,
148                                          bytes_per_page))
149                                 return (-EFAULT);
150
151                         user_ptr = ((char *)user_ptr) + bytes_per_page;
152                         p = list_entry(p->lwtp_list.next,
153                                        lwt_page_t, lwtp_list);
154                         
155                 }
156         }
157
158         return (0);
159 }
160
161 int
162 lwt_init () 
163 {
164         int     i;
165         int     j;
166         
167         if (num_online_cpus() > LWT_MAX_CPUS) {
168                 CERROR ("Too many CPUs\n");
169                 return (-EINVAL);
170         }
171
172         /* NULL pointers, zero scalars */
173         memset (lwt_cpus, 0, sizeof (lwt_cpus));
174         lwt_pages_per_cpu = LWT_MEMORY / (num_online_cpus() * PAGE_SIZE);
175
176         for (i = 0; i < num_online_cpus(); i++)
177                 for (j = 0; j < lwt_pages_per_cpu; j++) {
178                         struct page *page = alloc_page (GFP_KERNEL);
179                         lwt_page_t  *lwtp;
180
181                         if (page == NULL) {
182                                 CERROR ("Can't allocate page\n");
183                                 lwt_fini ();
184                                 return (-ENOMEM);
185                         }
186
187                         PORTAL_ALLOC(lwtp, sizeof (*lwtp));
188                         if (lwtp == NULL) {
189                                 CERROR ("Can't allocate lwtp\n");
190                                 __free_page(page);
191                                 lwt_fini ();
192                                 return (-ENOMEM);
193                         }
194
195                         lwtp->lwtp_page = page;
196                         lwtp->lwtp_events = page_address(page);
197                         memset (lwtp->lwtp_events, 0, PAGE_SIZE);
198
199                         if (j == 0) {
200                                 INIT_LIST_HEAD (&lwtp->lwtp_list);
201                                 lwt_cpus[i].lwtc_current_page = lwtp;
202                         } else {
203                                 list_add (&lwtp->lwtp_list,
204                                     &lwt_cpus[i].lwtc_current_page->lwtp_list);
205                         }
206                 }
207
208         lwt_enabled = 1;
209         mb();
210
211         return (0);
212 }
213
214 void
215 lwt_fini () 
216 {
217         int    i;
218         
219         if (num_online_cpus() > LWT_MAX_CPUS)
220                 return;
221
222         for (i = 0; i < num_online_cpus(); i++)
223                 while (lwt_cpus[i].lwtc_current_page != NULL) {
224                         lwt_page_t *lwtp = lwt_cpus[i].lwtc_current_page;
225                         
226                         if (list_empty (&lwtp->lwtp_list)) {
227                                 lwt_cpus[i].lwtc_current_page = NULL;
228                         } else {
229                                 lwt_cpus[i].lwtc_current_page =
230                                         list_entry (lwtp->lwtp_list.next,
231                                                     lwt_page_t, lwtp_list);
232
233                                 list_del (&lwtp->lwtp_list);
234                         }
235                         
236                         __free_page (lwtp->lwtp_page);
237                         PORTAL_FREE (lwtp, sizeof (*lwtp));
238                 }
239 }
240
241 EXPORT_SYMBOL(lwt_enabled);
242 EXPORT_SYMBOL(lwt_cpus);
243
244 EXPORT_SYMBOL(lwt_init);
245 EXPORT_SYMBOL(lwt_fini);
246 EXPORT_SYMBOL(lwt_lookup_string);
247 EXPORT_SYMBOL(lwt_control);
248 EXPORT_SYMBOL(lwt_snapshot);
249 #endif