xref: /xnu-10002.41.9/tests/file_leases.c (revision 699cd48037512bf4380799317ca44ca453c82f57)
1 /* compile: xcrun -sdk macosx.internal clang -ldarwintest -o test_file_leases file_leases.c -g -Weverything */
2 
3 #include <darwintest.h>
4 #include <darwintest_utils.h>
5 #include <darwintest_multiprocess.h>
6 #include <copyfile.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <sys/clonefile.h>
13 #include <sys/event.h>
14 #include <sys/resource.h>
15 #include <sys/sysctl.h>
16 #include <sys/xattr.h>
17 
18 #include "test_utils.h"
19 
20 
21 T_GLOBAL_META(
22 	T_META_NAMESPACE("xnu.vfs.lease"),
23 	T_META_RADAR_COMPONENT_NAME("xnu"),
24 	T_META_RADAR_COMPONENT_VERSION("vfs"),
25 	T_META_CHECK_LEAKS(false));
26 
27 #define TEST_LEASE_DIR  "lease_dir"
28 #define TEST_LEASE_FILE "lease_file"
29 
30 static char g_testfile[MAXPATHLEN];
31 static char g_testdir[MAXPATHLEN];
32 
33 /*
34  * This unit-test validates the behavior of file leasing (read and write leases)
35  * by utilizing the file leasing API (fcntl's F_SETLEASE and F_GETLEASE
36  * commands) provided by VFS.
37  */
38 
39 
40 static void
exit_cleanup(void)41 exit_cleanup(void)
42 {
43 	uint32_t val, new_val;
44 	size_t val_len, new_val_len;
45 
46 	(void)remove(g_testfile);
47 	(void)rmdir(g_testdir);
48 
49 	new_val = 60;
50 	new_val_len = val_len = sizeof(uint32_t);
51 	(void)sysctlbyname("vfs.lease.break_timeout", &val, &val_len,
52 	    (void *)&new_val, new_val_len);
53 }
54 
55 
56 static void
create_test_file(void)57 create_test_file(void)
58 {
59 	const char *tmpdir = dt_tmpdir();
60 	int fd;
61 
62 	T_SETUPBEGIN;
63 
64 	/*
65 	 * Make sure dataless file manipulation is enabled for this
66 	 * process (children will inherit).
67 	 *
68 	 * See kpi_vfs.c:vfs_context_can_break_leases().
69 	 */
70 	T_ASSERT_POSIX_SUCCESS(
71 		setiopolicy_np(IOPOL_TYPE_VFS_MATERIALIZE_DATALESS_FILES,
72 		IOPOL_SCOPE_PROCESS, IOPOL_MATERIALIZE_DATALESS_FILES_ON),
73 		"Setup: ensuring dataless file materialization is enabled");
74 
75 	atexit(exit_cleanup);
76 
77 	snprintf(g_testdir, MAXPATHLEN, "%s/%s", tmpdir, TEST_LEASE_DIR);
78 
79 	T_ASSERT_POSIX_SUCCESS(mkdir(g_testdir, 0777),
80 	    "Setup: creating test dir: %s", g_testdir);
81 
82 	snprintf(g_testfile, MAXPATHLEN, "%s/%s", g_testdir, TEST_LEASE_FILE);
83 
84 	T_WITH_ERRNO;
85 	fd = open(g_testfile, O_CREAT | O_RDWR, 0666);
86 	T_ASSERT_NE(fd, -1, "Create test fi1e: %s", g_testfile);
87 
88 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", TEST_LEASE_FILE);
89 
90 	T_SETUPEND;
91 }
92 
93 #define HELPER_TIMEOUT_SECS     60
94 #define MAX_HELPERS             10
95 
96 static void __attribute__((noreturn))
run_helpers(const char ** helper_test_names,int num_helpers)97 run_helpers(const char **helper_test_names, int num_helpers)
98 {
99 	dt_helper_t helpers[MAX_HELPERS];
100 	char *args[] = {g_testfile, g_testdir, NULL};
101 	int i;
102 
103 	T_QUIET;
104 	T_ASSERT_LE(num_helpers, MAX_HELPERS, "too many helpers");
105 
106 	for (i = 0; i < num_helpers; i++) {
107 		helpers[i] = dt_child_helper_args(helper_test_names[i], args);
108 	}
109 	dt_run_helpers(helpers, (size_t)num_helpers, HELPER_TIMEOUT_SECS);
110 }
111 
112 T_HELPER_DECL(open_rdonly_acquire_read_lease_succeed, "Open file in O_RDONLY mode and acquire read lease succeeded")
113 {
114 	char *testfile = argv[0];
115 	int err, fd;
116 
117 	T_WITH_ERRNO;
118 	fd = open(testfile, O_RDONLY, 0666);
119 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
120 
121 	T_WITH_ERRNO;
122 	err = fcntl(fd, F_SETLEASE, F_RDLCK);
123 	T_ASSERT_NE(err, -1, "Acquire read lease: %s", testfile);
124 
125 	T_WITH_ERRNO;
126 	err = fcntl(fd, F_GETLEASE);
127 	T_ASSERT_EQ(err, F_RDLCK, "Retrieve lease: %s", testfile);
128 
129 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", testfile);
130 }
131 
132 T_HELPER_DECL(open_rdonly_acquire_read_lease_EAGAIN, "Open file in O_RDONLY mode and acquire read lease failed with EAGAIN")
133 {
134 	char *testfile = argv[0];
135 	int err, fd;
136 
137 	T_WITH_ERRNO;
138 	fd = open(testfile, O_RDONLY, 0666);
139 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
140 
141 	T_WITH_ERRNO;
142 	err = fcntl(fd, F_SETLEASE, F_RDLCK);
143 	T_ASSERT_TRUE((err == -1) && (errno == EAGAIN), "Acquire read lease: %s",
144 	    testfile);
145 
146 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", testfile);
147 }
148 
149 T_HELPER_DECL(open_rdwr_acquire_write_lease_EAGAIN, "Open file in O_RDWR mode and acquire write lease failed with EAGAIN")
150 {
151 	char *testfile = argv[0];
152 	int err, fd;
153 
154 	T_WITH_ERRNO;
155 	fd = open(testfile, O_RDWR, 0666);
156 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDWR: %s", testfile);
157 
158 	T_WITH_ERRNO;
159 	err = fcntl(fd, F_SETLEASE, F_WRLCK);
160 	T_ASSERT_TRUE((err == -1) && (errno == EAGAIN), "Acquire write lease: %s",
161 	    testfile);
162 
163 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", testfile);
164 }
165 
166 T_HELPER_DECL(open_rdonly_read_lease_release, "Open file in O_RDONLY mode, acquire read lease, and release lease upon NOTE_LEASE_RELEASE event")
167 {
168 	struct kevent lease_kevent;
169 	struct timespec kevent_timeout;
170 	char *testfile = argv[0];
171 	int err, fd, kq;
172 
173 	T_WITH_ERRNO;
174 	fd = open(testfile, O_RDONLY, 0666);
175 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
176 
177 	T_WITH_ERRNO;
178 	err = fcntl(fd, F_SETLEASE, F_RDLCK);
179 	T_ASSERT_NE(err, -1, "Acquire read lease: %s", testfile);
180 
181 	kq = kqueue();
182 	T_ASSERT_NE(kq, -1, "Create kqueue");
183 
184 	kevent_timeout.tv_sec = kevent_timeout.tv_nsec = 0;
185 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, (EV_ADD | EV_ENABLE | EV_CLEAR),
186 	    (NOTE_LEASE_DOWNGRADE | NOTE_LEASE_RELEASE), 0, (void *)testfile);
187 	err = kevent(kq, &lease_kevent, 1, NULL, 0, &kevent_timeout);
188 	T_ASSERT_GE(err, 0, "Register lease event on kq: %d", kq);
189 
190 	kevent_timeout.tv_sec = 60;
191 	kevent_timeout.tv_nsec = 0;
192 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, EV_CLEAR, 0, 0, 0);
193 
194 	err = kevent(kq, NULL, 0, &lease_kevent, 1, &kevent_timeout);
195 	T_ASSERT_NE(err, -1, "Listen for lease event on kq: %d", kq);
196 
197 	if (err > 0) {
198 		T_ASSERT_EQ(lease_kevent.fflags, NOTE_LEASE_RELEASE,
199 		    "Got lease event 0x%x", lease_kevent.fflags);
200 
201 		T_WITH_ERRNO;
202 		err = fcntl(fd, F_SETLEASE, F_UNLCK);
203 		T_ASSERT_NE(err, -1, "Release lease: %s", testfile);
204 	} else {
205 		T_FAIL("Timedout listening for lease event on kq: %d", kq);
206 	}
207 }
208 
209 T_HELPER_DECL(open_rdonly_write_lease_downgrade, "Open file in O_RDONLY mode, acquire a write lease, and downgrade lease upon NOTE_LEASE_DOWNGRADE event")
210 {
211 	struct kevent lease_kevent;
212 	struct timespec kevent_timeout;
213 	char *testfile = argv[0];
214 	int err, fd, kq;
215 
216 	T_WITH_ERRNO;
217 	fd = open(testfile, O_RDONLY, 0666);
218 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
219 
220 	T_WITH_ERRNO;
221 	err = fcntl(fd, F_SETLEASE, F_WRLCK);
222 	T_ASSERT_NE(err, -1, "Acquire write lease: %s", testfile);
223 
224 	kq = kqueue();
225 	T_ASSERT_NE(kq, -1, "Create kqueue");
226 
227 	kevent_timeout.tv_sec = kevent_timeout.tv_nsec = 0;
228 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, (EV_ADD | EV_ENABLE | EV_CLEAR),
229 	    (NOTE_LEASE_DOWNGRADE | NOTE_LEASE_RELEASE), 0, (void *)testfile);
230 	err = kevent(kq, &lease_kevent, 1, NULL, 0, &kevent_timeout);
231 	T_ASSERT_GE(err, 0, "Register lease event on kq: %d", kq);
232 
233 	kevent_timeout.tv_sec = 60;
234 	kevent_timeout.tv_nsec = 0;
235 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, EV_CLEAR, 0, 0, 0);
236 
237 	err = kevent(kq, NULL, 0, &lease_kevent, 1, &kevent_timeout);
238 	T_ASSERT_NE(err, -1, "Listen for lease event on kq: %d", kq);
239 
240 	if (err > 0) {
241 		T_ASSERT_EQ(lease_kevent.fflags, NOTE_LEASE_DOWNGRADE,
242 		    "Got lease event 0x%x", lease_kevent.fflags);
243 
244 		T_WITH_ERRNO;
245 		err = fcntl(fd, F_SETLEASE, F_RDLCK);
246 		T_ASSERT_NE(err, -1, "Downgrade to read lease: %s", testfile);
247 	} else {
248 		T_FAIL("Timedout listening for lease event on kq: %d", kq);
249 	}
250 }
251 
252 T_HELPER_DECL(open_rw_write_lease_downgrade, "Open file multiple times in O_RDWR mode, acquire a write lease, and downgrade lease upon NOTE_LEASE_DOWNGRADE event")
253 {
254 	struct kevent lease_kevent;
255 	struct timespec kevent_timeout;
256 	char *testfile = argv[0];
257 	int err, rw_fd1, rw_fd2, fd, kq;
258 
259 	T_WITH_ERRNO;
260 	rw_fd1 = open(testfile, O_RDWR, 0666);
261 	T_ASSERT_NE(rw_fd1, -1, "Open test fi1e in O_RDWR: %s", testfile);
262 
263 	T_WITH_ERRNO;
264 	rw_fd2 = open(testfile, O_RDWR, 0666);
265 	T_ASSERT_NE(rw_fd2, -1, "Open test fi1e in O_RDWR: %s", testfile);
266 
267 	T_WITH_ERRNO;
268 	fd = open(testfile, O_EVTONLY, 0666);
269 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_EVTONLY: %s", testfile);
270 
271 	T_WITH_ERRNO;
272 	/* Pass in the expected open counts when placing a write lease. */
273 	err = fcntl(fd, F_SETLEASE, F_SETLEASE_ARG(F_WRLCK, 3));
274 	T_ASSERT_NE(err, -1, "Acquire write lease: %s", testfile);
275 
276 	kq = kqueue();
277 	T_ASSERT_NE(kq, -1, "Create kqueue");
278 
279 	kevent_timeout.tv_sec = kevent_timeout.tv_nsec = 0;
280 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, (EV_ADD | EV_ENABLE | EV_CLEAR),
281 	    (NOTE_LEASE_DOWNGRADE | NOTE_LEASE_RELEASE), 0, (void *)testfile);
282 	err = kevent(kq, &lease_kevent, 1, NULL, 0, &kevent_timeout);
283 	T_ASSERT_GE(err, 0, "Register lease event on kq: %d", kq);
284 
285 	kevent_timeout.tv_sec = 60;
286 	kevent_timeout.tv_nsec = 0;
287 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, EV_CLEAR, 0, 0, 0);
288 
289 	err = kevent(kq, NULL, 0, &lease_kevent, 1, &kevent_timeout);
290 	T_ASSERT_NE(err, -1, "Listen for lease event on kq: %d", kq);
291 
292 	if (err > 0) {
293 		T_ASSERT_EQ(lease_kevent.fflags, NOTE_LEASE_DOWNGRADE,
294 		    "Got lease event 0x%x", lease_kevent.fflags);
295 
296 		T_WITH_ERRNO;
297 		/* Pass in the expected write counts when placing a read lease. */
298 		err = fcntl(fd, F_SETLEASE, F_SETLEASE_ARG(F_RDLCK, 2));
299 		T_ASSERT_NE(err, -1, "Downgrade to read lease: %s", testfile);
300 	} else {
301 		T_FAIL("Timedout listening for lease event on kq: %d", kq);
302 	}
303 }
304 
305 T_HELPER_DECL(open_rdonly_read_lease_timedout, "Open file in O_RDONLY mode, acquire read lease, and hold lease beyond lease break timeout upon NOTE_LEASE_RELEASE event", T_META_ASROOT(true))
306 {
307 	struct kevent lease_kevent;
308 	struct timespec kevent_timeout;
309 	uint32_t val, new_val;
310 	size_t val_len, new_val_len;
311 	char *testfile = argv[0];
312 	int err, fd, kq;
313 
314 	if (!is_development_kernel()) {
315 		T_SKIP("Skipping test on release kernel");
316 	}
317 
318 	T_WITH_ERRNO;
319 	fd = open(testfile, O_RDONLY, 0666);
320 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
321 
322 	T_WITH_ERRNO;
323 	err = fcntl(fd, F_SETLEASE, F_RDLCK);
324 	T_ASSERT_NE(err, -1, "Acquire read lease: %s", testfile);
325 
326 	new_val = 10;
327 	new_val_len = val_len = sizeof(uint32_t);
328 	err = sysctlbyname("vfs.lease.break_timeout", (void *)&val, &val_len,
329 	    (void *)&new_val, new_val_len);
330 	T_ASSERT_NE(err, -1, "Change vfs.lease.break_timeout to %d secs", new_val);
331 
332 	kq = kqueue();
333 	T_ASSERT_NE(kq, -1, "Create kqueue");
334 
335 	kevent_timeout.tv_sec = kevent_timeout.tv_nsec = 0;
336 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, (EV_ADD | EV_ENABLE | EV_CLEAR),
337 	    (NOTE_LEASE_DOWNGRADE | NOTE_LEASE_RELEASE), 0, (void *)testfile);
338 	err = kevent(kq, &lease_kevent, 1, NULL, 0, &kevent_timeout);
339 	T_ASSERT_GE(err, 0, "Register lease event on kq: %d", kq);
340 
341 	kevent_timeout.tv_sec = 30;
342 	kevent_timeout.tv_nsec = 0;
343 	EV_SET(&lease_kevent, fd, EVFILT_VNODE, EV_CLEAR, 0, 0, 0);
344 
345 	err = kevent(kq, NULL, 0, &lease_kevent, 1, &kevent_timeout);
346 	T_ASSERT_NE(err, -1, "Listen for lease event on kq: %d", kq);
347 
348 	if (err > 0) {
349 		T_ASSERT_EQ(lease_kevent.fflags, NOTE_LEASE_RELEASE,
350 		    "Got lease event 0x%x", lease_kevent.fflags);
351 
352 		/* Sleep to force lease break timedout. */
353 		T_LOG("Sleep for %d secs to force lease break timedout", new_val + 5);
354 		sleep(new_val + 5);
355 	} else {
356 		T_FAIL("Timedout listening for lease event on kq: %d", kq);
357 	}
358 	T_ASSERT_NE(err, -1, "Change vfs.lease.break_timeout to %d secs", new_val);
359 }
360 
361 T_HELPER_DECL(open_rdonly_dir_read_lease, "Open directory in O_RDONLY mode, acquire read lease, and release lease upon NOTE_LEASE_RELEASE event")
362 {
363 	struct kevent lease_kevent;
364 	struct timespec kevent_timeout;
365 	char *testdir = argv[1];
366 	int err, dir_fd, kq;
367 
368 	T_WITH_ERRNO;
369 	dir_fd = open(testdir, O_RDONLY);
370 	T_ASSERT_NE(dir_fd, -1, "Open test dir in O_RDONLY: %s", testdir);
371 
372 	kq = kqueue();
373 	T_ASSERT_NE(kq, -1, "Create kqueue");
374 
375 retry:
376 	T_WITH_ERRNO;
377 	err = fcntl(dir_fd, F_SETLEASE, F_RDLCK);
378 	T_ASSERT_NE(err, -1, "Acquire read lease: %s", testdir);
379 
380 	kevent_timeout.tv_sec = kevent_timeout.tv_nsec = 0;
381 	EV_SET(&lease_kevent, dir_fd, EVFILT_VNODE, (EV_ADD | EV_ENABLE | EV_CLEAR),
382 	    (NOTE_LEASE_DOWNGRADE | NOTE_LEASE_RELEASE), 0, (void *)testdir);
383 	err = kevent(kq, &lease_kevent, 1, NULL, 0, &kevent_timeout);
384 	T_ASSERT_GE(err, 0, "Register lease event on kq: %d", kq);
385 
386 	kevent_timeout.tv_sec = 30;
387 	kevent_timeout.tv_nsec = 0;
388 	EV_SET(&lease_kevent, dir_fd, EVFILT_VNODE, EV_CLEAR, 0, 0, 0);
389 
390 	err = kevent(kq, NULL, 0, &lease_kevent, 1, &kevent_timeout);
391 	T_ASSERT_NE(err, -1, "Listen for lease event on kq: %d", kq);
392 
393 	if (err > 0) {
394 		T_ASSERT_EQ(lease_kevent.fflags, NOTE_LEASE_RELEASE,
395 		    "Got lease event 0x%x", lease_kevent.fflags);
396 
397 		T_WITH_ERRNO;
398 		err = fcntl(dir_fd, F_SETLEASE, F_UNLCK);
399 		T_ASSERT_NE(err, -1, "Release lease: %s", testdir);
400 
401 		/*
402 		 * Retry until we got no more events (kevent timedout) which means
403 		 * the other helper is done with all the tests.
404 		 */
405 		goto retry;
406 	} else {
407 		T_FAIL("Timedout listening for lease event on kq: %d", kq);
408 	}
409 }
410 
411 T_HELPER_DECL(open_rdwr, "Open file in O_RDWR mode")
412 {
413 	char *testfile = argv[0];
414 	int fd;
415 
416 	/* wait for the other helper to be in ready state */
417 	sleep(1);
418 
419 	T_WITH_ERRNO;
420 	fd = open(testfile, O_RDWR, 0666);
421 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDWR: %s", testfile);
422 }
423 
424 T_HELPER_DECL(open_rdonly, "Open file in O_RDONLY mode")
425 {
426 	char *testfile = argv[0];
427 	int fd;
428 
429 	/* wait for the other helper to be in ready state */
430 	sleep(1);
431 
432 	T_WITH_ERRNO;
433 	fd = open(testfile, O_RDONLY, 0666);
434 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
435 }
436 
437 T_HELPER_DECL(truncate, "Truncate file")
438 {
439 	char *testfile = argv[0];
440 	int err;
441 
442 	/* wait for the other helper to be in ready state */
443 	sleep(1);
444 
445 	T_WITH_ERRNO;
446 	err = truncate(testfile, 0);
447 	T_ASSERT_NE(err, -1, "Truncate test fi1e: %s", testfile);
448 }
449 
450 T_HELPER_DECL(open_rdonly_request_read_range_lock, "Open file in O_RDONLY mode and request byte range lock")
451 {
452 	struct flock lreq;
453 	char *testfile = argv[0];
454 	int err, fd;
455 
456 	/* wait for the other helper to be in ready state */
457 	sleep(1);
458 
459 	T_WITH_ERRNO;
460 	fd = open(testfile, O_RDONLY, 0666);
461 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
462 
463 	T_WITH_ERRNO;
464 	lreq.l_start = 0;
465 	lreq.l_len = 0;
466 	lreq.l_type = F_RDLCK;
467 	lreq.l_whence = 0;
468 
469 	err = fcntl(fd, F_SETLK, &lreq);
470 	T_ASSERT_NE(err, -1, "Acquire read range lock on test fi1e: %s", testfile);
471 
472 	T_WITH_ERRNO;
473 	lreq.l_start = 0;
474 	lreq.l_len = 0;
475 	lreq.l_type = F_UNLCK;
476 	lreq.l_whence = 0;
477 
478 	err = fcntl(fd, F_SETLK, &lreq);
479 	T_ASSERT_NE(err, -1, "Release read range lock on test fi1e: %s", testfile);
480 }
481 
482 T_HELPER_DECL(file_syscalls, "Call file syscalls")
483 {
484 	char destfile[MAXPATHLEN];
485 	struct attrlist attrlist;
486 	char *xattr_key = "com.apple.xattr_test";
487 	char xattr_val[] = "xattr_foo";
488 	char *testfile = argv[0];
489 	uint32_t flags;
490 	int err, fd;
491 
492 	/* wait for the other helper to be in ready state */
493 	sleep(1);
494 
495 	T_WITH_ERRNO;
496 	fd = open(testfile, O_RDWR | O_CREAT, 0666);
497 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDWR|O_CREAT: %s", testfile);
498 	sleep(1);
499 
500 	/* Test ftruncate (fd needs to be opened with write mode) */
501 	T_WITH_ERRNO;
502 	err = ftruncate(fd, 0);
503 	T_ASSERT_NE(err, -1, "fdtruncate: %s", testfile);
504 	sleep(1);
505 
506 	/* Test (p)write. */
507 	T_WITH_ERRNO;
508 	err = (int)write(fd, destfile, sizeof(destfile));
509 	T_ASSERT_NE(err, -1, "write: %s", testfile);
510 	sleep(1);
511 
512 	T_WITH_ERRNO;
513 	err = (int)pwrite(fd, destfile, sizeof(destfile), sizeof(destfile));
514 	T_ASSERT_NE(err, -1, "write: %s", testfile);
515 	sleep(1);
516 
517 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", testfile);
518 
519 	T_WITH_ERRNO;
520 	fd = open(testfile, O_RDONLY, 0666);
521 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", testfile);
522 
523 	/* Test (f)chflags syscall */
524 	T_WITH_ERRNO;
525 	err = chflags(testfile, 0);
526 	T_ASSERT_NE(err, -1, "chflags: %s", testfile);
527 	sleep(1);
528 
529 	T_WITH_ERRNO;
530 	err = fchflags(fd, 0);
531 	T_ASSERT_NE(err, -1, "fchflags: %s", testfile);
532 	sleep(1);
533 
534 	/* Test (f)chmod syscall */
535 	T_WITH_ERRNO;
536 	err = chmod(testfile, S_IRWXU);
537 	T_ASSERT_NE(err, -1, "chmod: %s", testfile);
538 	sleep(1);
539 
540 	T_WITH_ERRNO;
541 	err = fchmod(fd, S_IRWXU);
542 	T_ASSERT_NE(err, -1, "fchmod: %s", testfile);
543 	sleep(1);
544 
545 	/* Test clonefile */
546 	snprintf(destfile, sizeof(destfile), "%s.%d", testfile, rand());
547 	T_WITH_ERRNO;
548 	err = clonefile(testfile, destfile, CLONE_NOFOLLOW);
549 	T_ASSERT_NE(err, -1, "clonefile src: %s dest: %s", testfile, destfile);
550 	sleep(1);
551 
552 	/* Test copyfile */
553 	T_WITH_ERRNO;
554 	err = copyfile(testfile, destfile, NULL, COPYFILE_DATA | COPYFILE_STAT);
555 	T_ASSERT_NE(err, -1, "copyfile src: %s dest: %s", testfile, destfile);
556 	sleep(1);
557 
558 	/* Test unlink */
559 	T_WITH_ERRNO;
560 	err = unlink(destfile);
561 	T_ASSERT_NE(err, -1, "unlink: %s", destfile);
562 	sleep(1);
563 
564 	/* Test (f)setxattr and (f)removexattr */
565 	T_WITH_ERRNO;
566 	err = setxattr(testfile, xattr_key, &xattr_val[0], sizeof(xattr_val), 0, 0);
567 	T_ASSERT_NE(err, -1, "setxattr: %s", testfile);
568 	sleep(1);
569 
570 	T_WITH_ERRNO;
571 	err = removexattr(testfile, xattr_key, 0);
572 	T_ASSERT_NE(err, -1, "removexattr: %s", testfile);
573 	sleep(1);
574 
575 	T_WITH_ERRNO;
576 	err = fsetxattr(fd, xattr_key, &xattr_val[0], sizeof(xattr_val), 0, 0);
577 	T_ASSERT_NE(err, -1, "fsetxattr: %s", testfile);
578 	sleep(1);
579 
580 	T_WITH_ERRNO;
581 	err = fremovexattr(fd, xattr_key, 0);
582 	T_ASSERT_NE(err, -1, "fremovexattr: %s", testfile);
583 	sleep(1);
584 
585 	/* Test (f)setattrlist */
586 	flags = 0;
587 	memset(&attrlist, 0, sizeof(attrlist));
588 	attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
589 	attrlist.commonattr = (ATTR_CMN_FLAGS);
590 
591 	T_WITH_ERRNO;
592 	err = setattrlist(testfile, &attrlist, &flags, sizeof(flags), 0);
593 	T_ASSERT_NE(err, -1, "setattrlist: %s", testfile);
594 	sleep(1);
595 
596 	T_WITH_ERRNO;
597 	err = fsetattrlist(fd, &attrlist, &flags, sizeof(flags), 0);
598 	T_ASSERT_NE(err, -1, "fsetattrlist: %s", testfile);
599 	sleep(1);
600 
601 	/* Test truncate */
602 	T_WITH_ERRNO;
603 	err = truncate(testfile, 0);
604 	T_ASSERT_NE(err, -1, "truncate: %s", testfile);
605 	sleep(1);
606 
607 	/* Test (f)utimes */
608 	T_WITH_ERRNO;
609 	err = utimes(testfile, NULL);
610 	T_ASSERT_NE(err, -1, "utimes: %s", testfile);
611 	sleep(1);
612 
613 	T_WITH_ERRNO;
614 	err = futimes(fd, NULL);
615 	T_ASSERT_NE(err, -1, "futimes: %s", testfile);
616 
617 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", testfile);
618 }
619 
620 T_HELPER_DECL(file_syscalls_2, "Call file syscalls (mknod)", T_META_ASROOT(true))
621 {
622 	char destfile[MAXPATHLEN];
623 	char *testfile = argv[0];
624 	int err;
625 
626 	snprintf(destfile, sizeof(destfile), "%s.%d", testfile, rand());
627 
628 	/* wait for the other helper to be in ready state */
629 	sleep(1);
630 
631 	/* Test mknod */
632 	T_WITH_ERRNO;
633 	err = mknod(destfile, (S_IFCHR | S_IRWXU), 0);
634 	T_ASSERT_NE(err, -1, "mknod: %s", destfile);
635 	sleep(1);
636 
637 	/* Test unlink */
638 	T_WITH_ERRNO;
639 	err = unlink(destfile);
640 	T_ASSERT_NE(err, -1, "unlink: %s", destfile);
641 }
642 
643 /*
644  * Test acquire, downgrade, and release lease.
645  * a. Process A opens the file in O_RDONLY mode
646  * b. Process A acquires write lease
647  * c. Process A downgrade from write to read lease
648  * d. Process A release lease
649  *
650  * Result: Lease operations should succeed as expected.
651  */
652 T_DECL(acquire_downgrade_release, "Test acquire, downgrade and release lease", T_META_ENABLED(TARGET_OS_OSX))
653 {
654 	int err, fd;
655 
656 	create_test_file();
657 
658 	T_WITH_ERRNO;
659 	fd = open(g_testfile, O_RDONLY, 0666);
660 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", g_testfile);
661 
662 	T_WITH_ERRNO;
663 	err = fcntl(fd, F_SETLEASE, F_WRLCK);
664 	T_ASSERT_NE(err, -1, "Acquire write lease: %s", g_testfile);
665 
666 	T_WITH_ERRNO;
667 	err = fcntl(fd, F_GETLEASE);
668 	T_ASSERT_EQ(err, F_WRLCK, "Retrieve lease: %s", g_testfile);
669 
670 	T_WITH_ERRNO;
671 	err = fcntl(fd, F_SETLEASE, F_RDLCK);
672 	T_ASSERT_NE(err, -1, "Downgrade to read lease: %s", g_testfile);
673 
674 	T_WITH_ERRNO;
675 	err = fcntl(fd, F_GETLEASE);
676 	T_ASSERT_EQ(err, F_RDLCK, "Retrieve lease: %s", g_testfile);
677 
678 	T_WITH_ERRNO;
679 	err = fcntl(fd, F_SETLEASE, F_UNLCK);
680 	T_ASSERT_NE(err, -1, "Release lease: %s", g_testfile);
681 
682 	T_WITH_ERRNO;
683 	err = fcntl(fd, F_GETLEASE);
684 	T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease: %s", g_testfile);
685 
686 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", g_testfile);
687 }
688 
689 /*
690  * Test acquire lease failure due to open conflicts.
691  * a. Process A opens the file in O_RDWR mode
692  * b. Process B opens the file in O_RDONLY mode
693  * c. Process B tries to acquire read lease
694  *
695  * Result: Process B should fail to acquire read lease with EAGAIN due to the
696  *         file has been opened with write mode (O_RDWR).
697  */
698 T_DECL(open_conflict_1, "Test acquire read lease failure due to open conflicts", T_META_ENABLED(TARGET_OS_OSX))
699 {
700 	const char *helper_test_names[] = {"open_rdonly_acquire_read_lease_EAGAIN"};
701 	int fd;
702 
703 	create_test_file();
704 
705 	T_WITH_ERRNO;
706 	fd = open(g_testfile, O_RDWR, 0666);
707 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDWR: %s", g_testfile);
708 
709 	run_helpers(helper_test_names, 1);
710 
711 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", g_testfile);
712 }
713 
714 /*
715  * Test acquire lease failure due to open conflicts.
716  * a. Process A opens the file in O_RDONLY mode
717  * b. Process B opens the file in O_RDWR mode
718  * c. Process B tries to acquire write lease
719  *
720  * Result: Process B should fail to acquire write lease with EAGAIN due to the
721  *         file has been opened elsewhere.
722  */
723 T_DECL(open_conflict_2, "Test acquire write lease failure due to open conflicts", T_META_ENABLED(TARGET_OS_OSX))
724 {
725 	const char *helper_test_names[] = {"open_rdwr_acquire_write_lease_EAGAIN"};
726 	int fd;
727 
728 	create_test_file();
729 
730 	T_WITH_ERRNO;
731 	fd = open(g_testfile, O_RDONLY, 0666);
732 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", g_testfile);
733 
734 	run_helpers(helper_test_names, 1);
735 
736 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close test file: %s", g_testfile);
737 }
738 
739 /*
740  * Test multiple processes put a read lease on the file.
741  * a. Process A opens the file with O_RDONLY mode and place a read lease
742  * b. Process B opens the file with O_RDONLY mode and place a read lease
743  *
744  * Result: Both processes should succeed in placing read lease on the file.
745  */
746 T_DECL(multiple_read_leases, "Test multiple processes put a read lease on the file", T_META_ENABLED(TARGET_OS_OSX))
747 {
748 	const char *helper_test_names[] = {"open_rdonly_acquire_read_lease_succeed",
749 		                           "open_rdonly_acquire_read_lease_succeed"};
750 
751 	create_test_file();
752 	run_helpers(helper_test_names, 2);
753 }
754 
755 /*
756  * Test acquire and release lease when there is no lease is in place.
757  *
758  * Result: Acquire lease should succeed with F_UNLCK (no lease).
759  *         Release lease should fail with ENOLCK.
760  */
761 T_DECL(acquire_release_no_lease, "Test acquire and release lease when there is no lease is in place", T_META_ENABLED(TARGET_OS_OSX))
762 {
763 	int err, fd;
764 
765 	create_test_file();
766 
767 	T_WITH_ERRNO;
768 	fd = open(g_testfile, O_RDWR, 0666);
769 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDWR: %s", g_testfile);
770 
771 	T_WITH_ERRNO;
772 	err = fcntl(fd, F_GETLEASE);
773 	T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease: %s", g_testfile);
774 
775 	T_WITH_ERRNO;
776 	err = fcntl(fd, F_SETLEASE, F_UNLCK);
777 	T_ASSERT_TRUE((err == -1) && (errno == ENOLCK), "Release lease: %s",
778 	    g_testfile);
779 }
780 
781 /*
782  * Test acquire, release and retrieve lease on non-regular file.
783  *
784  * Result: Acquire, release and retrieve lease should fail with EBADF.
785  */
786 T_DECL(acquire_release_retrieve_non_file, "Test acquire, release and retrieve lease on non-regular file", T_META_ENABLED(TARGET_OS_OSX))
787 {
788 	int err, fd;
789 
790 	T_WITH_ERRNO;
791 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
792 	T_ASSERT_NE(fd, -1, "Open socket");
793 
794 	T_WITH_ERRNO;
795 	err = fcntl(fd, F_SETLEASE, F_RDLCK);
796 	T_ASSERT_TRUE((err == -1) && (errno == EBADF), "Acquire read lease on socket");
797 
798 	T_WITH_ERRNO;
799 	err = fcntl(fd, F_SETLEASE, F_WRLCK);
800 	T_ASSERT_TRUE((err == -1) && (errno == EBADF), "Acquire write lease on socket");
801 
802 	T_WITH_ERRNO;
803 	err = fcntl(fd, F_SETLEASE, F_UNLCK);
804 	T_ASSERT_TRUE((err == -1) && (errno == EBADF), "Release lease on socket");
805 
806 	T_WITH_ERRNO;
807 	err = fcntl(fd, F_GETLEASE);
808 	T_ASSERT_TRUE((err == -1) && (errno == EBADF), "Retrieve lease on socket");
809 
810 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close socket");
811 }
812 
813 /*
814  * Test retrieve and downgrade lease with duplicated fd created with dup(2).
815  * a. Process A opens the file with O_RDONLY mode and place a write lease
816  * b. Process A duplicates the existing file descriptor
817  * c. Process A retrieves and downgrade lease with duplicated fd
818  * d. Process A closes the original and duplicated fds to release lease.
819  *
820  * Result: Retrieve and downgrade with duplicated fd should succeed.
821  *         When all fds are closed, lease should be released implicity.
822  */
823 T_DECL(retrieve_downgrade_dup_fd, "Test retrieve and downgrade lease with duplicated fd created with dup()", T_META_ENABLED(TARGET_OS_OSX))
824 {
825 	int err, dup_fd, fd;
826 
827 	create_test_file();
828 
829 	T_WITH_ERRNO;
830 	fd = open(g_testfile, O_RDONLY, 0666);
831 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", g_testfile);
832 
833 	T_WITH_ERRNO;
834 	err = fcntl(fd, F_GETLEASE);
835 	T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease: %s", g_testfile);
836 
837 	T_WITH_ERRNO;
838 	err = fcntl(fd, F_SETLEASE, F_WRLCK);
839 	T_ASSERT_NE(err, -1, "Acquire write lease: %s", g_testfile);
840 
841 	T_WITH_ERRNO;
842 	dup_fd = dup(fd);
843 	T_ASSERT_NE(dup_fd, -1, "Duplicate existing fd: %d", fd);
844 
845 	T_WITH_ERRNO;
846 	err = fcntl(dup_fd, F_GETLEASE);
847 	T_ASSERT_EQ(err, F_WRLCK, "Retrieve lease with dup fd: %d", dup_fd);
848 
849 	T_WITH_ERRNO;
850 	err = fcntl(dup_fd, F_SETLEASE, F_RDLCK);
851 	T_ASSERT_NE(err, -1, "Downgrade to read lease with dup fd: %d", dup_fd);
852 
853 	T_WITH_ERRNO;
854 	err = fcntl(dup_fd, F_GETLEASE);
855 	T_ASSERT_EQ(err, F_RDLCK, "Retrieve lease with dup fd: %d", dup_fd);
856 
857 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close original fd");
858 	T_ASSERT_POSIX_SUCCESS(close(dup_fd), "Close duplicated fd");
859 
860 	T_WITH_ERRNO;
861 	fd = open(g_testfile, O_RDONLY, 0666);
862 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", g_testfile);
863 
864 	T_WITH_ERRNO;
865 	err = fcntl(fd, F_GETLEASE);
866 	T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease: %s", g_testfile);
867 
868 	T_ASSERT_POSIX_SUCCESS(close(fd), "Close fd");
869 }
870 
871 /*
872  * Test retrieve and release lease with duplicated fd created with fork(2).
873  * a. Process A opens the file with O_RDONLY mode and place a write lease
874  * b. Process A forks to create a child process
875  * c. Child process retrieves and releases lease with duplicated fd
876  * d. Child process exits
877  * e. Process A verifies the lease has been released
878  *
879  * Result: Retrieve and release with duplicated fd should succeed.
880  *         Child process should be able to release the leased placed by the
881  *         parent process.
882  */
883 T_DECL(retrieve_release_fork_fd, "Test retrieve and release lease with duplicated fd created with fork()", T_META_ENABLED(TARGET_OS_OSX))
884 {
885 	pid_t child_pid;
886 	int err, fd;
887 
888 	create_test_file();
889 
890 	T_WITH_ERRNO;
891 	fd = open(g_testfile, O_RDONLY, 0666);
892 	T_ASSERT_NE(fd, -1, "Open test fi1e in O_RDONLY: %s", g_testfile);
893 
894 	T_WITH_ERRNO;
895 	err = fcntl(fd, F_GETLEASE);
896 	T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease: %s", g_testfile);
897 
898 	T_WITH_ERRNO;
899 	err = fcntl(fd, F_SETLEASE, F_WRLCK);
900 	T_ASSERT_NE(err, -1, "Acquire write lease: %s", g_testfile);
901 
902 	child_pid = fork();
903 	T_ASSERT_POSIX_SUCCESS(child_pid, "Fork process");
904 
905 	if (child_pid == 0) {
906 		/* child process */
907 		err = fcntl(fd, F_GETLEASE);
908 		T_ASSERT_EQ(err, F_WRLCK, "Retrieve lease with fork fd: %d", fd);
909 
910 		T_WITH_ERRNO;
911 		err = fcntl(fd, F_SETLEASE, F_UNLCK);
912 		T_ASSERT_NE(err, -1, "Release lease with fork fd: %d", fd);
913 
914 		T_WITH_ERRNO;
915 		err = fcntl(fd, F_GETLEASE);
916 		T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease with fork fd: %d", fd);
917 
918 		exit(0);
919 	} else {
920 		/* wait for child process to exit */
921 		if (dt_waitpid(child_pid, &err, NULL, 30) == false) {
922 			T_FAIL("dt_waitpid() failed on child pid %d", child_pid);
923 		}
924 
925 		T_WITH_ERRNO;
926 		err = fcntl(fd, F_GETLEASE);
927 		T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease with parent fd: %d", fd);
928 
929 		T_ASSERT_POSIX_SUCCESS(close(fd), "Close fd");
930 	}
931 }
932 
933 /*
934  * Test lease break release event.
935  * a. Process A opens the file in O_RDONLY mode and place a read lease
936  * b. Process B opens the file in O_RDWR mode and open syscall is blocked
937  * c. Lease break release event is sent to Process A
938  *
939  * Result: Process A releases the lease and process B's open is unblocked
940  */
941 T_DECL(lease_break_release_1, "Test lease break release event when file is opened in O_RDWR mode", T_META_ENABLED(TARGET_OS_OSX))
942 {
943 	const char *helper_test_names[] = {"open_rdonly_read_lease_release", "open_rdwr"};
944 
945 	create_test_file();
946 
947 	run_helpers(helper_test_names, 2);
948 }
949 
950 /*
951  * Test lease break release event.
952  * a. Process A opens the file in O_RDONLY mode and place a read lease
953  * b. Process B truncates the file and truncate syscall is blocked
954  * c. Lease break release event is sent to Process A
955  *
956  * Result: Process A releases the lease and process B's truncate is unblocked.
957  */
958 T_DECL(lease_break_release_2, "Test lease break release event when file is truncated", T_META_ENABLED(TARGET_OS_OSX))
959 {
960 	const char *helper_test_names[] = {"open_rdonly_read_lease_release", "truncate"};
961 
962 	create_test_file();
963 
964 	run_helpers(helper_test_names, 2);
965 }
966 
967 /*
968  * Test lease break release event.
969  * a. Process A opens the file in O_RDONLY mode and place a read lease
970  * b. Process B opens the file in O_RDONLY mode and requests byte range lock
971  *    via fcntl(F_SETLK or F_OFD_SETLK)
972  * c. Lease break release event is sent to Process A
973  *
974  * Result: Process A releases the lease and process B's fcntl call is unblocked.
975  */
976 T_DECL(lease_break_release_3, "Test lease break release event when byte range lock is requested", T_META_ENABLED(TARGET_OS_OSX))
977 {
978 	const char *helper_test_names[] = {"open_rdonly_read_lease_release", "open_rdonly_request_read_range_lock"};
979 
980 	create_test_file();
981 
982 	run_helpers(helper_test_names, 2);
983 }
984 
985 /*
986  * Test lease break release event.
987  * a. Process A opens the file in O_RDONLY mode and place a read lease
988  * a. Process B opens the file in O_RDONLY mode and place a read lease
989  * b. Process C opens the file in O_RDWR mode and open syscall is blocked
990  * c. Lease break release events are sent to Process A and B
991  *
992  * Result: Process A and B release the lease and process C's open is unblocked
993  */
994 T_DECL(lease_break_release_4, "Test multiple lease break release events", T_META_ENABLED(TARGET_OS_OSX))
995 {
996 	const char *helper_test_names[] = {"open_rdonly_read_lease_release",
997 		                           "open_rdonly_read_lease_release", "open_rdwr"};
998 
999 	create_test_file();
1000 
1001 	run_helpers(helper_test_names, 3);
1002 }
1003 
1004 /*
1005  * Test lease break downgrade event.
1006  * a. Process A opens the file in O_RDONLY mode and place a write lease
1007  * b. Process B opens the file in O_RDONLY mode and open syscall is blocked
1008  * c. Lease break downgrade event is sent to Process A
1009  *
1010  * Result: Process A downgrades the lease and process B's open is unblocked.
1011  */
1012 T_DECL(lease_break_downgrade_1, "Test lease break downgrade event with read-only opens", T_META_ENABLED(TARGET_OS_OSX))
1013 {
1014 	const char *helper_test_names[] = {"open_rdonly_write_lease_downgrade", "open_rdonly"};
1015 
1016 	create_test_file();
1017 
1018 	run_helpers(helper_test_names, 2);
1019 }
1020 
1021 /*
1022  * Test lease break downgrade event.
1023  * a. Process A opens the file multiple times in O_RDWR mode and place a
1024  *    write lease
1025  * b. Process B opens the file in O_RDONLY mode and open syscall is blocked
1026  * c. Lease break downgrade event is sent to Process A
1027  *
1028  * Result: Process A downgrades the lease and process B's open is unblocked.
1029  */
1030 T_DECL(lease_break_downgrade_2, "Test lease break downgrade event with multiple read-write opens", T_META_ENABLED(TARGET_OS_OSX))
1031 {
1032 	const char *helper_test_names[] = {"open_rw_write_lease_downgrade", "open_rdonly"};
1033 
1034 	create_test_file();
1035 
1036 	run_helpers(helper_test_names, 2);
1037 }
1038 
1039 /*
1040  * Test lease break timedout
1041  * a. Process A opens the file in O_RDONLY mode and place a read lease
1042  * b. Process B opens the file in O_RDWR mode and open syscall is blocked
1043  * c. Lease break release event is sent to Process A
1044  * d. Lease is not release within sysctl's 'vfs.lease.break_timeout'
1045  *
1046  * Result: Kernel forcibly breaks the lease and process B's open is unblocked.
1047  */
1048 T_DECL(lease_break_timedout, "Test lease break timedout", T_META_ENABLED(TARGET_OS_OSX))
1049 {
1050 	const char *helper_test_names[] = {"open_rdonly_read_lease_timedout", "open_rdwr"};
1051 
1052 	create_test_file();
1053 
1054 	run_helpers(helper_test_names, 2);
1055 }
1056 
1057 /*
1058  * Test acquire and release lease on directory.
1059  * a. Process A opens the directory in O_RDONLY mode
1060  * b. Process A acquires read lease
1061  * d. Process A release lease
1062  *
1063  * Result: Lease operations should succeed as expected.
1064  */
1065 T_DECL(acquire_release_read_lease_dir, "Test acquire and release read lease", T_META_ENABLED(TARGET_OS_OSX))
1066 {
1067 	int err, dir_fd;
1068 
1069 	create_test_file();
1070 
1071 	T_WITH_ERRNO;
1072 	dir_fd = open(g_testdir, O_RDONLY);
1073 	T_ASSERT_NE(dir_fd, -1, "Open test dir in O_RDONLY: %s", g_testdir);
1074 
1075 	T_WITH_ERRNO;
1076 	err = fcntl(dir_fd, F_SETLEASE, F_RDLCK);
1077 	T_ASSERT_NE(err, -1, "Acquire read lease: %s", g_testdir);
1078 
1079 	T_WITH_ERRNO;
1080 	err = fcntl(dir_fd, F_GETLEASE);
1081 	T_ASSERT_EQ(err, F_RDLCK, "Retrieve lease: %s", g_testdir);
1082 
1083 	T_WITH_ERRNO;
1084 	err = fcntl(dir_fd, F_SETLEASE, F_UNLCK);
1085 	T_ASSERT_NE(err, -1, "Release lease: %s", g_testdir);
1086 
1087 	T_WITH_ERRNO;
1088 	err = fcntl(dir_fd, F_GETLEASE);
1089 	T_ASSERT_EQ(err, F_UNLCK, "Retrieve lease: %s", g_testdir);
1090 
1091 	T_ASSERT_POSIX_SUCCESS(close(dir_fd), "Close test dir: %s", g_testdir);
1092 }
1093 
1094 /*
1095  * Test acquire write lease on directory.
1096  *
1097  * Result: Acquire write lease should fail with EBADF.
1098  */
1099 T_DECL(acquire_write_lease_dir, "Test acquire write lease on directory", T_META_ENABLED(TARGET_OS_OSX))
1100 {
1101 	int err, dir_fd;
1102 
1103 	create_test_file();
1104 
1105 	T_WITH_ERRNO;
1106 	dir_fd = open(g_testdir, O_RDONLY);
1107 	T_ASSERT_NE(dir_fd, -1, "Open test dir in O_RDONLY: %s", g_testdir);
1108 
1109 	T_WITH_ERRNO;
1110 	err = fcntl(dir_fd, F_SETLEASE, F_WRLCK);
1111 	T_ASSERT_TRUE((err == -1) && (errno == ENOTSUP), "Acquire write lease on directory: %s", g_testdir);
1112 
1113 	T_ASSERT_POSIX_SUCCESS(close(dir_fd), "Close test dir");
1114 }
1115 
1116 /*
1117  * Test lease break release event for directory read leasing.
1118  * a. Process A opens the directory in O_RDONLY mode and place a read lease
1119  * b. Process B performs various syscalls that can cause its directory contents
1120  *    (namespace) to change, modify contents or change attributes on the
1121  *    immediate files.
1122  *
1123  * Result: Process A releases the lease and process B's syscall is unblocked.
1124  */
1125 T_DECL(read_lease_dir_1, "Test directory read leasing and lease break events", T_META_ENABLED(TARGET_OS_OSX))
1126 {
1127 	const char *helper_test_names[] = {"open_rdonly_dir_read_lease", "file_syscalls"};
1128 
1129 	create_test_file();
1130 
1131 	run_helpers(helper_test_names, 2);
1132 }
1133 
1134 T_DECL(read_lease_dir_2, "Test directory read leasing and lease break events", T_META_ENABLED(TARGET_OS_OSX))
1135 {
1136 	const char *helper_test_names[] = {"open_rdonly_dir_read_lease", "file_syscalls_2"};
1137 
1138 	create_test_file();
1139 
1140 	run_helpers(helper_test_names, 2);
1141 }
1142