Commit bc1fb82a authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net: annotate data-races around sk->sk_lingertime

sk_getsockopt() runs locklessly. This means sk->sk_lingertime
can be read while other threads are changing its value.

Other reads also happen without socket lock being held,
and must be annotated.

Remove preprocessor logic using BITS_PER_LONG, compilers
are smart enough to figure this by themselves.

v2: fixed a clang W=1 (-Wtautological-constant-out-of-range-compare) warning
    (Jakub)

Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b4672c73
...@@ -1475,7 +1475,7 @@ static int iso_sock_release(struct socket *sock) ...@@ -1475,7 +1475,7 @@ static int iso_sock_release(struct socket *sock)
iso_sock_close(sk); iso_sock_close(sk);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) &&
!(current->flags & PF_EXITING)) { !(current->flags & PF_EXITING)) {
lock_sock(sk); lock_sock(sk);
err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
......
...@@ -1245,7 +1245,7 @@ static int sco_sock_release(struct socket *sock) ...@@ -1245,7 +1245,7 @@ static int sco_sock_release(struct socket *sock)
sco_sock_close(sk); sco_sock_close(sk);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) &&
!(current->flags & PF_EXITING)) { !(current->flags & PF_EXITING)) {
lock_sock(sk); lock_sock(sk);
err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
......
...@@ -797,7 +797,7 @@ EXPORT_SYMBOL(sock_set_reuseport); ...@@ -797,7 +797,7 @@ EXPORT_SYMBOL(sock_set_reuseport);
void sock_no_linger(struct sock *sk) void sock_no_linger(struct sock *sk)
{ {
lock_sock(sk); lock_sock(sk);
sk->sk_lingertime = 0; WRITE_ONCE(sk->sk_lingertime, 0);
sock_set_flag(sk, SOCK_LINGER); sock_set_flag(sk, SOCK_LINGER);
release_sock(sk); release_sock(sk);
} }
...@@ -1230,15 +1230,15 @@ int sk_setsockopt(struct sock *sk, int level, int optname, ...@@ -1230,15 +1230,15 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
if (!ling.l_onoff) if (!ling.l_onoff) {
sock_reset_flag(sk, SOCK_LINGER); sock_reset_flag(sk, SOCK_LINGER);
else { } else {
#if (BITS_PER_LONG == 32) unsigned long t_sec = ling.l_linger;
if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; if (t_sec >= MAX_SCHEDULE_TIMEOUT / HZ)
WRITE_ONCE(sk->sk_lingertime, MAX_SCHEDULE_TIMEOUT);
else else
#endif WRITE_ONCE(sk->sk_lingertime, t_sec * HZ);
sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;
sock_set_flag(sk, SOCK_LINGER); sock_set_flag(sk, SOCK_LINGER);
} }
break; break;
...@@ -1692,7 +1692,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname, ...@@ -1692,7 +1692,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
case SO_LINGER: case SO_LINGER:
lv = sizeof(v.ling); lv = sizeof(v.ling);
v.ling.l_onoff = sock_flag(sk, SOCK_LINGER); v.ling.l_onoff = sock_flag(sk, SOCK_LINGER);
v.ling.l_linger = sk->sk_lingertime / HZ; v.ling.l_linger = READ_ONCE(sk->sk_lingertime) / HZ;
break; break;
case SO_BSDCOMPAT: case SO_BSDCOMPAT:
......
...@@ -502,7 +502,7 @@ META_COLLECTOR(int_sk_lingertime) ...@@ -502,7 +502,7 @@ META_COLLECTOR(int_sk_lingertime)
*err = -1; *err = -1;
return; return;
} }
dst->value = sk->sk_lingertime / HZ; dst->value = READ_ONCE(sk->sk_lingertime) / HZ;
} }
META_COLLECTOR(int_sk_err_qlen) META_COLLECTOR(int_sk_err_qlen)
......
...@@ -1840,7 +1840,7 @@ void smc_close_non_accepted(struct sock *sk) ...@@ -1840,7 +1840,7 @@ void smc_close_non_accepted(struct sock *sk)
lock_sock(sk); lock_sock(sk);
if (!sk->sk_lingertime) if (!sk->sk_lingertime)
/* wait for peer closing */ /* wait for peer closing */
sk->sk_lingertime = SMC_MAX_STREAM_WAIT_TIMEOUT; WRITE_ONCE(sk->sk_lingertime, SMC_MAX_STREAM_WAIT_TIMEOUT);
__smc_release(smc); __smc_release(smc);
release_sock(sk); release_sock(sk);
sock_put(sk); /* sock_hold above */ sock_put(sk); /* sock_hold above */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment