Home | History | Annotate | Line # | Download | only in kernel
t_fdrestart.c revision 1.3
      1  1.3  riastrad /*	$NetBSD: t_fdrestart.c,v 1.3 2023/10/15 15:18:17 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /*-
      4  1.1  riastrad  * Copyright (c) 2023 The NetBSD Foundation, Inc.
      5  1.1  riastrad  * All rights reserved.
      6  1.1  riastrad  *
      7  1.1  riastrad  * Redistribution and use in source and binary forms, with or without
      8  1.1  riastrad  * modification, are permitted provided that the following conditions
      9  1.1  riastrad  * are met:
     10  1.1  riastrad  * 1. Redistributions of source code must retain the above copyright
     11  1.1  riastrad  *    notice, this list of conditions and the following disclaimer.
     12  1.1  riastrad  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  riastrad  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  riastrad  *    documentation and/or other materials provided with the distribution.
     15  1.1  riastrad  *
     16  1.1  riastrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.1  riastrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.1  riastrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.1  riastrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.1  riastrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1  riastrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1  riastrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1  riastrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1  riastrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1  riastrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1  riastrad  * POSSIBILITY OF SUCH DAMAGE.
     27  1.1  riastrad  */
     28  1.1  riastrad 
     29  1.1  riastrad #define	_KMEMUSER		/* ERESTART */
     30  1.1  riastrad 
     31  1.1  riastrad #include <sys/cdefs.h>
     32  1.3  riastrad __RCSID("$NetBSD: t_fdrestart.c,v 1.3 2023/10/15 15:18:17 riastradh Exp $");
     33  1.1  riastrad 
     34  1.3  riastrad #include <sys/ioctl.h>
     35  1.1  riastrad #include <sys/socket.h>
     36  1.1  riastrad #include <sys/un.h>
     37  1.1  riastrad 
     38  1.1  riastrad #include <atf-c.h>
     39  1.1  riastrad #include <errno.h>
     40  1.1  riastrad #include <pthread.h>
     41  1.1  riastrad #include <unistd.h>
     42  1.1  riastrad 
     43  1.1  riastrad #include <rump/rump.h>
     44  1.1  riastrad #include <rump/rump_syscalls.h>
     45  1.1  riastrad 
     46  1.1  riastrad #include "h_macros.h"
     47  1.1  riastrad 
     48  1.1  riastrad struct fdrestart {
     49  1.1  riastrad 	void			(*op)(struct fdrestart *);
     50  1.1  riastrad 	int			fd;
     51  1.1  riastrad 	pthread_barrier_t	barrier;
     52  1.1  riastrad };
     53  1.1  riastrad 
     54  1.1  riastrad static void
     55  1.3  riastrad waitforbarrier(struct fdrestart *F, const char *caller)
     56  1.3  riastrad {
     57  1.3  riastrad 	int error;
     58  1.3  riastrad 
     59  1.3  riastrad 	error = pthread_barrier_wait(&F->barrier);
     60  1.3  riastrad 	switch (error) {
     61  1.3  riastrad 	case 0:
     62  1.3  riastrad 	case PTHREAD_BARRIER_SERIAL_THREAD:
     63  1.3  riastrad 		break;
     64  1.3  riastrad 	default:
     65  1.3  riastrad 		atf_tc_fail("%s: pthread_barrier_wait: %d, %s", caller, error,
     66  1.3  riastrad 		    strerror(error));
     67  1.3  riastrad 	}
     68  1.3  riastrad }
     69  1.3  riastrad 
     70  1.3  riastrad static void
     71  1.1  riastrad doread(struct fdrestart *F)
     72  1.1  riastrad {
     73  1.1  riastrad 	char c;
     74  1.1  riastrad 	ssize_t nread;
     75  1.1  riastrad 	int error;
     76  1.1  riastrad 
     77  1.3  riastrad 	/*
     78  1.3  riastrad 	 * Wait for the other thread to be ready.
     79  1.3  riastrad 	 */
     80  1.3  riastrad 	waitforbarrier(F, "reader");
     81  1.3  riastrad 
     82  1.3  riastrad 	/*
     83  1.3  riastrad 	 * Start a read.  This should block, and then, when the other
     84  1.3  riastrad 	 * thread closes the fd, should be woken to fail with ERESTART.
     85  1.3  riastrad 	 */
     86  1.1  riastrad 	nread = rump_sys_read(F->fd, &c, sizeof(c));
     87  1.1  riastrad 	ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread);
     88  1.1  riastrad 	error = errno;
     89  1.1  riastrad 	ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error,
     90  1.1  riastrad 	    strerror(error));
     91  1.1  riastrad 
     92  1.3  riastrad 	/*
     93  1.3  riastrad 	 * Now further attempts at I/O should fail with EBADF because
     94  1.3  riastrad 	 * the fd has been closed.
     95  1.3  riastrad 	 */
     96  1.1  riastrad 	nread = rump_sys_read(F->fd, &c, sizeof(c));
     97  1.1  riastrad 	ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread);
     98  1.1  riastrad 	error = errno;
     99  1.1  riastrad 	ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error,
    100  1.1  riastrad 	    strerror(error));
    101  1.1  riastrad }
    102  1.1  riastrad 
    103  1.1  riastrad static void
    104  1.1  riastrad dowrite(struct fdrestart *F)
    105  1.1  riastrad {
    106  1.1  riastrad 	static const char buf[1024*1024]; /* XXX >BIG_PIPE_SIZE */
    107  1.1  riastrad 	ssize_t nwrit;
    108  1.1  riastrad 	int error;
    109  1.1  riastrad 
    110  1.3  riastrad 	/*
    111  1.3  riastrad 	 * Make sure the pipe's buffer is full first.
    112  1.3  riastrad 	 */
    113  1.3  riastrad 	for (;;) {
    114  1.3  riastrad 		int nspace;
    115  1.3  riastrad 
    116  1.3  riastrad 		RL(rump_sys_ioctl(F->fd, FIONSPACE, &nspace));
    117  1.3  riastrad 		ATF_REQUIRE_MSG(nspace >= 0, "nspace=%d", nspace);
    118  1.3  riastrad 		if (nspace == 0)
    119  1.3  riastrad 			break;
    120  1.3  riastrad 		RL(rump_sys_write(F->fd, buf, (size_t)nspace));
    121  1.3  riastrad 	}
    122  1.3  riastrad 
    123  1.3  riastrad 	/*
    124  1.3  riastrad 	 * Wait for the other thread to be ready.
    125  1.3  riastrad 	 */
    126  1.3  riastrad 	waitforbarrier(F, "writer");
    127  1.3  riastrad 
    128  1.3  riastrad 	/*
    129  1.3  riastrad 	 * Start a write.  This should block, and then, when the other
    130  1.3  riastrad 	 * thread closes the fd, should be woken to fail with ERESTART.
    131  1.3  riastrad 	 */
    132  1.1  riastrad 	nwrit = rump_sys_write(F->fd, buf, sizeof(buf));
    133  1.1  riastrad 	ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit);
    134  1.1  riastrad 	error = errno;
    135  1.1  riastrad 	ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error,
    136  1.1  riastrad 	    strerror(error));
    137  1.1  riastrad 
    138  1.3  riastrad 	/*
    139  1.3  riastrad 	 * Now further attempts at I/O should fail with EBADF because
    140  1.3  riastrad 	 * the fd has been closed.
    141  1.3  riastrad 	 */
    142  1.1  riastrad 	nwrit = rump_sys_write(F->fd, buf, sizeof(buf));
    143  1.2  riastrad 	ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit);
    144  1.1  riastrad 	error = errno;
    145  1.1  riastrad 	ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error,
    146  1.1  riastrad 	    strerror(error));
    147  1.1  riastrad }
    148  1.1  riastrad 
    149  1.1  riastrad static void *
    150  1.1  riastrad doit(void *cookie)
    151  1.1  riastrad {
    152  1.1  riastrad 	struct fdrestart *F = cookie;
    153  1.1  riastrad 
    154  1.1  riastrad 	(*F->op)(F);
    155  1.1  riastrad 
    156  1.1  riastrad 	return NULL;
    157  1.1  riastrad }
    158  1.1  riastrad 
    159  1.1  riastrad static void
    160  1.1  riastrad on_sigalrm(int signo)
    161  1.1  riastrad {
    162  1.1  riastrad 
    163  1.1  riastrad 	atf_tc_fail("timed out");
    164  1.1  riastrad }
    165  1.1  riastrad 
    166  1.1  riastrad static void
    167  1.1  riastrad testfdrestart(struct fdrestart *F)
    168  1.1  riastrad {
    169  1.1  riastrad 	pthread_t t;
    170  1.1  riastrad 
    171  1.1  riastrad 	ATF_REQUIRE_MSG(signal(SIGALRM, &on_sigalrm) != SIG_ERR,
    172  1.1  riastrad 	    "errno=%d (%s)", errno, strerror(errno));
    173  1.1  riastrad 
    174  1.1  riastrad 	RZ(pthread_barrier_init(&F->barrier, NULL, 2));
    175  1.1  riastrad 	RZ(pthread_create(&t, NULL, &doit, F));
    176  1.1  riastrad 	waitforbarrier(F, "closer");	/* wait for thread to start */
    177  1.1  riastrad 	(void)sleep(1);			/* wait for op to start */
    178  1.3  riastrad 	(void)alarm(1);			/* set a deadline */
    179  1.3  riastrad 	RL(rump_sys_close(F->fd));	/* wake op in other thread */
    180  1.3  riastrad 	RZ(pthread_join(t, NULL));	/* wait for op to wake and fail */
    181  1.3  riastrad 	(void)alarm(0);			/* clear the deadline */
    182  1.1  riastrad }
    183  1.1  riastrad 
    184  1.1  riastrad ATF_TC(pipe_read);
    185  1.1  riastrad ATF_TC_HEAD(pipe_read, tc)
    186  1.1  riastrad {
    187  1.1  riastrad 	atf_tc_set_md_var(tc, "descr", "Test pipe read fails on close");
    188  1.1  riastrad }
    189  1.1  riastrad ATF_TC_BODY(pipe_read, tc)
    190  1.1  riastrad {
    191  1.1  riastrad 	struct fdrestart fdrestart, *F = &fdrestart;
    192  1.1  riastrad 	int fd[2];
    193  1.1  riastrad 
    194  1.1  riastrad 	rump_init();
    195  1.1  riastrad 
    196  1.1  riastrad 	RL(rump_sys_pipe(fd));
    197  1.1  riastrad 
    198  1.1  riastrad 	memset(F, 0, sizeof(*F));
    199  1.1  riastrad 	F->op = &doread;
    200  1.1  riastrad 	F->fd = fd[0];
    201  1.1  riastrad 	atf_tc_expect_fail("PR kern/57659");
    202  1.1  riastrad 	testfdrestart(F);
    203  1.1  riastrad }
    204  1.1  riastrad 
    205  1.1  riastrad ATF_TC(pipe_write);
    206  1.1  riastrad ATF_TC_HEAD(pipe_write, tc)
    207  1.1  riastrad {
    208  1.1  riastrad 	atf_tc_set_md_var(tc, "descr", "Test pipe write fails on close");
    209  1.1  riastrad }
    210  1.1  riastrad ATF_TC_BODY(pipe_write, tc)
    211  1.1  riastrad {
    212  1.1  riastrad 	struct fdrestart fdrestart, *F = &fdrestart;
    213  1.1  riastrad 	int fd[2];
    214  1.1  riastrad 
    215  1.1  riastrad 	rump_init();
    216  1.1  riastrad 
    217  1.1  riastrad 	RL(rump_sys_pipe(fd));
    218  1.1  riastrad 
    219  1.1  riastrad 	memset(F, 0, sizeof(*F));
    220  1.1  riastrad 	F->op = &dowrite;
    221  1.1  riastrad 	F->fd = fd[1];
    222  1.1  riastrad 	atf_tc_expect_fail("PR kern/57659");
    223  1.1  riastrad 	testfdrestart(F);
    224  1.1  riastrad }
    225  1.1  riastrad 
    226  1.1  riastrad ATF_TC(socketpair_read);
    227  1.1  riastrad ATF_TC_HEAD(socketpair_read, tc)
    228  1.1  riastrad {
    229  1.1  riastrad 	atf_tc_set_md_var(tc, "descr", "Test socketpair read fails on close");
    230  1.1  riastrad }
    231  1.1  riastrad ATF_TC_BODY(socketpair_read, tc)
    232  1.1  riastrad {
    233  1.1  riastrad 	struct fdrestart fdrestart, *F = &fdrestart;
    234  1.1  riastrad 	int fd[2];
    235  1.1  riastrad 
    236  1.1  riastrad 	rump_init();
    237  1.1  riastrad 
    238  1.1  riastrad 	RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd));
    239  1.1  riastrad 
    240  1.1  riastrad 	memset(F, 0, sizeof(*F));
    241  1.1  riastrad 	F->op = &doread;
    242  1.1  riastrad 	F->fd = fd[0];
    243  1.1  riastrad 	atf_tc_expect_fail("PR kern/57659");
    244  1.1  riastrad 	testfdrestart(F);
    245  1.1  riastrad }
    246  1.1  riastrad 
    247  1.1  riastrad ATF_TC(socketpair_write);
    248  1.1  riastrad ATF_TC_HEAD(socketpair_write, tc)
    249  1.1  riastrad {
    250  1.1  riastrad 	atf_tc_set_md_var(tc, "descr", "Test socketpair write fails on close");
    251  1.1  riastrad }
    252  1.1  riastrad ATF_TC_BODY(socketpair_write, tc)
    253  1.1  riastrad {
    254  1.1  riastrad 	struct fdrestart fdrestart, *F = &fdrestart;
    255  1.1  riastrad 	int fd[2];
    256  1.1  riastrad 
    257  1.1  riastrad 	rump_init();
    258  1.1  riastrad 
    259  1.1  riastrad 	RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd));
    260  1.1  riastrad 
    261  1.1  riastrad 	memset(F, 0, sizeof(*F));
    262  1.1  riastrad 	F->op = &dowrite;
    263  1.1  riastrad 	F->fd = fd[0];
    264  1.1  riastrad 	atf_tc_expect_fail("PR kern/57659");
    265  1.1  riastrad 	testfdrestart(F);
    266  1.1  riastrad }
    267  1.1  riastrad 
    268  1.1  riastrad ATF_TP_ADD_TCS(tp)
    269  1.1  riastrad {
    270  1.1  riastrad 
    271  1.1  riastrad 	ATF_TP_ADD_TC(tp, pipe_read);
    272  1.1  riastrad 	ATF_TP_ADD_TC(tp, pipe_write);
    273  1.1  riastrad 	ATF_TP_ADD_TC(tp, socketpair_read);
    274  1.1  riastrad 	ATF_TP_ADD_TC(tp, socketpair_write);
    275  1.1  riastrad 
    276  1.1  riastrad 	return atf_no_error();
    277  1.1  riastrad }
    278