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