Whamcloud - gitweb
file jbd-stats-2.6.9.patch was initially added on branch b1_4.
[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         case IOC_PORTAL_DMSG:
364                 if (data->ioc_inlbuf1 == NULL ||
365                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
366                         RETURN(-EINVAL);
367                 printk("%s", data->ioc_inlbuf1);
368                 RETURN(0);
369 #if LWT_SUPPORT
370         case IOC_PORTAL_LWT_CONTROL:
371                 err = lwt_control (data->ioc_flags, data->ioc_misc);
372                 break;
373
374         case IOC_PORTAL_LWT_SNAPSHOT: {
375                 cycles_t   now;
376                 int        ncpu;
377                 int        total_size;
378
379                 err = lwt_snapshot (&now, &ncpu, &total_size,
380                                     data->ioc_pbuf1, data->ioc_plen1);
381                 data->ioc_nid = now;
382                 data->ioc_count = ncpu;
383                 data->ioc_misc = total_size;
384
385                 /* Hedge against broken user/kernel typedefs (e.g. cycles_t) */
386                 data->ioc_nid2 = sizeof(lwt_event_t);
387                 data->ioc_nid3 = offsetof(lwt_event_t, lwte_where);
388
389                 if (err == 0 &&
390                     copy_to_user((char *)arg, data, sizeof (*data)))
391                         err = -EFAULT;
392                 break;
393         }
394
395         case IOC_PORTAL_LWT_LOOKUP_STRING:
396                 err = lwt_lookup_string (&data->ioc_count, data->ioc_pbuf1,
397                                          data->ioc_pbuf2, data->ioc_plen2);
398                 if (err == 0 &&
399                     copy_to_user((char *)arg, data, sizeof (*data)))
400                         err = -EFAULT;
401                 break;
402 #endif
403         case IOC_PORTAL_NAL_CMD: {
404                 struct portals_cfg pcfg;
405
406                 if (data->ioc_plen1 != sizeof(pcfg)) {
407                         CERROR("Bad ioc_plen1 %d (wanted "LPSZ")\n",
408                                data->ioc_plen1, sizeof(pcfg));
409                         err = -EINVAL;
410                         break;
411                 }
412
413                 if (copy_from_user(&pcfg, (void *)data->ioc_pbuf1,
414                                    sizeof(pcfg))) {
415                         err = -EFAULT;
416                         break;
417                 }
418
419                 CDEBUG (D_IOCTL, "nal command nal %x cmd %d\n", pcfg.pcfg_nal,
420                         pcfg.pcfg_command);
421                 if (pcfg.pcfg_version != PORTALS_CFG_VERSION) {
422                         /* set this so userspace can tell when they
423                          * have an incompatible version and print a
424                          * decent message to the user
425                          */
426                         pcfg.pcfg_version = PORTALS_CFG_VERSION;
427                         if (copy_to_user((char *)data->ioc_pbuf1, &pcfg,
428                                          sizeof (pcfg)))
429                                 err = -EFAULT;
430                         else
431                                 err = -EINVAL;
432                 } else {
433                         err = libcfs_nal_cmd(&pcfg);
434
435                         if (err == 0 &&
436                             copy_to_user((char *)data->ioc_pbuf1, &pcfg,
437                                          sizeof (pcfg)))
438                                 err = -EFAULT;
439                 }
440                 break;
441         }
442
443         case IOC_PORTAL_MEMHOG:
444                 if (pfile->private_data == NULL) {
445                         err = -EINVAL;
446                 } else {
447                         kportal_memhog_free(pfile->private_data);
448                         /* XXX The ioc_flags is not GFP flags now, need to be fixed */
449                         err = kportal_memhog_alloc(pfile->private_data,
450                                                    data->ioc_count,
451                                                    data->ioc_flags);
452                         if (err != 0)
453                                 kportal_memhog_free(pfile->private_data);
454                 }
455                 break;
456
457         default: {
458                 struct libcfs_ioctl_handler *hand;
459                 err = -EINVAL;
460                 down_read(&ioctl_list_sem);
461                 list_for_each_entry(hand, &ioctl_list, item) {
462                         err = hand->handle_ioctl(data, cmd, (unsigned long)arg);
463                         if (err != -EINVAL)
464                                 break;
465                 }
466                 up_read(&ioctl_list_sem);
467                 } break;
468         }
469
470         RETURN(err);
471 }
472
473 struct cfs_psdev_ops libcfs_psdev_ops = {
474         libcfs_psdev_open,
475         libcfs_psdev_release,
476         NULL,
477         NULL,
478         libcfs_ioctl
479 };
480
481 extern int insert_proc(void);
482 extern void remove_proc(void);
483 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
484 MODULE_DESCRIPTION("Portals v3.1");
485 MODULE_LICENSE("GPL");
486
487 extern cfs_psdev_t libcfs_dev;
488 extern struct rw_semaphore tracefile_sem;
489 extern struct semaphore trace_thread_sem;
490
491 extern int libcfs_arch_init(void);
492 extern void libcfs_arch_cleanup(void);
493
494 static int init_libcfs_module(void)
495 {
496         int rc;
497
498         libcfs_arch_init();
499         init_rwsem(&tracefile_sem);
500         init_mutex(&trace_thread_sem);
501         init_mutex(&nal_cmd_mutex);
502         init_rwsem(&ioctl_list_sem);
503         CFS_INIT_LIST_HEAD(&ioctl_list);
504
505         rc = portals_debug_init(5 * 1024 * 1024);
506         if (rc < 0) {
507                 printk(KERN_ERR "LustreError: portals_debug_init: %d\n", rc);
508                 return (rc);
509         }
510
511 #if LWT_SUPPORT
512         rc = lwt_init();
513         if (rc != 0) {
514                 CERROR("lwt_init: error %d\n", rc);
515                 goto cleanup_debug;
516         }
517 #endif
518         rc = cfs_psdev_register(&libcfs_dev);
519         if (rc) {
520                 CERROR("misc_register: error %d\n", rc);
521                 goto cleanup_lwt;
522         }
523
524         rc = insert_proc();
525         if (rc) {
526                 CERROR("insert_proc: error %d\n", rc);
527                 goto cleanup_deregister;
528         }
529
530         CDEBUG (D_OTHER, "portals setup OK\n");
531         return (0);
532
533  cleanup_deregister:
534         cfs_psdev_deregister(&libcfs_dev);
535  cleanup_lwt:
536 #if LWT_SUPPORT
537         lwt_fini();
538  cleanup_debug:
539 #endif
540         portals_debug_cleanup();
541         return rc;
542 }
543
544 static void exit_libcfs_module(void)
545 {
546         int rc;
547
548         remove_proc();
549
550         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
551                atomic_read(&portal_kmemory));
552
553         rc = cfs_psdev_deregister(&libcfs_dev);
554         if (rc)
555                 CERROR("misc_deregister error %d\n", rc);
556
557 #if LWT_SUPPORT
558         lwt_fini();
559 #endif
560
561         if (atomic_read(&portal_kmemory) != 0)
562                 CERROR("Portals memory leaked: %d bytes\n",
563                        atomic_read(&portal_kmemory));
564
565         rc = portals_debug_cleanup();
566         if (rc)
567                 printk(KERN_ERR "LustreError: portals_debug_cleanup: %d\n", rc);
568         libcfs_arch_cleanup();
569 }
570
571 EXPORT_SYMBOL(kportal_assertion_failed);
572
573 cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);