diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2016-04-08 09:11:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-13 22:37:20 -0400 |
commit | fafc4e1ea1a4c1eb13a30c9426fb799f5efacbc3 (patch) | |
tree | 643293e7032e9c3534e4de33d2a6820e75886f7d | |
parent | 18b46810eb61f1d1a66c5511d12e84ea8cb7f35c (diff) |
sock: tigthen lockdep checks for sock_owned_by_user
sock_owned_by_user should not be used without socket lock held. It seems
to be a common practice to check .owned before lock reclassification, so
provide a little help to abstract this check away.
Cc: linux-cifs@vger.kernel.org
Cc: linux-bluetooth@vger.kernel.org
Cc: linux-nfs@vger.kernel.org
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | fs/cifs/connect.c | 4 | ||||
-rw-r--r-- | include/net/sock.h | 44 | ||||
-rw-r--r-- | net/bluetooth/af_bluetooth.c | 2 | ||||
-rw-r--r-- | net/llc/llc_proc.c | 2 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 3 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 3 |
6 files changed, 35 insertions, 23 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 6f62ac821a84..2e2e0a6242d6 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -2918,7 +2918,7 @@ static inline void | |||
2918 | cifs_reclassify_socket4(struct socket *sock) | 2918 | cifs_reclassify_socket4(struct socket *sock) |
2919 | { | 2919 | { |
2920 | struct sock *sk = sock->sk; | 2920 | struct sock *sk = sock->sk; |
2921 | BUG_ON(sock_owned_by_user(sk)); | 2921 | BUG_ON(!sock_allow_reclassification(sk)); |
2922 | sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS", | 2922 | sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS", |
2923 | &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]); | 2923 | &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]); |
2924 | } | 2924 | } |
@@ -2927,7 +2927,7 @@ static inline void | |||
2927 | cifs_reclassify_socket6(struct socket *sock) | 2927 | cifs_reclassify_socket6(struct socket *sock) |
2928 | { | 2928 | { |
2929 | struct sock *sk = sock->sk; | 2929 | struct sock *sk = sock->sk; |
2930 | BUG_ON(sock_owned_by_user(sk)); | 2930 | BUG_ON(!sock_allow_reclassification(sk)); |
2931 | sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS", | 2931 | sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS", |
2932 | &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]); | 2932 | &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]); |
2933 | } | 2933 | } |
diff --git a/include/net/sock.h b/include/net/sock.h index 81d6fecec0a2..baba58770ac5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -1316,21 +1316,6 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb) | |||
1316 | __kfree_skb(skb); | 1316 | __kfree_skb(skb); |
1317 | } | 1317 | } |
1318 | 1318 | ||
1319 | /* Used by processes to "lock" a socket state, so that | ||
1320 | * interrupts and bottom half handlers won't change it | ||
1321 | * from under us. It essentially blocks any incoming | ||
1322 | * packets, so that we won't get any new data or any | ||
1323 | * packets that change the state of the socket. | ||
1324 | * | ||
1325 | * While locked, BH processing will add new packets to | ||
1326 | * the backlog queue. This queue is processed by the | ||
1327 | * owner of the socket lock right before it is released. | ||
1328 | * | ||
1329 | * Since ~2.3.5 it is also exclusive sleep lock serializing | ||
1330 | * accesses from user process context. | ||
1331 | */ | ||
1332 | #define sock_owned_by_user(sk) ((sk)->sk_lock.owned) | ||
1333 | |||
1334 | static inline void sock_release_ownership(struct sock *sk) | 1319 | static inline void sock_release_ownership(struct sock *sk) |
1335 | { | 1320 | { |
1336 | if (sk->sk_lock.owned) { | 1321 | if (sk->sk_lock.owned) { |
@@ -1403,6 +1388,35 @@ static inline void unlock_sock_fast(struct sock *sk, bool slow) | |||
1403 | spin_unlock_bh(&sk->sk_lock.slock); | 1388 | spin_unlock_bh(&sk->sk_lock.slock); |
1404 | } | 1389 | } |
1405 | 1390 | ||
1391 | /* Used by processes to "lock" a socket state, so that | ||
1392 | * interrupts and bottom half handlers won't change it | ||
1393 | * from under us. It essentially blocks any incoming | ||
1394 | * packets, so that we won't get any new data or any | ||
1395 | * packets that change the state of the socket. | ||
1396 | * | ||
1397 | * While locked, BH processing will add new packets to | ||
1398 | * the backlog queue. This queue is processed by the | ||
1399 | * owner of the socket lock right before it is released. | ||
1400 | * | ||
1401 | * Since ~2.3.5 it is also exclusive sleep lock serializing | ||
1402 | * accesses from user process context. | ||
1403 | */ | ||
1404 | |||
1405 | static inline bool sock_owned_by_user(const struct sock *sk) | ||
1406 | { | ||
1407 | #ifdef CONFIG_LOCKDEP | ||
1408 | WARN_ON(!lockdep_sock_is_held(sk)); | ||
1409 | #endif | ||
1410 | return sk->sk_lock.owned; | ||
1411 | } | ||
1412 | |||
1413 | /* no reclassification while locks are held */ | ||
1414 | static inline bool sock_allow_reclassification(const struct sock *csk) | ||
1415 | { | ||
1416 | struct sock *sk = (struct sock *)csk; | ||
1417 | |||
1418 | return !sk->sk_lock.owned && !spin_is_locked(&sk->sk_lock.slock); | ||
1419 | } | ||
1406 | 1420 | ||
1407 | struct sock *sk_alloc(struct net *net, int family, gfp_t priority, | 1421 | struct sock *sk_alloc(struct net *net, int family, gfp_t priority, |
1408 | struct proto *prot, int kern); | 1422 | struct proto *prot, int kern); |
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 955eda93e66f..3df7aefb7663 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
@@ -65,7 +65,7 @@ static const char *const bt_slock_key_strings[BT_MAX_PROTO] = { | |||
65 | void bt_sock_reclassify_lock(struct sock *sk, int proto) | 65 | void bt_sock_reclassify_lock(struct sock *sk, int proto) |
66 | { | 66 | { |
67 | BUG_ON(!sk); | 67 | BUG_ON(!sk); |
68 | BUG_ON(sock_owned_by_user(sk)); | 68 | BUG_ON(!sock_allow_reclassification(sk)); |
69 | 69 | ||
70 | sock_lock_init_class_and_name(sk, | 70 | sock_lock_init_class_and_name(sk, |
71 | bt_slock_key_strings[proto], &bt_slock_key[proto], | 71 | bt_slock_key_strings[proto], &bt_slock_key[proto], |
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 1a3c7e0f5d0d..29c509c54bb2 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c | |||
@@ -195,7 +195,7 @@ static int llc_seq_core_show(struct seq_file *seq, void *v) | |||
195 | timer_pending(&llc->pf_cycle_timer.timer), | 195 | timer_pending(&llc->pf_cycle_timer.timer), |
196 | timer_pending(&llc->rej_sent_timer.timer), | 196 | timer_pending(&llc->rej_sent_timer.timer), |
197 | timer_pending(&llc->busy_state_timer.timer), | 197 | timer_pending(&llc->busy_state_timer.timer), |
198 | !!sk->sk_backlog.tail, !!sock_owned_by_user(sk)); | 198 | !!sk->sk_backlog.tail, !!sk->sk_lock.owned); |
199 | out: | 199 | out: |
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 71d6072664d2..dadfec66dbd8 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -85,8 +85,7 @@ static void svc_reclassify_socket(struct socket *sock) | |||
85 | { | 85 | { |
86 | struct sock *sk = sock->sk; | 86 | struct sock *sk = sock->sk; |
87 | 87 | ||
88 | WARN_ON_ONCE(sock_owned_by_user(sk)); | 88 | if (WARN_ON_ONCE(!sock_allow_reclassification(sk))) |
89 | if (sock_owned_by_user(sk)) | ||
90 | return; | 89 | return; |
91 | 90 | ||
92 | switch (sk->sk_family) { | 91 | switch (sk->sk_family) { |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index c1fc7b20bbc1..d0756ac5c0f2 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -1880,8 +1880,7 @@ static inline void xs_reclassify_socket6(struct socket *sock) | |||
1880 | 1880 | ||
1881 | static inline void xs_reclassify_socket(int family, struct socket *sock) | 1881 | static inline void xs_reclassify_socket(int family, struct socket *sock) |
1882 | { | 1882 | { |
1883 | WARN_ON_ONCE(sock_owned_by_user(sock->sk)); | 1883 | if (WARN_ON_ONCE(!sock_allow_reclassification(sock->sk))) |
1884 | if (sock_owned_by_user(sock->sk)) | ||
1885 | return; | 1884 | return; |
1886 | 1885 | ||
1887 | switch (family) { | 1886 | switch (family) { |