Whamcloud - gitweb
5e273cbc0adfbe94fc953b769d075df1ee64e342
[fs/lustre-release.git] / libcfs / libcfs / module.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 # define EXPORT_SYMTAB
24 #endif
25 #define DEBUG_SUBSYSTEM S_LNET
26
27 #include <lnet/lib-lnet.h>
28 #include <lnet/lnet.h>
29 #include <libcfs/kp30.h>
30 #include "tracefile.h"
31
32 void
33 kportal_memhog_free (struct libcfs_device_userstate *ldu)
34 {
35         cfs_page_t **level0p = &ldu->ldu_memhog_root_page;
36         cfs_page_t **level1p;
37         cfs_page_t **level2p;
38         int           count1;
39         int           count2;
40
41         if (*level0p != NULL) {
42
43                 level1p = (cfs_page_t **)cfs_page_address(*level0p);
44                 count1 = 0;
45
46                 while (count1 < CFS_PAGE_SIZE/sizeof(cfs_page_t *) &&
47                        *level1p != NULL) {
48
49                         level2p = (cfs_page_t **)cfs_page_address(*level1p);
50                         count2 = 0;
51
52                         while (count2 < CFS_PAGE_SIZE/sizeof(cfs_page_t *) &&
53                                *level2p != NULL) {
54
55                                 cfs_free_page(*level2p);
56                                 ldu->ldu_memhog_pages--;
57                                 level2p++;
58                                 count2++;
59                         }
60
61                         cfs_free_page(*level1p);
62                         ldu->ldu_memhog_pages--;
63                         level1p++;
64                         count1++;
65                 }
66
67                 cfs_free_page(*level0p);
68                 ldu->ldu_memhog_pages--;
69
70                 *level0p = NULL;
71         }
72
73         LASSERT (ldu->ldu_memhog_pages == 0);
74 }
75
76 int
77 kportal_memhog_alloc (struct libcfs_device_userstate *ldu, int npages, int flags)
78 {
79         cfs_page_t **level0p;
80         cfs_page_t **level1p;
81         cfs_page_t **level2p;
82         int           count1;
83         int           count2;
84
85         LASSERT (ldu->ldu_memhog_pages == 0);
86         LASSERT (ldu->ldu_memhog_root_page == NULL);
87
88         if (npages < 0)
89                 return -EINVAL;
90
91         if (npages == 0)
92                 return 0;
93
94         level0p = &ldu->ldu_memhog_root_page;
95         *level0p = cfs_alloc_page(flags);
96         if (*level0p == NULL)
97                 return -ENOMEM;
98         ldu->ldu_memhog_pages++;
99
100         level1p = (cfs_page_t **)cfs_page_address(*level0p);
101         count1 = 0;
102         memset(level1p, 0, CFS_PAGE_SIZE);
103
104         while (ldu->ldu_memhog_pages < npages &&
105                count1 < CFS_PAGE_SIZE/sizeof(cfs_page_t *)) {
106
107                 if (cfs_signal_pending())
108                         return (-EINTR);
109
110                 *level1p = cfs_alloc_page(flags);
111                 if (*level1p == NULL)
112                         return -ENOMEM;
113                 ldu->ldu_memhog_pages++;
114
115                 level2p = (cfs_page_t **)cfs_page_address(*level1p);
116                 count2 = 0;
117                 memset(level2p, 0, CFS_PAGE_SIZE);
118
119                 while (ldu->ldu_memhog_pages < npages &&
120                        count2 < CFS_PAGE_SIZE/sizeof(cfs_page_t *)) {
121
122                         if (cfs_signal_pending())
123                                 return (-EINTR);
124
125                         *level2p = cfs_alloc_page(flags);
126                         if (*level2p == NULL)
127                                 return (-ENOMEM);
128                         ldu->ldu_memhog_pages++;
129
130                         level2p++;
131                         count2++;
132                 }
133
134                 level1p++;
135                 count1++;
136         }
137
138         return 0;
139 }
140
141 /* called when opening /dev/device */
142 static int libcfs_psdev_open(unsigned long flags, void *args)
143 {
144         struct libcfs_device_userstate *ldu;
145         ENTRY;
146
147         PORTAL_MODULE_USE;
148
149         LIBCFS_ALLOC(ldu, sizeof(*ldu));
150         if (ldu != NULL) {
151                 ldu->ldu_memhog_pages = 0;
152                 ldu->ldu_memhog_root_page = NULL;
153         }
154         *(struct libcfs_device_userstate **)args = ldu;
155
156         RETURN(0);
157 }
158
159 /* called when closing /dev/device */
160 static int libcfs_psdev_release(unsigned long flags, void *args)
161 {
162         struct libcfs_device_userstate *ldu;
163         ENTRY;
164
165         ldu = (struct libcfs_device_userstate *)args;
166         if (ldu != NULL) {
167                 kportal_memhog_free(ldu);
168                 LIBCFS_FREE(ldu, sizeof(*ldu));
169         }
170
171         PORTAL_MODULE_UNUSE;
172         RETURN(0);
173 }
174
175 static struct rw_semaphore ioctl_list_sem;
176 static struct list_head ioctl_list;
177
178 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
179 {
180         int rc = 0;
181
182         down_write(&ioctl_list_sem);
183         if (!list_empty(&hand->item))
184                 rc = -EBUSY;
185         else
186                 list_add_tail(&hand->item, &ioctl_list);
187         up_write(&ioctl_list_sem);
188
189         return rc;
190 }
191 EXPORT_SYMBOL(libcfs_register_ioctl);
192
193 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
194 {
195         int rc = 0;
196
197         down_write(&ioctl_list_sem);
198         if (list_empty(&hand->item))
199                 rc = -ENOENT;
200         else
201                 list_del_init(&hand->item);
202         up_write(&ioctl_list_sem);
203
204         return rc;
205 }
206 EXPORT_SYMBOL(libcfs_deregister_ioctl);
207
208 static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
209 {
210         char    buf[1024];
211         int err = -EINVAL;
212         struct libcfs_ioctl_data *data;
213         ENTRY;
214
215         /* 'cmd' and permissions get checked in our arch-specific caller */
216
217         if (libcfs_ioctl_getdata(buf, buf + 800, (void *)arg)) {
218                 CERROR("PORTALS ioctl: data error\n");
219                 RETURN(-EINVAL);
220         }
221         data = (struct libcfs_ioctl_data *)buf;
222
223         switch (cmd) {
224         case IOC_LIBCFS_CLEAR_DEBUG:
225                 libcfs_debug_clear_buffer();
226                 RETURN(0);
227         /*
228          * case IOC_LIBCFS_PANIC:
229          * Handled in arch/cfs_module.c
230          */
231         case IOC_LIBCFS_MARK_DEBUG:
232                 if (data->ioc_inlbuf1 == NULL ||
233                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
234                         RETURN(-EINVAL);
235                 libcfs_debug_mark_buffer(data->ioc_inlbuf1);
236                 RETURN(0);
237 #if LWT_SUPPORT
238         case IOC_LIBCFS_LWT_CONTROL:
239                 err = lwt_control ((data->ioc_flags & 1) != 0, 
240                                    (data->ioc_flags & 2) != 0);
241                 break;
242
243         case IOC_LIBCFS_LWT_SNAPSHOT: {
244                 cycles_t   now;
245                 int        ncpu;
246                 int        total_size;
247
248                 err = lwt_snapshot (&now, &ncpu, &total_size,
249                                     data->ioc_pbuf1, data->ioc_plen1);
250                 data->ioc_u64[0] = now;
251                 data->ioc_u32[0] = ncpu;
252                 data->ioc_u32[1] = total_size;
253
254                 /* Hedge against broken user/kernel typedefs (e.g. cycles_t) */
255                 data->ioc_u32[2] = sizeof(lwt_event_t);
256                 data->ioc_u32[3] = offsetof(lwt_event_t, lwte_where);
257
258                 if (err == 0 &&
259                     libcfs_ioctl_popdata(arg, data, sizeof (*data)))
260                         err = -EFAULT;
261                 break;
262         }
263
264         case IOC_LIBCFS_LWT_LOOKUP_STRING:
265                 err = lwt_lookup_string (&data->ioc_count, data->ioc_pbuf1,
266                                          data->ioc_pbuf2, data->ioc_plen2);
267                 if (err == 0 &&
268                     libcfs_ioctl_popdata(arg, data, sizeof (*data)))
269                         err = -EFAULT;
270                 break;
271 #endif
272         case IOC_LIBCFS_MEMHOG:
273                 if (pfile->private_data == NULL) {
274                         err = -EINVAL;
275                 } else {
276                         kportal_memhog_free(pfile->private_data);
277                         /* XXX The ioc_flags is not GFP flags now, need to be fixed */
278                         err = kportal_memhog_alloc(pfile->private_data,
279                                                    data->ioc_count,
280                                                    data->ioc_flags);
281                         if (err != 0)
282                                 kportal_memhog_free(pfile->private_data);
283                 }
284                 break;
285
286         case IOC_LIBCFS_PING_TEST: {
287                 extern void (kping_client)(struct libcfs_ioctl_data *);
288                 void (*ping)(struct libcfs_ioctl_data *);
289
290                 CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
291                        data->ioc_count, libcfs_nid2str(data->ioc_nid),
292                        libcfs_nid2str(data->ioc_nid));
293                 ping = PORTAL_SYMBOL_GET(kping_client);
294                 if (!ping)
295                         CERROR("PORTAL_SYMBOL_GET failed\n");
296                 else {
297                         ping(data);
298                         PORTAL_SYMBOL_PUT(kping_client);
299                 }
300                 RETURN(0);
301         }
302
303         default: {
304                 struct libcfs_ioctl_handler *hand;
305                 err = -EINVAL;
306                 down_read(&ioctl_list_sem);
307                 list_for_each_entry(hand, &ioctl_list, item) {
308                         err = hand->handle_ioctl(cmd, data);
309                         if (err != -EINVAL) {
310                                 if (err == 0)
311                                         err = libcfs_ioctl_popdata(arg, 
312                                                         data, sizeof (*data));
313                                 break;
314                         }
315                 }
316                 up_read(&ioctl_list_sem);
317                 break;
318         }
319         }
320
321         RETURN(err);
322 }
323
324 struct cfs_psdev_ops libcfs_psdev_ops = {
325         libcfs_psdev_open,
326         libcfs_psdev_release,
327         NULL,
328         NULL,
329         libcfs_ioctl
330 };
331
332 extern int insert_proc(void);
333 extern void remove_proc(void);
334 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
335 MODULE_DESCRIPTION("Portals v3.1");
336 MODULE_LICENSE("GPL");
337
338 extern cfs_psdev_t libcfs_dev;
339 extern struct rw_semaphore tracefile_sem;
340 extern struct semaphore trace_thread_sem;
341
342 extern void libcfs_init_nidstrings(void);
343 extern int libcfs_arch_init(void);
344 extern void libcfs_arch_cleanup(void);
345
346 static int init_libcfs_module(void)
347 {
348         int rc;
349
350         libcfs_arch_init();
351         libcfs_init_nidstrings();
352         init_rwsem(&tracefile_sem);
353         init_mutex(&trace_thread_sem);
354         init_rwsem(&ioctl_list_sem);
355         CFS_INIT_LIST_HEAD(&ioctl_list);
356
357         rc = libcfs_debug_init(5 * 1024 * 1024);
358         if (rc < 0) {
359                 printk(KERN_ERR "LustreError: libcfs_debug_init: %d\n", rc);
360                 return (rc);
361         }
362
363 #if LWT_SUPPORT
364         rc = lwt_init();
365         if (rc != 0) {
366                 CERROR("lwt_init: error %d\n", rc);
367                 goto cleanup_debug;
368         }
369 #endif
370         rc = cfs_psdev_register(&libcfs_dev);
371         if (rc) {
372                 CERROR("misc_register: error %d\n", rc);
373                 goto cleanup_lwt;
374         }
375
376         rc = insert_proc();
377         if (rc) {
378                 CERROR("insert_proc: error %d\n", rc);
379                 goto cleanup_deregister;
380         }
381
382         CDEBUG (D_OTHER, "portals setup OK\n");
383         return (0);
384
385  cleanup_deregister:
386         cfs_psdev_deregister(&libcfs_dev);
387  cleanup_lwt:
388 #if LWT_SUPPORT
389         lwt_fini();
390  cleanup_debug:
391 #endif
392         libcfs_debug_cleanup();
393         return rc;
394 }
395
396 static void exit_libcfs_module(void)
397 {
398         int rc;
399
400         remove_proc();
401
402         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
403                atomic_read(&libcfs_kmemory));
404
405         rc = cfs_psdev_deregister(&libcfs_dev);
406         if (rc)
407                 CERROR("misc_deregister error %d\n", rc);
408
409 #if LWT_SUPPORT
410         lwt_fini();
411 #endif
412
413         if (atomic_read(&libcfs_kmemory) != 0)
414                 CERROR("Portals memory leaked: %d bytes\n",
415                        atomic_read(&libcfs_kmemory));
416
417         rc = libcfs_debug_cleanup();
418         if (rc)
419                 printk(KERN_ERR "LustreError: libcfs_debug_cleanup: %d\n", rc);
420         libcfs_arch_cleanup();
421 }
422
423 cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);