net: fix a lockdep splat
We have for each socket :
One spinlock (sk_slock.slock)
One rwlock (sk_callback_lock)
Possible scenarios are :
(A) (this is used in net/sunrpc/xprtsock.c)
read_lock(&sk->sk_callback_lock) (without blocking BH)
<BH>
spin_lock(&sk->sk_slock.slock);
...
read_lock(&sk->sk_callback_lock);
...
(B)
write_lock_bh(&sk->sk_callback_lock)
stuff
write_unlock_bh(&sk->sk_callback_lock)
(C)
spin_lock_bh(&sk->sk_slock)
...
write_lock_bh(&sk->sk_callback_lock)
stuff
write_unlock_bh(&sk->sk_callback_lock)
spin_unlock_bh(&sk->sk_slock)
This (C) case conflicts with (A) :
CPU1 [A] CPU2 [C]
read_lock(callback_lock)
<BH> spin_lock_bh(slock)
<wait to spin_lock(slock)>
<wait to write_lock_bh(callback_lock)>
We have one problematic (C) use case in inet_csk_listen_stop() :
local_bh_disable();
bh_lock_sock(child); // spin_lock_bh(&sk->sk_slock)
WARN_ON(sock_owned_by_user(child));
...
sock_orphan(child); // write_lock_bh(&sk->sk_callback_lock)
lockdep is not happy with this, as reported by Tetsuo Handa
It seems only way to deal with this is to use read_lock_bh(callbacklock)
everywhere.
Thanks to Jarek for pointing a bug in my first attempt and suggesting
this solution.
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Tested-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Jarek Poplawski <jarkao2@gmail.com>
Tested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
605c82bab5
commit
f064af1e50
@@ -1351,9 +1351,9 @@ int sock_i_uid(struct sock *sk)
|
||||
{
|
||||
int uid;
|
||||
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
read_lock_bh(&sk->sk_callback_lock);
|
||||
uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0;
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
read_unlock_bh(&sk->sk_callback_lock);
|
||||
return uid;
|
||||
}
|
||||
EXPORT_SYMBOL(sock_i_uid);
|
||||
@@ -1362,9 +1362,9 @@ unsigned long sock_i_ino(struct sock *sk)
|
||||
{
|
||||
unsigned long ino;
|
||||
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
read_lock_bh(&sk->sk_callback_lock);
|
||||
ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0;
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
read_unlock_bh(&sk->sk_callback_lock);
|
||||
return ino;
|
||||
}
|
||||
EXPORT_SYMBOL(sock_i_ino);
|
||||
|
||||
Reference in New Issue
Block a user