Whamcloud - gitweb
LU-1589 lnet: read peers of /proc could be endless
[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[CFS_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 (cfs_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                         cfs_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                 cfs_mb();
104                 /* give people some time to stop adding traces */
105                 cfs_schedule_timeout(10);
106         }
107
108         for (i = 0; i < cfs_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, CFS_PAGE_SIZE);
119
120                         p = cfs_list_entry (p->lwtp_list.next,
121                                             lwt_page_t, lwtp_list);
122                 }
123         }
124
125         if (enable) {
126                 lwt_enabled = 1;
127                 cfs_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 = CFS_PAGE_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 = cfs_num_online_cpus();
148         *total_size = cfs_num_online_cpus() * lwt_pages_per_cpu *
149                 bytes_per_page;
150         *now = get_cycles();
151
152         if (user_ptr == NULL)
153                 return (0);
154
155         for (i = 0; i < cfs_num_online_cpus(); i++) {
156                 p = lwt_cpus[i].lwtc_current_page;
157
158                 if (p == NULL)
159                         return (-ENODATA);
160
161                 for (j = 0; j < lwt_pages_per_cpu; j++) {
162                         if (cfs_copy_to_user(user_ptr, p->lwtp_events,
163                                              bytes_per_page))
164                                 return (-EFAULT);
165
166                         user_ptr = ((char *)user_ptr) + bytes_per_page;
167                         p = cfs_list_entry(p->lwtp_list.next,
168                                            lwt_page_t, lwtp_list);
169                 }
170         }
171
172         return (0);
173 }
174
175 int
176 lwt_init ()
177 {
178         int     i;
179         int     j;
180
181         for (i = 0; i < cfs_num_online_cpus(); i++)
182                 if (lwt_cpus[i].lwtc_current_page != NULL)
183                         return (-EALREADY);
184
185         LASSERT (!lwt_enabled);
186
187         /* NULL pointers, zero scalars */
188         memset (lwt_cpus, 0, sizeof (lwt_cpus));
189         lwt_pages_per_cpu =
190                 LWT_MEMORY / (cfs_num_online_cpus() * CFS_PAGE_SIZE);
191
192         for (i = 0; i < cfs_num_online_cpus(); i++)
193                 for (j = 0; j < lwt_pages_per_cpu; j++) {
194                         struct page *page = alloc_page (GFP_KERNEL);
195                         lwt_page_t  *lwtp;
196
197                         if (page == NULL) {
198                                 CERROR ("Can't allocate page\n");
199                                 lwt_fini ();
200                                 return (-ENOMEM);
201                         }
202
203                         LIBCFS_ALLOC(lwtp, sizeof (*lwtp));
204                         if (lwtp == NULL) {
205                                 CERROR ("Can't allocate lwtp\n");
206                                 __free_page(page);
207                                 lwt_fini ();
208                                 return (-ENOMEM);
209                         }
210
211                         lwtp->lwtp_page = page;
212                         lwtp->lwtp_events = page_address(page);
213                         memset (lwtp->lwtp_events, 0, CFS_PAGE_SIZE);
214
215                         if (j == 0) {
216                                 CFS_INIT_LIST_HEAD (&lwtp->lwtp_list);
217                                 lwt_cpus[i].lwtc_current_page = lwtp;
218                         } else {
219                                 cfs_list_add (&lwtp->lwtp_list,
220                                     &lwt_cpus[i].lwtc_current_page->lwtp_list);
221                         }
222                 }
223
224         lwt_enabled = 1;
225         cfs_mb();
226
227         LWT_EVENT(0,0,0,0);
228
229         return (0);
230 }
231
232 void
233 lwt_fini ()
234 {
235         int    i;
236
237         lwt_control(0, 0);
238
239         for (i = 0; i < cfs_num_online_cpus(); i++)
240                 while (lwt_cpus[i].lwtc_current_page != NULL) {
241                         lwt_page_t *lwtp = lwt_cpus[i].lwtc_current_page;
242
243                         if (cfs_list_empty (&lwtp->lwtp_list)) {
244                                 lwt_cpus[i].lwtc_current_page = NULL;
245                         } else {
246                                 lwt_cpus[i].lwtc_current_page =
247                                         cfs_list_entry (lwtp->lwtp_list.next,
248                                                         lwt_page_t, lwtp_list);
249
250                                 cfs_list_del (&lwtp->lwtp_list);
251                         }
252                         
253                         __free_page (lwtp->lwtp_page);
254                         LIBCFS_FREE (lwtp, sizeof (*lwtp));
255                 }
256 }
257
258 EXPORT_SYMBOL(lwt_enabled);
259 EXPORT_SYMBOL(lwt_cpus);
260
261 EXPORT_SYMBOL(lwt_init);
262 EXPORT_SYMBOL(lwt_fini);
263 EXPORT_SYMBOL(lwt_lookup_string);
264 EXPORT_SYMBOL(lwt_control);
265 EXPORT_SYMBOL(lwt_snapshot);
266 #endif