1 /* 2 * Copyright (c) 2005 Topspin Communications. All rights reserved. 3 * Copyright (c) 2005 Cisco Systems. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 * 33 * $Id: uverbs_main.c 2733 2005-06-28 19:14:34Z roland $ 34 */ 35 36 #include <linux/module.h> 37 #include <linux/init.h> 38 #include <linux/device.h> 39 #include <linux/err.h> 40 #include <linux/fs.h> 41 #include <linux/poll.h> 42 #include <linux/file.h> 43 #include <linux/mount.h> 44 45 #include <asm/uaccess.h> 46 47 #include "uverbs.h" 48 49 MODULE_AUTHOR("Roland Dreier"); 50 MODULE_DESCRIPTION("InfiniBand userspace verbs access"); 51 MODULE_LICENSE("Dual BSD/GPL"); 52 53 #define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */ 54 55 enum { 56 IB_UVERBS_MAJOR = 231, 57 IB_UVERBS_BASE_MINOR = 192, 58 IB_UVERBS_MAX_DEVICES = 32 59 }; 60 61 #define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) 62 63 DECLARE_MUTEX(ib_uverbs_idr_mutex); 64 DEFINE_IDR(ib_uverbs_pd_idr); 65 DEFINE_IDR(ib_uverbs_mr_idr); 66 DEFINE_IDR(ib_uverbs_mw_idr); 67 DEFINE_IDR(ib_uverbs_ah_idr); 68 DEFINE_IDR(ib_uverbs_cq_idr); 69 DEFINE_IDR(ib_uverbs_qp_idr); 70 71 static spinlock_t map_lock; 72 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); 73 74 static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, 75 const char __user *buf, int in_len, 76 int out_len) = { 77 [IB_USER_VERBS_CMD_QUERY_PARAMS] = ib_uverbs_query_params, 78 [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, 79 [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, 80 [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, 81 [IB_USER_VERBS_CMD_QUERY_GID] = ib_uverbs_query_gid, 82 [IB_USER_VERBS_CMD_QUERY_PKEY] = ib_uverbs_query_pkey, 83 [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, 84 [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, 85 [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, 86 [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, 87 [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, 88 [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, 89 [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, 90 [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, 91 [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, 92 [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, 93 [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, 94 }; 95 96 static struct vfsmount *uverbs_event_mnt; 97 98 static void ib_uverbs_add_one(struct ib_device *device); 99 static void ib_uverbs_remove_one(struct ib_device *device); 100 101 static int ib_dealloc_ucontext(struct ib_ucontext *context) 102 { 103 struct ib_uobject *uobj, *tmp; 104 105 if (!context) 106 return 0; 107 108 down(&ib_uverbs_idr_mutex); 109 110 /* XXX Free AHs */ 111 112 list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { 113 struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); 114 idr_remove(&ib_uverbs_qp_idr, uobj->id); 115 ib_destroy_qp(qp); 116 list_del(&uobj->list); 117 kfree(uobj); 118 } 119 120 list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { 121 struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); 122 idr_remove(&ib_uverbs_cq_idr, uobj->id); 123 ib_destroy_cq(cq); 124 list_del(&uobj->list); 125 kfree(uobj); 126 } 127 128 /* XXX Free SRQs */ 129 /* XXX Free MWs */ 130 131 list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { 132 struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id); 133 struct ib_umem_object *memobj; 134 135 idr_remove(&ib_uverbs_mr_idr, uobj->id); 136 ib_dereg_mr(mr); 137 138 memobj = container_of(uobj, struct ib_umem_object, uobject); 139 ib_umem_release_on_close(mr->device, &memobj->umem); 140 141 list_del(&uobj->list); 142 kfree(memobj); 143 } 144 145 list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { 146 struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id); 147 idr_remove(&ib_uverbs_pd_idr, uobj->id); 148 ib_dealloc_pd(pd); 149 list_del(&uobj->list); 150 kfree(uobj); 151 } 152 153 up(&ib_uverbs_idr_mutex); 154 155 return context->device->dealloc_ucontext(context); 156 } 157 158 static void ib_uverbs_release_file(struct kref *ref) 159 { 160 struct ib_uverbs_file *file = 161 container_of(ref, struct ib_uverbs_file, ref); 162 163 module_put(file->device->ib_dev->owner); 164 kfree(file); 165 } 166 167 static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, 168 size_t count, loff_t *pos) 169 { 170 struct ib_uverbs_event_file *file = filp->private_data; 171 void *event; 172 int eventsz; 173 int ret = 0; 174 175 spin_lock_irq(&file->lock); 176 177 while (list_empty(&file->event_list) && file->fd >= 0) { 178 spin_unlock_irq(&file->lock); 179 180 if (filp->f_flags & O_NONBLOCK) 181 return -EAGAIN; 182 183 if (wait_event_interruptible(file->poll_wait, 184 !list_empty(&file->event_list) || 185 file->fd < 0)) 186 return -ERESTARTSYS; 187 188 spin_lock_irq(&file->lock); 189 } 190 191 if (file->fd < 0) { 192 spin_unlock_irq(&file->lock); 193 return -ENODEV; 194 } 195 196 if (file->is_async) { 197 event = list_entry(file->event_list.next, 198 struct ib_uverbs_async_event, list); 199 eventsz = sizeof (struct ib_uverbs_async_event_desc); 200 } else { 201 event = list_entry(file->event_list.next, 202 struct ib_uverbs_comp_event, list); 203 eventsz = sizeof (struct ib_uverbs_comp_event_desc); 204 } 205 206 if (eventsz > count) { 207 ret = -EINVAL; 208 event = NULL; 209 } else 210 list_del(file->event_list.next); 211 212 spin_unlock_irq(&file->lock); 213 214 if (event) { 215 if (copy_to_user(buf, event, eventsz)) 216 ret = -EFAULT; 217 else 218 ret = eventsz; 219 } 220 221 kfree(event); 222 223 return ret; 224 } 225 226 static unsigned int ib_uverbs_event_poll(struct file *filp, 227 struct poll_table_struct *wait) 228 { 229 unsigned int pollflags = 0; 230 struct ib_uverbs_event_file *file = filp->private_data; 231 232 poll_wait(filp, &file->poll_wait, wait); 233 234 spin_lock_irq(&file->lock); 235 if (file->fd < 0) 236 pollflags = POLLERR; 237 else if (!list_empty(&file->event_list)) 238 pollflags = POLLIN | POLLRDNORM; 239 spin_unlock_irq(&file->lock); 240 241 return pollflags; 242 } 243 244 static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) 245 { 246 struct list_head *entry, *tmp; 247 248 spin_lock_irq(&file->lock); 249 if (file->fd != -1) { 250 file->fd = -1; 251 list_for_each_safe(entry, tmp, &file->event_list) 252 if (file->is_async) 253 kfree(list_entry(entry, struct ib_uverbs_async_event, list)); 254 else 255 kfree(list_entry(entry, struct ib_uverbs_comp_event, list)); 256 } 257 spin_unlock_irq(&file->lock); 258 } 259 260 static int ib_uverbs_event_close(struct inode *inode, struct file *filp) 261 { 262 struct ib_uverbs_event_file *file = filp->private_data; 263 264 ib_uverbs_event_release(file); 265 kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); 266 267 return 0; 268 } 269 270 static struct file_operations uverbs_event_fops = { 271 /* 272 * No .owner field since we artificially create event files, 273 * so there is no increment to the module reference count in 274 * the open path. All event files come from a uverbs command 275 * file, which already takes a module reference, so this is OK. 276 */ 277 .read = ib_uverbs_event_read, 278 .poll = ib_uverbs_event_poll, 279 .release = ib_uverbs_event_close 280 }; 281 282 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) 283 { 284 struct ib_uverbs_file *file = cq_context; 285 struct ib_uverbs_comp_event *entry; 286 unsigned long flags; 287 288 entry = kmalloc(sizeof *entry, GFP_ATOMIC); 289 if (!entry) 290 return; 291 292 entry->desc.cq_handle = cq->uobject->user_handle; 293 294 spin_lock_irqsave(&file->comp_file[0].lock, flags); 295 list_add_tail(&entry->list, &file->comp_file[0].event_list); 296 spin_unlock_irqrestore(&file->comp_file[0].lock, flags); 297 298 wake_up_interruptible(&file->comp_file[0].poll_wait); 299 } 300 301 static void ib_uverbs_async_handler(struct ib_uverbs_file *file, 302 __u64 element, __u64 event) 303 { 304 struct ib_uverbs_async_event *entry; 305 unsigned long flags; 306 307 entry = kmalloc(sizeof *entry, GFP_ATOMIC); 308 if (!entry) 309 return; 310 311 entry->desc.element = element; 312 entry->desc.event_type = event; 313 314 spin_lock_irqsave(&file->async_file.lock, flags); 315 list_add_tail(&entry->list, &file->async_file.event_list); 316 spin_unlock_irqrestore(&file->async_file.lock, flags); 317 318 wake_up_interruptible(&file->async_file.poll_wait); 319 } 320 321 void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) 322 { 323 ib_uverbs_async_handler(context_ptr, 324 event->element.cq->uobject->user_handle, 325 event->event); 326 } 327 328 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) 329 { 330 ib_uverbs_async_handler(context_ptr, 331 event->element.qp->uobject->user_handle, 332 event->event); 333 } 334 335 static void ib_uverbs_event_handler(struct ib_event_handler *handler, 336 struct ib_event *event) 337 { 338 struct ib_uverbs_file *file = 339 container_of(handler, struct ib_uverbs_file, event_handler); 340 341 ib_uverbs_async_handler(file, event->element.port_num, event->event); 342 } 343 344 static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, 345 struct ib_uverbs_file *uverbs_file) 346 { 347 struct file *filp; 348 349 spin_lock_init(&file->lock); 350 INIT_LIST_HEAD(&file->event_list); 351 init_waitqueue_head(&file->poll_wait); 352 file->uverbs_file = uverbs_file; 353 354 file->fd = get_unused_fd(); 355 if (file->fd < 0) 356 return file->fd; 357 358 filp = get_empty_filp(); 359 if (!filp) { 360 put_unused_fd(file->fd); 361 return -ENFILE; 362 } 363 364 filp->f_op = &uverbs_event_fops; 365 filp->f_vfsmnt = mntget(uverbs_event_mnt); 366 filp->f_dentry = dget(uverbs_event_mnt->mnt_root); 367 filp->f_mapping = filp->f_dentry->d_inode->i_mapping; 368 filp->f_flags = O_RDONLY; 369 filp->f_mode = FMODE_READ; 370 filp->private_data = file; 371 372 fd_install(file->fd, filp); 373 374 return 0; 375 } 376 377 static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, 378 size_t count, loff_t *pos) 379 { 380 struct ib_uverbs_file *file = filp->private_data; 381 struct ib_uverbs_cmd_hdr hdr; 382 383 if (count < sizeof hdr) 384 return -EINVAL; 385 386 if (copy_from_user(&hdr, buf, sizeof hdr)) 387 return -EFAULT; 388 389 if (hdr.in_words * 4 != count) 390 return -EINVAL; 391 392 if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table)) 393 return -EINVAL; 394 395 if (!file->ucontext && 396 hdr.command != IB_USER_VERBS_CMD_QUERY_PARAMS && 397 hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) 398 return -EINVAL; 399 400 return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr, 401 hdr.in_words * 4, hdr.out_words * 4); 402 } 403 404 static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) 405 { 406 struct ib_uverbs_file *file = filp->private_data; 407 408 if (!file->ucontext) 409 return -ENODEV; 410 else 411 return file->device->ib_dev->mmap(file->ucontext, vma); 412 } 413 414 static int ib_uverbs_open(struct inode *inode, struct file *filp) 415 { 416 struct ib_uverbs_device *dev = 417 container_of(inode->i_cdev, struct ib_uverbs_device, dev); 418 struct ib_uverbs_file *file; 419 int i = 0; 420 int ret; 421 422 if (!try_module_get(dev->ib_dev->owner)) 423 return -ENODEV; 424 425 file = kmalloc(sizeof *file + 426 (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file), 427 GFP_KERNEL); 428 if (!file) 429 return -ENOMEM; 430 431 file->device = dev; 432 kref_init(&file->ref); 433 434 file->ucontext = NULL; 435 436 ret = ib_uverbs_event_init(&file->async_file, file); 437 if (ret) 438 goto err; 439 440 file->async_file.is_async = 1; 441 442 kref_get(&file->ref); 443 444 for (i = 0; i < dev->num_comp; ++i) { 445 ret = ib_uverbs_event_init(&file->comp_file[i], file); 446 if (ret) 447 goto err_async; 448 kref_get(&file->ref); 449 file->comp_file[i].is_async = 0; 450 } 451 452 453 filp->private_data = file; 454 455 INIT_IB_EVENT_HANDLER(&file->event_handler, dev->ib_dev, 456 ib_uverbs_event_handler); 457 if (ib_register_event_handler(&file->event_handler)) 458 goto err_async; 459 460 return 0; 461 462 err_async: 463 while (i--) 464 ib_uverbs_event_release(&file->comp_file[i]); 465 466 ib_uverbs_event_release(&file->async_file); 467 468 err: 469 kref_put(&file->ref, ib_uverbs_release_file); 470 471 return ret; 472 } 473 474 static int ib_uverbs_close(struct inode *inode, struct file *filp) 475 { 476 struct ib_uverbs_file *file = filp->private_data; 477 int i; 478 479 ib_unregister_event_handler(&file->event_handler); 480 ib_uverbs_event_release(&file->async_file); 481 ib_dealloc_ucontext(file->ucontext); 482 483 for (i = 0; i < file->device->num_comp; ++i) 484 ib_uverbs_event_release(&file->comp_file[i]); 485 486 kref_put(&file->ref, ib_uverbs_release_file); 487 488 return 0; 489 } 490 491 static struct file_operations uverbs_fops = { 492 .owner = THIS_MODULE, 493 .write = ib_uverbs_write, 494 .open = ib_uverbs_open, 495 .release = ib_uverbs_close 496 }; 497 498 static struct file_operations uverbs_mmap_fops = { 499 .owner = THIS_MODULE, 500 .write = ib_uverbs_write, 501 .mmap = ib_uverbs_mmap, 502 .open = ib_uverbs_open, 503 .release = ib_uverbs_close 504 }; 505 506 static struct ib_client uverbs_client = { 507 .name = "uverbs", 508 .add = ib_uverbs_add_one, 509 .remove = ib_uverbs_remove_one 510 }; 511 512 static ssize_t show_ibdev(struct class_device *class_dev, char *buf) 513 { 514 struct ib_uverbs_device *dev = 515 container_of(class_dev, struct ib_uverbs_device, class_dev); 516 517 return sprintf(buf, "%s\n", dev->ib_dev->name); 518 } 519 static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); 520 521 static void ib_uverbs_release_class_dev(struct class_device *class_dev) 522 { 523 struct ib_uverbs_device *dev = 524 container_of(class_dev, struct ib_uverbs_device, class_dev); 525 526 cdev_del(&dev->dev); 527 clear_bit(dev->devnum, dev_map); 528 kfree(dev); 529 } 530 531 static struct class uverbs_class = { 532 .name = "infiniband_verbs", 533 .release = ib_uverbs_release_class_dev 534 }; 535 536 static ssize_t show_abi_version(struct class *class, char *buf) 537 { 538 return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); 539 } 540 static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); 541 542 static void ib_uverbs_add_one(struct ib_device *device) 543 { 544 struct ib_uverbs_device *uverbs_dev; 545 546 if (!device->alloc_ucontext) 547 return; 548 549 uverbs_dev = kmalloc(sizeof *uverbs_dev, GFP_KERNEL); 550 if (!uverbs_dev) 551 return; 552 553 memset(uverbs_dev, 0, sizeof *uverbs_dev); 554 555 spin_lock(&map_lock); 556 uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); 557 if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { 558 spin_unlock(&map_lock); 559 goto err; 560 } 561 set_bit(uverbs_dev->devnum, dev_map); 562 spin_unlock(&map_lock); 563 564 uverbs_dev->ib_dev = device; 565 uverbs_dev->num_comp = 1; 566 567 if (device->mmap) 568 cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops); 569 else 570 cdev_init(&uverbs_dev->dev, &uverbs_fops); 571 uverbs_dev->dev.owner = THIS_MODULE; 572 kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum); 573 if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) 574 goto err; 575 576 uverbs_dev->class_dev.class = &uverbs_class; 577 uverbs_dev->class_dev.dev = device->dma_device; 578 uverbs_dev->class_dev.devt = uverbs_dev->dev.dev; 579 snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum); 580 if (class_device_register(&uverbs_dev->class_dev)) 581 goto err_cdev; 582 583 if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev)) 584 goto err_class; 585 586 ib_set_client_data(device, &uverbs_client, uverbs_dev); 587 588 return; 589 590 err_class: 591 class_device_unregister(&uverbs_dev->class_dev); 592 593 err_cdev: 594 cdev_del(&uverbs_dev->dev); 595 clear_bit(uverbs_dev->devnum, dev_map); 596 597 err: 598 kfree(uverbs_dev); 599 return; 600 } 601 602 static void ib_uverbs_remove_one(struct ib_device *device) 603 { 604 struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client); 605 606 if (!uverbs_dev) 607 return; 608 609 class_device_unregister(&uverbs_dev->class_dev); 610 } 611 612 static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags, 613 const char *dev_name, void *data) 614 { 615 return get_sb_pseudo(fs_type, "infinibandevent:", NULL, 616 INFINIBANDEVENTFS_MAGIC); 617 } 618 619 static struct file_system_type uverbs_event_fs = { 620 /* No owner field so module can be unloaded */ 621 .name = "infinibandeventfs", 622 .get_sb = uverbs_event_get_sb, 623 .kill_sb = kill_litter_super 624 }; 625 626 static int __init ib_uverbs_init(void) 627 { 628 int ret; 629 630 spin_lock_init(&map_lock); 631 632 ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES, 633 "infiniband_verbs"); 634 if (ret) { 635 printk(KERN_ERR "user_verbs: couldn't register device number\n"); 636 goto out; 637 } 638 639 ret = class_register(&uverbs_class); 640 if (ret) { 641 printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n"); 642 goto out_chrdev; 643 } 644 645 ret = class_create_file(&uverbs_class, &class_attr_abi_version); 646 if (ret) { 647 printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); 648 goto out_class; 649 } 650 651 ret = register_filesystem(&uverbs_event_fs); 652 if (ret) { 653 printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n"); 654 goto out_class; 655 } 656 657 uverbs_event_mnt = kern_mount(&uverbs_event_fs); 658 if (IS_ERR(uverbs_event_mnt)) { 659 ret = PTR_ERR(uverbs_event_mnt); 660 printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n"); 661 goto out_fs; 662 } 663 664 ret = ib_register_client(&uverbs_client); 665 if (ret) { 666 printk(KERN_ERR "user_verbs: couldn't register client\n"); 667 goto out_mnt; 668 } 669 670 return 0; 671 672 out_mnt: 673 mntput(uverbs_event_mnt); 674 675 out_fs: 676 unregister_filesystem(&uverbs_event_fs); 677 678 out_class: 679 class_unregister(&uverbs_class); 680 681 out_chrdev: 682 unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); 683 684 out: 685 return ret; 686 } 687 688 static void __exit ib_uverbs_cleanup(void) 689 { 690 ib_unregister_client(&uverbs_client); 691 mntput(uverbs_event_mnt); 692 unregister_filesystem(&uverbs_event_fs); 693 class_unregister(&uverbs_class); 694 unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); 695 } 696 697 module_init(ib_uverbs_init); 698 module_exit(ib_uverbs_cleanup); 699