Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Sep 2012 14:54:59 +0000 (UTC)
From:      Mikolaj Golub <trociny@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r240607 - stable/8/sys/kern
Message-ID:  <201209171454.q8HEsxEJ039404@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trociny
Date: Mon Sep 17 14:54:58 2012
New Revision: 240607
URL: http://svn.freebsd.org/changeset/base/240607

Log:
  MFC r240003, r240004:
  
  r240003:
  
  In soreceive_generic() when checking if the type of mbuf has changed
  check it for MT_CONTROL type too, otherwise the assertion
  "m->m_type == MT_DATA" below may be triggered by the following scenario:
  
  - the sender sends some data (MT_DATA) and then a file descriptor
    (MT_CONTROL);
  - the receiver calls recv(2) with a MSG_WAITALL asking for data larger
    than the receive buffer (uio_resid > hiwat).
  
  r240004:
  
  In soreceive_generic() remove the optimization for the case when
  MSG_WAITALL is set, and it is possible to do the entire receive
  operation at once if we block (resid <= hiwat). Actually it might make
  the recv(2) with MSG_WAITALL flag get stuck when there is enough space
  in the receiver buffer to satisfy the request but not enough to open
  the window closed previously due to the buffer being full.
  
  The issue can be reproduced using the following scenario:
  
  On the sender side do 2 send(2) requests:
  
  1) data of size much smaller than SOBUF_SIZE (e.g. SOBUF_SIZE / 10);
  2) data of size equal to SOBUF_SIZE.
  
  On the receiver side do 2 recv(2) requests with MSG_WAITALL flag set:
  
  1) recv() data of SOBUF_SIZE / 10 size;
  2) recv() data of SOBUF_SIZE size;
  
  We totally fill the receiver buffer with one SOBUF_SIZE/10 size request
  and partial SOBUF_SIZE request. When the first request is processed we
  get SOBUF_SIZE/10 free space. It is just enough to receive the rest of
  bytes for the second request, and soreceive_generic() blocks in the
  part that is a subject of this change waiting for the rest. But the
  window was closed when the buffer was filled and to avoid silly window
  syndrome it opens only when available space is larger than sb_hiwat/4
  or maxseg. So it is stuck and pending data is only sent via TCP window
  probes.
  
  Discussed with:	kib (long ago)

Modified:
  stable/8/sys/kern/uipc_socket.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/kern/   (props changed)

Modified: stable/8/sys/kern/uipc_socket.c
==============================================================================
--- stable/8/sys/kern/uipc_socket.c	Mon Sep 17 14:53:33 2012	(r240606)
+++ stable/8/sys/kern/uipc_socket.c	Mon Sep 17 14:54:58 2012	(r240607)
@@ -1483,17 +1483,11 @@ restart:
 	 * If we have less data than requested, block awaiting more (subject
 	 * to any timeout) if:
 	 *   1. the current count is less than the low water mark, or
-	 *   2. MSG_WAITALL is set, and it is possible to do the entire
-	 *	receive operation at once if we block (resid <= hiwat).
-	 *   3. MSG_DONTWAIT is not set
-	 * If MSG_WAITALL is set but resid is larger than the receive buffer,
-	 * we have to do the receive in sections, and thus risk returning a
-	 * short count if a timeout or signal occurs after we start.
+	 *   2. MSG_DONTWAIT is not set
 	 */
 	if (m == NULL || (((flags & MSG_DONTWAIT) == 0 &&
 	    so->so_rcv.sb_cc < uio->uio_resid) &&
-	    (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
-	    ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
+	    so->so_rcv.sb_cc < so->so_rcv.sb_lowat &&
 	    m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
 		KASSERT(m != NULL || !so->so_rcv.sb_cc,
 		    ("receive: m == %p so->so_rcv.sb_cc == %u",
@@ -1682,8 +1676,8 @@ dontblock:
 		 * examined ('type'), end the receive operation.
 	 	 */
 		SOCKBUF_LOCK_ASSERT(&so->so_rcv);
-		if (m->m_type == MT_OOBDATA) {
-			if (type != MT_OOBDATA)
+		if (m->m_type == MT_OOBDATA || m->m_type == MT_CONTROL) {
+			if (type != m->m_type)
 				break;
 		} else if (type == MT_OOBDATA)
 			break;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209171454.q8HEsxEJ039404>