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 39#include "../../include/linux/libcfs/libcfs.h" 40#include "../../include/linux/libcfs/libcfs_crypto.h" 41#include "../../include/linux/lnet/lib-lnet.h" 42#include "../../include/linux/lnet/lnet.h" 43#include "tracefile.h" 44 45void 46kportal_memhog_free (struct libcfs_device_userstate *ldu) 47{ 48 struct page **level0p = &ldu->ldu_memhog_root_page; 49 struct page **level1p; 50 struct page **level2p; 51 int count1; 52 int count2; 53 54 if (*level0p != NULL) { 55 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 89int 90kportal_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 */ 156static int libcfs_psdev_open(unsigned long flags, void *args) 157{ 158 struct libcfs_device_userstate *ldu; 159 160 try_module_get(THIS_MODULE); 161 162 LIBCFS_ALLOC(ldu, sizeof(*ldu)); 163 if (ldu != NULL) { 164 ldu->ldu_memhog_pages = 0; 165 ldu->ldu_memhog_root_page = NULL; 166 } 167 *(struct libcfs_device_userstate **)args = ldu; 168 169 return 0; 170} 171 172/* called when closing /dev/device */ 173static int libcfs_psdev_release(unsigned long flags, void *args) 174{ 175 struct libcfs_device_userstate *ldu; 176 177 ldu = (struct libcfs_device_userstate *)args; 178 if (ldu != NULL) { 179 kportal_memhog_free(ldu); 180 LIBCFS_FREE(ldu, sizeof(*ldu)); 181 } 182 183 module_put(THIS_MODULE); 184 return 0; 185} 186 187static struct rw_semaphore ioctl_list_sem; 188static struct list_head ioctl_list; 189 190int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand) 191{ 192 int rc = 0; 193 194 down_write(&ioctl_list_sem); 195 if (!list_empty(&hand->item)) 196 rc = -EBUSY; 197 else 198 list_add_tail(&hand->item, &ioctl_list); 199 up_write(&ioctl_list_sem); 200 201 return rc; 202} 203EXPORT_SYMBOL(libcfs_register_ioctl); 204 205int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand) 206{ 207 int rc = 0; 208 209 down_write(&ioctl_list_sem); 210 if (list_empty(&hand->item)) 211 rc = -ENOENT; 212 else 213 list_del_init(&hand->item); 214 up_write(&ioctl_list_sem); 215 216 return rc; 217} 218EXPORT_SYMBOL(libcfs_deregister_ioctl); 219 220static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd, 221 void *arg, struct libcfs_ioctl_data *data) 222{ 223 int err = -EINVAL; 224 225 switch (cmd) { 226 case IOC_LIBCFS_CLEAR_DEBUG: 227 libcfs_debug_clear_buffer(); 228 return 0; 229 /* 230 * case IOC_LIBCFS_PANIC: 231 * Handled in arch/cfs_module.c 232 */ 233 case IOC_LIBCFS_MARK_DEBUG: 234 if (data->ioc_inlbuf1 == NULL || 235 data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0') 236 return -EINVAL; 237 libcfs_debug_mark_buffer(data->ioc_inlbuf1); 238 return 0; 239 case IOC_LIBCFS_MEMHOG: 240 if (pfile->private_data == NULL) { 241 err = -EINVAL; 242 } else { 243 kportal_memhog_free(pfile->private_data); 244 /* XXX The ioc_flags is not GFP flags now, need to be fixed */ 245 err = kportal_memhog_alloc(pfile->private_data, 246 data->ioc_count, 247 data->ioc_flags); 248 if (err != 0) 249 kportal_memhog_free(pfile->private_data); 250 } 251 break; 252 253 case IOC_LIBCFS_PING_TEST: { 254 extern void (kping_client)(struct libcfs_ioctl_data *); 255 void (*ping)(struct libcfs_ioctl_data *); 256 257 CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n", 258 data->ioc_count, libcfs_nid2str(data->ioc_nid), 259 libcfs_nid2str(data->ioc_nid)); 260 ping = symbol_get(kping_client); 261 if (!ping) 262 CERROR("symbol_get failed\n"); 263 else { 264 ping(data); 265 symbol_put(kping_client); 266 } 267 return 0; 268 } 269 270 default: { 271 struct libcfs_ioctl_handler *hand; 272 err = -EINVAL; 273 down_read(&ioctl_list_sem); 274 list_for_each_entry(hand, &ioctl_list, item) { 275 err = hand->handle_ioctl(cmd, data); 276 if (err != -EINVAL) { 277 if (err == 0) 278 err = libcfs_ioctl_popdata(arg, 279 data, sizeof (*data)); 280 break; 281 } 282 } 283 up_read(&ioctl_list_sem); 284 break; 285 } 286 } 287 288 return err; 289} 290 291static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg) 292{ 293 char *buf; 294 struct libcfs_ioctl_data *data; 295 int err = 0; 296 297 LIBCFS_ALLOC_GFP(buf, 1024, GFP_IOFS); 298 if (buf == NULL) 299 return -ENOMEM; 300 301 /* 'cmd' and permissions get checked in our arch-specific caller */ 302 if (libcfs_ioctl_getdata(buf, buf + 800, (void *)arg)) { 303 CERROR("PORTALS ioctl: data error\n"); 304 err = -EINVAL; 305 goto out; 306 } 307 data = (struct libcfs_ioctl_data *)buf; 308 309 err = libcfs_ioctl_int(pfile, cmd, arg, data); 310 311out: 312 LIBCFS_FREE(buf, 1024); 313 return err; 314} 315 316 317struct cfs_psdev_ops libcfs_psdev_ops = { 318 libcfs_psdev_open, 319 libcfs_psdev_release, 320 NULL, 321 NULL, 322 libcfs_ioctl 323}; 324 325extern int insert_proc(void); 326extern void remove_proc(void); 327MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>"); 328MODULE_DESCRIPTION("Portals v3.1"); 329MODULE_LICENSE("GPL"); 330 331extern struct miscdevice libcfs_dev; 332extern struct rw_semaphore cfs_tracefile_sem; 333extern struct mutex cfs_trace_thread_mutex; 334extern struct cfs_wi_sched *cfs_sched_rehash; 335 336extern void libcfs_init_nidstrings(void); 337extern int libcfs_arch_init(void); 338extern void libcfs_arch_cleanup(void); 339 340static int init_libcfs_module(void) 341{ 342 int rc; 343 344 libcfs_arch_init(); 345 libcfs_init_nidstrings(); 346 init_rwsem(&cfs_tracefile_sem); 347 mutex_init(&cfs_trace_thread_mutex); 348 init_rwsem(&ioctl_list_sem); 349 INIT_LIST_HEAD(&ioctl_list); 350 init_waitqueue_head(&cfs_race_waitq); 351 352 rc = libcfs_debug_init(5 * 1024 * 1024); 353 if (rc < 0) { 354 printk(KERN_ERR "LustreError: libcfs_debug_init: %d\n", rc); 355 return rc; 356 } 357 358 rc = cfs_cpu_init(); 359 if (rc != 0) 360 goto cleanup_debug; 361 362 rc = misc_register(&libcfs_dev); 363 if (rc) { 364 CERROR("misc_register: error %d\n", rc); 365 goto cleanup_cpu; 366 } 367 368 rc = cfs_wi_startup(); 369 if (rc) { 370 CERROR("initialize workitem: error %d\n", rc); 371 goto cleanup_deregister; 372 } 373 374 /* max to 4 threads, should be enough for rehash */ 375 rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4); 376 rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY, 377 rc, &cfs_sched_rehash); 378 if (rc != 0) { 379 CERROR("Startup workitem scheduler: error: %d\n", rc); 380 goto cleanup_deregister; 381 } 382 383 rc = cfs_crypto_register(); 384 if (rc) { 385 CERROR("cfs_crypto_register: error %d\n", rc); 386 goto cleanup_wi; 387 } 388 389 390 rc = insert_proc(); 391 if (rc) { 392 CERROR("insert_proc: error %d\n", rc); 393 goto cleanup_crypto; 394 } 395 396 CDEBUG (D_OTHER, "portals setup OK\n"); 397 return 0; 398 cleanup_crypto: 399 cfs_crypto_unregister(); 400 cleanup_wi: 401 cfs_wi_shutdown(); 402 cleanup_deregister: 403 misc_deregister(&libcfs_dev); 404cleanup_cpu: 405 cfs_cpu_fini(); 406 cleanup_debug: 407 libcfs_debug_cleanup(); 408 return rc; 409} 410 411static void exit_libcfs_module(void) 412{ 413 int rc; 414 415 remove_proc(); 416 417 CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n", 418 atomic_read(&libcfs_kmemory)); 419 420 if (cfs_sched_rehash != NULL) { 421 cfs_wi_sched_destroy(cfs_sched_rehash); 422 cfs_sched_rehash = NULL; 423 } 424 425 cfs_crypto_unregister(); 426 cfs_wi_shutdown(); 427 428 rc = misc_deregister(&libcfs_dev); 429 if (rc) 430 CERROR("misc_deregister error %d\n", rc); 431 432 cfs_cpu_fini(); 433 434 if (atomic_read(&libcfs_kmemory) != 0) 435 CERROR("Portals memory leaked: %d bytes\n", 436 atomic_read(&libcfs_kmemory)); 437 438 rc = libcfs_debug_cleanup(); 439 if (rc) 440 printk(KERN_ERR "LustreError: libcfs_debug_cleanup: %d\n", 441 rc); 442 443 libcfs_arch_cleanup(); 444} 445 446MODULE_VERSION("1.0.0"); 447module_init(init_libcfs_module); 448module_exit(exit_libcfs_module); 449