11static int copies(
void) {
12 int failed = 0, group = -1, queued = -1;
13 struct fh_file first = {.fd = -1}, second = {.fd = -1};
15 unsigned char bytes[256];
16 void* bad = MAP_FAILED;
17 CHECK(!fh_create(&first) && !fh_create(&second));
18 CHECK(fh_record_size(&first.handle) == fh_record_size(&second.handle));
19 size_t length = fh_record_size(&first.handle);
20 CHECK(length <=
sizeof(bytes));
22 CHECK(group >= 0 && !fh_mark(group, &first, FAN_MARK_ADD, FAN_MODIFY) &&
23 !fh_mark(group, &second, FAN_MARK_ADD, FAN_MODIFY));
25 CHECK(read(group, bytes,
sizeof(bytes)) == -1 && errno == EAGAIN);
26 CHECK(!fh_modify(&first));
27 CHECK(!ioctl(group, FIONREAD, &queued) && queued == 24);
29 CHECK(read(group, bytes, length - 1) == -1 && errno == EINVAL);
30 CHECK(!ioctl(group, FIONREAD, &queued) && queued == 24);
31 CHECK(!fh_event(group, &first, FAN_MODIFY, getpid()));
32 bad = mmap(NULL, fh_page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
33 CHECK(bad != MAP_FAILED && !fh_modify(&first));
35 CHECK(read(group, bad, length) == -1 && errno == EFAULT);
36 CHECK(!ioctl(group, FIONREAD, &queued) && queued == 0);
37 CHECK(!fh_modify(&first));
38 struct iovec split[] = {{bytes, 3}, {bytes + 3, length - 3}};
39 CHECK(readv(group, split, 2) == (ssize_t)length);
40 CHECK(!fh_parse(bytes, length, &record) && fh_equal(&record.handle, &first.handle));
41 CHECK(!fh_modify(&first));
42 struct iovec partial[] = {{bytes, 3}, {bad, length - 3}};
44 CHECK(readv(group, partial, 2) == -1 && errno == EFAULT);
45 CHECK(!ioctl(group, FIONREAD, &queued) && queued == 0);
46 CHECK(!fh_modify(&first) && !fh_modify(&second));
47 CHECK(!ioctl(group, FIONREAD, &queued) && queued == 48);
48 memset(bytes, 0,
sizeof(bytes));
49 struct iovec fault[] = {{bytes, length}, {bad, length}};
51 CHECK(readv(group, fault, 2) == -1 && errno == EFAULT);
52 CHECK(!fh_parse(bytes, length, &record) && fh_equal(&record.handle, &first.handle));
53 CHECK(!ioctl(group, FIONREAD, &queued) && queued == 0);
55 CHECK(read(group, bytes,
sizeof(bytes)) == -1 && errno == EAGAIN);
57 if (bad != MAP_FAILED)
66static int readiness(
void) {
67 int failed = 0, group = -1, epoll = -1;
68 struct fh_file file = {.fd = -1};
69 struct epoll_event event = {.events = EPOLLIN | EPOLLET, .data.u64 = 0xf1d}, output;
70 CHECK(!fh_create(&file));
72 epoll = epoll_create1(EPOLL_CLOEXEC);
73 CHECK(group >= 0 && epoll >= 0 && !fh_mark(group, &file, FAN_MARK_ADD, FAN_MODIFY));
74 CHECK(!epoll_ctl(epoll, EPOLL_CTL_ADD, group, &event));
75 CHECK(fh_readable(group, 0) == 0 && epoll_wait(epoll, &output, 1, 0) == 0);
76 CHECK(!fh_modify(&file) && fh_readable(group, 0) == 1);
77 CHECK(epoll_wait(epoll, &output, 1, 1000) == 1 && (output.events & EPOLLIN) &&
78 output.data.u64 == event.data.u64);
79 CHECK(epoll_wait(epoll, &output, 1, 0) == 0);
80 CHECK(!fh_event(group, &file, FAN_MODIFY, getpid()));
81 CHECK(fh_readable(group, 0) == 0);
82 CHECK(!fh_modify(&file));
83 CHECK(epoll_wait(epoll, &output, 1, 1000) == 1);
84 CHECK(!fh_event(group, &file, FAN_MODIFY, getpid()));
85 event.events = EPOLLIN;
86 CHECK(!epoll_ctl(epoll, EPOLL_CTL_MOD, group, &event));
87 CHECK(!fh_modify(&file));
88 CHECK(epoll_wait(epoll, &output, 1, 1000) == 1);
89 CHECK(epoll_wait(epoll, &output, 1, 0) == 1);
90 CHECK(!fh_event(group, &file, FAN_MODIFY, getpid()));
91 CHECK(epoll_wait(epoll, &output, 1, 0) == 0);
101static int overflow(
void) {
102 enum { Targets = 32, Producers = 9 };
103 int failed = 0, group = -1, queued = -1, overflow_count = 0, ordinary = 0, recovery = -1;
104 pid_t child = -1, producers[Producers] = {0};
106 memset(files, 0,
sizeof(files));
107 for (
int n = 0; n < Targets; ++n)
111 for (
int n = 0; n < Targets; ++n) {
112 CHECK(!fh_create(&files[n]));
113 CHECK(!fh_mark(group, &files[n], FAN_MARK_ADD, FAN_OPEN));
115 for (
int producer = 0; producer < Producers; ++producer) {
120 for (
int target = 0; target < Targets; ++target) {
121 int fd = open(files[target].path, O_RDONLY | O_CLOEXEC);
122 if (fd < 0 || close(fd)) {
123 fprintf(stderr,
"overflow producer=%d target=%d errno=%d\n", producer, target, errno);
129 producers[producer] = child;
131 int status = fh_reap(child, 12000);
134 fprintf(stderr,
"overflow producer=%d pid=%d status=%d\n", producer, producers[producer],
138 CHECK(!ioctl(group, FIONREAD, &queued) && queued == (FH_QUEUE_LIMIT + 1) * 24);
139 for (
int n = 0; n < FH_QUEUE_LIMIT + 1; ++n) {
141 CHECK(!fh_take(group, &files[0].handle, &record));
142 if (record.mask & FAN_Q_OVERFLOW) {
143 CHECK(n == FH_QUEUE_LIMIT && record.mask == FAN_Q_OVERFLOW);
146 CHECK(ordinary < FH_QUEUE_LIMIT && record.mask == FAN_OPEN);
147 CHECK(record.pid == producers[ordinary / Targets]);
148 CHECK(fh_equal(&record.handle, &files[ordinary % Targets].handle));
152 CHECK(ordinary == FH_QUEUE_LIMIT && overflow_count == 1 && fh_readable(group, 0) == 0);
153 recovery = open(files[0].path, O_RDONLY | O_CLOEXEC);
154 CHECK(recovery >= 0 && !fh_event(group, &files[0], FAN_OPEN, getpid()));
155 CHECK(fh_readable(group, 0) == 0);
163 for (
int n = 0; n < Targets; ++n)
168 return copies() || readiness() || overflow();