Whamcloud - gitweb
4e63c8644ed5743b850fe1625e761a96356acab0
[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                 cycles_t   now;
406                 int        ncpu;
407                 int        total_size;
408                 
409                 err = lwt_snapshot (&now, &ncpu, &total_size,
410                                     data->ioc_pbuf1, data->ioc_plen1);
411                 data->ioc_nid = now;
412                 data->ioc_count = ncpu;
413                 data->ioc_misc = total_size;
414
415                 if (err == 0 &&
416                     copy_to_user((char *)arg, data, sizeof (*data)))
417                         err = -EFAULT;
418                 break;
419         }
420                 
421         case IOC_PORTAL_LWT_LOOKUP_STRING:
422                 err = lwt_lookup_string (&data->ioc_count, data->ioc_pbuf1,
423                                          data->ioc_pbuf2, data->ioc_plen2);
424                 if (err == 0 &&
425                     copy_to_user((char *)arg, data, sizeof (*data)))
426                         err = -EFAULT;
427                 break;
428 #endif
429         case IOC_PORTAL_NAL_CMD: {
430                 struct portals_cfg pcfg;
431
432                 if (data->ioc_plen1 != sizeof(pcfg)) {
433                         CERROR("Bad ioc_plen1 %d (wanted %d)\n",
434                                data->ioc_plen1, sizeof(pcfg));
435                         err = -EINVAL;
436                         break;
437                 }
438
439                 if (copy_from_user(&pcfg, (void *)data->ioc_pbuf1, 
440                                    sizeof(pcfg))) {
441                         err = -EFAULT;
442                         break;
443                 }
444
445                 CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", pcfg.pcfg_nal,
446                         pcfg.pcfg_command);
447                 err = libcfs_nal_cmd(&pcfg);
448
449                 if (err == 0 &&
450                     copy_to_user((char *)data->ioc_pbuf1, &pcfg, 
451                                  sizeof (pcfg)))
452                         err = -EFAULT;
453                 break;
454         }
455
456         case IOC_PORTAL_MEMHOG:
457                 if (!capable (CAP_SYS_ADMIN))
458                         err = -EPERM;
459                 else if (file->private_data == NULL) {
460                         err = -EINVAL;
461                 } else {
462                         kportal_memhog_free(file->private_data);
463                         err = kportal_memhog_alloc(file->private_data,
464                                                    data->ioc_count,
465                                                    data->ioc_flags);
466                         if (err != 0)
467                                 kportal_memhog_free(file->private_data);
468                 }
469                 break;
470
471         default: {
472                 struct libcfs_ioctl_handler *hand;
473                 err = -EINVAL;
474                 down_read(&ioctl_list_sem);
475                 list_for_each_entry(hand, &ioctl_list, item) {
476                         err = hand->handle_ioctl(data, cmd, arg);
477                         if (err != -EINVAL)
478                                 break;
479                 }
480                 up_read(&ioctl_list_sem);
481                 } break;
482         }
483
484         RETURN(err);
485 }
486
487
488 static struct file_operations libcfs_fops = {
489         ioctl:   libcfs_ioctl,
490         open:    libcfs_psdev_open,
491         release: libcfs_psdev_release
492 };
493
494
495 static struct miscdevice libcfs_dev = {
496         PORTAL_MINOR,
497         "portals",
498         &libcfs_fops
499 };
500
501 extern int insert_proc(void);
502 extern void remove_proc(void);
503 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
504 MODULE_DESCRIPTION("Portals v3.1");
505 MODULE_LICENSE("GPL");
506
507 static int init_libcfs_module(void)
508 {
509         int rc;
510
511         rc = portals_debug_init(5 * 1024 * 1024);
512         if (rc < 0) {
513                 printk(KERN_ERR "LustreError: portals_debug_init: %d\n", rc);
514                 return (rc);
515         }
516
517 #if LWT_SUPPORT
518         rc = lwt_init();
519         if (rc != 0) {
520                 CERROR("lwt_init: error %d\n", rc);
521                 goto cleanup_debug;
522         }
523 #endif
524         rc = misc_register(&libcfs_dev);
525         if (rc) {
526                 CERROR("misc_register: error %d\n", rc);
527                 goto cleanup_lwt;
528         }
529
530         rc = insert_proc();
531         if (rc) {
532                 CERROR("insert_proc: error %d\n", rc);
533                 goto cleanup_deregister;
534         }
535
536         CDEBUG (D_OTHER, "portals setup OK\n");
537         return (0);
538
539  cleanup_deregister:
540         misc_deregister(&libcfs_dev);
541  cleanup_lwt:
542 #if LWT_SUPPORT
543         lwt_fini();
544  cleanup_debug:
545 #endif
546         portals_debug_cleanup();
547         return rc;
548 }
549
550 static void exit_libcfs_module(void)
551 {
552         int rc;
553
554         remove_proc();
555
556         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
557                atomic_read(&portal_kmemory));
558
559
560         rc = misc_deregister(&libcfs_dev);
561         if (rc)
562                 CERROR("misc_deregister error %d\n", rc);
563
564 #if LWT_SUPPORT
565         lwt_fini();
566 #endif
567
568         if (atomic_read(&portal_kmemory) != 0)
569                 CERROR("Portals memory leaked: %d bytes\n",
570                        atomic_read(&portal_kmemory));
571
572         rc = portals_debug_cleanup();
573         if (rc)
574                 printk(KERN_ERR "LustreError: portals_debug_cleanup: %d\n", rc);
575 }
576
577 EXPORT_SYMBOL(kportal_daemonize);
578 EXPORT_SYMBOL(kportal_blockallsigs);
579 EXPORT_SYMBOL(kportal_assertion_failed);
580
581 module_init(init_libcfs_module);
582 module_exit(exit_libcfs_module);