diff options
| -rw-r--r-- | drivers/infiniband/core/device.c | 50 | ||||
| -rw-r--r-- | include/rdma/ib_verbs.h | 3 |
2 files changed, 47 insertions, 6 deletions
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 3a80f96c2919..f87d85659359 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c | |||
| @@ -65,15 +65,17 @@ struct workqueue_struct *ib_comp_unbound_wq; | |||
| 65 | struct workqueue_struct *ib_wq; | 65 | struct workqueue_struct *ib_wq; |
| 66 | EXPORT_SYMBOL_GPL(ib_wq); | 66 | EXPORT_SYMBOL_GPL(ib_wq); |
| 67 | 67 | ||
| 68 | /* The device_list and client_list contain devices and clients after their | 68 | /* The device_list and clients contain devices and clients after their |
| 69 | * registration has completed, and the devices and clients are removed | 69 | * registration has completed, and the devices and clients are removed |
| 70 | * during unregistration. */ | 70 | * during unregistration. */ |
| 71 | static LIST_HEAD(device_list); | 71 | static LIST_HEAD(device_list); |
| 72 | static LIST_HEAD(client_list); | 72 | static LIST_HEAD(client_list); |
| 73 | #define CLIENT_REGISTERED XA_MARK_1 | ||
| 74 | static DEFINE_XARRAY_FLAGS(clients, XA_FLAGS_ALLOC); | ||
| 73 | 75 | ||
| 74 | /* | 76 | /* |
| 75 | * device_mutex and lists_rwsem protect access to both device_list and | 77 | * device_mutex and lists_rwsem protect access to both device_list and |
| 76 | * client_list. device_mutex protects writer access by device and client | 78 | * clients. device_mutex protects writer access by device and client |
| 77 | * registration / de-registration. lists_rwsem protects reader access to | 79 | * registration / de-registration. lists_rwsem protects reader access to |
| 78 | * these lists. Iterators of these lists must lock it for read, while updates | 80 | * these lists. Iterators of these lists must lock it for read, while updates |
| 79 | * to the lists must be done with a write lock. A special case is when the | 81 | * to the lists must be done with a write lock. A special case is when the |
| @@ -564,6 +566,7 @@ int ib_register_device(struct ib_device *device, const char *name) | |||
| 564 | { | 566 | { |
| 565 | int ret; | 567 | int ret; |
| 566 | struct ib_client *client; | 568 | struct ib_client *client; |
| 569 | unsigned long index; | ||
| 567 | 570 | ||
| 568 | setup_dma_device(device); | 571 | setup_dma_device(device); |
| 569 | 572 | ||
| @@ -608,7 +611,7 @@ int ib_register_device(struct ib_device *device, const char *name) | |||
| 608 | 611 | ||
| 609 | refcount_set(&device->refcount, 1); | 612 | refcount_set(&device->refcount, 1); |
| 610 | 613 | ||
| 611 | list_for_each_entry(client, &client_list, list) | 614 | xa_for_each_marked (&clients, index, client, CLIENT_REGISTERED) |
| 612 | if (!add_client_context(device, client) && client->add) | 615 | if (!add_client_context(device, client) && client->add) |
| 613 | client->add(device); | 616 | client->add(device); |
| 614 | 617 | ||
| @@ -680,6 +683,32 @@ void ib_unregister_device(struct ib_device *device) | |||
| 680 | } | 683 | } |
| 681 | EXPORT_SYMBOL(ib_unregister_device); | 684 | EXPORT_SYMBOL(ib_unregister_device); |
| 682 | 685 | ||
| 686 | static int assign_client_id(struct ib_client *client) | ||
| 687 | { | ||
| 688 | int ret; | ||
| 689 | |||
| 690 | /* | ||
| 691 | * The add/remove callbacks must be called in FIFO/LIFO order. To | ||
| 692 | * achieve this we assign client_ids so they are sorted in | ||
| 693 | * registration order, and retain a linked list we can reverse iterate | ||
| 694 | * to get the LIFO order. The extra linked list can go away if xarray | ||
| 695 | * learns to reverse iterate. | ||
| 696 | */ | ||
| 697 | if (list_empty(&client_list)) | ||
| 698 | client->client_id = 0; | ||
| 699 | else | ||
| 700 | client->client_id = | ||
| 701 | list_last_entry(&client_list, struct ib_client, list) | ||
| 702 | ->client_id; | ||
| 703 | ret = xa_alloc(&clients, &client->client_id, INT_MAX, client, | ||
| 704 | GFP_KERNEL); | ||
| 705 | if (ret) | ||
| 706 | goto out; | ||
| 707 | |||
| 708 | out: | ||
| 709 | return ret; | ||
| 710 | } | ||
| 711 | |||
| 683 | /** | 712 | /** |
| 684 | * ib_register_client - Register an IB client | 713 | * ib_register_client - Register an IB client |
| 685 | * @client:Client to register | 714 | * @client:Client to register |
| @@ -696,15 +725,21 @@ EXPORT_SYMBOL(ib_unregister_device); | |||
| 696 | int ib_register_client(struct ib_client *client) | 725 | int ib_register_client(struct ib_client *client) |
| 697 | { | 726 | { |
| 698 | struct ib_device *device; | 727 | struct ib_device *device; |
| 728 | int ret; | ||
| 699 | 729 | ||
| 700 | mutex_lock(&device_mutex); | 730 | mutex_lock(&device_mutex); |
| 731 | ret = assign_client_id(client); | ||
| 732 | if (ret) { | ||
| 733 | mutex_unlock(&device_mutex); | ||
| 734 | return ret; | ||
| 735 | } | ||
| 701 | 736 | ||
| 702 | list_for_each_entry(device, &device_list, core_list) | 737 | list_for_each_entry(device, &device_list, core_list) |
| 703 | if (!add_client_context(device, client) && client->add) | 738 | if (!add_client_context(device, client) && client->add) |
| 704 | client->add(device); | 739 | client->add(device); |
| 705 | 740 | ||
| 706 | down_write(&lists_rwsem); | 741 | down_write(&lists_rwsem); |
| 707 | list_add_tail(&client->list, &client_list); | 742 | xa_set_mark(&clients, client->client_id, CLIENT_REGISTERED); |
| 708 | up_write(&lists_rwsem); | 743 | up_write(&lists_rwsem); |
| 709 | 744 | ||
| 710 | mutex_unlock(&device_mutex); | 745 | mutex_unlock(&device_mutex); |
| @@ -729,7 +764,7 @@ void ib_unregister_client(struct ib_client *client) | |||
| 729 | mutex_lock(&device_mutex); | 764 | mutex_lock(&device_mutex); |
| 730 | 765 | ||
| 731 | down_write(&lists_rwsem); | 766 | down_write(&lists_rwsem); |
| 732 | list_del(&client->list); | 767 | xa_clear_mark(&clients, client->client_id, CLIENT_REGISTERED); |
| 733 | up_write(&lists_rwsem); | 768 | up_write(&lists_rwsem); |
| 734 | 769 | ||
| 735 | list_for_each_entry(device, &device_list, core_list) { | 770 | list_for_each_entry(device, &device_list, core_list) { |
| @@ -765,6 +800,10 @@ void ib_unregister_client(struct ib_client *client) | |||
| 765 | kfree(found_context); | 800 | kfree(found_context); |
| 766 | } | 801 | } |
| 767 | 802 | ||
| 803 | down_write(&lists_rwsem); | ||
| 804 | list_del(&client->list); | ||
| 805 | xa_erase(&clients, client->client_id); | ||
| 806 | up_write(&lists_rwsem); | ||
| 768 | mutex_unlock(&device_mutex); | 807 | mutex_unlock(&device_mutex); |
| 769 | } | 808 | } |
| 770 | EXPORT_SYMBOL(ib_unregister_client); | 809 | EXPORT_SYMBOL(ib_unregister_client); |
| @@ -1422,6 +1461,7 @@ static void __exit ib_core_cleanup(void) | |||
| 1422 | destroy_workqueue(ib_comp_wq); | 1461 | destroy_workqueue(ib_comp_wq); |
| 1423 | /* Make sure that any pending umem accounting work is done. */ | 1462 | /* Make sure that any pending umem accounting work is done. */ |
| 1424 | destroy_workqueue(ib_wq); | 1463 | destroy_workqueue(ib_wq); |
| 1464 | WARN_ON(!xa_empty(&clients)); | ||
| 1425 | } | 1465 | } |
| 1426 | 1466 | ||
| 1427 | MODULE_ALIAS_RDMA_NETLINK(RDMA_NL_LS, 4); | 1467 | MODULE_ALIAS_RDMA_NETLINK(RDMA_NL_LS, 4); |
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index d8ba987e8b29..cc15820513cd 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h | |||
| @@ -2610,7 +2610,7 @@ struct ib_device { | |||
| 2610 | }; | 2610 | }; |
| 2611 | 2611 | ||
| 2612 | struct ib_client { | 2612 | struct ib_client { |
| 2613 | char *name; | 2613 | const char *name; |
| 2614 | void (*add) (struct ib_device *); | 2614 | void (*add) (struct ib_device *); |
| 2615 | void (*remove)(struct ib_device *, void *client_data); | 2615 | void (*remove)(struct ib_device *, void *client_data); |
| 2616 | 2616 | ||
| @@ -2637,6 +2637,7 @@ struct ib_client { | |||
| 2637 | const struct sockaddr *addr, | 2637 | const struct sockaddr *addr, |
| 2638 | void *client_data); | 2638 | void *client_data); |
| 2639 | struct list_head list; | 2639 | struct list_head list; |
| 2640 | u32 client_id; | ||
| 2640 | 2641 | ||
| 2641 | /* kverbs are not required by the client */ | 2642 | /* kverbs are not required by the client */ |
| 2642 | u8 no_kverbs_req:1; | 2643 | u8 no_kverbs_req:1; |
