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