Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Jan 2014 21:05:08 GMT
From:      Alan Somers <asomers@FreeBSD.org>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/185812: send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN
Message-ID:  <201401152105.s0FL58Qd081508@oldred.freebsd.org>
Resent-Message-ID: <201401152110.s0FLA0q9071434@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         185812
>Category:       kern
>Synopsis:       send(2) on a UNIX domain SEQPACKET socket returns EMSGSIZE instead of EAGAIN
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jan 15 21:10:00 UTC 2014
>Closed-Date:
>Last-Modified:
>Originator:     Alan Somers
>Release:        CURRENT
>Organization:
Spectra Logic
>Environment:
FreeBSD alans-fbsd-head 11.0-CURRENT FreeBSD 11.0-CURRENT #22 r260496: Thu Jan  9 16:39:42 MST 2014     alans@ns1.eng.sldomain.com:/vmpool/obj/usr/home/alans/freebsd/head/sys/GENERIC  amd64
>Description:
If you overflow the buffer of a nonblocking unix domain seqpacket socket, send(2) should return EAGAIN.  Instead, it returns EMSGSIZE.
>How-To-Repeat:
The bug is reproduced by several testcases in the attached ATF test program.  Most consise is unix_seqpacket:eagain_8k_8k
>Fix:
None known.  But a clue is offered by this comment at sys/kern/uipc_usrreq.c:987

                /*
                 * XXXRW: While fine for SOCK_STREAM, this conflates maximum
                 * datagram size and back-pressure for SOCK_SEQPACKET, which
                 * can lead to undesired return of EMSGSIZE on send instead
                 * of more desirable blocking.
                 */

Patch attached with submission follows:

