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