Whamcloud - gitweb
a53ea6b41e8bbec1b84ee8090f9e0cb7a91975e7
[fs/lustre-release.git] / lnet / 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_PORTALS
26
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/mm.h>
31 #include <linux/string.h>
32 #include <linux/stat.h>
33 #include <linux/init.h>
34 #include <linux/errno.h>
35 #include <linux/smp_lock.h>
36 #include <linux/unistd.h>
37
38 #include <asm/system.h>
39 #include <asm/uaccess.h>
40
41 #include <linux/fs.h>
42 #include <linux/stat.h>
43 #include <asm/uaccess.h>
44 #include <asm/segment.h>
45 #include <linux/miscdevice.h>
46
47 #include <portals/lib-p30.h>
48 #include <portals/p30.h>
49 #include <linux/kp30.h>
50 #include <linux/portals_compat25.h>
51
52 #define PORTAL_MINOR 240
53
54 struct nal_cmd_handler {
55         nal_cmd_handler_fn  *nch_handler;
56         void                *nch_private;
57 };
58
59 static struct nal_cmd_handler nal_cmd[NAL_MAX_NR + 1];
60 static DECLARE_MUTEX(nal_cmd_sem);
61
62 #ifdef PORTAL_DEBUG
63 void kportal_assertion_failed(char *expr, char *file, const char *func,
64                               const int line)
65 {
66         portals_debug_msg(0, D_EMERG, file, func, line, CDEBUG_STACK,
67                           "ASSERTION(%s) failed\n", expr);
68         LBUG_WITH_LOC(file, func, line);
69 }
70 #endif
71
72 void
73 kportal_daemonize (char *str) 
74 {
75 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,63))
76         daemonize(str);
77 #else
78         daemonize();
79         snprintf (current->comm, sizeof (current->comm), "%s", str);
80 #endif
81 }
82
83 void
84 kportal_memhog_free (struct portals_device_userstate *pdu)
85 {
86         struct page **level0p = &pdu->pdu_memhog_root_page;
87         struct page **level1p;
88         struct page **level2p;
89         int           count1;
90         int           count2;
91         
92         if (*level0p != NULL) {
93
94                 level1p = (struct page **)page_address(*level0p);
95                 count1 = 0;
96                 
97                 while (count1 < PAGE_SIZE/sizeof(struct page *) &&
98                        *level1p != NULL) {
99
100                         level2p = (struct page **)page_address(*level1p);
101                         count2 = 0;
102                         
103                         while (count2 < PAGE_SIZE/sizeof(struct page *) &&
104                                *level2p != NULL) {
105                                 
106                                 __free_page(*level2p);
107                                 pdu->pdu_memhog_pages--;
108                                 level2p++;
109                                 count2++;
110                         }
111                         
112                         __free_page(*level1p);
113                         pdu->pdu_memhog_pages--;
114                         level1p++;
115                         count1++;
116                 }
117                 
118                 __free_page(*level0p);
119                 pdu->pdu_memhog_pages--;
120
121                 *level0p = NULL;
122         }
123         
124         LASSERT (pdu->pdu_memhog_pages == 0);
125 }
126
127 int
128 kportal_memhog_alloc (struct portals_device_userstate *pdu, int npages, int flags)
129 {
130         struct page **level0p;
131         struct page **level1p;
132         struct page **level2p;
133         int           count1;
134         int           count2;
135         
136         LASSERT (pdu->pdu_memhog_pages == 0);
137         LASSERT (pdu->pdu_memhog_root_page == NULL);
138
139         if (npages < 0)
140                 return -EINVAL;
141
142         if (npages == 0)
143                 return 0;
144
145         level0p = &pdu->pdu_memhog_root_page;
146         *level0p = alloc_page(flags);
147         if (*level0p == NULL)
148                 return -ENOMEM;
149         pdu->pdu_memhog_pages++;
150
151         level1p = (struct page **)page_address(*level0p);
152         count1 = 0;
153         memset(level1p, 0, PAGE_SIZE);
154         
155         while (pdu->pdu_memhog_pages < npages &&
156                count1 < PAGE_SIZE/sizeof(struct page *)) {
157
158                 if (signal_pending(current))
159                         return (-EINTR);
160                 
161                 *level1p = alloc_page(flags);
162                 if (*level1p == NULL)
163                         return -ENOMEM;
164                 pdu->pdu_memhog_pages++;
165
166                 level2p = (struct page **)page_address(*level1p);
167                 count2 = 0;
168                 memset(level2p, 0, PAGE_SIZE);
169                 
170                 while (pdu->pdu_memhog_pages < npages &&
171                        count2 < PAGE_SIZE/sizeof(struct page *)) {
172                         
173                         if (signal_pending(current))
174                                 return (-EINTR);
175
176                         *level2p = alloc_page(flags);
177                         if (*level2p == NULL)
178                                 return (-ENOMEM);
179                         pdu->pdu_memhog_pages++;
180                         
181                         level2p++;
182                         count2++;
183                 }
184                 
185                 level1p++;
186                 count1++;
187         }
188
189         return 0;
190 }
191
192 void
193 kportal_blockallsigs ()
194 {
195         unsigned long  flags;
196
197         SIGNAL_MASK_LOCK(current, flags);
198         sigfillset(&current->blocked);
199         RECALC_SIGPENDING;
200         SIGNAL_MASK_UNLOCK(current, flags);
201 }
202
203 /* called when opening /dev/device */
204 static int libcfs_psdev_open(struct inode * inode, struct file * file)
205 {
206         struct portals_device_userstate *pdu;
207         ENTRY;
208         
209         if (!inode)
210                 RETURN(-EINVAL);
211
212         PORTAL_MODULE_USE;
213
214         PORTAL_ALLOC(pdu, sizeof(*pdu));
215         if (pdu != NULL) {
216                 pdu->pdu_memhog_pages = 0;
217                 pdu->pdu_memhog_root_page = NULL;
218         }
219         file->private_data = pdu;
220         
221         RETURN(0);
222 }
223
224 /* called when closing /dev/device */
225 static int libcfs_psdev_release(struct inode * inode, struct file * file)
226 {
227         struct portals_device_userstate *pdu;
228         ENTRY;
229
230         if (!inode)
231                 RETURN(-EINVAL);
232
233         pdu = file->private_data;
234         if (pdu != NULL) {
235                 kportal_memhog_free(pdu);
236                 PORTAL_FREE(pdu, sizeof(*pdu));
237         }
238         
239         PORTAL_MODULE_UNUSE;
240         RETURN(0);
241 }
242
243 static inline void freedata(void *data, int len)
244 {
245         PORTAL_FREE(data, len);
246 }
247
248 int
249 libcfs_nal_cmd_register(int nal, nal_cmd_handler_fn *handler, void *private)
250 {
251         int rc = 0;
252
253         CDEBUG(D_IOCTL, "Register NAL %d, handler: %p\n", nal, handler);
254
255         if (nal > 0  && nal <= NAL_MAX_NR) {
256                 down(&nal_cmd_sem);
257                 if (nal_cmd[nal].nch_handler != NULL)
258                         rc = -EBUSY;
259                 else {
260                         nal_cmd[nal].nch_handler = handler;
261                         nal_cmd[nal].nch_private = private;
262                 }
263                 up(&nal_cmd_sem);
264         }
265         return rc;
266 }
267 EXPORT_SYMBOL(libcfs_nal_cmd_register);
268
269 void
270 libcfs_nal_cmd_unregister(int nal)
271 {
272         CDEBUG(D_IOCTL, "Unregister NAL %d\n", nal);
273
274         LASSERT(nal > 0 && nal <= NAL_MAX_NR);
275         LASSERT(nal_cmd[nal].nch_handler != NULL);
276
277         down(&nal_cmd_sem);
278         nal_cmd[nal].nch_handler = NULL;
279         nal_cmd[nal].nch_private = NULL;
280         up(&nal_cmd_sem);
281 }
282 EXPORT_SYMBOL(libcfs_nal_cmd_unregister);
283
284 int
285 libcfs_nal_cmd(struct portals_cfg *pcfg)
286 {
287         __u32 nal = pcfg->pcfg_nal;
288         int   rc = -EINVAL;
289         ENTRY;
290
291         down(&nal_cmd_sem);
292         if (nal > 0 && nal <= NAL_MAX_NR && 
293             nal_cmd[nal].nch_handler != NULL) {
294                 CDEBUG(D_IOCTL, "calling handler nal: %d, cmd: %d\n", nal, 
295                        pcfg->pcfg_command);
296                 rc = nal_cmd[nal].nch_handler(pcfg, nal_cmd[nal].nch_private);
297         }
298         up(&nal_cmd_sem);
299
300         RETURN(rc);
301 }
302 EXPORT_SYMBOL(libcfs_nal_cmd);
303
304 static DECLARE_RWSEM(ioctl_list_sem);
305 static LIST_HEAD(ioctl_list);
306
307 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
308 {
309         int rc = 0;
310         down_read(&ioctl_list_sem);
311         if (!list_empty(&hand->item))
312                 rc = -EBUSY;
313         up_read(&ioctl_list_sem);
314
315         if (rc == 0) {
316                 down_write(&ioctl_list_sem);
317                 list_add_tail(&hand->item, &ioctl_list);
318                 up_write(&ioctl_list_sem);
319         }
320         RETURN(0);
321 }
322 EXPORT_SYMBOL(libcfs_register_ioctl);
323
324 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
325 {
326         int rc = 0;
327         down_read(&ioctl_list_sem);
328         if (list_empty(&hand->item))
329                 rc = -ENOENT;
330         up_read(&ioctl_list_sem);
331
332         if (rc == 0) {
333                 down_write(&ioctl_list_sem);
334                 list_del_init(&hand->item);
335                 up_write(&ioctl_list_sem);
336         }
337         RETURN(0);
338 }
339 EXPORT_SYMBOL(libcfs_deregister_ioctl);
340
341 static int libcfs_ioctl(struct inode *inode, struct file *file,
342                         unsigned int cmd, unsigned long arg)
343 {
344         int err = -EINVAL;
345         char buf[1024];
346         struct portal_ioctl_data *data;
347         ENTRY;
348
349         if (current->fsuid != 0)
350                 RETURN(err = -EACCES);
351
352         if ( _IOC_TYPE(cmd) != IOC_PORTAL_TYPE ||
353              _IOC_NR(cmd) < IOC_PORTAL_MIN_NR  ||
354              _IOC_NR(cmd) > IOC_PORTAL_MAX_NR ) {
355                 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
356                                 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
357                 RETURN(-EINVAL);
358         }
359
360         if (portal_ioctl_getdata(buf, buf + 800, (void *)arg)) {
361                 CERROR("PORTALS ioctl: data error\n");
362                 RETURN(-EINVAL);
363         }
364
365         data = (struct portal_ioctl_data *)buf;
366
367         switch (cmd) {
368         case IOC_PORTAL_SET_DAEMON: 
369                 RETURN (portals_debug_set_daemon ( 
370                                         (unsigned int) data->ioc_count,
371                                         (unsigned int) data->ioc_inllen1,
372                                         (char *) data->ioc_inlbuf1,
373                                         (unsigned int) data->ioc_misc)); 
374         case IOC_PORTAL_GET_DEBUG: {
375                 __s32 size = portals_debug_copy_to_user(data->ioc_pbuf1,
376                                                         data->ioc_plen1);
377
378                 if (size < 0)
379                         RETURN(size);
380
381                 data->ioc_size = size;
382                 err = copy_to_user((char *)arg, data, sizeof(*data));
383                 RETURN(err);
384         }
385         case IOC_PORTAL_CLEAR_DEBUG:
386                 portals_debug_clear_buffer();
387                 RETURN(0);
388         case IOC_PORTAL_PANIC:
389                 if (!capable (CAP_SYS_BOOT))
390                         RETURN (-EPERM);
391                 panic("debugctl-invoked panic");
392                 RETURN(0);
393         case IOC_PORTAL_MARK_DEBUG:
394                 if (data->ioc_inlbuf1 == NULL ||
395                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
396                         RETURN(-EINVAL);
397                 portals_debug_mark_buffer(data->ioc_inlbuf1);
398                 RETURN(0);
399 #if LWT_SUPPORT
400         case IOC_PORTAL_LWT_CONTROL: 
401                 err = lwt_control (data->ioc_flags, data->ioc_misc);
402                 break;
403                 
404         case IOC_PORTAL_LWT_SNAPSHOT:
405                 err = lwt_snapshot (&data->ioc_nid,
406                                     &data->ioc_count, &data->ioc_misc,
407                                     data->ioc_pbuf1, data->ioc_plen1);
408                 if (err == 0 &&
409                     copy_to_user((char *)arg, data, sizeof (*data)))
410                         err = -EFAULT;
411                 break;
412                 
413         case IOC_PORTAL_LWT_LOOKUP_STRING:
414                 err = lwt_lookup_string (&data->ioc_count, data->ioc_pbuf1,
415                                          data->ioc_pbuf2, data->ioc_plen2);
416                 if (err == 0 &&
417                     copy_to_user((char *)arg, data, sizeof (*data)))
418                         err = -EFAULT;
419                 break;
420 #endif
421         case IOC_PORTAL_NAL_CMD: {
422                 struct portals_cfg pcfg;
423
424                 LASSERT (data->ioc_plen1 == sizeof(pcfg));
425                 if (copy_from_user(&pcfg, (void *)data->ioc_pbuf1, 
426                                    sizeof(pcfg))) {
427                         err = -EFAULT;
428                         break;
429                 }
430
431                 CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", pcfg.pcfg_nal,
432                         pcfg.pcfg_command);
433                 err = libcfs_nal_cmd(&pcfg);
434
435                 if (err == 0 &&
436                     copy_to_user((char *)data->ioc_pbuf1, &pcfg, 
437                                  sizeof (pcfg)))
438                         err = -EFAULT;
439                 break;
440         }
441
442         case IOC_PORTAL_MEMHOG:
443                 if (!capable (CAP_SYS_ADMIN))
444                         err = -EPERM;
445                 else if (file->private_data == NULL) {
446                         err = -EINVAL;
447                 } else {
448                         kportal_memhog_free(file->private_data);
449                         err = kportal_memhog_alloc(file->private_data,
450                                                    data->ioc_count,
451                                                    data->ioc_flags);
452                         if (err != 0)
453                                 kportal_memhog_free(file->private_data);
454                 }
455                 break;
456
457         default: {
458                 struct libcfs_ioctl_handler *hand;
459                 err = -EINVAL;
460                 down_read(&ioctl_list_sem);
461                 list_for_each_entry(hand, &ioctl_list, item) {
462                         err = hand->handle_ioctl(data, cmd, arg);
463                         if (err != -EINVAL)
464                                 break;
465                 }
466                 up_read(&ioctl_list_sem);
467                 } break;
468         }
469
470         RETURN(err);
471 }
472
473
474 static struct file_operations libcfs_fops = {
475         ioctl:   libcfs_ioctl,
476         open:    libcfs_psdev_open,
477         release: libcfs_psdev_release
478 };
479
480
481 static struct miscdevice libcfs_dev = {
482         PORTAL_MINOR,
483         "portals",
484         &libcfs_fops
485 };
486
487 extern int insert_proc(void);
488 extern void remove_proc(void);
489 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
490 MODULE_DESCRIPTION("Portals v3.1");
491 MODULE_LICENSE("GPL");
492
493 static int init_libcfs_module(void)
494 {
495         int rc;
496
497         rc = portals_debug_init(5 * 1024 * 1024);
498         if (rc < 0) {
499                 printk(KERN_ERR "LustreError: portals_debug_init: %d\n", rc);
500                 return (rc);
501         }
502
503 #if LWT_SUPPORT
504         rc = lwt_init();
505         if (rc != 0) {
506                 CERROR("lwt_init: error %d\n", rc);
507                 goto cleanup_debug;
508         }
509 #endif
510         rc = misc_register(&libcfs_dev);
511         if (rc) {
512                 CERROR("misc_register: error %d\n", rc);
513                 goto cleanup_lwt;
514         }
515
516         rc = insert_proc();
517         if (rc) {
518                 CERROR("insert_proc: error %d\n", rc);
519                 goto cleanup_deregister;
520         }
521
522         CDEBUG (D_OTHER, "portals setup OK\n");
523         return (0);
524
525  cleanup_deregister:
526         misc_deregister(&libcfs_dev);
527  cleanup_lwt:
528 #if LWT_SUPPORT
529         lwt_fini();
530  cleanup_debug:
531 #endif
532         portals_debug_cleanup();
533         return rc;
534 }
535
536 static void exit_libcfs_module(void)
537 {
538         int rc;
539
540         remove_proc();
541
542         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
543                atomic_read(&portal_kmemory));
544
545
546         rc = misc_deregister(&libcfs_dev);
547         if (rc)
548                 CERROR("misc_deregister error %d\n", rc);
549
550 #if LWT_SUPPORT
551         lwt_fini();
552 #endif
553
554         if (atomic_read(&portal_kmemory) != 0)
555                 CERROR("Portals memory leaked: %d bytes\n",
556                        atomic_read(&portal_kmemory));
557
558         rc = portals_debug_cleanup();
559         if (rc)
560                 printk(KERN_ERR "LustreError: portals_debug_cleanup: %d\n", rc);
561 }
562
563 EXPORT_SYMBOL(kportal_daemonize);
564 EXPORT_SYMBOL(kportal_blockallsigs);
565 EXPORT_SYMBOL(kportal_assertion_failed);
566
567 module_init(init_libcfs_module);
568 module_exit(exit_libcfs_module);