Whamcloud - gitweb
16d0a1601a75ae3caf14d310037b546d14d62ea3
[fs/lustre-release.git] / libcfs / libcfs / module.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #define DEBUG_SUBSYSTEM S_LNET
38 #define LNET_MAX_IOCTL_BUF_LEN (sizeof(struct lnet_ioctl_net_config) + \
39                                  sizeof(struct lnet_ioctl_config_data))
40
41 #include <libcfs/libcfs.h>
42 #include <libcfs/libcfs_crypto.h>
43 #include <lnet/lib-lnet.h>
44 #include <lnet/lib-dlc.h>
45 #include <lnet/lnet.h>
46 #include "tracefile.h"
47
48 void
49 kportal_memhog_free (struct libcfs_device_userstate *ldu)
50 {
51         struct page **level0p = &ldu->ldu_memhog_root_page;
52         struct page **level1p;
53         struct page **level2p;
54         int           count1;
55         int           count2;
56
57         if (*level0p != NULL) {
58                 level1p = (struct page **)page_address(*level0p);
59                 count1 = 0;
60
61                 while (count1 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
62                        *level1p != NULL) {
63
64                         level2p = (struct page **)page_address(*level1p);
65                         count2 = 0;
66
67                         while (count2 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
68                                *level2p != NULL) {
69
70                                 __free_page(*level2p);
71                                 ldu->ldu_memhog_pages--;
72                                 level2p++;
73                                 count2++;
74                         }
75
76                         __free_page(*level1p);
77                         ldu->ldu_memhog_pages--;
78                         level1p++;
79                         count1++;
80                 }
81
82                 __free_page(*level0p);
83                 ldu->ldu_memhog_pages--;
84
85                 *level0p = NULL;
86         }
87
88         LASSERT(ldu->ldu_memhog_pages == 0);
89 }
90
91 int
92 kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
93                      gfp_t flags)
94 {
95         struct page **level0p;
96         struct page **level1p;
97         struct page **level2p;
98         int           count1;
99         int           count2;
100
101         LASSERT(ldu->ldu_memhog_pages == 0);
102         LASSERT(ldu->ldu_memhog_root_page == NULL);
103
104         if (npages < 0)
105                 return -EINVAL;
106
107         if (npages == 0)
108                 return 0;
109
110         level0p = &ldu->ldu_memhog_root_page;
111         *level0p = alloc_page(flags);
112         if (*level0p == NULL)
113                 return -ENOMEM;
114         ldu->ldu_memhog_pages++;
115
116         level1p = (struct page **)page_address(*level0p);
117         count1 = 0;
118         memset(level1p, 0, PAGE_CACHE_SIZE);
119
120         while (ldu->ldu_memhog_pages < npages &&
121                count1 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
122
123                 if (cfs_signal_pending())
124                         return -EINTR;
125
126                 *level1p = alloc_page(flags);
127                 if (*level1p == NULL)
128                         return -ENOMEM;
129                 ldu->ldu_memhog_pages++;
130
131                 level2p = (struct page **)page_address(*level1p);
132                 count2 = 0;
133                 memset(level2p, 0, PAGE_CACHE_SIZE);
134
135                 while (ldu->ldu_memhog_pages < npages &&
136                        count2 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
137
138                         if (cfs_signal_pending())
139                                 return -EINTR;
140
141                         *level2p = alloc_page(flags);
142                         if (*level2p == NULL)
143                                 return -ENOMEM;
144                         ldu->ldu_memhog_pages++;
145
146                         level2p++;
147                         count2++;
148                 }
149
150                 level1p++;
151                 count1++;
152         }
153
154         return 0;
155 }
156
157 /* called when opening /dev/device */
158 static int libcfs_psdev_open(unsigned long flags, void *args)
159 {
160         struct libcfs_device_userstate *ldu;
161         ENTRY;
162
163         try_module_get(THIS_MODULE);
164
165         LIBCFS_ALLOC(ldu, sizeof(*ldu));
166         if (ldu != NULL) {
167                 ldu->ldu_memhog_pages = 0;
168                 ldu->ldu_memhog_root_page = NULL;
169         }
170         *(struct libcfs_device_userstate **)args = ldu;
171
172         RETURN(0);
173 }
174
175 /* called when closing /dev/device */
176 static int libcfs_psdev_release(unsigned long flags, void *args)
177 {
178         struct libcfs_device_userstate *ldu;
179         ENTRY;
180
181         ldu = (struct libcfs_device_userstate *)args;
182         if (ldu != NULL) {
183                 kportal_memhog_free(ldu);
184                 LIBCFS_FREE(ldu, sizeof(*ldu));
185         }
186
187         module_put(THIS_MODULE);
188         RETURN(0);
189 }
190
191 static struct rw_semaphore ioctl_list_sem;
192 static struct list_head ioctl_list;
193
194 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
195 {
196         int rc = 0;
197
198         down_write(&ioctl_list_sem);
199         if (!list_empty(&hand->item))
200                 rc = -EBUSY;
201         else
202                 list_add_tail(&hand->item, &ioctl_list);
203         up_write(&ioctl_list_sem);
204
205         return rc;
206 }
207 EXPORT_SYMBOL(libcfs_register_ioctl);
208
209 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
210 {
211         int rc = 0;
212
213         down_write(&ioctl_list_sem);
214         if (list_empty(&hand->item))
215                 rc = -ENOENT;
216         else
217                 list_del_init(&hand->item);
218         up_write(&ioctl_list_sem);
219
220         return rc;
221 }
222 EXPORT_SYMBOL(libcfs_deregister_ioctl);
223
224 static int libcfs_ioctl_handle(struct cfs_psdev_file *pfile, unsigned long cmd,
225                                void *arg, struct libcfs_ioctl_hdr *hdr)
226 {
227         struct libcfs_ioctl_data *data = NULL;
228         int err;
229         ENTRY;
230
231         /* The libcfs_ioctl_data_adjust() function performs adjustment
232          * operations on the libcfs_ioctl_data structure to make
233          * it usable by the code.  This doesn't need to be called
234          * for new data structures added. */
235         if (hdr->ioc_version == LIBCFS_IOCTL_VERSION) {
236                 data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr);
237                 err = libcfs_ioctl_data_adjust(data);
238                 if (err != 0) {
239                         RETURN(err);
240                 }
241         }
242
243         switch (cmd) {
244         case IOC_LIBCFS_CLEAR_DEBUG:
245                 libcfs_debug_clear_buffer();
246                 RETURN(0);
247         /*
248          * case IOC_LIBCFS_PANIC:
249          * Handled in arch/cfs_module.c
250          */
251         case IOC_LIBCFS_MARK_DEBUG:
252                 if (data->ioc_inlbuf1 == NULL ||
253                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
254                         RETURN(-EINVAL);
255                 libcfs_debug_mark_buffer(data->ioc_inlbuf1);
256                 RETURN(0);
257         case IOC_LIBCFS_MEMHOG:
258                 if (pfile->private_data == NULL) {
259                         err = -EINVAL;
260                 } else {
261                         kportal_memhog_free(pfile->private_data);
262                         /* XXX The ioc_flags is not GFP flags now, need to
263                          * be fixed */
264                         err = kportal_memhog_alloc(pfile->private_data,
265                                                    data->ioc_count,
266                                                    data->ioc_flags);
267                         if (err != 0)
268                                 kportal_memhog_free(pfile->private_data);
269                 }
270                 break;
271
272         case IOC_LIBCFS_PING_TEST: {
273                 extern void (kping_client)(struct libcfs_ioctl_data *);
274                 void (*ping)(struct libcfs_ioctl_data *);
275
276                 CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
277                        data->ioc_count, libcfs_nid2str(data->ioc_nid),
278                        libcfs_nid2str(data->ioc_nid));
279                 ping = symbol_get(kping_client);
280                 if (!ping) {
281                         CERROR("symbol_get failed\n");
282                 } else {
283                         ping(data);
284                         symbol_put(kping_client);
285                 }
286                 RETURN(0);
287         }
288
289         default: {
290                 struct libcfs_ioctl_handler *hand;
291
292                 err = -EINVAL;
293                 down_read(&ioctl_list_sem);
294                 list_for_each_entry(hand, &ioctl_list, item) {
295                         err = hand->handle_ioctl(cmd, hdr);
296                         if (err != -EINVAL) {
297                                 if (err == 0)
298                                         err = libcfs_ioctl_popdata(arg,
299                                                         hdr, hdr->ioc_len);
300                                 break;
301                         }
302                 }
303                 up_read(&ioctl_list_sem);
304                 break;
305         }
306         }
307
308         RETURN(err);
309 }
310
311 static int libcfs_ioctl(struct cfs_psdev_file *pfile,
312                         unsigned long cmd, void *arg)
313 {
314         struct libcfs_ioctl_hdr *hdr;
315         int err = 0;
316         __u32 buf_len;
317         ENTRY;
318
319         err = libcfs_ioctl_getdata_len(arg, &buf_len);
320         if (err != 0)
321                 RETURN(err);
322
323         /*
324          * do a check here to restrict the size of the memory
325          * to allocate to guard against DoS attacks.
326          */
327         if (buf_len > LNET_MAX_IOCTL_BUF_LEN) {
328                 CERROR("LNET: user buffer exceeds kernel buffer\n");
329                 RETURN(-EINVAL);
330         }
331
332         LIBCFS_ALLOC_GFP(hdr, buf_len, GFP_IOFS);
333         if (hdr == NULL)
334                 RETURN(-ENOMEM);
335
336         /* 'cmd' and permissions get checked in our arch-specific caller */
337         if (libcfs_ioctl_getdata(hdr, buf_len, arg)) {
338                 CERROR("LNET ioctl: data error\n");
339                 GOTO(out, err = -EINVAL);
340         }
341
342         err = libcfs_ioctl_handle(pfile, cmd, arg, hdr);
343
344 out:
345         LIBCFS_FREE(hdr, buf_len);
346         RETURN(err);
347 }
348
349
350 struct cfs_psdev_ops libcfs_psdev_ops = {
351         libcfs_psdev_open,
352         libcfs_psdev_release,
353         NULL,
354         NULL,
355         libcfs_ioctl
356 };
357
358 extern int insert_proc(void);
359 extern void remove_proc(void);
360 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
361 MODULE_DESCRIPTION("Portals v3.1");
362 MODULE_LICENSE("GPL");
363
364 extern struct miscdevice libcfs_dev;
365 extern struct rw_semaphore cfs_tracefile_sem;
366 extern struct mutex cfs_trace_thread_mutex;
367 extern struct cfs_wi_sched *cfs_sched_rehash;
368
369 extern void libcfs_init_nidstrings(void);
370 extern int libcfs_arch_init(void);
371 extern void libcfs_arch_cleanup(void);
372
373 static int init_libcfs_module(void)
374 {
375         int rc;
376
377         libcfs_arch_init();
378         libcfs_init_nidstrings();
379         init_rwsem(&cfs_tracefile_sem);
380         mutex_init(&cfs_trace_thread_mutex);
381         init_rwsem(&ioctl_list_sem);
382         INIT_LIST_HEAD(&ioctl_list);
383         init_waitqueue_head(&cfs_race_waitq);
384
385         rc = libcfs_debug_init(5 * 1024 * 1024);
386         if (rc < 0) {
387                 printk(KERN_ERR "LustreError: libcfs_debug_init: %d\n", rc);
388                 return (rc);
389         }
390
391         rc = cfs_cpu_init();
392         if (rc != 0)
393                 goto cleanup_debug;
394
395         rc = misc_register(&libcfs_dev);
396         if (rc) {
397                 CERROR("misc_register: error %d\n", rc);
398                 goto cleanup_cpu;
399         }
400
401         rc = cfs_wi_startup();
402         if (rc) {
403                 CERROR("initialize workitem: error %d\n", rc);
404                 goto cleanup_deregister;
405         }
406
407         /* max to 4 threads, should be enough for rehash */
408         rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4);
409         rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY,
410                                  rc, &cfs_sched_rehash);
411         if (rc != 0) {
412                 CERROR("Startup workitem scheduler: error: %d\n", rc);
413                 goto cleanup_deregister;
414         }
415
416         rc = cfs_crypto_register();
417         if (rc) {
418                 CERROR("cfs_crypto_regster: error %d\n", rc);
419                 goto cleanup_wi;
420         }
421
422
423         rc = insert_proc();
424         if (rc) {
425                 CERROR("insert_proc: error %d\n", rc);
426                 goto cleanup_crypto;
427         }
428
429         CDEBUG (D_OTHER, "portals setup OK\n");
430         return 0;
431 cleanup_crypto:
432         cfs_crypto_unregister();
433 cleanup_wi:
434         cfs_wi_shutdown();
435 cleanup_deregister:
436         misc_deregister(&libcfs_dev);
437 cleanup_cpu:
438         cfs_cpu_fini();
439 cleanup_debug:
440         libcfs_debug_cleanup();
441         return rc;
442 }
443
444 static void exit_libcfs_module(void)
445 {
446         int rc;
447
448         remove_proc();
449
450         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
451                atomic_read(&libcfs_kmemory));
452
453         if (cfs_sched_rehash != NULL) {
454                 cfs_wi_sched_destroy(cfs_sched_rehash);
455                 cfs_sched_rehash = NULL;
456         }
457
458         cfs_crypto_unregister();
459         cfs_wi_shutdown();
460
461         rc = misc_deregister(&libcfs_dev);
462         if (rc)
463                 CERROR("misc_deregister error %d\n", rc);
464
465         cfs_cpu_fini();
466
467         if (atomic_read(&libcfs_kmemory) != 0)
468                 CERROR("Portals memory leaked: %d bytes\n",
469                        atomic_read(&libcfs_kmemory));
470
471         rc = libcfs_debug_cleanup();
472         if (rc)
473                 printk(KERN_ERR "LustreError: libcfs_debug_cleanup: %d\n",
474                        rc);
475
476         fini_rwsem(&ioctl_list_sem);
477         fini_rwsem(&cfs_tracefile_sem);
478
479         libcfs_arch_cleanup();
480 }
481
482 cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);