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