aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeon Romanovsky <leonro@mellanox.com>2018-01-01 06:07:15 -0500
committerJason Gunthorpe <jgg@mellanox.com>2018-01-02 16:11:40 -0500
commitf8978bd95cf92f869f3d9b34c1b699f49253b8c6 (patch)
tree54b791e66ed3e93338982601d5f9eec8cad75e7d
parent16ba3defb8bd01a9464ba4820a487f5b196b455b (diff)
RDMA/netlink: Fix locking around __ib_get_device_by_index
Holding locks is mandatory when calling __ib_device_get_by_index, otherwise there are races during the list iteration with device removal. Since the locks are static to device.c, __ib_device_get_by_index can never be called correctly by any user out side the file. Make the function static and provide a safe function that gets the correct locks and returns a kref'd pointer. Fix all callers. Fixes: e5c9469efcb1 ("RDMA/netlink: Add nldev device doit implementation") Fixes: c3f66f7b0052 ("RDMA/netlink: Implement nldev port doit callback") Fixes: 7d02f605f0dc ("RDMA/netlink: Add nldev port dumpit implementation") Reviewed-by: Mark Bloch <markb@mellanox.com> Signed-off-by: Leon Romanovsky <leonro@mellanox.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
-rw-r--r--drivers/infiniband/core/core_priv.h2
-rw-r--r--drivers/infiniband/core/device.c18
-rw-r--r--drivers/infiniband/core/nldev.c54
3 files changed, 54 insertions, 20 deletions
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index a1d687a664f8..66f0268f37a6 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -314,7 +314,7 @@ static inline int ib_mad_enforce_security(struct ib_mad_agent_private *map,
314} 314}
315#endif 315#endif
316 316
317struct ib_device *__ib_device_get_by_index(u32 ifindex); 317struct ib_device *ib_device_get_by_index(u32 ifindex);
318/* RDMA device netlink */ 318/* RDMA device netlink */
319void nldev_init(void); 319void nldev_init(void);
320void nldev_exit(void); 320void nldev_exit(void);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 30914f3baa5f..465520627e4b 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -134,7 +134,7 @@ static int ib_device_check_mandatory(struct ib_device *device)
134 return 0; 134 return 0;
135} 135}
136 136
137struct ib_device *__ib_device_get_by_index(u32 index) 137static struct ib_device *__ib_device_get_by_index(u32 index)
138{ 138{
139 struct ib_device *device; 139 struct ib_device *device;
140 140
@@ -145,6 +145,22 @@ struct ib_device *__ib_device_get_by_index(u32 index)
145 return NULL; 145 return NULL;
146} 146}
147 147
148/*
149 * Caller is responsible to return refrerence count by calling put_device()
150 */
151struct ib_device *ib_device_get_by_index(u32 index)
152{
153 struct ib_device *device;
154
155 down_read(&lists_rwsem);
156 device = __ib_device_get_by_index(index);
157 if (device)
158 get_device(&device->dev);
159
160 up_read(&lists_rwsem);
161 return device;
162}
163
148static struct ib_device *__ib_device_get_by_name(const char *name) 164static struct ib_device *__ib_device_get_by_name(const char *name)
149{ 165{
150 struct ib_device *device; 166 struct ib_device *device;
diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 9a05245a1acf..0dcd1aa6f683 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -142,27 +142,34 @@ static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
142 142
143 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 143 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
144 144
145 device = __ib_device_get_by_index(index); 145 device = ib_device_get_by_index(index);
146 if (!device) 146 if (!device)
147 return -EINVAL; 147 return -EINVAL;
148 148
149 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 149 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
150 if (!msg) 150 if (!msg) {
151 return -ENOMEM; 151 err = -ENOMEM;
152 goto err;
153 }
152 154
153 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 155 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
154 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET), 156 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
155 0, 0); 157 0, 0);
156 158
157 err = fill_dev_info(msg, device); 159 err = fill_dev_info(msg, device);
158 if (err) { 160 if (err)
159 nlmsg_free(msg); 161 goto err_free;
160 return err;
161 }
162 162
163 nlmsg_end(msg, nlh); 163 nlmsg_end(msg, nlh);
164 164
165 put_device(&device->dev);
165 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid); 166 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
167
168err_free:
169 nlmsg_free(msg);
170err:
171 put_device(&device->dev);
172 return err;
166} 173}
167 174
168static int _nldev_get_dumpit(struct ib_device *device, 175static int _nldev_get_dumpit(struct ib_device *device,
@@ -220,31 +227,40 @@ static int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
220 return -EINVAL; 227 return -EINVAL;
221 228
222 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 229 index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
223 device = __ib_device_get_by_index(index); 230 device = ib_device_get_by_index(index);
224 if (!device) 231 if (!device)
225 return -EINVAL; 232 return -EINVAL;
226 233
227 port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 234 port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
228 if (!rdma_is_port_valid(device, port)) 235 if (!rdma_is_port_valid(device, port)) {
229 return -EINVAL; 236 err = -EINVAL;
237 goto err;
238 }
230 239
231 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 240 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
232 if (!msg) 241 if (!msg) {
233 return -ENOMEM; 242 err = -ENOMEM;
243 goto err;
244 }
234 245
235 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 246 nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
236 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET), 247 RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET),
237 0, 0); 248 0, 0);
238 249
239 err = fill_port_info(msg, device, port); 250 err = fill_port_info(msg, device, port);
240 if (err) { 251 if (err)
241 nlmsg_free(msg); 252 goto err_free;
242 return err;
243 }
244 253
245 nlmsg_end(msg, nlh); 254 nlmsg_end(msg, nlh);
255 put_device(&device->dev);
246 256
247 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid); 257 return rdma_nl_unicast(msg, NETLINK_CB(skb).portid);
258
259err_free:
260 nlmsg_free(msg);
261err:
262 put_device(&device->dev);
263 return err;
248} 264}
249 265
250static int nldev_port_get_dumpit(struct sk_buff *skb, 266static int nldev_port_get_dumpit(struct sk_buff *skb,
@@ -265,7 +281,7 @@ static int nldev_port_get_dumpit(struct sk_buff *skb,
265 return -EINVAL; 281 return -EINVAL;
266 282
267 ifindex = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 283 ifindex = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
268 device = __ib_device_get_by_index(ifindex); 284 device = ib_device_get_by_index(ifindex);
269 if (!device) 285 if (!device)
270 return -EINVAL; 286 return -EINVAL;
271 287
@@ -299,7 +315,9 @@ static int nldev_port_get_dumpit(struct sk_buff *skb,
299 nlmsg_end(skb, nlh); 315 nlmsg_end(skb, nlh);
300 } 316 }
301 317
302out: cb->args[0] = idx; 318out:
319 put_device(&device->dev);
320 cb->args[0] = idx;
303 return skb->len; 321 return skb->len;
304} 322}
305 323