[Devel] [PATCH RHEL7 COMMIT] net: fix false-positive deadlock detection for sk_receive_queue lock
Konstantin Khorenko
khorenko at virtuozzo.com
Tue May 21 18:11:22 MSK 2019
The commit is pushed to "branch-rh7-3.10.0-957.12.2.vz7.96.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.12.2.vz7.96.1
------>
commit 6a1516602b04cbc461112b3a5dc8833e80449e94
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date: Tue May 21 18:11:19 2019 +0300
net: fix false-positive deadlock detection for sk_receive_queue lock
Here is the code path of false-positive deadlock:
CPU1 CPU2
__udp_enqueue_schedule_skb
spin_lock(sk->sk_receive_queue.lock) <- udp
ipoib_start_xmit
spin_lock_irqsave(((struct rdma_netdev *)netdev_priv(net_device))->clnt_priv->lock)
path_rec_start
...
__netlink_sendskb
skb_queue_tail
spin_lock_irqsave(sk->sk_receive_queue.lock) <- netlink
do_IRQ
...
ipoib_cm_rx_event_handler
spin_lock_irqsave(((struct rdma_netdev *)netdev_priv(net_device))->clnt_priv->lock)
For sockets of different protocols these sk->sk_receive_queue.lock's
are different on the right and on the left, thus no real deadlock will
happen as CPU2 will continue execution instead of waiting for lock.
So mark the udp lock with separate lockdep class.
https://jira.sw.ru/browse/HCI-223
https://pmc.acronis.com/browse/VSTOR-18951
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
include/linux/skbuff.h | 3 ++-
include/net/sock.h | 1 +
net/core/sock.c | 4 ++--
net/ipv4/udp.c | 3 +++
4 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 28a112d06ece..a850fc9285fc 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1608,7 +1608,8 @@ static inline void skb_queue_head_init_class(struct sk_buff_head *list,
struct lock_class_key *class)
{
skb_queue_head_init(list);
- lockdep_set_class(&list->lock, class);
+ if (class)
+ lockdep_set_class(&list->lock, class);
}
/*
diff --git a/include/net/sock.h b/include/net/sock.h
index 6ac59b86b3a2..f90941ef02a2 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1083,6 +1083,7 @@ struct proto {
void (*destroy_cgroup)(struct mem_cgroup *memcg);
struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg);
#endif
+ struct lock_class_key *lockdep_class;
};
/*
diff --git a/net/core/sock.c b/net/core/sock.c
index 97fdfa5da687..ffd747cc30a4 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1556,7 +1556,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
*/
atomic_set(&newsk->sk_wmem_alloc, 1);
atomic_set(&newsk->sk_omem_alloc, 0);
- skb_queue_head_init(&newsk->sk_receive_queue);
+ skb_queue_head_init_class(&newsk->sk_receive_queue, newsk->sk_prot->lockdep_class);
skb_queue_head_init(&newsk->sk_write_queue);
rwlock_init(&newsk->sk_callback_lock);
@@ -2412,7 +2412,7 @@ EXPORT_SYMBOL(sk_stop_timer);
void sock_init_data(struct socket *sock, struct sock *sk)
{
- skb_queue_head_init(&sk->sk_receive_queue);
+ skb_queue_head_init_class(&sk->sk_receive_queue, sk->sk_prot->lockdep_class);
skb_queue_head_init(&sk->sk_write_queue);
skb_queue_head_init(&sk->sk_error_queue);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index a35aea149358..9c3efcb04a0c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2315,6 +2315,8 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
}
EXPORT_SYMBOL(udp_poll);
+static struct lock_class_key udp_sk_class;
+
struct proto udp_prot = {
.name = "UDP",
.owner = THIS_MODULE,
@@ -2351,6 +2353,7 @@ struct proto udp_prot = {
.destroy_cgroup = udp_destroy_cgroup,
.proto_cgroup = udp_proto_cgroup,
#endif
+ .lockdep_class = udp_sk_class,
};
EXPORT_SYMBOL(udp_prot);
More information about the Devel
mailing list