Whamcloud - gitweb
5fe401bc8f3b6e35a2010eee1478a7f53982ac22
[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         mutex_down(&nal_cmd_mutex);
278         cmd = libcfs_find_nal_cmd_handler(nal);
279         if (cmd != NULL) {
280                 CDEBUG(D_IOCTL, "calling handler nal: %x, cmd: %d\n", nal,
281                        pcfg->pcfg_command);
282                 rc = cmd->nch_handler(pcfg, cmd->nch_private);
283         } else {
284                 CERROR("invalid nal: %x, cmd: %d\n", nal, pcfg->pcfg_command);
285         }
286         mutex_up(&nal_cmd_mutex);
287
288         RETURN(rc);
289 #endif
290 }
291 EXPORT_SYMBOL(libcfs_nal_cmd);
292
293 static struct rw_semaphore ioctl_list_sem;
294 static struct list_head ioctl_list;
295
296 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
297 {
298         int rc = 0;
299         down_read(&ioctl_list_sem);
300         if (!list_empty(&hand->item))
301                 rc = -EBUSY;
302         up_read(&ioctl_list_sem);
303
304         if (rc == 0) {
305                 down_write(&ioctl_list_sem);
306                 list_add_tail(&hand->item, &ioctl_list);
307                 up_write(&ioctl_list_sem);
308         }
309         RETURN(0);
310 }
311 EXPORT_SYMBOL(libcfs_register_ioctl);
312
313 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
314 {
315         int rc = 0;
316         down_read(&ioctl_list_sem);
317         if (list_empty(&hand->item))
318                 rc = -ENOENT;
319         up_read(&ioctl_list_sem);
320
321         if (rc == 0) {
322                 down_write(&ioctl_list_sem);
323                 list_del_init(&hand->item);
324                 up_write(&ioctl_list_sem);
325         }
326         RETURN(0);
327 }
328 EXPORT_SYMBOL(libcfs_deregister_ioctl);
329
330 static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
331 {
332         char    buf[1024];
333         int err = -EINVAL;
334         struct portal_ioctl_data *data;
335         ENTRY;
336
337         /* 'cmd' and permissions get checked in our arch-specific caller */
338
339         if (portal_ioctl_getdata(buf, buf + 800, (void *)arg)) {
340                 CERROR("PORTALS ioctl: data error\n");
341                 return (-EINVAL);
342         }
343         data = (struct portal_ioctl_data *)buf;
344
345         switch (cmd) {
346         case IOC_PORTAL_CLEAR_DEBUG:
347                 portals_debug_clear_buffer();
348                 RETURN(0);
349         /*
350          * case IOC_PORTAL_PANIC:
351          * Handled in arch/cfs_module.c
352          */
353         case IOC_PORTAL_MARK_DEBUG:
354                 if (data->ioc_inlbuf1 == NULL ||
355                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
356                         RETURN(-EINVAL);
357                 portals_debug_mark_buffer(data->ioc_inlbuf1);
358                 RETURN(0);
359 #if LWT_SUPPORT
360         case IOC_PORTAL_LWT_CONTROL:
361                 err = lwt_control (data->ioc_flags, data->ioc_misc);
362                 break;
363
364         case IOC_PORTAL_LWT_SNAPSHOT: {
365                 cycles_t   now;
366                 int        ncpu;
367                 int        total_size;
368
369                 err = lwt_snapshot (&now, &ncpu, &total_size,
370                                     data->ioc_pbuf1, data->ioc_plen1);
371                 data->ioc_nid = now;
372                 data->ioc_count = ncpu;
373                 data->ioc_misc = total_size;
374
375                 /* Hedge against broken user/kernel typedefs (e.g. cycles_t) */
376                 data->ioc_nid2 = sizeof(lwt_event_t);
377                 data->ioc_nid3 = offsetof(lwt_event_t, lwte_where);
378
379                 if (err == 0 &&
380                     copy_to_user((char *)arg, data, sizeof (*data)))
381                         err = -EFAULT;
382                 break;
383         }
384
385         case IOC_PORTAL_LWT_LOOKUP_STRING:
386                 err = lwt_lookup_string (&data->ioc_count, data->ioc_pbuf1,
387                                          data->ioc_pbuf2, data->ioc_plen2);
388                 if (err == 0 &&
389                     copy_to_user((char *)arg, data, sizeof (*data)))
390                         err = -EFAULT;
391                 break;
392 #endif
393         case IOC_PORTAL_NAL_CMD: {
394                 struct portals_cfg pcfg;
395
396                 if (data->ioc_plen1 != sizeof(pcfg)) {
397                         CERROR("Bad ioc_plen1 %d (wanted "LPSZ")\n",
398                                data->ioc_plen1, sizeof(pcfg));
399                         err = -EINVAL;
400                         break;
401                 }
402
403                 if (copy_from_user(&pcfg, (void *)data->ioc_pbuf1,
404                                    sizeof(pcfg))) {
405                         err = -EFAULT;
406                         break;
407                 }
408
409                 CDEBUG (D_IOCTL, "nal command nal %x cmd %d\n", pcfg.pcfg_nal,
410                         pcfg.pcfg_command);
411                 err = libcfs_nal_cmd(&pcfg);
412
413                 if (err == 0 &&
414                     copy_to_user((char *)data->ioc_pbuf1, &pcfg,
415                                  sizeof (pcfg)))
416                         err = -EFAULT;
417                 break;
418         }
419
420         case IOC_PORTAL_MEMHOG:
421                 if (pfile->private_data == NULL) {
422                         err = -EINVAL;
423                 } else {
424                         kportal_memhog_free(pfile->private_data);
425                         /* XXX The ioc_flags is not GFP flags now, need to be fixed */
426                         err = kportal_memhog_alloc(pfile->private_data,
427                                                    data->ioc_count,
428                                                    data->ioc_flags);
429                         if (err != 0)
430                                 kportal_memhog_free(pfile->private_data);
431                 }
432                 break;
433
434         default: {
435                 struct libcfs_ioctl_handler *hand;
436                 err = -EINVAL;
437                 down_read(&ioctl_list_sem);
438                 list_for_each_entry(hand, &ioctl_list, item) {
439                         err = hand->handle_ioctl(data, cmd, (unsigned long)arg);
440                         if (err != -EINVAL)
441                                 break;
442                 }
443                 up_read(&ioctl_list_sem);
444                 } break;
445         }
446
447         RETURN(err);
448 }
449
450 struct cfs_psdev_ops libcfs_psdev_ops = {
451         libcfs_psdev_open,
452         libcfs_psdev_release,
453         NULL,
454         NULL,
455         libcfs_ioctl
456 };
457
458 extern int insert_proc(void);
459 extern void remove_proc(void);
460 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
461 MODULE_DESCRIPTION("Portals v3.1");
462 MODULE_LICENSE("GPL");
463
464 extern cfs_psdev_t libcfs_dev;
465 extern struct rw_semaphore tracefile_sem;
466 extern struct semaphore trace_thread_sem;
467
468 extern int libcfs_arch_init(void);
469 extern void libcfs_arch_cleanup(void);
470
471 static int init_libcfs_module(void)
472 {
473         int rc;
474
475         libcfs_arch_init();
476         init_rwsem(&tracefile_sem);
477         init_mutex(&trace_thread_sem);
478         init_mutex(&nal_cmd_mutex);
479         init_rwsem(&ioctl_list_sem);
480         CFS_INIT_LIST_HEAD(&ioctl_list);
481
482         rc = portals_debug_init(5 * 1024 * 1024);
483         if (rc < 0) {
484                 printk(KERN_ERR "LustreError: portals_debug_init: %d\n", rc);
485                 return (rc);
486         }
487
488 #if LWT_SUPPORT
489         rc = lwt_init();
490         if (rc != 0) {
491                 CERROR("lwt_init: error %d\n", rc);
492                 goto cleanup_debug;
493         }
494 #endif
495         rc = cfs_psdev_register(&libcfs_dev);
496         if (rc) {
497                 CERROR("misc_register: error %d\n", rc);
498                 goto cleanup_lwt;
499         }
500
501         rc = insert_proc();
502         if (rc) {
503                 CERROR("insert_proc: error %d\n", rc);
504                 goto cleanup_deregister;
505         }
506
507         CDEBUG (D_OTHER, "portals setup OK\n");
508         return (0);
509
510  cleanup_deregister:
511         cfs_psdev_deregister(&libcfs_dev);
512  cleanup_lwt:
513 #if LWT_SUPPORT
514         lwt_fini();
515  cleanup_debug:
516 #endif
517         portals_debug_cleanup();
518         return rc;
519 }
520
521 static void exit_libcfs_module(void)
522 {
523         int rc;
524
525         remove_proc();
526
527         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
528                atomic_read(&portal_kmemory));
529
530         rc = cfs_psdev_deregister(&libcfs_dev);
531         if (rc)
532                 CERROR("misc_deregister error %d\n", rc);
533
534 #if LWT_SUPPORT
535         lwt_fini();
536 #endif
537
538         if (atomic_read(&portal_kmemory) != 0)
539                 CERROR("Portals memory leaked: %d bytes\n",
540                        atomic_read(&portal_kmemory));
541
542         rc = portals_debug_cleanup();
543         if (rc)
544                 printk(KERN_ERR "LustreError: portals_debug_cleanup: %d\n", rc);
545         libcfs_arch_cleanup();
546 }
547
548 EXPORT_SYMBOL(kportal_assertion_failed);
549
550 cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);