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