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  * 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 #ifndef AUTOCONF_INCLUDED
28 #include <linux/config.h>
29 #endif
30 #include <linux/module.h>
31 #include <linux/kmod.h>
32 #include <linux/kernel.h>
33 #include <linux/kernel.h>
34 #include <linux/mm.h>
35 #include <linux/string.h>
36 #include <linux/stat.h>
37 #include <linux/errno.h>
38 #include <linux/smp_lock.h>
39 #include <linux/unistd.h>
40 #include <linux/interrupt.h>
41 #include <asm/system.h>
42 #include <asm/uaccess.h>
43
44 #define DEBUG_SUBSYSTEM S_LNET
45
46 #include <libcfs/libcfs.h>
47
48 #if LWT_SUPPORT
49
50 #if !KLWT_SUPPORT
51 int         lwt_enabled;
52 lwt_cpu_t   lwt_cpus[NR_CPUS];
53 #endif
54
55 int         lwt_pages_per_cpu;
56
57 /* NB only root is allowed to retrieve LWT info; it's an open door into the
58  * kernel... */
59
60 int
61 lwt_lookup_string (int *size, char *knl_ptr,
62                    char *user_ptr, int user_size)
63 {
64         int   maxsize = 128;
65         
66         /* knl_ptr was retrieved from an LWT snapshot and the caller wants to
67          * turn it into a string.  NB we can crash with an access violation
68          * trying to determine the string length, so we're trusting our
69          * caller... */
70
71         if (!capable(CAP_SYS_ADMIN))
72                 return (-EPERM);
73
74         if (user_size > 0 && 
75             maxsize > user_size)
76                 maxsize = user_size;
77
78         *size = strnlen (knl_ptr, maxsize - 1) + 1;
79         
80         if (user_ptr != NULL) {
81                 if (user_size < 4)
82                         return (-EINVAL);
83                 
84                 if (copy_to_user (user_ptr, knl_ptr, *size))
85                         return (-EFAULT);
86
87                 /* Did I truncate the string?  */
88                 if (knl_ptr[*size - 1] != 0)
89                         copy_to_user (user_ptr + *size - 4, "...", 4);
90         }
91
92         return (0);
93 }
94
95 int
96 lwt_control (int enable, int clear)
97 {
98         lwt_page_t  *p;
99         int          i;
100         int          j;
101
102         if (!capable(CAP_SYS_ADMIN))
103                 return (-EPERM);
104
105         if (!enable) {
106                 LWT_EVENT(0,0,0,0);
107                 lwt_enabled = 0;
108                 mb();
109                 /* give people some time to stop adding traces */
110                 schedule_timeout(10);
111         }
112
113         for (i = 0; i < num_online_cpus(); i++) {
114                 p = lwt_cpus[i].lwtc_current_page;
115
116                 if (p == NULL)
117                         return (-ENODATA);
118
119                 if (!clear)
120                         continue;
121
122                 for (j = 0; j < lwt_pages_per_cpu; j++) {
123                         memset (p->lwtp_events, 0, CFS_PAGE_SIZE);
124
125                         p = list_entry (p->lwtp_list.next,
126                                         lwt_page_t, lwtp_list);
127                 }
128         }
129
130         if (enable) {
131                 lwt_enabled = 1;
132                 mb();
133                 LWT_EVENT(0,0,0,0);
134         }
135
136         return (0);
137 }
138
139 int
140 lwt_snapshot (cycles_t *now, int *ncpu, int *total_size, 
141               void *user_ptr, int user_size)
142 {
143         const int    events_per_page = CFS_PAGE_SIZE / sizeof(lwt_event_t);
144         const int    bytes_per_page = events_per_page * sizeof(lwt_event_t);
145         lwt_page_t  *p;
146         int          i;
147         int          j;
148
149         if (!capable(CAP_SYS_ADMIN))
150                 return (-EPERM);
151
152         *ncpu = num_online_cpus();
153         *total_size = num_online_cpus() * lwt_pages_per_cpu * bytes_per_page;
154         *now = get_cycles();
155         
156         if (user_ptr == NULL)
157                 return (0);
158
159         for (i = 0; i < 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 (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 = list_entry(p->lwtp_list.next,
172                                        lwt_page_t, lwtp_list);
173                         
174                 }
175         }
176
177         return (0);
178 }
179
180 int
181 lwt_init () 
182 {
183         int     i;
184         int     j;
185
186         for (i = 0; i < num_online_cpus(); i++)
187                 if (lwt_cpus[i].lwtc_current_page != NULL)
188                         return (-EALREADY);
189         
190         LASSERT (!lwt_enabled);
191
192         /* NULL pointers, zero scalars */
193         memset (lwt_cpus, 0, sizeof (lwt_cpus));
194         lwt_pages_per_cpu = LWT_MEMORY / (num_online_cpus() * CFS_PAGE_SIZE);
195
196         for (i = 0; i < 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                                 INIT_LIST_HEAD (&lwtp->lwtp_list);
221                                 lwt_cpus[i].lwtc_current_page = lwtp;
222                         } else {
223                                 list_add (&lwtp->lwtp_list,
224                                     &lwt_cpus[i].lwtc_current_page->lwtp_list);
225                         }
226                 }
227
228         lwt_enabled = 1;
229         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 < 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 (list_empty (&lwtp->lwtp_list)) {
248                                 lwt_cpus[i].lwtc_current_page = NULL;
249                         } else {
250                                 lwt_cpus[i].lwtc_current_page =
251                                         list_entry (lwtp->lwtp_list.next,
252                                                     lwt_page_t, lwtp_list);
253
254                                 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