summaryrefslogtreecommitdiffstats
path: root/regress/sys
diff options
context:
space:
mode:
authoranton <anton@openbsd.org>2020-12-03 19:16:57 +0000
committeranton <anton@openbsd.org>2020-12-03 19:16:57 +0000
commit340aa6c7a94bb7588da3a3ab820cdd3a62738daf (patch)
treea34b140e6933f5809f0c88c696414b4025fd27dd /regress/sys
parentMake sure that the strcasecmp for .tal is only done if dlen is large enough. (diff)
downloadwireguard-openbsd-340aa6c7a94bb7588da3a3ab820cdd3a62738daf.tar.xz
wireguard-openbsd-340aa6c7a94bb7588da3a3ab820cdd3a62738daf.zip
restructure, making room for several tests
Diffstat (limited to 'regress/sys')
-rw-r--r--regress/sys/uvm/vnode/Makefile17
-rw-r--r--regress/sys/uvm/vnode/extern.h32
-rw-r--r--regress/sys/uvm/vnode/test-deadlock.c147
-rw-r--r--regress/sys/uvm/vnode/vnode.c182
4 files changed, 258 insertions, 120 deletions
diff --git a/regress/sys/uvm/vnode/Makefile b/regress/sys/uvm/vnode/Makefile
index 89073fa7a7d..df56cc3510c 100644
--- a/regress/sys/uvm/vnode/Makefile
+++ b/regress/sys/uvm/vnode/Makefile
@@ -1,13 +1,22 @@
-# $OpenBSD: Makefile,v 1.2 2020/11/05 18:25:39 anton Exp $
+# $OpenBSD: Makefile,v 1.3 2020/12/03 19:16:57 anton Exp $
PROG= vnode
+
+SRCS+= vnode.c
+SRCS+= test-deadlock.c
+
WARNINGS= yes
+TESTS+= deadlock
+
REGRESS_SETUP_ONCE= setup
setup: ${PROG}
-REGRESS_TARGETS+= run-vnode
-run-vnode:
- t=`mktemp`; trap 'rm $$t' EXIT; ${.OBJDIR}/vnode $$t
+.for t in ${TESTS}
+${t}:
+ @echo "\n======== ${@} ========"
+ f=`mktemp`; trap 'rm $$f' EXIT; ./${PROG} -f $$f ${t}
+REGRESS_TARGETS+= ${t}
+.endfor
.include <bsd.regress.mk>
diff --git a/regress/sys/uvm/vnode/extern.h b/regress/sys/uvm/vnode/extern.h
new file mode 100644
index 00000000000..73bf1022c09
--- /dev/null
+++ b/regress/sys/uvm/vnode/extern.h
@@ -0,0 +1,32 @@
+/* $OpenBSD: extern.h,v 1.1 2020/12/03 19:16:57 anton Exp $ */
+
+/*
+ * Copyright (c) 2020 Anton Lindqvist <anton@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define LOG(l, x...) do { if (loglevel >= l) logit(x); } while (0)
+
+struct context {
+ const char *c_path;
+ int c_iterations;
+};
+
+int ctx_abort(struct context *);
+
+void logit(const char *, ...) __attribute__((__format__ (printf, 1, 2)));
+
+int test_deadlock(struct context *);
+
+extern int loglevel;
diff --git a/regress/sys/uvm/vnode/test-deadlock.c b/regress/sys/uvm/vnode/test-deadlock.c
new file mode 100644
index 00000000000..763973c3585
--- /dev/null
+++ b/regress/sys/uvm/vnode/test-deadlock.c
@@ -0,0 +1,147 @@
+/* $OpenBSD: test-deadlock.c,v 1.1 2020/12/03 19:16:57 anton Exp $ */
+
+/*
+ * Copyright (c) 2020 Anton Lindqvist <anton@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h> /* PAGE_SIZE */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static void growshrink(const char *);
+static void writer(const char *, int);
+
+static int npages = 2;
+
+/*
+ * Trigger a deadlock between uvn_flush() and uvn_io() caused by uvn_flush()
+ * holding the vnode lock while waiting for pages to become unbusy; the busy
+ * pages are allocated and marked as busy by uvn_io() which in turn is trying to
+ * lock the same vnode while populating the page(s) using I/O on the vnode.
+ */
+int
+test_deadlock(struct context *ctx)
+{
+ int killpip[2];
+ int status;
+ pid_t pid;
+
+ if (pipe2(killpip, O_NONBLOCK) == -1)
+ err(1, "pipe2");
+
+ pid = fork();
+ if (pid == -1)
+ err(1, "fork");
+ if (pid == 0) {
+ close(killpip[1]);
+ writer(ctx->c_path, killpip[0]);
+ return 0;
+ }
+ close(killpip[0]);
+
+ fprintf(stderr, "parent = %d, child = %d\n", getpid(), pid);
+
+ for (;;) {
+ if (ctx_abort(ctx))
+ break;
+ growshrink(ctx->c_path);
+ }
+
+ /* Signal shutdown to writer() process. */
+ write(killpip[1], "X", 1);
+ close(killpip[1]);
+
+ if (waitpid(pid, &status, 0) == -1)
+ err(1, "waitpid");
+ if (WIFSIGNALED(status))
+ return 128 + WTERMSIG(status);
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ return 0;
+}
+
+static void
+growshrink(const char *path)
+{
+ char *p;
+ int fd;
+
+ /*
+ * Open and truncate the file causing uvn_flush() to try evict pages
+ * which are currently being populated by the writer() process.
+ */
+ fd = open(path, O_RDWR | O_TRUNC);
+ if (fd == -1)
+ err(1, "open: %s", path);
+
+ /* Grow the file again. */
+ if (ftruncate(fd, npages * PAGE_SIZE) == -1)
+ err(1, "ftruncate");
+
+ p = mmap(NULL, npages * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0);
+ if (p == MAP_FAILED)
+ err(1, "mmap");
+
+ /* Populate the last page. */
+ memset(&p[(npages - 1) * PAGE_SIZE], 'x', PAGE_SIZE);
+
+ if (munmap(p, npages * PAGE_SIZE) == -1)
+ err(1, "munmap");
+ close(fd);
+}
+
+static void
+writer(const char *path, int killfd)
+{
+ char *p;
+ int fd;
+ char c;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ err(1, "open: %s", path);
+ p = mmap(NULL, npages * PAGE_SIZE, PROT_READ, MAP_SHARED,
+ fd, 0);
+ if (p == MAP_FAILED)
+ err(1, "mmap");
+
+ for (;;) {
+ const struct iovec *iov = (const struct iovec *)p;
+
+ if (read(killfd, &c, 1) == 1)
+ break;
+
+ /*
+ * This write should never succeed since the file descriptor is
+ * invalid. However, it should cause a page fault during
+ * copyin() which in turn will invoke uvn_io() while trying to
+ * populate the page. At this point, it will try to lock the
+ * vnode, which is potentially already locked by the
+ * growshrink() process.
+ */
+ pwritev(-1, iov, 1, 0);
+ }
+}
diff --git a/regress/sys/uvm/vnode/vnode.c b/regress/sys/uvm/vnode/vnode.c
index 51140fb31b3..c794c01df49 100644
--- a/regress/sys/uvm/vnode/vnode.c
+++ b/regress/sys/uvm/vnode/vnode.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vnode.c,v 1.2 2020/11/03 13:58:45 bluhm Exp $ */
+/* $OpenBSD: vnode.c,v 1.3 2020/12/03 19:16:57 anton Exp $ */
/*
* Copyright (c) 2020 Anton Lindqvist <anton@openbsd.org>
@@ -16,50 +16,51 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/types.h>
-#include <sys/param.h> /* PAGE_SIZE */
-#include <sys/mman.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-
#include <err.h>
-#include <fcntl.h>
-#include <signal.h>
+#include <errno.h>
#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-static void growshrink(const char *);
-static void writer(const char *, int);
+#include "extern.h"
static void sighandler(int);
static void __dead usage(void);
+int loglevel = 0;
+
static int gotsig;
-static int npages = 2;
-/*
- * Trigger a deadlock between uvn_flush() and uvn_io() caused by uvn_flush()
- * holding the vnode lock while waiting for pages to become unbusy; the busy
- * pages are allocated and marked as busy by uvn_io() which in turn is trying to
- * lock the same vnode while populating the page(s) using I/O on the vnode.
- */
int
main(int argc, char *argv[])
{
- const char *path;
- pid_t pid;
- int killpip[2];
- int status;
- int iterations = 100;
- int ch;
-
- while ((ch = getopt(argc, argv, "I")) != -1) {
+ struct {
+ const char *t_name;
+ int (*t_func)(struct context *);
+ } tests[] = {
+ { "deadlock", test_deadlock },
+
+ { NULL, NULL },
+ };
+ struct context ctx;
+ int ch, i;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.c_iterations = 100;
+
+ while ((ch = getopt(argc, argv, "If:v")) != -1) {
switch (ch) {
case 'I':
- iterations = -1;
+ ctx.c_iterations = -1;
+ break;
+ case 'f':
+ ctx.c_path = optarg;
+ break;
+ case 'v':
+ loglevel++;
break;
default:
usage();
@@ -67,110 +68,59 @@ main(int argc, char *argv[])
}
argc -= optind;
argv += optind;
- if (argc != 1)
+ if (argc != 1 || ctx.c_path == NULL)
usage();
- path = argv[0];
-
- if (pipe2(killpip, O_NONBLOCK) == -1)
- err(1, "pipe2");
if (signal(SIGINT, sighandler) == SIG_ERR)
err(1, "signal");
- pid = fork();
- if (pid == -1)
- err(1, "fork");
- if (pid == 0) {
- close(killpip[1]);
- writer(path, killpip[0]);
- return 0;
- }
- close(killpip[0]);
-
- fprintf(stderr, "parent = %d, child = %d\n", getpid(), pid);
+ for (i = 0;; i++) {
+ if (tests[i].t_name == NULL)
+ err(1, "%s: no such test", *argv);
- while (gotsig == 0) {
- if (iterations > 0 && --iterations == 0)
- break;
+ if (strcmp(tests[i].t_name, *argv))
+ continue;
- growshrink(path);
+ return tests[i].t_func(&ctx);
}
- /* Signal shutdown to writer() process. */
- write(killpip[1], "X", 1);
- close(killpip[1]);
-
- if (waitpid(pid, &status, 0) == -1)
- err(1, "waitpid");
- if (WIFSIGNALED(status))
- return 128 + WTERMSIG(status);
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
return 0;
}
-static void
-growshrink(const char *path)
+int
+ctx_abort(struct context *ctx)
{
- char *p;
- int fd;
-
- /*
- * Open and truncate the file causing uvn_flush() to try evict pages
- * which are currently being populated by the writer() process.
- */
- fd = open(path, O_RDWR | O_TRUNC);
- if (fd == -1)
- err(1, "open: %s", path);
-
- /* Grow the file again. */
- if (ftruncate(fd, npages * PAGE_SIZE) == -1)
- err(1, "ftruncate");
-
- p = mmap(NULL, npages * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
- fd, 0);
- if (p == MAP_FAILED)
- err(1, "mmap");
-
- /* Populate the last page. */
- memset(&p[(npages - 1) * PAGE_SIZE], 'x', PAGE_SIZE);
-
- if (munmap(p, npages * PAGE_SIZE) == -1)
- err(1, "munmap");
- close(fd);
+ if (gotsig)
+ return 1;
+ if (ctx->c_iterations > 0 && --ctx->c_iterations == 0)
+ return 1;
+ return 0;
}
-static void
-writer(const char *path, int killfd)
+void
+logit(const char *fmt, ...)
{
- char *p;
- int fd;
- char c;
-
- fd = open(path, O_RDONLY);
- if (fd == -1)
- err(1, "open: %s", path);
- p = mmap(NULL, npages * PAGE_SIZE, PROT_READ, MAP_SHARED,
- fd, 0);
- if (p == MAP_FAILED)
- err(1, "mmap");
-
- for (;;) {
- const struct iovec *iov = (const struct iovec *)p;
-
- if (read(killfd, &c, 1) == 1)
- break;
-
- /*
- * This write should never succeed since the file descriptor is
- * invalid. However, it should cause a page fault during
- * copyin() which in turn will invoke uvn_io() while trying to
- * populate the page. At this point, it will try to lock the
- * vnode, which is potentially already locked by the
- * growshrink() process.
- */
- pwritev(-1, iov, 1, 0);
- }
+ char buf[1024];
+ va_list ap;
+ char *p = buf;
+ ssize_t siz = sizeof(buf);
+ int n;
+
+ n = snprintf(p, siz, "[%d] ", getpid());
+ if (n < 0 || n >= siz)
+ errc(1, ENAMETOOLONG, "%s", __func__);
+ p += n;
+ siz -= n;
+
+ va_start(ap, fmt);
+ n = vsnprintf(p, siz, fmt, ap);
+ va_end(ap);
+ if (n < 0 || n >= siz)
+ errc(1, ENAMETOOLONG, "%s", __func__);
+ p += n;
+ siz -= n;
+
+ fprintf(stderr, "%s\n", buf);
}
static void
@@ -182,6 +132,6 @@ sighandler(int signo)
static void __dead
usage(void)
{
- fprintf(stderr, "usage: vnode [-I] path\n");
+ fprintf(stderr, "usage: vnode [-Iv] -f path test-case\n");
exit(1);
}