diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-12-04 20:23:53 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-08 13:07:24 -0500 |
commit | 941666c2e3e0f9f6a1cb5808d02352d445bd702c (patch) | |
tree | 389a773580ef22908391cc71f98982b03de62804 /net/llc/af_llc.c | |
parent | a2d4b65d477aad1fe8c7218781a031fa9cf5abfc (diff) |
net: RCU conversion of dev_getbyhwaddr() and arp_ioctl()
Le dimanche 05 décembre 2010 à 09:19 +0100, Eric Dumazet a écrit :
> Hmm..
>
> If somebody can explain why RTNL is held in arp_ioctl() (and therefore
> in arp_req_delete()), we might first remove RTNL use in arp_ioctl() so
> that your patch can be applied.
>
> Right now it is not good, because RTNL wont be necessarly held when you
> are going to call arp_invalidate() ?
While doing this analysis, I found a refcount bug in llc, I'll send a
patch for net-2.6
Meanwhile, here is the patch for net-next-2.6
Your patch then can be applied after mine.
Thanks
[PATCH] net: RCU conversion of dev_getbyhwaddr() and arp_ioctl()
dev_getbyhwaddr() was called under RTNL.
Rename it to dev_getbyhwaddr_rcu() and change all its caller to now use
RCU locking instead of RTNL.
Change arp_ioctl() to use RCU instead of RTNL locking.
Note: this fix a dev refcount bug in llc
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/llc/af_llc.c')
-rw-r--r-- | net/llc/af_llc.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 582612998211..dfd3a648a551 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c | |||
@@ -316,9 +316,9 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
316 | if (unlikely(addr->sllc_family != AF_LLC)) | 316 | if (unlikely(addr->sllc_family != AF_LLC)) |
317 | goto out; | 317 | goto out; |
318 | rc = -ENODEV; | 318 | rc = -ENODEV; |
319 | rtnl_lock(); | 319 | rcu_read_lock(); |
320 | if (sk->sk_bound_dev_if) { | 320 | if (sk->sk_bound_dev_if) { |
321 | llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); | 321 | llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); |
322 | if (llc->dev) { | 322 | if (llc->dev) { |
323 | if (!addr->sllc_arphrd) | 323 | if (!addr->sllc_arphrd) |
324 | addr->sllc_arphrd = llc->dev->type; | 324 | addr->sllc_arphrd = llc->dev->type; |
@@ -329,14 +329,15 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
329 | !llc_mac_match(addr->sllc_mac, | 329 | !llc_mac_match(addr->sllc_mac, |
330 | llc->dev->dev_addr)) { | 330 | llc->dev->dev_addr)) { |
331 | rc = -EINVAL; | 331 | rc = -EINVAL; |
332 | dev_put(llc->dev); | ||
333 | llc->dev = NULL; | 332 | llc->dev = NULL; |
334 | } | 333 | } |
335 | } | 334 | } |
336 | } else | 335 | } else |
337 | llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, | 336 | llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, |
338 | addr->sllc_mac); | 337 | addr->sllc_mac); |
339 | rtnl_unlock(); | 338 | if (llc->dev) |
339 | dev_hold(llc->dev); | ||
340 | rcu_read_unlock(); | ||
340 | if (!llc->dev) | 341 | if (!llc->dev) |
341 | goto out; | 342 | goto out; |
342 | if (!addr->sllc_sap) { | 343 | if (!addr->sllc_sap) { |