Whamcloud - gitweb
land b_smallfix 20040407_1414:
[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 int         lwt_enabled;
49 int         lwt_pages_per_cpu;
50 lwt_cpu_t   lwt_cpus[LWT_MAX_CPUS];
51
52 /* NB only root is allowed to retrieve LWT info; it's an open door into the
53  * kernel... */
54
55 int
56 lwt_lookup_string (int *size, char *knl_ptr,
57                    char *user_ptr, int user_size)
58 {
59         int   maxsize = 128;
60         
61         /* knl_ptr was retrieved from an LWT snapshot and the caller wants to
62          * turn it into a string.  NB we can crash with an access violation
63          * trying to determine the string length, so we're trusting our
64          * caller... */
65
66         if (!capable(CAP_SYS_ADMIN))
67                 return (-EPERM);
68
69         if (user_size > 0 && 
70             maxsize > user_size)
71                 maxsize = user_size;
72
73         *size = strnlen (knl_ptr, maxsize - 1) + 1;
74         
75         if (user_ptr != NULL) {
76                 if (user_size < 4)
77                         return (-EINVAL);
78                 
79                 if (copy_to_user (user_ptr, knl_ptr, *size))
80                         return (-EFAULT);
81
82                 /* Did I truncate the string?  */
83                 if (knl_ptr[*size - 1] != 0)
84                         copy_to_user (user_ptr + *size - 4, "...", 4);
85         }
86
87         return (0);
88 }
89
90 int
91 lwt_control (int enable, int clear)
92 {
93         lwt_page_t  *p;
94         int          i;
95         int          j;
96
97         if (!capable(CAP_SYS_ADMIN))
98                 return (-EPERM);
99
100         if (clear)
101                 for (i = 0; i < num_online_cpus(); i++) {
102                         p = lwt_cpus[i].lwtc_current_page;
103
104                         for (j = 0; j < lwt_pages_per_cpu; j++) {
105                                 memset (p->lwtp_events, 0, PAGE_SIZE);
106
107                                 p = list_entry (p->lwtp_list.next,
108                                                 lwt_page_t, lwtp_list);
109                         }
110         }
111
112         lwt_enabled = enable;
113         mb();
114         if (!enable) {
115                 /* give people some time to stop adding traces */
116                 schedule_timeout(10);
117         }
118
119         return (0);
120 }
121
122 int
123 lwt_snapshot (cycles_t *now, int *ncpu, int *total_size, 
124               void *user_ptr, int user_size)
125 {
126         const int    events_per_page = PAGE_SIZE / sizeof(lwt_event_t);
127         const int    bytes_per_page = events_per_page * sizeof(lwt_event_t);
128         lwt_page_t  *p;
129         int          i;
130         int          j;
131
132         if (!capable(CAP_SYS_ADMIN))
133                 return (-EPERM);
134
135         *ncpu = num_online_cpus();
136         *total_size = num_online_cpus() * lwt_pages_per_cpu * bytes_per_page;
137         *now = get_cycles();
138         
139         if (user_ptr == NULL)
140                 return (0);
141
142         for (i = 0; i < num_online_cpus(); i++) {
143                 p = lwt_cpus[i].lwtc_current_page;
144                 
145                 for (j = 0; j < lwt_pages_per_cpu; j++) {
146                         if (copy_to_user(user_ptr, p->lwtp_events,
147                                          bytes_per_page))
148                                 return (-EFAULT);
149
150                         user_ptr = ((char *)user_ptr) + bytes_per_page;
151                         p = list_entry(p->lwtp_list.next,
152                                        lwt_page_t, lwtp_list);
153                         
154                 }
155         }
156
157         return (0);
158 }
159
160 int
161 lwt_init () 
162 {
163         int     i;
164         int     j;
165         
166         if (num_online_cpus() > LWT_MAX_CPUS) {
167                 CERROR ("Too many CPUs\n");
168                 return (-EINVAL);
169         }
170
171         /* NULL pointers, zero scalars */
172         memset (lwt_cpus, 0, sizeof (lwt_cpus));
173         lwt_pages_per_cpu = LWT_MEMORY / (num_online_cpus() * PAGE_SIZE);
174
175         for (i = 0; i < num_online_cpus(); i++)
176                 for (j = 0; j < lwt_pages_per_cpu; j++) {
177                         struct page *page = alloc_page (GFP_KERNEL);
178                         lwt_page_t  *lwtp;
179
180                         if (page == NULL) {
181                                 CERROR ("Can't allocate page\n");
182                                 lwt_fini ();
183                                 return (-ENOMEM);
184                         }
185
186                         PORTAL_ALLOC(lwtp, sizeof (*lwtp));
187                         if (lwtp == NULL) {
188                                 CERROR ("Can't allocate lwtp\n");
189                                 __free_page(page);
190                                 lwt_fini ();
191                                 return (-ENOMEM);
192                         }
193
194                         lwtp->lwtp_page = page;
195                         lwtp->lwtp_events = page_address(page);
196                         memset (lwtp->lwtp_events, 0, PAGE_SIZE);
197
198                         if (j == 0) {
199                                 INIT_LIST_HEAD (&lwtp->lwtp_list);
200                                 lwt_cpus[i].lwtc_current_page = lwtp;
201                         } else {
202                                 list_add (&lwtp->lwtp_list,
203                                     &lwt_cpus[i].lwtc_current_page->lwtp_list);
204                         }
205                 }
206
207         lwt_enabled = 1;
208         mb();
209
210         return (0);
211 }
212
213 void
214 lwt_fini () 
215 {
216         int    i;
217         
218         if (num_online_cpus() > LWT_MAX_CPUS)
219                 return;
220
221         for (i = 0; i < num_online_cpus(); i++)
222                 while (lwt_cpus[i].lwtc_current_page != NULL) {
223                         lwt_page_t *lwtp = lwt_cpus[i].lwtc_current_page;
224                         
225                         if (list_empty (&lwtp->lwtp_list)) {
226                                 lwt_cpus[i].lwtc_current_page = NULL;
227                         } else {
228                                 lwt_cpus[i].lwtc_current_page =
229                                         list_entry (lwtp->lwtp_list.next,
230                                                     lwt_page_t, lwtp_list);
231
232                                 list_del (&lwtp->lwtp_list);
233                         }
234                         
235                         __free_page (lwtp->lwtp_page);
236                         PORTAL_FREE (lwtp, sizeof (*lwtp));
237                 }
238 }
239
240 EXPORT_SYMBOL(lwt_enabled);
241 EXPORT_SYMBOL(lwt_cpus);
242
243 EXPORT_SYMBOL(lwt_init);
244 EXPORT_SYMBOL(lwt_fini);
245 EXPORT_SYMBOL(lwt_lookup_string);
246 EXPORT_SYMBOL(lwt_control);
247 EXPORT_SYMBOL(lwt_snapshot);
248 #endif