diff options
author | Leon Romanovsky <leonro@mellanox.com> | 2017-06-05 03:20:11 -0400 |
---|---|---|
committer | Leon Romanovsky <leon@kernel.org> | 2017-08-10 06:13:06 -0400 |
commit | c9901724a2f14128ef6a57986babcbfbcf61a257 (patch) | |
tree | a7312ed62f5dee155077aeb4abaa33e055fd643a /drivers/infiniband/core/netlink.c | |
parent | 9047811b776ce09ba06623dd2a846cc501f0065b (diff) |
RDMA/netlink: Remove netlink clients infrastructure
RDMA netlink has a complicated infrastructure for dynamically
registering and de-registering netlink clients to the NETLINK_RDMA
group. The complicated portion of this code is not widely used because
2 of the 3 current clients are statically compiled together with
netlink.c. The infrastructure, therefore, is deemed overkill.
Refactor the code to eliminate the dynamically added clients. Now all
clients are pre-registered in a client array at compile time, and at run
time they merely check-in with the infrastructure to pass their callback
table for inclusion in the pre-sized client array.
This also allows for future cleanups and removal of unneeded code in the
iwcm* netlink handler.
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Reviewed-by: Chien Tin Tung <chien.tin.tung@intel.com>
Diffstat (limited to 'drivers/infiniband/core/netlink.c')
-rw-r--r-- | drivers/infiniband/core/netlink.c | 185 |
1 files changed, 89 insertions, 96 deletions
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c index 0fc50e15ae22..06f7ba31fbdd 100644 --- a/drivers/infiniband/core/netlink.c +++ b/drivers/infiniband/core/netlink.c | |||
@@ -39,16 +39,13 @@ | |||
39 | #include <rdma/rdma_netlink.h> | 39 | #include <rdma/rdma_netlink.h> |
40 | #include "core_priv.h" | 40 | #include "core_priv.h" |
41 | 41 | ||
42 | struct ibnl_client { | 42 | #include "core_priv.h" |
43 | struct list_head list; | ||
44 | int index; | ||
45 | int nops; | ||
46 | const struct ibnl_client_cbs *cb_table; | ||
47 | }; | ||
48 | 43 | ||
49 | static DEFINE_MUTEX(ibnl_mutex); | 44 | static DEFINE_MUTEX(rdma_nl_mutex); |
50 | static struct sock *nls; | 45 | static struct sock *nls; |
51 | static LIST_HEAD(client_list); | 46 | static struct { |
47 | const struct ibnl_client_cbs *cb_table; | ||
48 | } rdma_nl_types[RDMA_NL_NUM_CLIENTS]; | ||
52 | 49 | ||
53 | int ibnl_chk_listeners(unsigned int group) | 50 | int ibnl_chk_listeners(unsigned int group) |
54 | { | 51 | { |
@@ -57,58 +54,74 @@ int ibnl_chk_listeners(unsigned int group) | |||
57 | return 0; | 54 | return 0; |
58 | } | 55 | } |
59 | 56 | ||
60 | int ibnl_add_client(int index, int nops, | 57 | static bool is_nl_msg_valid(unsigned int type, unsigned int op) |
61 | const struct ibnl_client_cbs cb_table[]) | ||
62 | { | 58 | { |
63 | struct ibnl_client *cur; | 59 | static const unsigned int max_num_ops[RDMA_NL_NUM_CLIENTS - 1] = { |
64 | struct ibnl_client *nl_client; | 60 | RDMA_NL_RDMA_CM_NUM_OPS, |
61 | RDMA_NL_IWPM_NUM_OPS, | ||
62 | 0, | ||
63 | RDMA_NL_LS_NUM_OPS, | ||
64 | 0 }; | ||
65 | 65 | ||
66 | nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL); | 66 | /* |
67 | if (!nl_client) | 67 | * This BUILD_BUG_ON is intended to catch addition of new |
68 | return -ENOMEM; | 68 | * RDMA netlink protocol without updating the array above. |
69 | */ | ||
70 | BUILD_BUG_ON(RDMA_NL_NUM_CLIENTS != 6); | ||
69 | 71 | ||
70 | nl_client->index = index; | 72 | if (type > RDMA_NL_NUM_CLIENTS - 1) |
71 | nl_client->nops = nops; | 73 | return false; |
72 | nl_client->cb_table = cb_table; | ||
73 | 74 | ||
74 | mutex_lock(&ibnl_mutex); | 75 | return (op < max_num_ops[type - 1]) ? true : false; |
76 | } | ||
75 | 77 | ||
76 | list_for_each_entry(cur, &client_list, list) { | 78 | static bool is_nl_valid(unsigned int type, unsigned int op) |
77 | if (cur->index == index) { | 79 | { |
78 | pr_warn("Client for %d already exists\n", index); | 80 | if (!is_nl_msg_valid(type, op) || |
79 | mutex_unlock(&ibnl_mutex); | 81 | !rdma_nl_types[type].cb_table || |
80 | kfree(nl_client); | 82 | !rdma_nl_types[type].cb_table[op].dump) |
81 | return -EINVAL; | 83 | return false; |
82 | } | 84 | return true; |
83 | } | 85 | } |
84 | 86 | ||
85 | list_add_tail(&nl_client->list, &client_list); | 87 | void rdma_nl_register(unsigned int index, |
88 | const struct ibnl_client_cbs cb_table[]) | ||
89 | { | ||
90 | mutex_lock(&rdma_nl_mutex); | ||
91 | if (!is_nl_msg_valid(index, 0)) { | ||
92 | /* | ||
93 | * All clients are not interesting in success/failure of | ||
94 | * this call. They want to see the print to error log and | ||
95 | * continue their initialization. Print warning for them, | ||
96 | * because it is programmer's error to be here. | ||
97 | */ | ||
98 | mutex_unlock(&rdma_nl_mutex); | ||
99 | WARN(true, | ||
100 | "The not-valid %u index was supplied to RDMA netlink\n", | ||
101 | index); | ||
102 | return; | ||
103 | } | ||
86 | 104 | ||
87 | mutex_unlock(&ibnl_mutex); | 105 | if (rdma_nl_types[index].cb_table) { |
106 | mutex_unlock(&rdma_nl_mutex); | ||
107 | WARN(true, | ||
108 | "The %u index is already registered in RDMA netlink\n", | ||
109 | index); | ||
110 | return; | ||
111 | } | ||
88 | 112 | ||
89 | return 0; | 113 | rdma_nl_types[index].cb_table = cb_table; |
114 | mutex_unlock(&rdma_nl_mutex); | ||
90 | } | 115 | } |
91 | EXPORT_SYMBOL(ibnl_add_client); | 116 | EXPORT_SYMBOL(rdma_nl_register); |
92 | 117 | ||
93 | int ibnl_remove_client(int index) | 118 | void rdma_nl_unregister(unsigned int index) |
94 | { | 119 | { |
95 | struct ibnl_client *cur, *next; | 120 | mutex_lock(&rdma_nl_mutex); |
96 | 121 | rdma_nl_types[index].cb_table = NULL; | |
97 | mutex_lock(&ibnl_mutex); | 122 | mutex_unlock(&rdma_nl_mutex); |
98 | list_for_each_entry_safe(cur, next, &client_list, list) { | ||
99 | if (cur->index == index) { | ||
100 | list_del(&(cur->list)); | ||
101 | mutex_unlock(&ibnl_mutex); | ||
102 | kfree(cur); | ||
103 | return 0; | ||
104 | } | ||
105 | } | ||
106 | pr_warn("Can't remove callback for client idx %d. Not found\n", index); | ||
107 | mutex_unlock(&ibnl_mutex); | ||
108 | |||
109 | return -EINVAL; | ||
110 | } | 123 | } |
111 | EXPORT_SYMBOL(ibnl_remove_client); | 124 | EXPORT_SYMBOL(rdma_nl_unregister); |
112 | 125 | ||
113 | void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, | 126 | void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, |
114 | int len, int client, int op, int flags) | 127 | int len, int client, int op, int flags) |
@@ -149,45 +162,31 @@ EXPORT_SYMBOL(ibnl_put_attr); | |||
149 | static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | 162 | static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, |
150 | struct netlink_ext_ack *extack) | 163 | struct netlink_ext_ack *extack) |
151 | { | 164 | { |
152 | struct ibnl_client *client; | ||
153 | int type = nlh->nlmsg_type; | 165 | int type = nlh->nlmsg_type; |
154 | int index = RDMA_NL_GET_CLIENT(type); | 166 | unsigned int index = RDMA_NL_GET_CLIENT(type); |
155 | unsigned int op = RDMA_NL_GET_OP(type); | 167 | unsigned int op = RDMA_NL_GET_OP(type); |
168 | struct netlink_callback cb = {}; | ||
169 | struct netlink_dump_control c = {}; | ||
156 | 170 | ||
157 | list_for_each_entry(client, &client_list, list) { | 171 | if (!is_nl_valid(index, op)) |
158 | if (client->index == index) { | 172 | return -EINVAL; |
159 | if (op >= client->nops || !client->cb_table[op].dump) | 173 | |
160 | return -EINVAL; | 174 | /* |
161 | 175 | * For response or local service set_timeout request, | |
162 | /* | 176 | * there is no need to use netlink_dump_start. |
163 | * For response or local service set_timeout request, | 177 | */ |
164 | * there is no need to use netlink_dump_start. | 178 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST) || |
165 | */ | 179 | (index == RDMA_NL_LS && op == RDMA_NL_LS_OP_SET_TIMEOUT)) { |
166 | if (!(nlh->nlmsg_flags & NLM_F_REQUEST) || | 180 | cb.skb = skb; |
167 | (index == RDMA_NL_LS && | 181 | cb.nlh = nlh; |
168 | op == RDMA_NL_LS_OP_SET_TIMEOUT)) { | 182 | cb.dump = rdma_nl_types[index].cb_table[op].dump; |
169 | struct netlink_callback cb = { | 183 | cb.module = rdma_nl_types[index].cb_table[op].module; |
170 | .skb = skb, | 184 | return cb.dump(skb, &cb); |
171 | .nlh = nlh, | ||
172 | .dump = client->cb_table[op].dump, | ||
173 | .module = client->cb_table[op].module, | ||
174 | }; | ||
175 | |||
176 | return cb.dump(skb, &cb); | ||
177 | } | ||
178 | |||
179 | { | ||
180 | struct netlink_dump_control c = { | ||
181 | .dump = client->cb_table[op].dump, | ||
182 | .module = client->cb_table[op].module, | ||
183 | }; | ||
184 | return netlink_dump_start(nls, skb, nlh, &c); | ||
185 | } | ||
186 | } | ||
187 | } | 185 | } |
188 | 186 | ||
189 | pr_info("Index %d wasn't found in client list\n", index); | 187 | c.dump = rdma_nl_types[index].cb_table[op].dump; |
190 | return -EINVAL; | 188 | c.module = rdma_nl_types[index].cb_table[op].module; |
189 | return netlink_dump_start(nls, skb, nlh, &c); | ||
191 | } | 190 | } |
192 | 191 | ||
193 | static void ibnl_rcv_reply_skb(struct sk_buff *skb) | 192 | static void ibnl_rcv_reply_skb(struct sk_buff *skb) |
@@ -221,10 +220,10 @@ static void ibnl_rcv_reply_skb(struct sk_buff *skb) | |||
221 | 220 | ||
222 | static void ibnl_rcv(struct sk_buff *skb) | 221 | static void ibnl_rcv(struct sk_buff *skb) |
223 | { | 222 | { |
224 | mutex_lock(&ibnl_mutex); | 223 | mutex_lock(&rdma_nl_mutex); |
225 | ibnl_rcv_reply_skb(skb); | 224 | ibnl_rcv_reply_skb(skb); |
226 | netlink_rcv_skb(skb, &ibnl_rcv_msg); | 225 | netlink_rcv_skb(skb, &ibnl_rcv_msg); |
227 | mutex_unlock(&ibnl_mutex); | 226 | mutex_unlock(&rdma_nl_mutex); |
228 | } | 227 | } |
229 | 228 | ||
230 | int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh, | 229 | int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh, |
@@ -254,32 +253,26 @@ int ibnl_multicast(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
254 | } | 253 | } |
255 | EXPORT_SYMBOL(ibnl_multicast); | 254 | EXPORT_SYMBOL(ibnl_multicast); |
256 | 255 | ||
257 | int __init ibnl_init(void) | 256 | int __init rdma_nl_init(void) |
258 | { | 257 | { |
259 | struct netlink_kernel_cfg cfg = { | 258 | struct netlink_kernel_cfg cfg = { |
260 | .input = ibnl_rcv, | 259 | .input = ibnl_rcv, |
261 | }; | 260 | }; |
262 | 261 | ||
263 | nls = netlink_kernel_create(&init_net, NETLINK_RDMA, &cfg); | 262 | nls = netlink_kernel_create(&init_net, NETLINK_RDMA, &cfg); |
264 | if (!nls) { | 263 | if (!nls) |
265 | pr_warn("Failed to create netlink socket\n"); | ||
266 | return -ENOMEM; | 264 | return -ENOMEM; |
267 | } | ||
268 | 265 | ||
269 | nls->sk_sndtimeo = 10 * HZ; | 266 | nls->sk_sndtimeo = 10 * HZ; |
270 | return 0; | 267 | return 0; |
271 | } | 268 | } |
272 | 269 | ||
273 | void ibnl_cleanup(void) | 270 | void rdma_nl_exit(void) |
274 | { | 271 | { |
275 | struct ibnl_client *cur, *next; | 272 | int idx; |
276 | 273 | ||
277 | mutex_lock(&ibnl_mutex); | 274 | for (idx = 0; idx < RDMA_NL_NUM_CLIENTS; idx++) |
278 | list_for_each_entry_safe(cur, next, &client_list, list) { | 275 | rdma_nl_unregister(idx); |
279 | list_del(&(cur->list)); | ||
280 | kfree(cur); | ||
281 | } | ||
282 | mutex_unlock(&ibnl_mutex); | ||
283 | 276 | ||
284 | netlink_kernel_release(nls); | 277 | netlink_kernel_release(nls); |
285 | } | 278 | } |