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