Whamcloud - gitweb
* landed unified portals (b_hd_cleanup_merge_singleportals) on HEAD
[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 %d, 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 %d\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         struct nal_cmd_handler *cmd;
320         __u32 nal = pcfg->pcfg_nal;
321         int   rc = -EINVAL;
322         ENTRY;
323
324         down(&nal_cmd_sem);
325         cmd = libcfs_find_nal_cmd_handler(nal);
326         if (cmd != NULL) {
327                 CDEBUG(D_IOCTL, "calling handler nal: %d, cmd: %d\n", nal, 
328                        pcfg->pcfg_command);
329                 rc = cmd->nch_handler(pcfg, cmd->nch_private);
330         } else {
331                 CERROR("invalid nal: %d, cmd: %d\n", nal, pcfg->pcfg_command);
332         }
333         up(&nal_cmd_sem);
334
335         RETURN(rc);
336 }
337 EXPORT_SYMBOL(libcfs_nal_cmd);
338
339 static DECLARE_RWSEM(ioctl_list_sem);
340 static LIST_HEAD(ioctl_list);
341
342 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
343 {
344         int rc = 0;
345         down_read(&ioctl_list_sem);
346         if (!list_empty(&hand->item))
347                 rc = -EBUSY;
348         up_read(&ioctl_list_sem);
349
350         if (rc == 0) {
351                 down_write(&ioctl_list_sem);
352                 list_add_tail(&hand->item, &ioctl_list);
353                 up_write(&ioctl_list_sem);
354         }
355         RETURN(0);
356 }
357 EXPORT_SYMBOL(libcfs_register_ioctl);
358
359 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
360 {
361         int rc = 0;
362         down_read(&ioctl_list_sem);
363         if (list_empty(&hand->item))
364                 rc = -ENOENT;
365         up_read(&ioctl_list_sem);
366
367         if (rc == 0) {
368                 down_write(&ioctl_list_sem);
369                 list_del_init(&hand->item);
370                 up_write(&ioctl_list_sem);
371         }
372         RETURN(0);
373 }
374 EXPORT_SYMBOL(libcfs_deregister_ioctl);
375
376 static int libcfs_ioctl(struct inode *inode, struct file *file,
377                         unsigned int cmd, unsigned long arg)
378 {
379         int err = -EINVAL;
380         char buf[1024];
381         struct portal_ioctl_data *data;
382         ENTRY;
383
384         if (current->fsuid != 0)
385                 RETURN(err = -EACCES);
386
387         if ( _IOC_TYPE(cmd) != IOC_PORTAL_TYPE ||
388              _IOC_NR(cmd) < IOC_PORTAL_MIN_NR  ||
389              _IOC_NR(cmd) > IOC_PORTAL_MAX_NR ) {
390                 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
391                                 _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
392                 RETURN(-EINVAL);
393         }
394
395         if (portal_ioctl_getdata(buf, buf + 800, (void *)arg)) {
396                 CERROR("PORTALS ioctl: data error\n");
397                 RETURN(-EINVAL);
398         }
399
400         data = (struct portal_ioctl_data *)buf;
401
402         switch (cmd) {
403         case IOC_PORTAL_CLEAR_DEBUG:
404                 portals_debug_clear_buffer();
405                 RETURN(0);
406         case IOC_PORTAL_PANIC:
407                 if (!capable (CAP_SYS_BOOT))
408                         RETURN (-EPERM);
409                 panic("debugctl-invoked panic");
410                 RETURN(0);
411         case IOC_PORTAL_MARK_DEBUG:
412                 if (data->ioc_inlbuf1 == NULL ||
413                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
414                         RETURN(-EINVAL);
415                 portals_debug_mark_buffer(data->ioc_inlbuf1);
416                 RETURN(0);
417 #if LWT_SUPPORT
418         case IOC_PORTAL_LWT_CONTROL:
419                 err = lwt_control (data->ioc_flags, data->ioc_misc);
420                 break;
421
422         case IOC_PORTAL_LWT_SNAPSHOT: {
423                 cycles_t   now;
424                 int        ncpu;
425                 int        total_size;
426
427                 err = lwt_snapshot (&now, &ncpu, &total_size,
428                                     data->ioc_pbuf1, data->ioc_plen1);
429                 data->ioc_nid = now;
430                 data->ioc_count = ncpu;
431                 data->ioc_misc = total_size;
432
433                 /* Hedge against broken user/kernel typedefs (e.g. cycles_t) */
434                 data->ioc_nid2 = sizeof(lwt_event_t);
435                 data->ioc_nid3 = offsetof(lwt_event_t, lwte_where);
436
437                 if (err == 0 &&
438                     copy_to_user((char *)arg, data, sizeof (*data)))
439                         err = -EFAULT;
440                 break;
441         }
442
443         case IOC_PORTAL_LWT_LOOKUP_STRING:
444                 err = lwt_lookup_string (&data->ioc_count, data->ioc_pbuf1,
445                                          data->ioc_pbuf2, data->ioc_plen2);
446                 if (err == 0 &&
447                     copy_to_user((char *)arg, data, sizeof (*data)))
448                         err = -EFAULT;
449                 break;
450 #endif
451         case IOC_PORTAL_NAL_CMD: {
452                 struct portals_cfg pcfg;
453
454                 if (data->ioc_plen1 != sizeof(pcfg)) {
455                         CERROR("Bad ioc_plen1 %d (wanted %d)\n",
456                                data->ioc_plen1, sizeof(pcfg));
457                         err = -EINVAL;
458                         break;
459                 }
460
461                 if (copy_from_user(&pcfg, (void *)data->ioc_pbuf1,
462                                    sizeof(pcfg))) {
463                         err = -EFAULT;
464                         break;
465                 }
466
467                 CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", pcfg.pcfg_nal,
468                         pcfg.pcfg_command);
469                 err = libcfs_nal_cmd(&pcfg);
470
471                 if (err == 0 &&
472                     copy_to_user((char *)data->ioc_pbuf1, &pcfg,
473                                  sizeof (pcfg)))
474                         err = -EFAULT;
475                 break;
476         }
477
478         case IOC_PORTAL_MEMHOG:
479                 if (!capable (CAP_SYS_ADMIN))
480                         err = -EPERM;
481                 else if (file->private_data == NULL) {
482                         err = -EINVAL;
483                 } else {
484                         kportal_memhog_free(file->private_data);
485                         err = kportal_memhog_alloc(file->private_data,
486                                                    data->ioc_count,
487                                                    data->ioc_flags);
488                         if (err != 0)
489                                 kportal_memhog_free(file->private_data);
490                 }
491                 break;
492
493         default: {
494                 struct libcfs_ioctl_handler *hand;
495                 err = -EINVAL;
496                 down_read(&ioctl_list_sem);
497                 list_for_each_entry(hand, &ioctl_list, item) {
498                         err = hand->handle_ioctl(data, cmd, arg);
499                         if (err != -EINVAL)
500                                 break;
501                 }
502                 up_read(&ioctl_list_sem);
503                 } break;
504         }
505
506         RETURN(err);
507 }
508
509
510 static struct file_operations libcfs_fops = {
511         ioctl:   libcfs_ioctl,
512         open:    libcfs_psdev_open,
513         release: libcfs_psdev_release
514 };
515
516
517 static struct miscdevice libcfs_dev = {
518         PORTAL_MINOR,
519         "portals",
520         &libcfs_fops
521 };
522
523 extern int insert_proc(void);
524 extern void remove_proc(void);
525 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
526 MODULE_DESCRIPTION("Portals v3.1");
527 MODULE_LICENSE("GPL");
528
529 static int init_libcfs_module(void)
530 {
531         int rc;
532
533         rc = portals_debug_init(5 * 1024 * 1024);
534         if (rc < 0) {
535                 printk(KERN_ERR "LustreError: portals_debug_init: %d\n", rc);
536                 return (rc);
537         }
538
539 #if LWT_SUPPORT
540         rc = lwt_init();
541         if (rc != 0) {
542                 CERROR("lwt_init: error %d\n", rc);
543                 goto cleanup_debug;
544         }
545 #endif
546         rc = misc_register(&libcfs_dev);
547         if (rc) {
548                 CERROR("misc_register: error %d\n", rc);
549                 goto cleanup_lwt;
550         }
551
552         rc = insert_proc();
553         if (rc) {
554                 CERROR("insert_proc: error %d\n", rc);
555                 goto cleanup_deregister;
556         }
557
558         CDEBUG (D_OTHER, "portals setup OK\n");
559         return (0);
560
561  cleanup_deregister:
562         misc_deregister(&libcfs_dev);
563  cleanup_lwt:
564 #if LWT_SUPPORT
565         lwt_fini();
566  cleanup_debug:
567 #endif
568         portals_debug_cleanup();
569         return rc;
570 }
571
572 static void exit_libcfs_module(void)
573 {
574         int rc;
575
576         remove_proc();
577
578         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
579                atomic_read(&portal_kmemory));
580
581         rc = misc_deregister(&libcfs_dev);
582         if (rc)
583                 CERROR("misc_deregister error %d\n", rc);
584
585 #if LWT_SUPPORT
586         lwt_fini();
587 #endif
588
589         if (atomic_read(&portal_kmemory) != 0)
590                 CERROR("Portals memory leaked: %d bytes\n",
591                        atomic_read(&portal_kmemory));
592
593         rc = portals_debug_cleanup();
594         if (rc)
595                 printk(KERN_ERR "LustreError: portals_debug_cleanup: %d\n", rc);
596 }
597
598 EXPORT_SYMBOL(kportal_daemonize);
599 EXPORT_SYMBOL(kportal_blockallsigs);
600 EXPORT_SYMBOL(kportal_assertion_failed);
601
602 module_init(init_libcfs_module);
603 module_exit(exit_libcfs_module);