1*251becc8SAndy Fiddaman /*
2*251becc8SAndy Fiddaman * This file and its contents are supplied under the terms of the
3*251becc8SAndy Fiddaman * Common Development and Distribution License ("CDDL"), version 1.0.
4*251becc8SAndy Fiddaman * You may only use this file in accordance with the terms of version
5*251becc8SAndy Fiddaman * 1.0 of the CDDL.
6*251becc8SAndy Fiddaman *
7*251becc8SAndy Fiddaman * A full copy of the text of the CDDL should have accompanied this
8*251becc8SAndy Fiddaman * source. A copy of the CDDL is also available via the Internet at
9*251becc8SAndy Fiddaman * http://www.illumos.org/license/CDDL.
10*251becc8SAndy Fiddaman */
11*251becc8SAndy Fiddaman
12*251becc8SAndy Fiddaman /*
13*251becc8SAndy Fiddaman * Copyright 2018 Joyent, Inc.
14*251becc8SAndy Fiddaman * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
15*251becc8SAndy Fiddaman */
16*251becc8SAndy Fiddaman
17*251becc8SAndy Fiddaman #include <errno.h>
18*251becc8SAndy Fiddaman #include <fcntl.h>
19*251becc8SAndy Fiddaman #include <libzfs.h>
20*251becc8SAndy Fiddaman #include <pthread.h>
21*251becc8SAndy Fiddaman #include <signal.h>
22*251becc8SAndy Fiddaman #include <stdio.h>
23*251becc8SAndy Fiddaman #include <stdlib.h>
24*251becc8SAndy Fiddaman #include <strings.h>
25*251becc8SAndy Fiddaman #include <unistd.h>
26*251becc8SAndy Fiddaman #include <zone.h>
27*251becc8SAndy Fiddaman
28*251becc8SAndy Fiddaman #include <sys/types.h>
29*251becc8SAndy Fiddaman #include <sys/stat.h>
30*251becc8SAndy Fiddaman
31*251becc8SAndy Fiddaman #include "testlib.h"
32*251becc8SAndy Fiddaman #include "mevent.h"
33*251becc8SAndy Fiddaman
34*251becc8SAndy Fiddaman #define MB (1024 * 1024)
35*251becc8SAndy Fiddaman
36*251becc8SAndy Fiddaman static char *cookie = "Chocolate chip with fudge stripes";
37*251becc8SAndy Fiddaman
38*251becc8SAndy Fiddaman static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
39*251becc8SAndy Fiddaman static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
40*251becc8SAndy Fiddaman
41*251becc8SAndy Fiddaman static void
callback(int fd,enum ev_type ev,void * arg)42*251becc8SAndy Fiddaman callback(int fd, enum ev_type ev, void *arg)
43*251becc8SAndy Fiddaman {
44*251becc8SAndy Fiddaman static off_t size = 0;
45*251becc8SAndy Fiddaman struct stat st;
46*251becc8SAndy Fiddaman
47*251becc8SAndy Fiddaman ASSERT_INT_EQ(("bad event"), ev, EVF_VNODE);
48*251becc8SAndy Fiddaman ASSERT_PTR_EQ(("bad cookie"), arg, cookie);
49*251becc8SAndy Fiddaman
50*251becc8SAndy Fiddaman if (fstat(fd, &st) != 0)
51*251becc8SAndy Fiddaman FAIL_ERRNO("fstat failed");
52*251becc8SAndy Fiddaman
53*251becc8SAndy Fiddaman ASSERT_INT64_NEQ(("Size has not changed"), size, st.st_size);
54*251becc8SAndy Fiddaman size = st.st_size;
55*251becc8SAndy Fiddaman
56*251becc8SAndy Fiddaman pthread_mutex_lock(&mtx);
57*251becc8SAndy Fiddaman pthread_cond_signal(&cv);
58*251becc8SAndy Fiddaman VERBOSE(("wakeup"));
59*251becc8SAndy Fiddaman pthread_mutex_unlock(&mtx);
60*251becc8SAndy Fiddaman }
61*251becc8SAndy Fiddaman
62*251becc8SAndy Fiddaman static void
destroy_zpool(libzfs_handle_t * zfshdl,zpool_handle_t * poolhdl,zfs_handle_t * volhdl)63*251becc8SAndy Fiddaman destroy_zpool(libzfs_handle_t *zfshdl, zpool_handle_t *poolhdl,
64*251becc8SAndy Fiddaman zfs_handle_t *volhdl)
65*251becc8SAndy Fiddaman {
66*251becc8SAndy Fiddaman if (volhdl != NULL) {
67*251becc8SAndy Fiddaman if (zfs_destroy(volhdl, B_FALSE) != 0) {
68*251becc8SAndy Fiddaman FAIL(("Failed to destroy ZVOL - %s",
69*251becc8SAndy Fiddaman libzfs_error_description(zfshdl)));
70*251becc8SAndy Fiddaman }
71*251becc8SAndy Fiddaman }
72*251becc8SAndy Fiddaman
73*251becc8SAndy Fiddaman if (poolhdl != NULL) {
74*251becc8SAndy Fiddaman if (zpool_destroy(poolhdl, testlib_prog) != 0) {
75*251becc8SAndy Fiddaman FAIL(("Failed to destroy ZPOOL - %s",
76*251becc8SAndy Fiddaman libzfs_error_description(zfshdl)));
77*251becc8SAndy Fiddaman }
78*251becc8SAndy Fiddaman }
79*251becc8SAndy Fiddaman }
80*251becc8SAndy Fiddaman
81*251becc8SAndy Fiddaman static void
create_zpool(libzfs_handle_t * zfshdl,const char * pool,const char * file)82*251becc8SAndy Fiddaman create_zpool(libzfs_handle_t *zfshdl, const char *pool, const char *file)
83*251becc8SAndy Fiddaman {
84*251becc8SAndy Fiddaman nvlist_t *nvroot, *props;
85*251becc8SAndy Fiddaman nvlist_t *vdevs[1];
86*251becc8SAndy Fiddaman
87*251becc8SAndy Fiddaman nvroot = fnvlist_alloc();
88*251becc8SAndy Fiddaman props = fnvlist_alloc();
89*251becc8SAndy Fiddaman vdevs[0] = fnvlist_alloc();
90*251becc8SAndy Fiddaman
91*251becc8SAndy Fiddaman fnvlist_add_string(vdevs[0], ZPOOL_CONFIG_PATH, file);
92*251becc8SAndy Fiddaman fnvlist_add_string(vdevs[0], ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE);
93*251becc8SAndy Fiddaman fnvlist_add_uint64(vdevs[0], ZPOOL_CONFIG_IS_LOG, 0);
94*251becc8SAndy Fiddaman
95*251becc8SAndy Fiddaman fnvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT);
96*251becc8SAndy Fiddaman fnvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, vdevs, 1);
97*251becc8SAndy Fiddaman
98*251becc8SAndy Fiddaman fnvlist_add_string(props,
99*251becc8SAndy Fiddaman zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), ZFS_MOUNTPOINT_NONE);
100*251becc8SAndy Fiddaman
101*251becc8SAndy Fiddaman if (zpool_create(zfshdl, pool, nvroot, NULL, props) != 0) {
102*251becc8SAndy Fiddaman FAIL(("Failed to create ZPOOL %s using %s - %s",
103*251becc8SAndy Fiddaman pool, file, libzfs_error_description(zfshdl)));
104*251becc8SAndy Fiddaman }
105*251becc8SAndy Fiddaman
106*251becc8SAndy Fiddaman VERBOSE(("Created ZFS pool %s", pool));
107*251becc8SAndy Fiddaman }
108*251becc8SAndy Fiddaman
109*251becc8SAndy Fiddaman static bool
create_zvol(libzfs_handle_t * zfshdl,const char * vol)110*251becc8SAndy Fiddaman create_zvol(libzfs_handle_t *zfshdl, const char *vol)
111*251becc8SAndy Fiddaman {
112*251becc8SAndy Fiddaman nvlist_t *volprops;
113*251becc8SAndy Fiddaman int err;
114*251becc8SAndy Fiddaman
115*251becc8SAndy Fiddaman volprops = fnvlist_alloc();
116*251becc8SAndy Fiddaman fnvlist_add_uint64(volprops,
117*251becc8SAndy Fiddaman zfs_prop_to_name(ZFS_PROP_VOLSIZE), 1 * MB);
118*251becc8SAndy Fiddaman
119*251becc8SAndy Fiddaman err = zfs_create(zfshdl, vol, ZFS_TYPE_VOLUME, volprops);
120*251becc8SAndy Fiddaman if (err != 0) {
121*251becc8SAndy Fiddaman (void) printf("Failed to create ZVOL %s - %s",
122*251becc8SAndy Fiddaman vol, libzfs_error_description(zfshdl));
123*251becc8SAndy Fiddaman return (false);
124*251becc8SAndy Fiddaman }
125*251becc8SAndy Fiddaman
126*251becc8SAndy Fiddaman VERBOSE(("Created ZVOL %s", vol));
127*251becc8SAndy Fiddaman return (true);
128*251becc8SAndy Fiddaman }
129*251becc8SAndy Fiddaman
130*251becc8SAndy Fiddaman int
main(int argc,const char ** argv)131*251becc8SAndy Fiddaman main(int argc, const char **argv)
132*251becc8SAndy Fiddaman {
133*251becc8SAndy Fiddaman libzfs_handle_t *zfshdl;
134*251becc8SAndy Fiddaman char *template, *pool, *vol, *backend;
135*251becc8SAndy Fiddaman struct mevent *evp;
136*251becc8SAndy Fiddaman zpool_handle_t *poolhdl = NULL;
137*251becc8SAndy Fiddaman zfs_handle_t *volhdl = NULL;
138*251becc8SAndy Fiddaman int err, fd;
139*251becc8SAndy Fiddaman
140*251becc8SAndy Fiddaman start_test(argv[0], 10);
141*251becc8SAndy Fiddaman set_mevent_file_poll_interval_ms(1000);
142*251becc8SAndy Fiddaman
143*251becc8SAndy Fiddaman if (getzoneid() != GLOBAL_ZONEID)
144*251becc8SAndy Fiddaman FAIL(("Can only be run in the global zone"));
145*251becc8SAndy Fiddaman
146*251becc8SAndy Fiddaman if ((zfshdl = libzfs_init()) == NULL)
147*251becc8SAndy Fiddaman FAIL_ERRNO("Could not open ZFS library");
148*251becc8SAndy Fiddaman
149*251becc8SAndy Fiddaman template = strdup("/tmp/mevent.vnode.zvol.XXXXXX");
150*251becc8SAndy Fiddaman ASSERT_PTR_NEQ(("strdup"), template, NULL);
151*251becc8SAndy Fiddaman fd = mkstemp(template);
152*251becc8SAndy Fiddaman if (fd == -1)
153*251becc8SAndy Fiddaman FAIL_ERRNO("Couldn't create temporary file with mkstemp");
154*251becc8SAndy Fiddaman VERBOSE(("Opened temporary file at '%s'", template));
155*251becc8SAndy Fiddaman
156*251becc8SAndy Fiddaman err = asprintf(&pool, "mevent_test_%d", getpid());
157*251becc8SAndy Fiddaman ASSERT_INT_NEQ(("asprintf pool"), err, -1);
158*251becc8SAndy Fiddaman
159*251becc8SAndy Fiddaman err = asprintf(&vol, "%s/test_zvol_%d", pool, getpid());
160*251becc8SAndy Fiddaman ASSERT_INT_NEQ(("asprintf vol"), err, -1);
161*251becc8SAndy Fiddaman
162*251becc8SAndy Fiddaman err = asprintf(&backend, "/dev/zvol/rdsk/%s", vol);
163*251becc8SAndy Fiddaman ASSERT_INT_NEQ(("asprintf backend"), err, -1);
164*251becc8SAndy Fiddaman
165*251becc8SAndy Fiddaman err = ftruncate(fd, 64 * MB);
166*251becc8SAndy Fiddaman if (err != 0)
167*251becc8SAndy Fiddaman FAIL_ERRNO("ftruncate");
168*251becc8SAndy Fiddaman (void) close(fd);
169*251becc8SAndy Fiddaman fd = -1;
170*251becc8SAndy Fiddaman
171*251becc8SAndy Fiddaman /*
172*251becc8SAndy Fiddaman * Create the pool as late as possible to reduce the risk of leaving
173*251becc8SAndy Fiddaman * a test pool hanging around.
174*251becc8SAndy Fiddaman */
175*251becc8SAndy Fiddaman create_zpool(zfshdl, pool, template);
176*251becc8SAndy Fiddaman
177*251becc8SAndy Fiddaman if ((poolhdl = zpool_open(zfshdl, pool)) == NULL) {
178*251becc8SAndy Fiddaman (void) printf("Could not open ZPOOL - %s\n",
179*251becc8SAndy Fiddaman libzfs_error_description(zfshdl));
180*251becc8SAndy Fiddaman err = EXIT_FAIL;
181*251becc8SAndy Fiddaman goto out;
182*251becc8SAndy Fiddaman }
183*251becc8SAndy Fiddaman
184*251becc8SAndy Fiddaman if (!create_zvol(zfshdl, vol)) {
185*251becc8SAndy Fiddaman err = EXIT_FAIL;
186*251becc8SAndy Fiddaman goto out;
187*251becc8SAndy Fiddaman }
188*251becc8SAndy Fiddaman
189*251becc8SAndy Fiddaman if ((volhdl = zfs_open(zfshdl, vol, ZFS_TYPE_VOLUME)) == NULL) {
190*251becc8SAndy Fiddaman (void) printf("Could not open ZFS volume - %s\n",
191*251becc8SAndy Fiddaman libzfs_error_description(zfshdl));
192*251becc8SAndy Fiddaman err = EXIT_FAIL;
193*251becc8SAndy Fiddaman goto out;
194*251becc8SAndy Fiddaman }
195*251becc8SAndy Fiddaman
196*251becc8SAndy Fiddaman if ((fd = open(backend, O_RDWR)) == -1) {
197*251becc8SAndy Fiddaman (void) printf("Failed to open '%s': %s\n",
198*251becc8SAndy Fiddaman backend, strerror(errno));
199*251becc8SAndy Fiddaman err = EXIT_FAIL;
200*251becc8SAndy Fiddaman goto out;
201*251becc8SAndy Fiddaman }
202*251becc8SAndy Fiddaman VERBOSE(("Opened backend %s", backend));
203*251becc8SAndy Fiddaman
204*251becc8SAndy Fiddaman start_event_thread();
205*251becc8SAndy Fiddaman
206*251becc8SAndy Fiddaman evp = mevent_add_flags(fd, EVF_VNODE, EVFF_ATTRIB, callback, cookie);
207*251becc8SAndy Fiddaman if (evp == NULL) {
208*251becc8SAndy Fiddaman (void) printf("mevent_add returned NULL\n");
209*251becc8SAndy Fiddaman err = EXIT_FAIL;
210*251becc8SAndy Fiddaman goto out;
211*251becc8SAndy Fiddaman }
212*251becc8SAndy Fiddaman
213*251becc8SAndy Fiddaman for (uint_t i = 2; i < 4; i++) {
214*251becc8SAndy Fiddaman ssize_t written;
215*251becc8SAndy Fiddaman char buf[64];
216*251becc8SAndy Fiddaman
217*251becc8SAndy Fiddaman /*
218*251becc8SAndy Fiddaman * Check that a write to the volume does not trigger an event.
219*251becc8SAndy Fiddaman */
220*251becc8SAndy Fiddaman if (lseek(fd, 0, SEEK_SET) == -1)
221*251becc8SAndy Fiddaman FAIL_ERRNO("lseek");
222*251becc8SAndy Fiddaman written = write(fd, cookie, strlen(cookie));
223*251becc8SAndy Fiddaman if (written < 0)
224*251becc8SAndy Fiddaman FAIL_ERRNO("bad write");
225*251becc8SAndy Fiddaman ASSERT_INT64_EQ(("write cookie", i), written, strlen(cookie));
226*251becc8SAndy Fiddaman
227*251becc8SAndy Fiddaman (void) snprintf(buf, sizeof (buf), "%llu", i * MB);
228*251becc8SAndy Fiddaman VERBOSE(("Setting volsize to %s", buf));
229*251becc8SAndy Fiddaman
230*251becc8SAndy Fiddaman if (zfs_prop_set(volhdl,
231*251becc8SAndy Fiddaman zfs_prop_to_name(ZFS_PROP_VOLSIZE), buf) != 0) {
232*251becc8SAndy Fiddaman (void) printf("Failed to increase ZFS volume size\n");
233*251becc8SAndy Fiddaman pthread_mutex_unlock(&mtx);
234*251becc8SAndy Fiddaman err = EXIT_FAIL;
235*251becc8SAndy Fiddaman goto out;
236*251becc8SAndy Fiddaman }
237*251becc8SAndy Fiddaman
238*251becc8SAndy Fiddaman /* Wait for the size change to be processed */
239*251becc8SAndy Fiddaman pthread_mutex_lock(&mtx);
240*251becc8SAndy Fiddaman pthread_cond_wait(&cv, &mtx);
241*251becc8SAndy Fiddaman pthread_mutex_unlock(&mtx);
242*251becc8SAndy Fiddaman }
243*251becc8SAndy Fiddaman
244*251becc8SAndy Fiddaman (void) mevent_disable(evp);
245*251becc8SAndy Fiddaman
246*251becc8SAndy Fiddaman err = EXIT_PASS;
247*251becc8SAndy Fiddaman
248*251becc8SAndy Fiddaman out:
249*251becc8SAndy Fiddaman
250*251becc8SAndy Fiddaman (void) close(fd);
251*251becc8SAndy Fiddaman destroy_zpool(zfshdl, poolhdl, volhdl);
252*251becc8SAndy Fiddaman (void) libzfs_fini(zfshdl);
253*251becc8SAndy Fiddaman (void) unlink(template);
254*251becc8SAndy Fiddaman
255*251becc8SAndy Fiddaman if (err == EXIT_PASS)
256*251becc8SAndy Fiddaman PASS();
257*251becc8SAndy Fiddaman
258*251becc8SAndy Fiddaman exit(err);
259*251becc8SAndy Fiddaman }
260