xref: /illumos-gate/usr/src/cmd/bhyve/test/tests/mevent/vnode_file.c (revision e8d712970f7ec76e09d5013b0b9aa5f0e0cf3e62)
1251becc8SAndy Fiddaman /*
2251becc8SAndy Fiddaman  * This file and its contents are supplied under the terms of the
3251becc8SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
4251becc8SAndy Fiddaman  * You may only use this file in accordance with the terms of version
5251becc8SAndy Fiddaman  * 1.0 of the CDDL.
6251becc8SAndy Fiddaman  *
7251becc8SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
8251becc8SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
9251becc8SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
10251becc8SAndy Fiddaman  */
11251becc8SAndy Fiddaman 
12251becc8SAndy Fiddaman /*
13251becc8SAndy Fiddaman  * Copyright 2018 Joyent, Inc.
14251becc8SAndy Fiddaman  * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
15251becc8SAndy Fiddaman  */
16251becc8SAndy Fiddaman 
17251becc8SAndy Fiddaman #include <errno.h>
18251becc8SAndy Fiddaman #include <fcntl.h>
19251becc8SAndy Fiddaman #include <pthread.h>
20251becc8SAndy Fiddaman #include <signal.h>
21251becc8SAndy Fiddaman #include <stdio.h>
22251becc8SAndy Fiddaman #include <stdlib.h>
23251becc8SAndy Fiddaman #include <strings.h>
24251becc8SAndy Fiddaman #include <unistd.h>
25251becc8SAndy Fiddaman 
26251becc8SAndy Fiddaman #include <sys/types.h>
27251becc8SAndy Fiddaman #include <sys/stat.h>
28251becc8SAndy Fiddaman 
29251becc8SAndy Fiddaman #include "testlib.h"
30251becc8SAndy Fiddaman #include "mevent.h"
31251becc8SAndy Fiddaman 
32*e8d71297SAndy Fiddaman static char *cookie = "Shortcake";
33251becc8SAndy Fiddaman 
34251becc8SAndy Fiddaman static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
35251becc8SAndy Fiddaman static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
36251becc8SAndy Fiddaman 
37251becc8SAndy Fiddaman static void
callback(int fd,enum ev_type ev,void * arg)38251becc8SAndy Fiddaman callback(int fd, enum ev_type ev, void *arg)
39251becc8SAndy Fiddaman {
40251becc8SAndy Fiddaman 	static off_t size = 0;
41251becc8SAndy Fiddaman 	struct stat st;
42251becc8SAndy Fiddaman 
43251becc8SAndy Fiddaman 	ASSERT_INT_EQ(("bad event"), ev, EVF_VNODE);
44251becc8SAndy Fiddaman 	ASSERT_PTR_EQ(("bad cookie"), arg, cookie);
45251becc8SAndy Fiddaman 
46251becc8SAndy Fiddaman 	if (fstat(fd, &st) != 0)
47251becc8SAndy Fiddaman 		FAIL_ERRNO("fstat failed");
48251becc8SAndy Fiddaman 
49251becc8SAndy Fiddaman 	ASSERT_INT64_NEQ(("File size has not changed"), size, st.st_size);
50251becc8SAndy Fiddaman 	size = st.st_size;
51251becc8SAndy Fiddaman 
52251becc8SAndy Fiddaman 	pthread_mutex_lock(&mtx);
53251becc8SAndy Fiddaman 	pthread_cond_signal(&cv);
54251becc8SAndy Fiddaman 	VERBOSE(("wakeup"));
55251becc8SAndy Fiddaman 	pthread_mutex_unlock(&mtx);
56251becc8SAndy Fiddaman }
57251becc8SAndy Fiddaman 
58251becc8SAndy Fiddaman static void
test_fd(int fd,char * tag)59251becc8SAndy Fiddaman test_fd(int fd, char *tag)
60251becc8SAndy Fiddaman {
61251becc8SAndy Fiddaman 	struct mevent *evp;
62251becc8SAndy Fiddaman 	int err;
63251becc8SAndy Fiddaman 
64251becc8SAndy Fiddaman 	evp = mevent_add_flags(fd, EVF_VNODE, EVFF_ATTRIB, callback, cookie);
65251becc8SAndy Fiddaman 	ASSERT_PTR_NEQ(("%s: mevent_add", tag), evp, NULL);
66251becc8SAndy Fiddaman 
67251becc8SAndy Fiddaman 	for (uint_t i = 0; cookie[i] != '\0'; i++) {
68251becc8SAndy Fiddaman 		ssize_t written;
69251becc8SAndy Fiddaman 
70251becc8SAndy Fiddaman 		if (i > 0) {
71251becc8SAndy Fiddaman 			/*
72251becc8SAndy Fiddaman 			 * Check that no events are emitted for writes which do
73251becc8SAndy Fiddaman 			 * not alter the size.
74251becc8SAndy Fiddaman 			 */
75251becc8SAndy Fiddaman 			if (lseek(fd, -1, SEEK_CUR) == -1)
76251becc8SAndy Fiddaman 				FAIL_ERRNO("lseek");
77251becc8SAndy Fiddaman 			if (write(fd, "X", 1) == -1)
78251becc8SAndy Fiddaman 				FAIL_ERRNO("write");
79*e8d71297SAndy Fiddaman 			/*
80*e8d71297SAndy Fiddaman 			 * Allow time for the callback to fire if it is going
81*e8d71297SAndy Fiddaman 			 * to.
82*e8d71297SAndy Fiddaman 			 */
83*e8d71297SAndy Fiddaman 			VERBOSE(("Write within"));
84*e8d71297SAndy Fiddaman 			usleep(100);
85251becc8SAndy Fiddaman 		}
86251becc8SAndy Fiddaman 
87*e8d71297SAndy Fiddaman 		pthread_mutex_lock(&mtx);
88*e8d71297SAndy Fiddaman 
89251becc8SAndy Fiddaman 		written = write(fd, cookie + i, 1);
90251becc8SAndy Fiddaman 		if (written < 0)
91251becc8SAndy Fiddaman 			FAIL_ERRNO("bad write");
92251becc8SAndy Fiddaman 		ASSERT_INT64_EQ(("write byte %d of cookie", i), written, 1);
93*e8d71297SAndy Fiddaman 		VERBOSE(("Write extend"));
94251becc8SAndy Fiddaman 
95251becc8SAndy Fiddaman 		/* Wait for the size change to be processed */
96251becc8SAndy Fiddaman 		pthread_cond_wait(&cv, &mtx);
97251becc8SAndy Fiddaman 		pthread_mutex_unlock(&mtx);
98251becc8SAndy Fiddaman 		/*
99251becc8SAndy Fiddaman 		 * This is a bit unsatisfactory but we need to allow time
100251becc8SAndy Fiddaman 		 * for mevent to re-associate the port or the next write could
101251becc8SAndy Fiddaman 		 * be missed.
102251becc8SAndy Fiddaman 		 */
103*e8d71297SAndy Fiddaman 		usleep(100);
104251becc8SAndy Fiddaman 	}
105251becc8SAndy Fiddaman 
106251becc8SAndy Fiddaman 	err = mevent_disable(evp);
107251becc8SAndy Fiddaman 	ASSERT_INT_EQ(("%s: mevent_disable: %s", tag, strerror(err)), err, 0);
108251becc8SAndy Fiddaman 
109251becc8SAndy Fiddaman 	(void) printf("PASS %s - %s\n", testlib_prog, tag);
110251becc8SAndy Fiddaman }
111251becc8SAndy Fiddaman 
112251becc8SAndy Fiddaman int
main(int argc,const char ** argv)113251becc8SAndy Fiddaman main(int argc, const char **argv)
114251becc8SAndy Fiddaman {
115251becc8SAndy Fiddaman 	int fd;
116251becc8SAndy Fiddaman 
117*e8d71297SAndy Fiddaman 	start_test(argv[0], 20);
118*e8d71297SAndy Fiddaman 	set_mevent_file_poll_interval_ms(500);
119*e8d71297SAndy Fiddaman 	start_event_thread();
120*e8d71297SAndy Fiddaman 
121251becc8SAndy Fiddaman 	/* Test with a temporary file in /tmp */
122251becc8SAndy Fiddaman 	char *template = strdup("/tmp/mevent.vnode.XXXXXX");
123251becc8SAndy Fiddaman 	ASSERT_PTR_NEQ(("strdup"), template, NULL);
124251becc8SAndy Fiddaman 	fd = mkstemp(template);
125251becc8SAndy Fiddaman 	if (fd == -1)
126251becc8SAndy Fiddaman 		FAIL_ERRNO("Couldn't create temporary file with mkstemp");
127251becc8SAndy Fiddaman 
128251becc8SAndy Fiddaman 	VERBOSE(("Opened temporary file at '%s'", template));
129251becc8SAndy Fiddaman 
130251becc8SAndy Fiddaman 	test_fd(fd, "temporary file");
131251becc8SAndy Fiddaman 
132251becc8SAndy Fiddaman 	/* Test with a file which is unlinked from the filesystem */
133251becc8SAndy Fiddaman 	FILE *fp = tmpfile();
134251becc8SAndy Fiddaman 	ASSERT_PTR_NEQ(("tmpfile"), fp, NULL);
135251becc8SAndy Fiddaman 
136251becc8SAndy Fiddaman 	fd = fileno(fp);
137251becc8SAndy Fiddaman 	if (fd == -1)
138251becc8SAndy Fiddaman 		FAIL_ERRNO("Couldn't get file descriptor for temporary file");
139251becc8SAndy Fiddaman 
140251becc8SAndy Fiddaman 	test_fd(fd, "anon file");
141251becc8SAndy Fiddaman 
142251becc8SAndy Fiddaman 	/*
143251becc8SAndy Fiddaman 	 * Defer to here to avoid generating a new event before the disable has
144251becc8SAndy Fiddaman 	 * been processed and the port deassociated.
145251becc8SAndy Fiddaman 	 */
146251becc8SAndy Fiddaman 	unlink(template);
147251becc8SAndy Fiddaman 	free(template);
148251becc8SAndy Fiddaman 
149251becc8SAndy Fiddaman 	PASS();
150251becc8SAndy Fiddaman }
151