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