From: Greg Kroah-Hartman Date: Mon, 27 Nov 2017 11:57:59 +0000 (+0100) Subject: 4.4-stable patches X-Git-Tag: v3.18.85~50 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=64c5fb292a1559aa8e289ba1640f96b1b4f246f7;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: af_vsock-shrink-the-area-influenced-by-prepare_to_wait.patch ipv6-only-call-ip6_route_dev_notify-once-for-netdev_unregister.patch vsock-use-new-wait-api-for-vsock_stream_sendmsg.patch --- diff --git a/queue-4.4/af_vsock-shrink-the-area-influenced-by-prepare_to_wait.patch b/queue-4.4/af_vsock-shrink-the-area-influenced-by-prepare_to_wait.patch new file mode 100644 index 00000000000..27fb3a991ef --- /dev/null +++ b/queue-4.4/af_vsock-shrink-the-area-influenced-by-prepare_to_wait.patch @@ -0,0 +1,337 @@ +From f7f9b5e7f8eccfd68ffa7b8d74b07c478bb9e7f0 Mon Sep 17 00:00:00 2001 +From: Claudio Imbrenda +Date: Tue, 22 Mar 2016 17:05:52 +0100 +Subject: AF_VSOCK: Shrink the area influenced by prepare_to_wait + +From: Claudio Imbrenda + +commit f7f9b5e7f8eccfd68ffa7b8d74b07c478bb9e7f0 upstream. + +When a thread is prepared for waiting by calling prepare_to_wait, sleeping +is not allowed until either the wait has taken place or finish_wait has +been called. The existing code in af_vsock imposed unnecessary no-sleep +assumptions to a broad list of backend functions. +This patch shrinks the influence of prepare_to_wait to the area where it +is strictly needed, therefore relaxing the no-sleep restriction there. + +Signed-off-by: Claudio Imbrenda +Signed-off-by: David S. Miller +Cc: "Jorgen S. Hansen" +Signed-off-by: Greg Kroah-Hartman + +--- + net/vmw_vsock/af_vsock.c | 158 +++++++++++++++++++++++++---------------------- + 1 file changed, 85 insertions(+), 73 deletions(-) + +--- a/net/vmw_vsock/af_vsock.c ++++ b/net/vmw_vsock/af_vsock.c +@@ -1209,10 +1209,14 @@ static int vsock_stream_connect(struct s + + if (signal_pending(current)) { + err = sock_intr_errno(timeout); +- goto out_wait_error; ++ sk->sk_state = SS_UNCONNECTED; ++ sock->state = SS_UNCONNECTED; ++ goto out_wait; + } else if (timeout == 0) { + err = -ETIMEDOUT; +- goto out_wait_error; ++ sk->sk_state = SS_UNCONNECTED; ++ sock->state = SS_UNCONNECTED; ++ goto out_wait; + } + + prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); +@@ -1220,20 +1224,17 @@ static int vsock_stream_connect(struct s + + if (sk->sk_err) { + err = -sk->sk_err; +- goto out_wait_error; +- } else ++ sk->sk_state = SS_UNCONNECTED; ++ sock->state = SS_UNCONNECTED; ++ } else { + err = 0; ++ } + + out_wait: + finish_wait(sk_sleep(sk), &wait); + out: + release_sock(sk); + return err; +- +-out_wait_error: +- sk->sk_state = SS_UNCONNECTED; +- sock->state = SS_UNCONNECTED; +- goto out_wait; + } + + static int vsock_accept(struct socket *sock, struct socket *newsock, int flags) +@@ -1270,18 +1271,20 @@ static int vsock_accept(struct socket *s + listener->sk_err == 0) { + release_sock(listener); + timeout = schedule_timeout(timeout); ++ finish_wait(sk_sleep(listener), &wait); + lock_sock(listener); + + if (signal_pending(current)) { + err = sock_intr_errno(timeout); +- goto out_wait; ++ goto out; + } else if (timeout == 0) { + err = -EAGAIN; +- goto out_wait; ++ goto out; + } + + prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE); + } ++ finish_wait(sk_sleep(listener), &wait); + + if (listener->sk_err) + err = -listener->sk_err; +@@ -1301,19 +1304,15 @@ static int vsock_accept(struct socket *s + */ + if (err) { + vconnected->rejected = true; +- release_sock(connected); +- sock_put(connected); +- goto out_wait; ++ } else { ++ newsock->state = SS_CONNECTED; ++ sock_graft(connected, newsock); + } + +- newsock->state = SS_CONNECTED; +- sock_graft(connected, newsock); + release_sock(connected); + sock_put(connected); + } + +-out_wait: +- finish_wait(sk_sleep(listener), &wait); + out: + release_sock(listener); + return err; +@@ -1557,11 +1556,11 @@ static int vsock_stream_sendmsg(struct s + if (err < 0) + goto out; + +- prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + + while (total_written < len) { + ssize_t written; + ++ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + while (vsock_stream_has_space(vsk) == 0 && + sk->sk_err == 0 && + !(sk->sk_shutdown & SEND_SHUTDOWN) && +@@ -1570,27 +1569,33 @@ static int vsock_stream_sendmsg(struct s + /* Don't wait for non-blocking sockets. */ + if (timeout == 0) { + err = -EAGAIN; +- goto out_wait; ++ finish_wait(sk_sleep(sk), &wait); ++ goto out_err; + } + + err = transport->notify_send_pre_block(vsk, &send_data); +- if (err < 0) +- goto out_wait; ++ if (err < 0) { ++ finish_wait(sk_sleep(sk), &wait); ++ goto out_err; ++ } + + release_sock(sk); + timeout = schedule_timeout(timeout); + lock_sock(sk); + if (signal_pending(current)) { + err = sock_intr_errno(timeout); +- goto out_wait; ++ finish_wait(sk_sleep(sk), &wait); ++ goto out_err; + } else if (timeout == 0) { + err = -EAGAIN; +- goto out_wait; ++ finish_wait(sk_sleep(sk), &wait); ++ goto out_err; + } + + prepare_to_wait(sk_sleep(sk), &wait, + TASK_INTERRUPTIBLE); + } ++ finish_wait(sk_sleep(sk), &wait); + + /* These checks occur both as part of and after the loop + * conditional since we need to check before and after +@@ -1598,16 +1603,16 @@ static int vsock_stream_sendmsg(struct s + */ + if (sk->sk_err) { + err = -sk->sk_err; +- goto out_wait; ++ goto out_err; + } else if ((sk->sk_shutdown & SEND_SHUTDOWN) || + (vsk->peer_shutdown & RCV_SHUTDOWN)) { + err = -EPIPE; +- goto out_wait; ++ goto out_err; + } + + err = transport->notify_send_pre_enqueue(vsk, &send_data); + if (err < 0) +- goto out_wait; ++ goto out_err; + + /* Note that enqueue will only write as many bytes as are free + * in the produce queue, so we don't need to ensure len is +@@ -1620,7 +1625,7 @@ static int vsock_stream_sendmsg(struct s + len - total_written); + if (written < 0) { + err = -ENOMEM; +- goto out_wait; ++ goto out_err; + } + + total_written += written; +@@ -1628,14 +1633,13 @@ static int vsock_stream_sendmsg(struct s + err = transport->notify_send_post_enqueue( + vsk, written, &send_data); + if (err < 0) +- goto out_wait; ++ goto out_err; + + } + +-out_wait: ++out_err: + if (total_written > 0) + err = total_written; +- finish_wait(sk_sleep(sk), &wait); + out: + release_sock(sk); + return err; +@@ -1716,21 +1720,61 @@ vsock_stream_recvmsg(struct socket *sock + if (err < 0) + goto out; + +- prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + + while (1) { +- s64 ready = vsock_stream_has_data(vsk); ++ s64 ready; + +- if (ready < 0) { +- /* Invalid queue pair content. XXX This should be +- * changed to a connection reset in a later change. +- */ ++ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); ++ ready = vsock_stream_has_data(vsk); + +- err = -ENOMEM; +- goto out_wait; +- } else if (ready > 0) { ++ if (ready == 0) { ++ if (sk->sk_err != 0 || ++ (sk->sk_shutdown & RCV_SHUTDOWN) || ++ (vsk->peer_shutdown & SEND_SHUTDOWN)) { ++ finish_wait(sk_sleep(sk), &wait); ++ break; ++ } ++ /* Don't wait for non-blocking sockets. */ ++ if (timeout == 0) { ++ err = -EAGAIN; ++ finish_wait(sk_sleep(sk), &wait); ++ break; ++ } ++ ++ err = transport->notify_recv_pre_block( ++ vsk, target, &recv_data); ++ if (err < 0) { ++ finish_wait(sk_sleep(sk), &wait); ++ break; ++ } ++ release_sock(sk); ++ timeout = schedule_timeout(timeout); ++ lock_sock(sk); ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeout); ++ finish_wait(sk_sleep(sk), &wait); ++ break; ++ } else if (timeout == 0) { ++ err = -EAGAIN; ++ finish_wait(sk_sleep(sk), &wait); ++ break; ++ } ++ } else { + ssize_t read; + ++ finish_wait(sk_sleep(sk), &wait); ++ ++ if (ready < 0) { ++ /* Invalid queue pair content. XXX This should ++ * be changed to a connection reset in a later ++ * change. ++ */ ++ ++ err = -ENOMEM; ++ goto out; ++ } ++ + err = transport->notify_recv_pre_dequeue( + vsk, target, &recv_data); + if (err < 0) +@@ -1750,42 +1794,12 @@ vsock_stream_recvmsg(struct socket *sock + vsk, target, read, + !(flags & MSG_PEEK), &recv_data); + if (err < 0) +- goto out_wait; ++ goto out; + + if (read >= target || flags & MSG_PEEK) + break; + + target -= read; +- } else { +- if (sk->sk_err != 0 || (sk->sk_shutdown & RCV_SHUTDOWN) +- || (vsk->peer_shutdown & SEND_SHUTDOWN)) { +- break; +- } +- /* Don't wait for non-blocking sockets. */ +- if (timeout == 0) { +- err = -EAGAIN; +- break; +- } +- +- err = transport->notify_recv_pre_block( +- vsk, target, &recv_data); +- if (err < 0) +- break; +- +- release_sock(sk); +- timeout = schedule_timeout(timeout); +- lock_sock(sk); +- +- if (signal_pending(current)) { +- err = sock_intr_errno(timeout); +- break; +- } else if (timeout == 0) { +- err = -EAGAIN; +- break; +- } +- +- prepare_to_wait(sk_sleep(sk), &wait, +- TASK_INTERRUPTIBLE); + } + } + +@@ -1797,8 +1811,6 @@ vsock_stream_recvmsg(struct socket *sock + if (copied > 0) + err = copied; + +-out_wait: +- finish_wait(sk_sleep(sk), &wait); + out: + release_sock(sk); + return err; diff --git a/queue-4.4/ipv6-only-call-ip6_route_dev_notify-once-for-netdev_unregister.patch b/queue-4.4/ipv6-only-call-ip6_route_dev_notify-once-for-netdev_unregister.patch new file mode 100644 index 00000000000..21662e2b785 --- /dev/null +++ b/queue-4.4/ipv6-only-call-ip6_route_dev_notify-once-for-netdev_unregister.patch @@ -0,0 +1,48 @@ +From 76da0704507bbc51875013f6557877ab308cfd0a Mon Sep 17 00:00:00 2001 +From: WANG Cong +Date: Tue, 20 Jun 2017 11:42:27 -0700 +Subject: ipv6: only call ip6_route_dev_notify() once for NETDEV_UNREGISTER + +From: WANG Cong + +commit 76da0704507bbc51875013f6557877ab308cfd0a upstream. + +In commit 242d3a49a2a1 ("ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf") +I assumed NETDEV_REGISTER and NETDEV_UNREGISTER are paired, +unfortunately, as reported by jeffy, netdev_wait_allrefs() +could rebroadcast NETDEV_UNREGISTER event until all refs are +gone. + +We have to add an additional check to avoid this corner case. +For netdev_wait_allrefs() dev->reg_state is NETREG_UNREGISTERED, +for dev_change_net_namespace(), dev->reg_state is +NETREG_REGISTERED. So check for dev->reg_state != NETREG_UNREGISTERED. + +Fixes: 242d3a49a2a1 ("ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf") +Reported-by: jeffy +Cc: David Ahern +Signed-off-by: Cong Wang +Acked-by: David Ahern +Signed-off-by: David S. Miller +Cc: Konstantin Khlebnikov +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv6/route.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -3378,7 +3378,11 @@ static int ip6_route_dev_notify(struct n + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +- } else if (event == NETDEV_UNREGISTER) { ++ } else if (event == NETDEV_UNREGISTER && ++ dev->reg_state != NETREG_UNREGISTERED) { ++ /* NETDEV_UNREGISTER could be fired for multiple times by ++ * netdev_wait_allrefs(). Make sure we only call this once. ++ */ + in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); diff --git a/queue-4.4/series b/queue-4.4/series index 882466d2cc8..b79613805f4 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -2,3 +2,6 @@ s390-fix-transactional-execution-control-register-handling.patch s390-runtime-instrumention-fix-possible-memory-corruption.patch s390-disassembler-add-missing-end-marker-for-e7-table.patch s390-disassembler-increase-show_code-buffer-size.patch +ipv6-only-call-ip6_route_dev_notify-once-for-netdev_unregister.patch +af_vsock-shrink-the-area-influenced-by-prepare_to_wait.patch +vsock-use-new-wait-api-for-vsock_stream_sendmsg.patch diff --git a/queue-4.4/vsock-use-new-wait-api-for-vsock_stream_sendmsg.patch b/queue-4.4/vsock-use-new-wait-api-for-vsock_stream_sendmsg.patch new file mode 100644 index 00000000000..f6f34579936 --- /dev/null +++ b/queue-4.4/vsock-use-new-wait-api-for-vsock_stream_sendmsg.patch @@ -0,0 +1,102 @@ +From 499fde662f1957e3cb8d192a94a099ebe19c714b Mon Sep 17 00:00:00 2001 +From: WANG Cong +Date: Fri, 19 May 2017 11:21:59 -0700 +Subject: vsock: use new wait API for vsock_stream_sendmsg() + +From: WANG Cong + +commit 499fde662f1957e3cb8d192a94a099ebe19c714b upstream. + +As reported by Michal, vsock_stream_sendmsg() could still +sleep at vsock_stream_has_space() after prepare_to_wait(): + + vsock_stream_has_space + vmci_transport_stream_has_space + vmci_qpair_produce_free_space + qp_lock + qp_acquire_queue_mutex + mutex_lock + +Just switch to the new wait API like we did for commit +d9dc8b0f8b4e ("net: fix sleeping for sk_wait_event()"). + +Reported-by: Michal Kubecek +Cc: Stefan Hajnoczi +Cc: Jorgen Hansen +Cc: "Michael S. Tsirkin" +Cc: Claudio Imbrenda +Signed-off-by: Cong Wang +Reviewed-by: Stefan Hajnoczi +Signed-off-by: David S. Miller +Cc: "Jorgen S. Hansen" +Signed-off-by: Greg Kroah-Hartman + +--- + net/vmw_vsock/af_vsock.c | 21 ++++++++------------- + 1 file changed, 8 insertions(+), 13 deletions(-) + +--- a/net/vmw_vsock/af_vsock.c ++++ b/net/vmw_vsock/af_vsock.c +@@ -1512,8 +1512,7 @@ static int vsock_stream_sendmsg(struct s + long timeout; + int err; + struct vsock_transport_send_notify_data send_data; +- +- DEFINE_WAIT(wait); ++ DEFINE_WAIT_FUNC(wait, woken_wake_function); + + sk = sock->sk; + vsk = vsock_sk(sk); +@@ -1556,11 +1555,10 @@ static int vsock_stream_sendmsg(struct s + if (err < 0) + goto out; + +- + while (total_written < len) { + ssize_t written; + +- prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); ++ add_wait_queue(sk_sleep(sk), &wait); + while (vsock_stream_has_space(vsk) == 0 && + sk->sk_err == 0 && + !(sk->sk_shutdown & SEND_SHUTDOWN) && +@@ -1569,33 +1567,30 @@ static int vsock_stream_sendmsg(struct s + /* Don't wait for non-blocking sockets. */ + if (timeout == 0) { + err = -EAGAIN; +- finish_wait(sk_sleep(sk), &wait); ++ remove_wait_queue(sk_sleep(sk), &wait); + goto out_err; + } + + err = transport->notify_send_pre_block(vsk, &send_data); + if (err < 0) { +- finish_wait(sk_sleep(sk), &wait); ++ remove_wait_queue(sk_sleep(sk), &wait); + goto out_err; + } + + release_sock(sk); +- timeout = schedule_timeout(timeout); ++ timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, timeout); + lock_sock(sk); + if (signal_pending(current)) { + err = sock_intr_errno(timeout); +- finish_wait(sk_sleep(sk), &wait); ++ remove_wait_queue(sk_sleep(sk), &wait); + goto out_err; + } else if (timeout == 0) { + err = -EAGAIN; +- finish_wait(sk_sleep(sk), &wait); ++ remove_wait_queue(sk_sleep(sk), &wait); + goto out_err; + } +- +- prepare_to_wait(sk_sleep(sk), &wait, +- TASK_INTERRUPTIBLE); + } +- finish_wait(sk_sleep(sk), &wait); ++ remove_wait_queue(sk_sleep(sk), &wait); + + /* These checks occur both as part of and after the loop + * conditional since we need to check before and after