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