diff options
author | Bob Peterson <rpeterso@redhat.com> | 2017-08-23 10:43:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-24 17:02:26 -0400 |
commit | 6c7e983b220f89e03286dc70a41c7ef3a8b409df (patch) | |
tree | 1ebaac5eee32fab5d7360c852260e500150b6ab9 /net/tipc/socket.c | |
parent | e58f95831e7468d25eb6e41f234842ecfe6f014f (diff) |
tipc: Fix tipc_sk_reinit handling of -EAGAIN
In 9dbbfb0ab6680c6a85609041011484e6658e7d3c function tipc_sk_reinit
had additional logic added to loop in the event that function
rhashtable_walk_next() returned -EAGAIN. No worries.
However, if rhashtable_walk_start returns -EAGAIN, it does "continue",
and therefore skips the call to rhashtable_walk_stop(). That has
the effect of calling rcu_read_lock() without its paired call to
rcu_read_unlock(). Since rcu_read_lock() may be nested, the problem
may not be apparent for a while, especially since resize events may
be rare. But the comments to rhashtable_walk_start() state:
* ...Note that we take the RCU lock in all
* cases including when we return an error. So you must always call
* rhashtable_walk_stop to clean up.
This patch replaces the continue with a goto and label to ensure a
matching call to rhashtable_walk_stop().
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 101e3597338f..d50edd6e0019 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -2255,8 +2255,8 @@ void tipc_sk_reinit(struct net *net) | |||
2255 | 2255 | ||
2256 | do { | 2256 | do { |
2257 | tsk = ERR_PTR(rhashtable_walk_start(&iter)); | 2257 | tsk = ERR_PTR(rhashtable_walk_start(&iter)); |
2258 | if (tsk) | 2258 | if (IS_ERR(tsk)) |
2259 | continue; | 2259 | goto walk_stop; |
2260 | 2260 | ||
2261 | while ((tsk = rhashtable_walk_next(&iter)) && !IS_ERR(tsk)) { | 2261 | while ((tsk = rhashtable_walk_next(&iter)) && !IS_ERR(tsk)) { |
2262 | spin_lock_bh(&tsk->sk.sk_lock.slock); | 2262 | spin_lock_bh(&tsk->sk.sk_lock.slock); |
@@ -2265,7 +2265,7 @@ void tipc_sk_reinit(struct net *net) | |||
2265 | msg_set_orignode(msg, tn->own_addr); | 2265 | msg_set_orignode(msg, tn->own_addr); |
2266 | spin_unlock_bh(&tsk->sk.sk_lock.slock); | 2266 | spin_unlock_bh(&tsk->sk.sk_lock.slock); |
2267 | } | 2267 | } |
2268 | 2268 | walk_stop: | |
2269 | rhashtable_walk_stop(&iter); | 2269 | rhashtable_walk_stop(&iter); |
2270 | } while (tsk == ERR_PTR(-EAGAIN)); | 2270 | } while (tsk == ERR_PTR(-EAGAIN)); |
2271 | } | 2271 | } |