Whamcloud - gitweb
LU-6245 libcfs: cleanup libcfs lock handling
[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, 2014, 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
39 #include <libcfs/libcfs.h>
40 #include <libcfs/libcfs_crypto.h>
41 #include <lnet/lib-lnet.h>
42 #include <lnet/lib-dlc.h>
43 #include <lnet/lnet.h>
44 #include <lnet/nidstr.h>
45
46 static void
47 kportal_memhog_free (struct libcfs_device_userstate *ldu)
48 {
49         struct page **level0p = &ldu->ldu_memhog_root_page;
50         struct page **level1p;
51         struct page **level2p;
52         int           count1;
53         int           count2;
54
55         if (*level0p != NULL) {
56                 level1p = (struct page **)page_address(*level0p);
57                 count1 = 0;
58
59                 while (count1 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
60                        *level1p != NULL) {
61
62                         level2p = (struct page **)page_address(*level1p);
63                         count2 = 0;
64
65                         while (count2 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
66                                *level2p != NULL) {
67
68                                 __free_page(*level2p);
69                                 ldu->ldu_memhog_pages--;
70                                 level2p++;
71                                 count2++;
72                         }
73
74                         __free_page(*level1p);
75                         ldu->ldu_memhog_pages--;
76                         level1p++;
77                         count1++;
78                 }
79
80                 __free_page(*level0p);
81                 ldu->ldu_memhog_pages--;
82
83                 *level0p = NULL;
84         }
85
86         LASSERT(ldu->ldu_memhog_pages == 0);
87 }
88
89 static int
90 kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
91                      gfp_t flags)
92 {
93         struct page **level0p;
94         struct page **level1p;
95         struct page **level2p;
96         int           count1;
97         int           count2;
98
99         LASSERT(ldu->ldu_memhog_pages == 0);
100         LASSERT(ldu->ldu_memhog_root_page == NULL);
101
102         if (npages < 0)
103                 return -EINVAL;
104
105         if (npages == 0)
106                 return 0;
107
108         level0p = &ldu->ldu_memhog_root_page;
109         *level0p = alloc_page(flags);
110         if (*level0p == NULL)
111                 return -ENOMEM;
112         ldu->ldu_memhog_pages++;
113
114         level1p = (struct page **)page_address(*level0p);
115         count1 = 0;
116         memset(level1p, 0, PAGE_CACHE_SIZE);
117
118         while (ldu->ldu_memhog_pages < npages &&
119                count1 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
120
121                 if (cfs_signal_pending())
122                         return -EINTR;
123
124                 *level1p = alloc_page(flags);
125                 if (*level1p == NULL)
126                         return -ENOMEM;
127                 ldu->ldu_memhog_pages++;
128
129                 level2p = (struct page **)page_address(*level1p);
130                 count2 = 0;
131                 memset(level2p, 0, PAGE_CACHE_SIZE);
132
133                 while (ldu->ldu_memhog_pages < npages &&
134                        count2 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
135
136                         if (cfs_signal_pending())
137                                 return -EINTR;
138
139                         *level2p = alloc_page(flags);
140                         if (*level2p == NULL)
141                                 return -ENOMEM;
142                         ldu->ldu_memhog_pages++;
143
144                         level2p++;
145                         count2++;
146                 }
147
148                 level1p++;
149                 count1++;
150         }
151
152         return 0;
153 }
154
155 /* called when opening /dev/device */
156 static int libcfs_psdev_open(unsigned long flags, void *args)
157 {
158         struct libcfs_device_userstate *ldu;
159         ENTRY;
160
161         try_module_get(THIS_MODULE);
162
163         LIBCFS_ALLOC(ldu, sizeof(*ldu));
164         if (ldu != NULL) {
165                 ldu->ldu_memhog_pages = 0;
166                 ldu->ldu_memhog_root_page = NULL;
167         }
168         *(struct libcfs_device_userstate **)args = ldu;
169
170         RETURN(0);
171 }
172
173 /* called when closing /dev/device */
174 static int libcfs_psdev_release(unsigned long flags, void *args)
175 {
176         struct libcfs_device_userstate *ldu;
177         ENTRY;
178
179         ldu = (struct libcfs_device_userstate *)args;
180         if (ldu != NULL) {
181                 kportal_memhog_free(ldu);
182                 LIBCFS_FREE(ldu, sizeof(*ldu));
183         }
184
185         module_put(THIS_MODULE);
186         RETURN(0);
187 }
188
189 static DECLARE_RWSEM(ioctl_list_sem);
190 static LIST_HEAD(ioctl_list);
191
192 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
193 {
194         int rc = 0;
195
196         down_write(&ioctl_list_sem);
197         if (!list_empty(&hand->item))
198                 rc = -EBUSY;
199         else
200                 list_add_tail(&hand->item, &ioctl_list);
201         up_write(&ioctl_list_sem);
202
203         return rc;
204 }
205 EXPORT_SYMBOL(libcfs_register_ioctl);
206
207 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
208 {
209         int rc = 0;
210
211         down_write(&ioctl_list_sem);
212         if (list_empty(&hand->item))
213                 rc = -ENOENT;
214         else
215                 list_del_init(&hand->item);
216         up_write(&ioctl_list_sem);
217
218         return rc;
219 }
220 EXPORT_SYMBOL(libcfs_deregister_ioctl);
221
222 static int libcfs_ioctl(struct cfs_psdev_file *pfile,
223                         unsigned long cmd, void __user *uparam)
224 {
225         struct libcfs_ioctl_data *data = NULL;
226         struct libcfs_ioctl_hdr  *hdr;
227         int                       err;
228         ENTRY;
229
230         /* 'cmd' and permissions get checked in our arch-specific caller */
231         err = libcfs_ioctl_getdata(&hdr, uparam);
232         if (err != 0) {
233                 CDEBUG_LIMIT(D_ERROR,
234                              "libcfs ioctl: data header error %d\n", err);
235                 RETURN(err);
236         }
237
238         if (hdr->ioc_version == LIBCFS_IOCTL_VERSION) {
239                 /* The libcfs_ioctl_data_adjust() function performs adjustment
240                  * operations on the libcfs_ioctl_data structure to make
241                  * it usable by the code.  This doesn't need to be called
242                  * for new data structures added. */
243                 data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr);
244                 err = libcfs_ioctl_data_adjust(data);
245                 if (err != 0)
246                         GOTO(out, err);
247         }
248
249         CDEBUG(D_IOCTL, "libcfs ioctl cmd %lu\n", cmd);
250         switch (cmd) {
251         case IOC_LIBCFS_CLEAR_DEBUG:
252                 libcfs_debug_clear_buffer();
253                 break;
254         /*
255          * case IOC_LIBCFS_PANIC:
256          * Handled in arch/cfs_module.c
257          */
258         case IOC_LIBCFS_MARK_DEBUG:
259                 if (data == NULL ||
260                     data->ioc_inlbuf1 == NULL ||
261                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
262                         GOTO(out, err = -EINVAL);
263
264                 libcfs_debug_mark_buffer(data->ioc_inlbuf1);
265                 break;
266
267         case IOC_LIBCFS_MEMHOG:
268                 if (data == NULL)
269                         GOTO(out, err = -EINVAL);
270
271                 if (pfile->private_data == NULL)
272                         GOTO(out, err = -EINVAL);
273
274                 kportal_memhog_free(pfile->private_data);
275                 err = kportal_memhog_alloc(pfile->private_data,
276                                            data->ioc_count, data->ioc_flags);
277                 if (err != 0)
278                         kportal_memhog_free(pfile->private_data);
279                 break;
280
281         default: {
282                 struct libcfs_ioctl_handler *hand;
283
284                 err = -EINVAL;
285                 down_read(&ioctl_list_sem);
286                 list_for_each_entry(hand, &ioctl_list, item) {
287                         err = hand->handle_ioctl(cmd, hdr);
288                         if (err == -EINVAL)
289                                 continue;
290
291                         if (err == 0)
292                                 err = libcfs_ioctl_popdata(hdr, uparam);
293                         break;
294                 }
295                 up_read(&ioctl_list_sem);
296                 break; }
297         }
298 out:
299         libcfs_ioctl_freedata(hdr);
300         RETURN(err);
301 }
302
303 struct cfs_psdev_ops libcfs_psdev_ops = {
304         libcfs_psdev_open,
305         libcfs_psdev_release,
306         NULL,
307         NULL,
308         libcfs_ioctl
309 };
310
311 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
312 MODULE_DESCRIPTION("Portals v3.1");
313 MODULE_LICENSE("GPL");
314
315 static int init_libcfs_module(void)
316 {
317         int rc;
318
319         libcfs_arch_init();
320         libcfs_init_nidstrings();
321
322         rc = libcfs_debug_init(5 * 1024 * 1024);
323         if (rc < 0) {
324                 printk(KERN_ERR "LustreError: libcfs_debug_init: %d\n", rc);
325                 return (rc);
326         }
327
328         rc = cfs_cpu_init();
329         if (rc != 0)
330                 goto cleanup_debug;
331
332         rc = misc_register(&libcfs_dev);
333         if (rc) {
334                 CERROR("misc_register: error %d\n", rc);
335                 goto cleanup_cpu;
336         }
337
338         rc = cfs_wi_startup();
339         if (rc) {
340                 CERROR("initialize workitem: error %d\n", rc);
341                 goto cleanup_deregister;
342         }
343
344         /* max to 4 threads, should be enough for rehash */
345         rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4);
346         rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY,
347                                  rc, &cfs_sched_rehash);
348         if (rc != 0) {
349                 CERROR("Startup workitem scheduler: error: %d\n", rc);
350                 goto cleanup_deregister;
351         }
352
353         rc = cfs_crypto_register();
354         if (rc) {
355                 CERROR("cfs_crypto_regster: error %d\n", rc);
356                 goto cleanup_wi;
357         }
358
359
360         rc = insert_proc();
361         if (rc) {
362                 CERROR("insert_proc: error %d\n", rc);
363                 goto cleanup_crypto;
364         }
365
366         CDEBUG (D_OTHER, "portals setup OK\n");
367         return 0;
368 cleanup_crypto:
369         cfs_crypto_unregister();
370 cleanup_wi:
371         cfs_wi_shutdown();
372 cleanup_deregister:
373         misc_deregister(&libcfs_dev);
374 cleanup_cpu:
375         cfs_cpu_fini();
376 cleanup_debug:
377         libcfs_debug_cleanup();
378         return rc;
379 }
380
381 static void exit_libcfs_module(void)
382 {
383         int rc;
384
385         remove_proc();
386
387         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
388                atomic_read(&libcfs_kmemory));
389
390         if (cfs_sched_rehash != NULL) {
391                 cfs_wi_sched_destroy(cfs_sched_rehash);
392                 cfs_sched_rehash = NULL;
393         }
394
395         cfs_crypto_unregister();
396         cfs_wi_shutdown();
397
398         rc = misc_deregister(&libcfs_dev);
399         if (rc)
400                 CERROR("misc_deregister error %d\n", rc);
401
402         cfs_cpu_fini();
403
404         if (atomic_read(&libcfs_kmemory) != 0)
405                 CERROR("Portals memory leaked: %d bytes\n",
406                        atomic_read(&libcfs_kmemory));
407
408         rc = libcfs_debug_cleanup();
409         if (rc)
410                 printk(KERN_ERR "LustreError: libcfs_debug_cleanup: %d\n",
411                        rc);
412
413         libcfs_arch_cleanup();
414 }
415
416 cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);