diff options
Diffstat (limited to 'usr/src/cmd/bhyve/test')
-rw-r--r-- | usr/src/cmd/bhyve/test/tests/mevent/Makefile | 9 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/test/tests/mevent/mevent.c | 6 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/test/tests/mevent/testlib.h | 2 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c | 141 | ||||
-rw-r--r-- | usr/src/cmd/bhyve/test/tests/mevent/vnode_zvol.c | 259 |
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); +} |