svn commit: r339170 - head/sys/kern
Gleb Smirnoff
glebius at FreeBSD.org
Wed Oct 3 17:40:06 UTC 2018
Author: glebius
Date: Wed Oct 3 17:40:04 2018
New Revision: 339170
URL: https://svnweb.freebsd.org/changeset/base/339170
Log:
In PR 227259, a user is reporting that they have code which is using
shutdown() to wakeup another thread blocked on a stream listen socket.
This code is failing, while it used to work on FreeBSD 10 and still
works on Linux.
It seems reasonable to add another exception to support something users are
actually doing, which used to work on FreeBSD 10, and still works on Linux.
And, it seems like it should be acceptable to POSIX, as we still return
ENOTCONN.
This patch is different to what had been committed to stable/11, since
code around listening sockets is different. Patch in D15019 is written
by jtl@, slightly modified by me.
PR: 227259
Obtained from: jtl
Approved by: re (kib)
Differential Revision: D15019
Modified:
head/sys/kern/uipc_socket.c
Modified: head/sys/kern/uipc_socket.c
==============================================================================
--- head/sys/kern/uipc_socket.c Wed Oct 3 17:32:02 2018 (r339169)
+++ head/sys/kern/uipc_socket.c Wed Oct 3 17:40:04 2018 (r339170)
@@ -917,12 +917,13 @@ solisten_dequeue(struct socket *head, struct socket **
if (head->so_error) {
error = head->so_error;
head->so_error = 0;
+ } else if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->sol_comp))
+ error = EWOULDBLOCK;
+ else
+ error = 0;
+ if (error) {
SOLISTEN_UNLOCK(head);
return (error);
- }
- if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->sol_comp)) {
- SOLISTEN_UNLOCK(head);
- return (EWOULDBLOCK);
}
so = TAILQ_FIRST(&head->sol_comp);
SOCK_LOCK(so);
@@ -2585,11 +2586,20 @@ soshutdown(struct socket *so, int how)
* both backward-compatibility and POSIX requirements by forcing
* ENOTCONN but still asking protocol to perform pru_shutdown().
*/
- if (so->so_type != SOCK_DGRAM)
+ if (so->so_type != SOCK_DGRAM && !SOLISTENING(so))
return (ENOTCONN);
soerror_enotconn = 1;
}
+ if (SOLISTENING(so)) {
+ if (how != SHUT_WR) {
+ SOLISTEN_LOCK(so);
+ so->so_error = ECONNABORTED;
+ solisten_wakeup(so); /* unlocks so */
+ }
+ goto done;
+ }
+
CURVNET_SET(so->so_vnet);
if (pr->pr_usrreqs->pru_flush != NULL)
(*pr->pr_usrreqs->pru_flush)(so, how);
@@ -2604,6 +2614,7 @@ soshutdown(struct socket *so, int how)
wakeup(&so->so_timeo);
CURVNET_RESTORE();
+done:
return (soerror_enotconn ? ENOTCONN : 0);
}
@@ -3279,6 +3290,8 @@ sopoll_generic(struct socket *so, int events, struct u
revents = 0;
else if (!TAILQ_EMPTY(&so->sol_comp))
revents = events & (POLLIN | POLLRDNORM);
+ else if ((events & POLLINIGNEOF) == 0 && so->so_error)
+ revents = (events & (POLLIN | POLLRDNORM)) | POLLHUP;
else {
selrecord(td, &so->so_rdsel);
revents = 0;
@@ -3555,6 +3568,11 @@ filt_soread(struct knote *kn, long hint)
if (SOLISTENING(so)) {
SOCK_LOCK_ASSERT(so);
kn->kn_data = so->sol_qlen;
+ if (so->so_error) {
+ kn->kn_flags |= EV_EOF;
+ kn->kn_fflags = so->so_error;
+ return (1);
+ }
return (!TAILQ_EMPTY(&so->sol_comp));
}
More information about the svn-src-all
mailing list