summaryrefslogtreecommitdiff
path: root/usr/src/cmd/bhyve/test
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/bhyve/test')
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/Makefile9
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/mevent.c6
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/testlib.h2
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c141
-rw-r--r--usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c259
5 files changed, 416 insertions, 1 deletions
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/Makefile b/usr/src/cmd/bhyve/test/tests/mevent/Makefile
index 363deb02cc..9d93e17f5a 100644
--- a/usr/src/cmd/bhyve/test/tests/mevent/Makefile
+++ b/usr/src/cmd/bhyve/test/tests/mevent/Makefile
@@ -12,6 +12,7 @@
#
# Copyright 2018 Joyent, Inc.
# Copyright 2022 Oxide Computer Company
+# Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
#
TESTSUBDIR = mevent
@@ -19,7 +20,9 @@ PROG = \
lists_delete \
read_disable \
read_pause \
- read_requeue
+ read_requeue \
+ vnode_file \
+ vnode_zvol
SUPOBJS = mevent.o testlib.o
@@ -34,8 +37,12 @@ install: $(TESTDIR) $(CMDS)
$(CMDS): $(PROG)
+vnode_zvol := LDLIBS += -lzfs -lnvpair
+
include ../../Makefile.targ
%: %.o $(SUPOBJS)
$(LINK.c) -o $@ $< $(SUPOBJS) $(LDLIBS)
$(POST_PROCESS)
+
+mevent.o: ../../../mevent.c
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/mevent.c b/usr/src/cmd/bhyve/test/tests/mevent/mevent.c
index 971cf4aa77..51c94a4c09 100644
--- a/usr/src/cmd/bhyve/test/tests/mevent/mevent.c
+++ b/usr/src/cmd/bhyve/test/tests/mevent/mevent.c
@@ -55,3 +55,9 @@ test_mevent_count_lists(int *ret_global, int *ret_change, int *ret_del_pending)
*ret_change = change;
*ret_del_pending = del_pending;
}
+
+void
+set_mevent_file_poll_interval_ms(int ms)
+{
+ mevent_file_poll_interval_ms = ms;
+}
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/testlib.h b/usr/src/cmd/bhyve/test/tests/mevent/testlib.h
index 7e5ca2e9c9..1639f29f87 100644
--- a/usr/src/cmd/bhyve/test/tests/mevent/testlib.h
+++ b/usr/src/cmd/bhyve/test/tests/mevent/testlib.h
@@ -71,6 +71,7 @@
#define ASSERT_INT_EQ(msg, got, exp) ASSERT_CMP(msg, got, ==, exp, "%d")
#define ASSERT_INT_NEQ(msg, got, exp) ASSERT_CMP(msg, got, !=, exp, "%d")
#define ASSERT_INT64_EQ(msg, got, exp) ASSERT_CMP(msg, got, ==, exp, "%ld")
+#define ASSERT_INT64_NEQ(msg, got, exp) ASSERT_CMP(msg, got, !=, exp, "%ld")
#define ASSERT_PTR_EQ(msg, got, exp) ASSERT_CMP(msg, got, ==, exp, "%p")
#define ASSERT_PTR_NEQ(msg, got, exp) ASSERT_CMP(msg, got, !=, exp, "%p")
@@ -89,5 +90,6 @@ extern boolean_t testlib_verbose;
extern void start_test(const char *, uint32_t);
extern void start_event_thread(void);
extern void test_mevent_count_lists(int *, int *, int *);
+extern void set_mevent_file_poll_interval_ms(int);
#endif /* _TESTLIB_H_ */
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c b/usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c
new file mode 100644
index 0000000000..850ac1be27
--- /dev/null
+++ b/usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c
@@ -0,0 +1,141 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "testlib.h"
+#include "mevent.h"
+
+static char *cookie = "Chocolate chip with fudge stripes";
+
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+
+static void
+callback(int fd, enum ev_type ev, void *arg)
+{
+ static off_t size = 0;
+ struct stat st;
+
+ ASSERT_INT_EQ(("bad event"), ev, EVF_VNODE);
+ ASSERT_PTR_EQ(("bad cookie"), arg, cookie);
+
+ if (fstat(fd, &st) != 0)
+ FAIL_ERRNO("fstat failed");
+
+ ASSERT_INT64_NEQ(("File size has not changed"), size, st.st_size);
+ size = st.st_size;
+
+ pthread_mutex_lock(&mtx);
+ pthread_cond_signal(&cv);
+ VERBOSE(("wakeup"));
+ pthread_mutex_unlock(&mtx);
+}
+
+static void
+test_fd(int fd, char *tag)
+{
+ struct mevent *evp;
+ int err;
+
+ evp = mevent_add_flags(fd, EVF_VNODE, EVFF_ATTRIB, callback, cookie);
+ ASSERT_PTR_NEQ(("%s: mevent_add", tag), evp, NULL);
+
+ for (uint_t i = 0; cookie[i] != '\0'; i++) {
+ ssize_t written;
+
+ pthread_mutex_lock(&mtx);
+
+ if (i > 0) {
+ /*
+ * Check that no events are emitted for writes which do
+ * not alter the size.
+ */
+ if (lseek(fd, -1, SEEK_CUR) == -1)
+ FAIL_ERRNO("lseek");
+ if (write(fd, "X", 1) == -1)
+ FAIL_ERRNO("write");
+ }
+
+ written = write(fd, cookie + i, 1);
+ if (written < 0)
+ FAIL_ERRNO("bad write");
+ ASSERT_INT64_EQ(("write byte %d of cookie", i), written, 1);
+
+ /* Wait for the size change to be processed */
+ pthread_cond_wait(&cv, &mtx);
+ pthread_mutex_unlock(&mtx);
+ /*
+ * This is a bit unsatisfactory but we need to allow time
+ * for mevent to re-associate the port or the next write could
+ * be missed.
+ */
+ usleep(500);
+ }
+
+ err = mevent_disable(evp);
+ ASSERT_INT_EQ(("%s: mevent_disable: %s", tag, strerror(err)), err, 0);
+
+ (void) printf("PASS %s - %s\n", testlib_prog, tag);
+}
+
+int
+main(int argc, const char **argv)
+{
+ start_test(argv[0], 5);
+ start_event_thread();
+ int fd;
+
+ /* Test with a temporary file in /tmp */
+ char *template = strdup("/tmp/mevent.vnode.XXXXXX");
+ ASSERT_PTR_NEQ(("strdup"), template, NULL);
+ fd = mkstemp(template);
+ if (fd == -1)
+ FAIL_ERRNO("Couldn't create temporary file with mkstemp");
+
+ VERBOSE(("Opened temporary file at '%s'", template));
+
+ test_fd(fd, "temporary file");
+
+ /* Test with a file which is unlinked from the filesystem */
+ FILE *fp = tmpfile();
+ ASSERT_PTR_NEQ(("tmpfile"), fp, NULL);
+
+ fd = fileno(fp);
+ if (fd == -1)
+ FAIL_ERRNO("Couldn't get file descriptor for temporary file");
+
+ test_fd(fd, "anon file");
+
+ /*
+ * Defer to here to avoid generating a new event before the disable has
+ * been processed and the port deassociated.
+ */
+ unlink(template);
+ free(template);
+
+ PASS();
+}
diff --git a/usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c b/usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c
new file mode 100644
index 0000000000..8e99d7ba0d
--- /dev/null
+++ b/usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c
@@ -0,0 +1,259 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Joyent, Inc.
+ * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libzfs.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <zone.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "testlib.h"
+#include "mevent.h"
+
+#define MB (1024 * 1024)
+
+static char *cookie = "Chocolate chip with fudge stripes";
+
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+
+static void
+callback(int fd, enum ev_type ev, void *arg)
+{
+ static off_t size = 0;
+ struct stat st;
+
+ ASSERT_INT_EQ(("bad event"), ev, EVF_VNODE);
+ ASSERT_PTR_EQ(("bad cookie"), arg, cookie);
+
+ if (fstat(fd, &st) != 0)
+ FAIL_ERRNO("fstat failed");
+
+ ASSERT_INT64_NEQ(("Size has not changed"), size, st.st_size);
+ size = st.st_size;
+
+ pthread_mutex_lock(&mtx);
+ pthread_cond_signal(&cv);
+ VERBOSE(("wakeup"));
+ pthread_mutex_unlock(&mtx);
+}
+
+static void
+destroy_zpool(libzfs_handle_t *zfshdl, zpool_handle_t *poolhdl,
+ zfs_handle_t *volhdl)
+{
+ if (volhdl != NULL) {
+ if (zfs_destroy(volhdl, B_FALSE) != 0) {
+ FAIL(("Failed to destroy ZVOL - %s",
+ libzfs_error_description(zfshdl)));
+ }
+ }
+
+ if (poolhdl != NULL) {
+ if (zpool_destroy(poolhdl, testlib_prog) != 0) {
+ FAIL(("Failed to destroy ZPOOL - %s",
+ libzfs_error_description(zfshdl)));
+ }
+ }
+}
+
+static void
+create_zpool(libzfs_handle_t *zfshdl, const char *pool, const char *file)
+{
+ nvlist_t *nvroot, *props;
+ nvlist_t *vdevs[1];
+
+ nvroot = fnvlist_alloc();
+ props = fnvlist_alloc();
+ vdevs[0] = fnvlist_alloc();
+
+ fnvlist_add_string(vdevs[0], ZPOOL_CONFIG_PATH, file);
+ fnvlist_add_string(vdevs[0], ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE);
+ fnvlist_add_uint64(vdevs[0], ZPOOL_CONFIG_IS_LOG, 0);
+
+ fnvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT);
+ fnvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, vdevs, 1);
+
+ fnvlist_add_string(props,
+ zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), ZFS_MOUNTPOINT_NONE);
+
+ if (zpool_create(zfshdl, pool, nvroot, NULL, props) != 0) {
+ FAIL(("Failed to create ZPOOL %s using %s - %s",
+ pool, file, libzfs_error_description(zfshdl)));
+ }
+
+ VERBOSE(("Created ZFS pool %s", pool));
+}
+
+static bool
+create_zvol(libzfs_handle_t *zfshdl, const char *vol)
+{
+ nvlist_t *volprops;
+ int err;
+
+ volprops = fnvlist_alloc();
+ fnvlist_add_uint64(volprops,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1 * MB);
+
+ err = zfs_create(zfshdl, vol, ZFS_TYPE_VOLUME, volprops);
+ if (err != 0) {
+ (void) printf("Failed to create ZVOL %s - %s",
+ vol, libzfs_error_description(zfshdl));
+ return (false);
+ }
+
+ VERBOSE(("Created ZVOL %s", vol));
+ return (true);
+}
+
+int
+main(int argc, const char **argv)
+{
+ libzfs_handle_t *zfshdl;
+ char *template, *pool, *vol, *backend;
+ struct mevent *evp;
+ zpool_handle_t *poolhdl = NULL;
+ zfs_handle_t *volhdl = NULL;
+ int err, fd;
+
+ start_test(argv[0], 10);
+ set_mevent_file_poll_interval_ms(1000);
+
+ if (getzoneid() != GLOBAL_ZONEID)
+ FAIL(("Can only be run in the global zone"));
+
+ if ((zfshdl = libzfs_init()) == NULL)
+ FAIL_ERRNO("Could not open ZFS library");
+
+ template = strdup("/tmp/mevent.vnode.zvol.XXXXXX");
+ ASSERT_PTR_NEQ(("strdup"), template, NULL);
+ fd = mkstemp(template);
+ if (fd == -1)
+ FAIL_ERRNO("Couldn't create temporary file with mkstemp");
+ VERBOSE(("Opened temporary file at '%s'", template));
+
+ err = asprintf(&pool, "mevent_test_%d", getpid());
+ ASSERT_INT_NEQ(("asprintf pool"), err, -1);
+
+ err = asprintf(&vol, "%s/test_zvol_%d", pool, getpid());
+ ASSERT_INT_NEQ(("asprintf vol"), err, -1);
+
+ err = asprintf(&backend, "/dev/zvol/rdsk/%s", vol);
+ ASSERT_INT_NEQ(("asprintf backend"), err, -1);
+
+ err = ftruncate(fd, 64 * MB);
+ if (err != 0)
+ FAIL_ERRNO("ftruncate");
+ (void) close(fd);
+ fd = -1;
+
+ /*
+ * Create the pool as late as possible to reduce the risk of leaving
+ * a test pool hanging around.
+ */
+ create_zpool(zfshdl, pool, template);
+
+ if ((poolhdl = zpool_open(zfshdl, pool)) == NULL) {
+ (void) printf("Could not open ZPOOL - %s\n",
+ libzfs_error_description(zfshdl));
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ if (!create_zvol(zfshdl, vol)) {
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ if ((volhdl = zfs_open(zfshdl, vol, ZFS_TYPE_VOLUME)) == NULL) {
+ (void) printf("Could not open ZFS volume - %s\n",
+ libzfs_error_description(zfshdl));
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ if ((fd = open(backend, O_RDWR)) == -1) {
+ (void) printf("Failed to open '%s': %s\n",
+ backend, strerror(errno));
+ err = EXIT_FAIL;
+ goto out;
+ }
+ VERBOSE(("Opened backend %s", backend));
+
+ start_event_thread();
+
+ evp = mevent_add_flags(fd, EVF_VNODE, EVFF_ATTRIB, callback, cookie);
+ if (evp == NULL) {
+ (void) printf("mevent_add returned NULL\n");
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ for (uint_t i = 2; i < 4; i++) {
+ ssize_t written;
+ char buf[64];
+
+ /*
+ * Check that a write to the volume does not trigger an event.
+ */
+ if (lseek(fd, 0, SEEK_SET) == -1)
+ FAIL_ERRNO("lseek");
+ written = write(fd, cookie, strlen(cookie));
+ if (written < 0)
+ FAIL_ERRNO("bad write");
+ ASSERT_INT64_EQ(("write cookie", i), written, strlen(cookie));
+
+ (void) snprintf(buf, sizeof (buf), "%llu", i * MB);
+ VERBOSE(("Setting volsize to %s", buf));
+
+ if (zfs_prop_set(volhdl,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), buf) != 0) {
+ (void) printf("Failed to increase ZFS volume size\n");
+ pthread_mutex_unlock(&mtx);
+ err = EXIT_FAIL;
+ goto out;
+ }
+
+ /* Wait for the size change to be processed */
+ pthread_mutex_lock(&mtx);
+ pthread_cond_wait(&cv, &mtx);
+ pthread_mutex_unlock(&mtx);
+ }
+
+ (void) mevent_disable(evp);
+
+ err = EXIT_PASS;
+
+out:
+
+ (void) close(fd);
+ destroy_zpool(zfshdl, poolhdl, volhdl);
+ (void) libzfs_fini(zfshdl);
+ (void) unlink(template);
+
+ if (err == EXIT_PASS)
+ PASS();
+
+ exit(err);
+}