aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/core/device.c50
-rw-r--r--include/rdma/ib_verbs.h3
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;
65struct workqueue_struct *ib_wq; 65struct workqueue_struct *ib_wq;
66EXPORT_SYMBOL_GPL(ib_wq); 66EXPORT_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. */
71static LIST_HEAD(device_list); 71static LIST_HEAD(device_list);
72static LIST_HEAD(client_list); 72static LIST_HEAD(client_list);
73#define CLIENT_REGISTERED XA_MARK_1
74static 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}
681EXPORT_SYMBOL(ib_unregister_device); 684EXPORT_SYMBOL(ib_unregister_device);
682 685
686static 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
708out:
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);
696int ib_register_client(struct ib_client *client) 725int 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}
770EXPORT_SYMBOL(ib_unregister_client); 809EXPORT_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
1427MODULE_ALIAS_RDMA_NETLINK(RDMA_NL_LS, 4); 1467MODULE_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
2612struct ib_client { 2612struct 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;