• Eric Dumazet's avatar
    net: fix a lockdep splat · f064af1e
    Eric Dumazet authored
    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: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    Tested-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
    CC: Jarek Poplawski <jarkao2@gmail.com>
    Tested-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    f064af1e
sock.c 63.5 KB