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