Whamcloud - gitweb
* lctl set_route <nid> <up/down> enables or disables particular portals
[fs/lustre-release.git] / lustre / portals / 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 #define EXPORT_SYMTAB
24
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/kmod.h>
28 #include <linux/kernel.h>
29 #include <linux/kernel.h>
30 #include <linux/mm.h>
31 #include <linux/string.h>
32 #include <linux/stat.h>
33 #include <linux/errno.h>
34 #include <linux/smp_lock.h>
35 #include <linux/unistd.h>
36 #include <linux/interrupt.h>
37 #include <asm/system.h>
38 #include <asm/uaccess.h>
39
40 #define DEBUG_SUBSYSTEM S_PORTALS
41
42 #include <linux/kp30.h>
43
44 #if LWT_SUPPORT
45
46 #define LWT_MEMORY              (1<<20)         /* 1Mb of trace memory */
47 #define LWT_MAX_CPUS             4
48
49 int         lwt_enabled;
50 int         lwt_pages_per_cpu;
51 lwt_cpu_t   lwt_cpus[LWT_MAX_CPUS];
52
53 /* NB only root is allowed to retrieve LWT info; it's an open door into the
54  * kernel... */
55
56 int
57 lwt_lookup_string (int *size, char *knl_ptr,
58                    char *user_ptr, int user_size)
59 {
60         /* knl_ptr was retrieved from an LWT snapshot and the caller wants to
61          * turn it into a string.  NB we can crash with an access violation
62          * trying to determine the string length, so we're trusting our
63          * caller... */
64
65         if (!capable(CAP_SYS_ADMIN))
66                 return (-EPERM);
67
68         *size = strlen (knl_ptr) + 1;
69         
70         if (user_ptr != NULL &&
71             copy_to_user (user_ptr, knl_ptr, *size))
72                 return (-EFAULT);
73         
74         return (0);
75 }
76
77 int
78 lwt_control (int enable, int clear)
79 {
80         lwt_page_t  *p;
81         int          i;
82         int          j;
83
84         if (!capable(CAP_SYS_ADMIN))
85                 return (-EPERM);
86
87         if (clear)
88                 for (i = 0; i < num_online_cpus(); i++) {
89                         p = lwt_cpus[i].lwtc_current_page;
90                         
91                         for (j = 0; j < lwt_pages_per_cpu; j++) {
92                                 
93                                 memset (p->lwtp_events, 0, PAGE_SIZE);
94                                 
95                                 p = list_entry (p->lwtp_list.next,
96                                                 lwt_page_t, lwtp_list);
97                         }
98         }
99
100         lwt_enabled = enable;
101         mb();
102         if (!enable) {
103                 /* give people some time to stop adding traces */
104                 schedule_timeout(10);
105         }
106
107         return (0);
108 }
109
110 int
111 lwt_snapshot (int *ncpu, int *total_size, 
112               void *user_ptr, int user_size) 
113 {
114         const int    events_per_page = PAGE_SIZE / sizeof(lwt_event_t);
115         const int    bytes_per_page = events_per_page * sizeof(lwt_event_t);
116         lwt_page_t  *p;
117         int          i;
118         int          j;
119
120         if (!capable(CAP_SYS_ADMIN))
121                 return (-EPERM);
122
123         *ncpu = num_online_cpus();
124         *total_size = num_online_cpus() * lwt_pages_per_cpu * bytes_per_page;
125
126         if (user_ptr == NULL)
127                 return (0);
128
129         for (i = 0; i < num_online_cpus(); i++) {
130                 p = lwt_cpus[i].lwtc_current_page;
131                 
132                 for (j = 0; j < lwt_pages_per_cpu; j++) {
133                         if (copy_to_user(user_ptr, p->lwtp_events,
134                                          bytes_per_page))
135                                 return (-EFAULT);
136
137                         user_ptr = ((char *)user_ptr) + bytes_per_page;
138                         p = list_entry(p->lwtp_list.next,
139                                        lwt_page_t, lwtp_list);
140                         
141                 }
142         }
143
144         return (0);
145 }
146
147 int
148 lwt_init () 
149 {
150         int     i;
151         int     j;
152         
153         if (num_online_cpus() > LWT_MAX_CPUS) {
154                 CERROR ("Too many CPUs\n");
155                 return (-EINVAL);
156         }
157
158         /* NULL pointers, zero scalars */
159         memset (lwt_cpus, 0, sizeof (lwt_cpus));
160         lwt_pages_per_cpu = LWT_MEMORY / (num_online_cpus() * PAGE_SIZE);
161
162         for (i = 0; i < num_online_cpus(); i++)
163                 for (j = 0; j < lwt_pages_per_cpu; j++) {
164                         struct page *page = alloc_page (GFP_KERNEL);
165                         lwt_page_t  *lwtp;
166
167                         if (page == NULL) {
168                                 CERROR ("Can't allocate page\n");
169                                 lwt_fini ();
170                                 return (-ENOMEM);
171                         }
172
173                         PORTAL_ALLOC(lwtp, sizeof (*lwtp));
174                         if (lwtp == NULL) {
175                                 CERROR ("Can't allocate lwtp\n");
176                                 __free_page(page);
177                                 lwt_fini ();
178                                 return (-ENOMEM);
179                         }
180
181                         lwtp->lwtp_page = page;
182                         lwtp->lwtp_events = page_address(page);
183                         memset (lwtp->lwtp_events, 0, PAGE_SIZE);
184
185                         if (j == 0) {
186                                 INIT_LIST_HEAD (&lwtp->lwtp_list);
187                                 lwt_cpus[i].lwtc_current_page = lwtp;
188                         } else {
189                                 list_add (&lwtp->lwtp_list,
190                                     &lwt_cpus[i].lwtc_current_page->lwtp_list);
191                         }
192                 }
193
194         lwt_enabled = 1;
195         mb();
196
197         return (0);
198 }
199
200 void
201 lwt_fini () 
202 {
203         int    i;
204         
205         if (num_online_cpus() > LWT_MAX_CPUS)
206                 return;
207
208         for (i = 0; i < num_online_cpus(); i++)
209                 while (lwt_cpus[i].lwtc_current_page != NULL) {
210                         lwt_page_t *lwtp = lwt_cpus[i].lwtc_current_page;
211                         
212                         if (list_empty (&lwtp->lwtp_list)) {
213                                 lwt_cpus[i].lwtc_current_page = NULL;
214                         } else {
215                                 lwt_cpus[i].lwtc_current_page =
216                                         list_entry (lwtp->lwtp_list.next,
217                                                     lwt_page_t, lwtp_list);
218
219                                 list_del (&lwtp->lwtp_list);
220                         }
221                         
222                         __free_page (lwtp->lwtp_page);
223                         PORTAL_FREE (lwtp, sizeof (*lwtp));
224                 }
225 }
226
227 EXPORT_SYMBOL(lwt_enabled);
228 EXPORT_SYMBOL(lwt_cpus);
229
230 EXPORT_SYMBOL(lwt_init);
231 EXPORT_SYMBOL(lwt_fini);
232 EXPORT_SYMBOL(lwt_lookup_string);
233 EXPORT_SYMBOL(lwt_control);
234 EXPORT_SYMBOL(lwt_snapshot);
235 #endif