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