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