Whamcloud - gitweb
- landing of b_hd_cleanup_merge to HEAD.
[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 #if !KLWT_SUPPORT
49 int         lwt_enabled;
50 lwt_cpu_t   lwt_cpus[NR_CPUS];
51 #endif
52
53 int         lwt_pages_per_cpu;
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 (!enable) {
104                 LWT_EVENT(0,0,0,0);
105                 lwt_enabled = 0;
106                 mb();
107                 /* give people some time to stop adding traces */
108                 schedule_timeout(10);
109         }
110
111         for (i = 0; i < num_online_cpus(); i++) {
112                 p = lwt_cpus[i].lwtc_current_page;
113
114                 if (p == NULL)
115                         return (-ENODATA);
116
117                 if (!clear)
118                         continue;
119
120                 for (j = 0; j < lwt_pages_per_cpu; j++) {
121                         memset (p->lwtp_events, 0, PAGE_SIZE);
122
123                         p = list_entry (p->lwtp_list.next,
124                                         lwt_page_t, lwtp_list);
125                 }
126         }
127
128         if (enable) {
129                 lwt_enabled = 1;
130                 mb();
131                 LWT_EVENT(0,0,0,0);
132         }
133
134         return (0);
135 }
136
137 int
138 lwt_snapshot (cycles_t *now, int *ncpu, int *total_size, 
139               void *user_ptr, int user_size)
140 {
141         const int    events_per_page = PAGE_SIZE / sizeof(lwt_event_t);
142         const int    bytes_per_page = events_per_page * sizeof(lwt_event_t);
143         lwt_page_t  *p;
144         int          i;
145         int          j;
146
147         if (!capable(CAP_SYS_ADMIN))
148                 return (-EPERM);
149
150         *ncpu = num_online_cpus();
151         *total_size = num_online_cpus() * lwt_pages_per_cpu * bytes_per_page;
152         *now = get_cycles();
153         
154         if (user_ptr == NULL)
155                 return (0);
156
157         for (i = 0; i < num_online_cpus(); i++) {
158                 p = lwt_cpus[i].lwtc_current_page;
159
160                 if (p == NULL)
161                         return (-ENODATA);
162                 
163                 for (j = 0; j < lwt_pages_per_cpu; j++) {
164                         if (copy_to_user(user_ptr, p->lwtp_events,
165                                          bytes_per_page))
166                                 return (-EFAULT);
167
168                         user_ptr = ((char *)user_ptr) + bytes_per_page;
169                         p = list_entry(p->lwtp_list.next,
170                                        lwt_page_t, lwtp_list);
171                         
172                 }
173         }
174
175         return (0);
176 }
177
178 int
179 lwt_init () 
180 {
181         int     i;
182         int     j;
183
184         for (i = 0; i < num_online_cpus(); i++)
185                 if (lwt_cpus[i].lwtc_current_page != NULL)
186                         return (-EALREADY);
187         
188         LASSERT (!lwt_enabled);
189
190         /* NULL pointers, zero scalars */
191         memset (lwt_cpus, 0, sizeof (lwt_cpus));
192         lwt_pages_per_cpu = LWT_MEMORY / (num_online_cpus() * PAGE_SIZE);
193
194         for (i = 0; i < num_online_cpus(); i++)
195                 for (j = 0; j < lwt_pages_per_cpu; j++) {
196                         struct page *page = alloc_page (GFP_KERNEL);
197                         lwt_page_t  *lwtp;
198
199                         if (page == NULL) {
200                                 CERROR ("Can't allocate page\n");
201                                 lwt_fini ();
202                                 return (-ENOMEM);
203                         }
204
205                         PORTAL_ALLOC(lwtp, sizeof (*lwtp));
206                         if (lwtp == NULL) {
207                                 CERROR ("Can't allocate lwtp\n");
208                                 __free_page(page);
209                                 lwt_fini ();
210                                 return (-ENOMEM);
211                         }
212
213                         lwtp->lwtp_page = page;
214                         lwtp->lwtp_events = page_address(page);
215                         memset (lwtp->lwtp_events, 0, PAGE_SIZE);
216
217                         if (j == 0) {
218                                 INIT_LIST_HEAD (&lwtp->lwtp_list);
219                                 lwt_cpus[i].lwtc_current_page = lwtp;
220                         } else {
221                                 list_add (&lwtp->lwtp_list,
222                                     &lwt_cpus[i].lwtc_current_page->lwtp_list);
223                         }
224                 }
225
226         lwt_enabled = 1;
227         mb();
228
229         LWT_EVENT(0,0,0,0);
230
231         return (0);
232 }
233
234 void
235 lwt_fini () 
236 {
237         int    i;
238
239         lwt_control(0, 0);
240         
241         for (i = 0; i < num_online_cpus(); i++)
242                 while (lwt_cpus[i].lwtc_current_page != NULL) {
243                         lwt_page_t *lwtp = lwt_cpus[i].lwtc_current_page;
244                         
245                         if (list_empty (&lwtp->lwtp_list)) {
246                                 lwt_cpus[i].lwtc_current_page = NULL;
247                         } else {
248                                 lwt_cpus[i].lwtc_current_page =
249                                         list_entry (lwtp->lwtp_list.next,
250                                                     lwt_page_t, lwtp_list);
251
252                                 list_del (&lwtp->lwtp_list);
253                         }
254                         
255                         __free_page (lwtp->lwtp_page);
256                         PORTAL_FREE (lwtp, sizeof (*lwtp));
257                 }
258 }
259
260 EXPORT_SYMBOL(lwt_enabled);
261 EXPORT_SYMBOL(lwt_cpus);
262
263 EXPORT_SYMBOL(lwt_init);
264 EXPORT_SYMBOL(lwt_fini);
265 EXPORT_SYMBOL(lwt_lookup_string);
266 EXPORT_SYMBOL(lwt_control);
267 EXPORT_SYMBOL(lwt_snapshot);
268 #endif