Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / libcfs / libcfs / lwt.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * libcfs/libcfs/lwt.c
37  *
38  * Author: Eric Barton <eeb@clusterfs.com>
39  */
40
41 #ifndef EXPORT_SYMTAB
42 # define EXPORT_SYMTAB
43 #endif
44
45 #define DEBUG_SUBSYSTEM S_LNET
46
47 #include <libcfs/libcfs.h>
48
49 #if LWT_SUPPORT
50
51 #if !KLWT_SUPPORT
52 int         lwt_enabled;
53 lwt_cpu_t   lwt_cpus[NR_CPUS];
54 #endif
55
56 int         lwt_pages_per_cpu;
57
58 /* NB only root is allowed to retrieve LWT info; it's an open door into the
59  * kernel... */
60
61 int
62 lwt_lookup_string (int *size, char *knl_ptr,
63                    char *user_ptr, int user_size)
64 {
65         int   maxsize = 128;
66         
67         /* knl_ptr was retrieved from an LWT snapshot and the caller wants to
68          * turn it into a string.  NB we can crash with an access violation
69          * trying to determine the string length, so we're trusting our
70          * caller... */
71
72         if (!cfs_capable(CFS_CAP_SYS_ADMIN))
73                 return (-EPERM);
74
75         if (user_size > 0 && 
76             maxsize > user_size)
77                 maxsize = user_size;
78
79         *size = strnlen (knl_ptr, maxsize - 1) + 1;
80         
81         if (user_ptr != NULL) {
82                 if (user_size < 4)
83                         return (-EINVAL);
84                 
85                 if (copy_to_user (user_ptr, knl_ptr, *size))
86                         return (-EFAULT);
87
88                 /* Did I truncate the string?  */
89                 if (knl_ptr[*size - 1] != 0)
90                         copy_to_user (user_ptr + *size - 4, "...", 4);
91         }
92
93         return (0);
94 }
95
96 int
97 lwt_control (int enable, int clear)
98 {
99         lwt_page_t  *p;
100         int          i;
101         int          j;
102
103         if (!cfs_capable(CFS_CAP_SYS_ADMIN))
104                 return (-EPERM);
105
106         if (!enable) {
107                 LWT_EVENT(0,0,0,0);
108                 lwt_enabled = 0;
109                 mb();
110                 /* give people some time to stop adding traces */
111                 schedule_timeout(10);
112         }
113
114         for (i = 0; i < num_online_cpus(); i++) {
115                 p = lwt_cpus[i].lwtc_current_page;
116
117                 if (p == NULL)
118                         return (-ENODATA);
119
120                 if (!clear)
121                         continue;
122
123                 for (j = 0; j < lwt_pages_per_cpu; j++) {
124                         memset (p->lwtp_events, 0, CFS_PAGE_SIZE);
125
126                         p = list_entry (p->lwtp_list.next,
127                                         lwt_page_t, lwtp_list);
128                 }
129         }
130
131         if (enable) {
132                 lwt_enabled = 1;
133                 mb();
134                 LWT_EVENT(0,0,0,0);
135         }
136
137         return (0);
138 }
139
140 int
141 lwt_snapshot (cycles_t *now, int *ncpu, int *total_size, 
142               void *user_ptr, int user_size)
143 {
144         const int    events_per_page = CFS_PAGE_SIZE / sizeof(lwt_event_t);
145         const int    bytes_per_page = events_per_page * sizeof(lwt_event_t);
146         lwt_page_t  *p;
147         int          i;
148         int          j;
149
150         if (!cfs_capable(CFS_CAP_SYS_ADMIN))
151                 return (-EPERM);
152
153         *ncpu = num_online_cpus();
154         *total_size = num_online_cpus() * lwt_pages_per_cpu * bytes_per_page;
155         *now = get_cycles();
156         
157         if (user_ptr == NULL)
158                 return (0);
159
160         for (i = 0; i < num_online_cpus(); i++) {
161                 p = lwt_cpus[i].lwtc_current_page;
162
163                 if (p == NULL)
164                         return (-ENODATA);
165                 
166                 for (j = 0; j < lwt_pages_per_cpu; j++) {
167                         if (copy_to_user(user_ptr, p->lwtp_events,
168                                          bytes_per_page))
169                                 return (-EFAULT);
170
171                         user_ptr = ((char *)user_ptr) + bytes_per_page;
172                         p = list_entry(p->lwtp_list.next,
173                                        lwt_page_t, lwtp_list);
174                         
175                 }
176         }
177
178         return (0);
179 }
180
181 int
182 lwt_init () 
183 {
184         int     i;
185         int     j;
186
187         for (i = 0; i < num_online_cpus(); i++)
188                 if (lwt_cpus[i].lwtc_current_page != NULL)
189                         return (-EALREADY);
190         
191         LASSERT (!lwt_enabled);
192
193         /* NULL pointers, zero scalars */
194         memset (lwt_cpus, 0, sizeof (lwt_cpus));
195         lwt_pages_per_cpu = LWT_MEMORY / (num_online_cpus() * CFS_PAGE_SIZE);
196
197         for (i = 0; i < num_online_cpus(); i++)
198                 for (j = 0; j < lwt_pages_per_cpu; j++) {
199                         struct page *page = alloc_page (GFP_KERNEL);
200                         lwt_page_t  *lwtp;
201
202                         if (page == NULL) {
203                                 CERROR ("Can't allocate page\n");
204                                 lwt_fini ();
205                                 return (-ENOMEM);
206                         }
207
208                         LIBCFS_ALLOC(lwtp, sizeof (*lwtp));
209                         if (lwtp == NULL) {
210                                 CERROR ("Can't allocate lwtp\n");
211                                 __free_page(page);
212                                 lwt_fini ();
213                                 return (-ENOMEM);
214                         }
215
216                         lwtp->lwtp_page = page;
217                         lwtp->lwtp_events = page_address(page);
218                         memset (lwtp->lwtp_events, 0, CFS_PAGE_SIZE);
219
220                         if (j == 0) {
221                                 INIT_LIST_HEAD (&lwtp->lwtp_list);
222                                 lwt_cpus[i].lwtc_current_page = lwtp;
223                         } else {
224                                 list_add (&lwtp->lwtp_list,
225                                     &lwt_cpus[i].lwtc_current_page->lwtp_list);
226                         }
227                 }
228
229         lwt_enabled = 1;
230         mb();
231
232         LWT_EVENT(0,0,0,0);
233
234         return (0);
235 }
236
237 void
238 lwt_fini () 
239 {
240         int    i;
241
242         lwt_control(0, 0);
243         
244         for (i = 0; i < num_online_cpus(); i++)
245                 while (lwt_cpus[i].lwtc_current_page != NULL) {
246                         lwt_page_t *lwtp = lwt_cpus[i].lwtc_current_page;
247                         
248                         if (list_empty (&lwtp->lwtp_list)) {
249                                 lwt_cpus[i].lwtc_current_page = NULL;
250                         } else {
251                                 lwt_cpus[i].lwtc_current_page =
252                                         list_entry (lwtp->lwtp_list.next,
253                                                     lwt_page_t, lwtp_list);
254
255                                 list_del (&lwtp->lwtp_list);
256                         }
257                         
258                         __free_page (lwtp->lwtp_page);
259                         LIBCFS_FREE (lwtp, sizeof (*lwtp));
260                 }
261 }
262
263 EXPORT_SYMBOL(lwt_enabled);
264 EXPORT_SYMBOL(lwt_cpus);
265
266 EXPORT_SYMBOL(lwt_init);
267 EXPORT_SYMBOL(lwt_fini);
268 EXPORT_SYMBOL(lwt_lookup_string);
269 EXPORT_SYMBOL(lwt_control);
270 EXPORT_SYMBOL(lwt_snapshot);
271 #endif