Index: sys/kern/tests/Makefile
===================================================================
--- sys/kern/tests/Makefile	(revision 0)
+++ sys/kern/tests/Makefile	(working copy)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+TESTSDIR=	${TESTSBASE}/sys/kern
+
+ATF_TESTS_C=	unix_seqpacket
+
+.include <atf.test.mk>
Index: sys/kern/tests/unix_seqpacket.c
===================================================================
--- sys/kern/tests/unix_seqpacket.c	(revision 0)
+++ sys/kern/tests/unix_seqpacket.c	(working copy)
@@ -0,0 +1,649 @@
+/*-
+ * Copyright (c) 2014 Spectra Logic Corporation. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <stdio.h>
+
+#include <atf-c.h>
+
+/*
+ * Helper functions
+ */
+
+#define MIN(x, y)	((x) < (y) ? (x) : (y))
+#define MAX(x, y)	((x) > (y) ? (x) : (y))
+
+void
+do_socketpair(int *sv)
+{
+	int s;
+	
+	s = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sv);
+	ATF_REQUIRE_EQ(0, s);
+	ATF_REQUIRE(sv[0] >= 0);
+	ATF_REQUIRE(sv[1] >= 0);
+	ATF_REQUIRE(sv[0] != sv[1]);
+}
+
+void
+do_socketpair_nonblocking(int *sv)
+{
+	int s;
+	
+	s = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sv);
+	ATF_REQUIRE_EQ(0, s);
+	ATF_REQUIRE(sv[0] >= 0);
+	ATF_REQUIRE(sv[1] >= 0);
+	ATF_REQUIRE(sv[0] != sv[1]);
+	ATF_REQUIRE(-1 != fcntl(sv[0], F_SETFL, O_NONBLOCK));
+	ATF_REQUIRE(-1 != fcntl(sv[1], F_SETFL, O_NONBLOCK));
+}
+
+/*
+ * Parameterized test function bodies
+ */
+void
+test_eagain(size_t sndbufsize, size_t rcvbufsize)
+{
+	int i;
+	int sv[2];
+	const size_t totalsize = (sndbufsize + rcvbufsize) * 2;
+	const size_t pktsize = MIN(sndbufsize, rcvbufsize) / 4;
+	char sndbuf[pktsize];
+	char recv_buf[pktsize];
+	ssize_t ssize, rsize;
+
+	/* setup the socket pair */
+	do_socketpair(sv);
+	/* Setup the buffers */
+	ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize,
+	    sizeof(sndbufsize)));
+	ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
+	    sizeof(rcvbufsize)));
+
+	bzero(sndbuf, pktsize);
+	/* Send data until we get EAGAIN */
+	for(i=0; i < totalsize / pktsize; i++) {
+		ssize = send(sv[0], sndbuf, pktsize, MSG_EOR);
+		if (ssize == -1) {
+			if (errno == EAGAIN)
+				atf_tc_pass();
+			else {
+				perror("send");
+				atf_tc_fail("send returned < 0 but not EAGAIN");
+			}
+		}
+	}
+	atf_tc_fail("Never got EAGAIN");
+}
+
+void
+test_nonblocking_symmetric_buffers(size_t bufsize) {
+	int s;
+	int sv[2];
+	const size_t pktsize = bufsize / 2;
+	char sndbuf[pktsize];
+	char recv_buf[pktsize];
+	ssize_t ssize, rsize;
+
+	/* setup the socket pair */
+	do_socketpair_nonblocking(sv);
+	/* Setup the buffers */
+	s = setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
+	ATF_REQUIRE_EQ(0, s);
+	s = setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize));
+	ATF_REQUIRE_EQ(0, s);
+
+	/* Fill the send buffer */
+	bzero(sndbuf, pktsize);
+
+	/* send and receive the packet */
+	ssize = send(sv[0], sndbuf, pktsize, MSG_EOR);
+	if (ssize < 0) {
+		perror("send");
+		atf_tc_fail("send returned < 0");
+	}
+	ATF_CHECK_EQ_MSG(pktsize, ssize, "expected %zd=send(...) but got %zd",
+	    pktsize, ssize);
+
+	rsize = recv(sv[1], recv_buf, pktsize, MSG_WAITALL);
+	if (rsize < 0) {
+		perror("recv");
+		atf_tc_fail("recv returned < 0");
+	}
+	ATF_CHECK_EQ_MSG(pktsize, rsize, "expected %zd=send(...) but got %zd",
+	    pktsize, rsize);
+}
+
+void
+test_pipe_simulator(size_t sndbufsize, size_t rcvbufsize)
+{
+	int s, num_sent, num_received;
+	int sv[2];
+	const size_t pktsize = MIN(sndbufsize, rcvbufsize) / 4;
+	int numpkts;
+	char sndbuf[pktsize];
+	char rcvbuf[pktsize];
+	char comparebuf[pktsize];
+	ssize_t ssize, rsize;
+	bool currently_sending = true;
+
+	/* setup the socket pair */
+	do_socketpair_nonblocking(sv);
+	/* Setup the buffers */
+	ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize,
+	    sizeof(sndbufsize)));
+	ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
+	    sizeof(rcvbufsize)));
+
+	/* Send a total amount of data comfortably greater than the buffers */
+	numpkts = MAX(sndbufsize, rcvbufsize) * 8 / pktsize;
+	for (num_sent=0, num_received=0;
+	     num_sent < numpkts || num_received < numpkts; ) {
+		if (currently_sending && num_sent < numpkts) {
+			/* The simulated sending process */
+			/* fill the buffer */
+			memset(sndbuf, num_sent, pktsize);
+			ssize = send(sv[0], sndbuf, pktsize, MSG_EOR);
+			if (ssize < 0) {
+				/* 
+				 * XXX: This is bug-compatible with the kernel.
+				 * The kernel returns EMSGSIZE when it should
+				 * return EAGAIN
+				 */
+				if (errno == EAGAIN || errno == EMSGSIZE)
+					currently_sending = false;
+				else {
+					perror("send");
+					atf_tc_fail("send failed");
+				}
+			} else  {
+				ATF_CHECK_EQ_MSG(pktsize, ssize,
+				    "expected %zd=send(...) but got %zd",
+				    pktsize, ssize);
+				num_sent++;
+			}
+		} else {
+			/* The simulated receiving process */
+			rsize = recv(sv[1], rcvbuf, pktsize, MSG_WAITALL);
+			if (rsize < 0) {
+				if (errno == EAGAIN) {
+					currently_sending = true;
+					ATF_REQUIRE_MSG(num_sent < numpkts,
+					    "Packets were lost!");
+				}
+				else {
+					perror("recv");
+					atf_tc_fail("recv failed");
+				}
+			} else  {
+				ATF_CHECK_EQ_MSG(pktsize, rsize,
+				    "expected %zd=recv(...) but got %zd",
+				    pktsize, rsize);
+				memset(comparebuf, num_received, pktsize);
+				ATF_CHECK_EQ_MSG(0, memcmp(comparebuf, rcvbuf,
+				    			   pktsize), 
+				    "Received data miscompare");
+				num_received++;
+			}
+		}
+	}
+}
+
+
+/*
+ * Test Cases
+ */
+
+/* Create a SEQPACKET socket */
+ATF_TC_WITHOUT_HEAD(create_socket);
+ATF_TC_BODY(create_socket, tc)
+{
+	int s;
+
+	s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+	ATF_CHECK(s >= 0);
+}
+
+/* Create SEQPACKET sockets using socketpair(2) */
+ATF_TC_WITHOUT_HEAD(create_socketpair);
+ATF_TC_BODY(create_socketpair, tc)
+{
+	int sv[2];
+	int s;
+
+	s = socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sv);
+	ATF_CHECK_EQ(0, s);
+	ATF_CHECK(sv[0] >= 0);
+	ATF_CHECK(sv[1] >= 0);
+	ATF_CHECK(sv[0] != sv[1]);
+}
+
+/* Call listen(2) without first calling bind(2).  It should fail */
+ATF_TC_WITHOUT_HEAD(listen_unbound);
+ATF_TC_BODY(listen_unbound, tc)
+{
+	int s, r;
+
+	s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+	ATF_REQUIRE(s > 0);
+	r = listen(s, -1);
+	/* expect listen to fail since we haven't called bind(2) */
+	ATF_CHECK(r != 0);
+}
+
+/* Bind the socket to a file */
+ATF_TC_WITHOUT_HEAD(bind);
+ATF_TC_BODY(bind, tc)
+{
+	struct sockaddr_un sun;
+	/* ATF's isolation mechanisms will guarantee uniqueness of this file */
+	const char *path = "sock";
+	int s, r;
+
+	s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+	ATF_REQUIRE(s >= 0);
+
+	bzero(&sun, sizeof(sun));
+	sun.sun_family = AF_LOCAL;
+	sun.sun_len = sizeof(sun);
+	strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+	r = bind(s, (struct sockaddr *)&sun, sizeof(sun));
+	ATF_CHECK_EQ(0, r);
+}
+
+/* listen(2) a socket that is already bound(2) should succeed */
+ATF_TC_WITHOUT_HEAD(listen_bound);
+ATF_TC_BODY(listen_bound, tc)
+{
+	struct sockaddr_un sun;
+	/* ATF's isolation mechanisms will guarantee uniqueness of this file */
+	const char *path = "sock";
+	int s, r, l;
+
+	s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+	ATF_REQUIRE(s >= 0);
+
+	bzero(&sun, sizeof(sun));
+	sun.sun_family = AF_LOCAL;
+	sun.sun_len = sizeof(sun);
+	strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
+	r = bind(s, (struct sockaddr *)&sun, sizeof(sun));
+	l = listen(s, -1);
+	ATF_CHECK_EQ(0, r);
+	ATF_CHECK_EQ(0, l);
+}
+
+/* Set O_NONBLOCK on the socket */
+ATF_TC_WITHOUT_HEAD(fcntl_nonblock);
+ATF_TC_BODY(fcntl_nonblock, tc)
+{
+	int s;
+
+	s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+	ATF_REQUIRE(s >= 0);
+	if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
+		perror("fcntl");
+		atf_tc_fail("fcntl failed");
+	}
+}
+
+/* Resize the send and receive buffers */
+ATF_TC_WITHOUT_HEAD(resize_buffers);
+ATF_TC_BODY(resize_buffers, tc)
+{
+	int s;
+	int sndbuf = 8192;
+	int rcvbuf = 8192;
+
+	s = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+	ATF_REQUIRE(s >= 0);
+	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) != 0){
+		perror("setsockopt");
+		atf_tc_fail("setsockopt(SO_SNDBUF) failed");
+	}
+	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sndbuf, sizeof(sndbuf)) != 0){
+		perror("setsockopt");
+		atf_tc_fail("setsockopt(SO_RCVBUF) failed");
+	}
+}
+
+/* send(2) and recv(2) a single short record */
+ATF_TC_WITHOUT_HEAD(send_recv);
+ATF_TC_BODY(send_recv, tc)
+{
+	int s;
+	int sv[2];
+	const int bufsize = 64;
+	const char *data = "data";
+	char recv_buf[bufsize];
+	size_t datalen;
+	ssize_t ssize, rsize;
+
+	/* setup the socket pair */
+	do_socketpair(sv);
+
+	/* send and receive a small packet */
+	datalen = strlen(data) + 1;	/* +1 for the null */
+	ssize = send(sv[0], data, datalen, MSG_EOR);
+	if (ssize < 0) {
+		perror("send");
+		atf_tc_fail("send returned < 0");
+	}
+	ATF_CHECK_EQ_MSG(datalen, ssize, "expected %zd=send(...) but got %zd",
+	    datalen, ssize);
+
+	rsize = recv(sv[1], recv_buf, bufsize, MSG_WAITALL);
+	ATF_CHECK_EQ(datalen, rsize);
+}
+
+/* nonblocking send(2) and recv(2) a single short record */
+ATF_TC_WITHOUT_HEAD(send_recv_nonblocking);
+ATF_TC_BODY(send_recv_nonblocking, tc)
+{
+	int s;
+	int sv[2];
+	const int bufsize = 64;
+	const char *data = "data";
+	char recv_buf[bufsize];
+	size_t datalen;
+	ssize_t ssize, rsize;
+
+	/* setup the socket pair */
+	do_socketpair_nonblocking(sv);
+
+	/* Verify that there is nothing to receive */
+	rsize = recv(sv[1], recv_buf, bufsize, MSG_WAITALL);
+	ATF_CHECK_EQ(EAGAIN, errno);
+	ATF_CHECK_EQ(-1, rsize);
+
+	/* send and receive a small packet */
+	datalen = strlen(data) + 1;	/* +1 for the null */
+	ssize = send(sv[0], data, datalen, MSG_EOR);
+	if (ssize < 0) {
+		perror("send");
+		atf_tc_fail("send returned < 0");
+	}
+	ATF_CHECK_EQ_MSG(datalen, ssize, "expected %zd=send(...) but got %zd",
+	    datalen, ssize);
+
+	rsize = recv(sv[1], recv_buf, bufsize, MSG_WAITALL);
+	ATF_CHECK_EQ(datalen, rsize);
+}
+
+/* 
+ * We should get EMSGSIZE if we try to send a message larger than the socket
+ * buffer, with blocking sockets
+ */
+ATF_TC_WITHOUT_HEAD(emsgsize);
+ATF_TC_BODY(emsgsize, tc)
+{
+	int s;
+	int sv[2];
+	const size_t sndbufsize = 8192;
+	const size_t rcvbufsize = 8192;
+	const size_t pktsize = (sndbufsize + rcvbufsize) * 2;
+	char sndbuf[pktsize];
+	char recv_buf[pktsize];
+	ssize_t ssize, rsize;
+
+	/* setup the socket pair */
+	do_socketpair(sv);
+	/* Setup the buffers */
+	ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize,
+	    sizeof(sndbufsize)));
+	ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
+	    sizeof(rcvbufsize)));
+
+	ssize = send(sv[0], sndbuf, pktsize, MSG_EOR);
+	ATF_CHECK_EQ(EMSGSIZE, errno);
+	ATF_CHECK_EQ(-1, ssize);
+}
+
+/* 
+ * We should get EMSGSIZE if we try to send a message larger than the socket
+ * buffer, with nonblocking sockets
+ */
+ATF_TC_WITHOUT_HEAD(emsgsize_nonblocking);
+ATF_TC_BODY(emsgsize_nonblocking, tc)
+{
+	int s;
+	int sv[2];
+	const size_t sndbufsize = 8192;
+	const size_t rcvbufsize = 8192;
+	const size_t pktsize = (sndbufsize + rcvbufsize) * 2;
+	char sndbuf[pktsize];
+	char recv_buf[pktsize];
+	ssize_t ssize, rsize;
+
+	/* setup the socket pair */
+	do_socketpair_nonblocking(sv);
+	/* Setup the buffers */
+	ATF_REQUIRE_EQ(0, setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &sndbufsize,
+	    sizeof(sndbufsize)));
+	ATF_REQUIRE_EQ(0, setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &rcvbufsize,
+	    sizeof(rcvbufsize)));
+
+	ssize = send(sv[0], sndbuf, pktsize, MSG_EOR);
+	ATF_CHECK_EQ(EMSGSIZE, errno);
+	ATF_CHECK_EQ(-1, ssize);
+}
+
+
+/* 
+ * We should get EAGAIN if we try to send a message larger than the socket
+ * buffer, with nonblocking sockets.  Test with several different sockbuf sizes
+ */
+ATF_TC_WITHOUT_HEAD(eagain_8k_8k);
+ATF_TC_BODY(eagain_8k_8k, tc)
+{
+	test_eagain(8192, 8192);
+}
+ATF_TC_WITHOUT_HEAD(eagain_8k_128k);
+ATF_TC_BODY(eagain_8k_128k, tc)
+{
+	test_eagain(8192, 131072);
+}
+ATF_TC_WITHOUT_HEAD(eagain_128k_8k);
+ATF_TC_BODY(eagain_128k_8k, tc)
+{
+	test_eagain(131072, 8192);
+}
+ATF_TC_WITHOUT_HEAD(eagain_128k_128k);
+ATF_TC_BODY(eagain_128k_128k, tc)
+{
+	test_eagain(131072, 131072);
+}
+
+
+/* 
+ * nonblocking send(2) and recv(2) of several records, which should collectively
+ * fill up the send buffer but not the receive buffer
+ */
+ATF_TC_WITHOUT_HEAD(rcvbuf_oversized);
+ATF_TC_BODY(rcvbuf_oversized, tc)
+{
+	int s, i, j;
+	int sv[2];
+	const size_t sndbufsize = 8192;
+	const size_t rcvbufsize = 131072;
+	const size_t geom_mean_bufsize = 32768;
+	const int pktsize = 1024;
+	char sndbuf[pktsize];
+	char recv_buf[pktsize];
+	size_t datalen;
+	ssize_t ssize, rsize;
+
+	/* setup the socket pair */
+	do_socketpair_nonblocking(sv);
+
+	/* 
+	 * Send and receive packets that are collectively greater than the send
+	 * buffer, but less than the receive buffer
+	 */
+	for (i=0; i < geom_mean_bufsize / pktsize; i++) {
+		/* Fill the buffer */
+		memset(sndbuf, i, pktsize);
+
+		/* send the packet */
+		ssize = send(sv[0], sndbuf, pktsize, MSG_EOR);
+		if (ssize < 0) {
+			perror("send");
+			atf_tc_fail("send returned < 0");
+		}
+		ATF_CHECK_EQ_MSG(pktsize, ssize,
+		    "expected %zd=send(...) but got %zd", pktsize, ssize);
+
+		/* Receive it */
+
+		rsize = recv(sv[1], recv_buf, pktsize, MSG_WAITALL);
+		if (rsize < 0) {
+			perror("recv");
+			atf_tc_fail("recv returned < 0");
+		}
+		ATF_CHECK_EQ_MSG(pktsize, rsize,
+		    "expected %zd=send(...) but got %zd", pktsize, rsize);
+
+		/* Verify the contents */
+		ATF_CHECK_EQ_MSG(0, memcmp(sndbuf, recv_buf, pktsize), 
+		    "Received data miscompare");
+	}
+
+	/* Trying to receive again should return EAGAIN */
+	rsize = recv(sv[1], recv_buf, pktsize, MSG_WAITALL);
+	ATF_CHECK_EQ(EAGAIN, errno);
+	ATF_CHECK_EQ(-1, rsize);
+}
+
+/* 
+ * Simulate the behavior of a blocking pipe.  The sender will send until his
+ * buffer fills up, then we'll simulate a scheduler switch that will allow the
+ * receiver to read until his buffer empties.  Repeat the process until the
+ * transfer is complete.
+ * Repeat the test with multiple send and receive buffer sizes
+ */
+ATF_TC_WITHOUT_HEAD(pipe_simulator_8k_8k);
+ATF_TC_BODY(pipe_simulator_8k_8k, tc)
+{
+	test_pipe_simulator(8192, 8192);
+}
+
+ATF_TC_WITHOUT_HEAD(pipe_simulator_8k_128k);
+ATF_TC_BODY(pipe_simulator_8k_128k, tc)
+{
+	test_pipe_simulator(8192, 131072);
+}
+
+ATF_TC_WITHOUT_HEAD(pipe_simulator_128k_8k);
+ATF_TC_BODY(pipe_simulator_128k_8k, tc)
+{
+	test_pipe_simulator(131072, 8192);
+}
+
+ATF_TC_WITHOUT_HEAD(pipe_simulator_128k_128k);
+ATF_TC_BODY(pipe_simulator_128k_128k, tc)
+{
+	test_pipe_simulator(131072, 131072);
+}
+
+/* Test nonblocking I/O with 8K buffers */
+ATF_TC_WITHOUT_HEAD(sendrecv_8k_nonblocking);
+ATF_TC_BODY(sendrecv_8k_nonblocking, tc)
+{
+	test_nonblocking_symmetric_buffers(8 * 1024);
+}
+
+/* Test nonblocking I/O with 16K buffers */
+ATF_TC_WITHOUT_HEAD(sendrecv_16k_nonblocking);
+ATF_TC_BODY(sendrecv_16k_nonblocking, tc)
+{
+	test_nonblocking_symmetric_buffers(16 * 1024);
+}
+
+/* Test nonblocking I/O with 32K buffers */
+ATF_TC_WITHOUT_HEAD(sendrecv_32k_nonblocking);
+ATF_TC_BODY(sendrecv_32k_nonblocking, tc)
+{
+	test_nonblocking_symmetric_buffers(32 * 1024);
+}
+
+/* Test nonblocking I/O with 64K buffers */
+ATF_TC_WITHOUT_HEAD(sendrecv_64k_nonblocking);
+ATF_TC_BODY(sendrecv_64k_nonblocking, tc)
+{
+	test_nonblocking_symmetric_buffers(64 * 1024);
+}
+
+/* Test nonblocking I/O with 128K buffers */
+ATF_TC_WITHOUT_HEAD(sendrecv_128k_nonblocking);
+ATF_TC_BODY(sendrecv_128k_nonblocking, tc)
+{
+	test_nonblocking_symmetric_buffers(128 * 1024);
+}
+
+
+/*
+ * Main.
+ */
+
+ATF_TP_ADD_TCS(tp)
+{
+	/* Basic creation and connection tests */
+	ATF_TP_ADD_TC(tp, create_socket);
+	ATF_TP_ADD_TC(tp, create_socketpair);
+	ATF_TP_ADD_TC(tp, listen_unbound);
+	ATF_TP_ADD_TC(tp, bind);
+	ATF_TP_ADD_TC(tp, listen_bound);
+	ATF_TP_ADD_TC(tp, fcntl_nonblock);
+	ATF_TP_ADD_TC(tp, resize_buffers);
+
+	/* Unthreaded I/O tests */
+	ATF_TP_ADD_TC(tp, send_recv);
+	ATF_TP_ADD_TC(tp, send_recv_nonblocking);
+	ATF_TP_ADD_TC(tp, emsgsize);
+	ATF_TP_ADD_TC(tp, emsgsize_nonblocking);
+	ATF_TP_ADD_TC(tp, eagain_8k_8k);
+	ATF_TP_ADD_TC(tp, eagain_8k_128k);
+	ATF_TP_ADD_TC(tp, eagain_128k_8k);
+	ATF_TP_ADD_TC(tp, eagain_128k_128k);
+	ATF_TP_ADD_TC(tp, sendrecv_8k_nonblocking);
+	ATF_TP_ADD_TC(tp, sendrecv_16k_nonblocking);
+	ATF_TP_ADD_TC(tp, sendrecv_32k_nonblocking);
+	ATF_TP_ADD_TC(tp, sendrecv_64k_nonblocking);
+	ATF_TP_ADD_TC(tp, sendrecv_128k_nonblocking);
+	ATF_TP_ADD_TC(tp, rcvbuf_oversized);
+	ATF_TP_ADD_TC(tp, pipe_simulator_8k_8k);
+	ATF_TP_ADD_TC(tp, pipe_simulator_8k_128k);
+	ATF_TP_ADD_TC(tp, pipe_simulator_128k_8k);
+	ATF_TP_ADD_TC(tp, pipe_simulator_128k_128k);
+
+	return atf_no_error();
+}
Index: sys/tests/Makefile
===================================================================
--- sys/tests/Makefile	(revision 0)
+++ sys/tests/Makefile	(working copy)
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/sys
+
+.PATH:		${.CURDIR:H:H}/tests
+KYUAFILE=	yes
+
+.include <bsd.test.mk>
Index: etc/mtree/BSD.tests.dist
===================================================================
--- etc/mtree/BSD.tests.dist	(revision 260696)
+++ etc/mtree/BSD.tests.dist	(working copy)
@@ -78,6 +78,10 @@
                 ..
             ..
         ..
+	sys
+	    kern
+	    ..
+	..
         usr.bin
             atf
                 atf-sh


>Release-Note:
>Audit-Trail:
>Unformatted:



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