a6a2a44d2a4bf45ff2b8cdee04f5919254917f25
[lttng-tools.git] / tests / unit / test_fd_tracker.c
1 /*
2 * Copyright (c) - 2018 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by as
6 * published by the Free Software Foundation; only version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #include <stdlib.h>
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <assert.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <tap/tap.h>
25 #include <sys/types.h>
26 #include <dirent.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33
34 #include <urcu.h>
35
36 #include <common/fd-tracker/fd-tracker.h>
37 #include <common/error.h>
38
39 /* For error.h */
40 int lttng_opt_quiet = 1;
41 int lttng_opt_verbose;
42 int lttng_opt_mi;
43
44 /* Number of TAP tests in this file */
45 #define NUM_TESTS 49
46 /* 3 for stdin, stdout, and stderr */
47 #define STDIO_FD_COUNT 3
48 #define TRACKER_FD_LIMIT 50
49 #define TMP_DIR_PATTERN "/tmp/fd-tracker-XXXXXX"
50
51 /*
52 * Count of fds, beyond stdin, stderr, stdout that were open
53 * at the launch of the test. This allows the test to succeed when
54 * run by automake's test runner or valgrind which both open
55 * fds behind our back.
56 */
57 int unknown_fds_count;
58
59 const char file_contents[] = "Bacon ipsum dolor amet jerky drumstick sirloin "
60 "strip steak venison boudin filet mignon picanha doner shoulder. "
61 "Strip steak brisket alcatra, venison beef chuck cupim pastrami. "
62 "Landjaeger tri-tip salami leberkas ball tip, ham hock chuck sausage "
63 "flank jerky cupim. Pig bacon chuck pancetta andouille.";
64
65 int fd_count(void)
66 {
67 DIR *dir;
68 struct dirent *entry;
69 int count = 0;
70
71 dir = opendir("/proc/self/fd");
72 if (!dir) {
73 perror("# Failed to enumerate /proc/self/fd/ to count the number of used file descriptors");
74 count = -1;
75 goto end;
76 }
77
78 while ((entry = readdir(dir)) != NULL) {
79 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
80 continue;
81 }
82 count++;
83 }
84 /* Don't account for the file descriptor opened by opendir(). */
85 count--;
86 if (closedir(dir)) {
87 perror("# Failed to close test program's self/fd directory file descriptor");
88 }
89 end:
90 return count;
91 }
92
93 static
94 void check_fd_count(int expected_count)
95 {
96 int count = 0;
97
98 count = fd_count();
99 ok(count == expected_count, "Expected %d open file descriptors (%d are open)",
100 expected_count, count);
101 }
102
103 static
104 int noop_open(void *data, int *fds)
105 {
106 *fds = *((int *) data);
107 return 0;
108 }
109
110 static
111 int noop_close(void *data, int *fds)
112 {
113 return 0;
114 }
115
116 static
117 void track_std_fds(struct fd_tracker *tracker)
118 {
119 int i;
120 struct { int fd; const char *name; } files[] = {
121 { .fd = fileno(stdin), .name = "stdin" },
122 { .fd = fileno(stdout), .name = "stdout" },
123 { .fd = fileno(stderr), .name = "stderr" },
124 };
125
126 for (i = 0; i < sizeof(files) / sizeof(*files); i++) {
127 int out_fd, ret;
128
129 ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
130 &files[i].name, 1, noop_open, &files[i].fd);
131 assert(out_fd == files[i].fd);
132
133 ok(ret == 0, "Track unsuspendable fd %d (%s)", files[i].fd,
134 files[i].name);
135 }
136 }
137
138 static
139 void untrack_std_fds(struct fd_tracker *tracker)
140 {
141 int i;
142 struct { int fd; const char *name; } files[] = {
143 { .fd = fileno(stdin), .name = "stdin" },
144 { .fd = fileno(stdout), .name = "stdout" },
145 { .fd = fileno(stderr), .name = "stderr" },
146 };
147 unsigned int fds_set_to_minus_1 = 0;
148
149 for (i = 0; i < sizeof(files) / sizeof(*files); i++) {
150 int fd = files[i].fd;
151 int ret = fd_tracker_close_unsuspendable_fd(tracker,
152 &files[i].fd, 1, noop_close, NULL);
153
154 ok(ret == 0, "Untrack unsuspendable fd %d (%s)", fd,
155 files[i].name);
156 fds_set_to_minus_1 += (files[i].fd == -1);
157 }
158 }
159
160 /*
161 * Basic test opening and closing three unsuspendable fds.
162 */
163 static
164 void test_unsuspendable_basic(void)
165 {
166 struct fd_tracker *tracker;
167
168 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
169 ok(tracker, "Created an fd tracker with a limit of %d simulateously opened file descriptors",
170 TRACKER_FD_LIMIT);
171 if (!tracker) {
172 return;
173 }
174
175 track_std_fds(tracker);
176 untrack_std_fds(tracker);
177
178 fd_tracker_destroy(tracker);
179 }
180
181 static
182 int error_open(void *data, int *fds)
183 {
184 return *((int *) data);
185 }
186
187 static
188 int error_close(void *data, int *fds)
189 {
190 return *((int *) data);
191 }
192
193 /*
194 * Validate that user callback return values are returned to the
195 * caller of the fd tracker.
196 */
197 static
198 void test_unsuspendable_cb_return(void)
199 {
200 int ret, stdout_fd = fileno(stdout), out_fd = 42;
201 struct fd_tracker *tracker;
202 int expected_error = -ENETDOWN;
203
204 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
205 assert(tracker);
206
207 /* The error_open callback should fail and return 'expected_error'. */
208 ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
209 NULL, 1, error_open, &expected_error);
210 ok(ret == expected_error, "fd_tracker_open_unsuspendable_fd() forwards the user callback's error code");
211 ok(out_fd == 42, "Output fd parameter is unaffected on error of fd_tracker_open_unsuspendable_fd()");
212
213 /*
214 * Track a valid fd since we don't want the tracker to fail with an
215 * invalid fd error for this test.
216 */
217 ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
218 NULL, 1, noop_open, &stdout_fd);
219 ok(out_fd == stdout_fd, "fd_tracker_open_unsuspendable_fd() sets the output fd parameter to the newly-tracked fd's value");
220 assert(!ret);
221
222 ret = fd_tracker_close_unsuspendable_fd(tracker,
223 &stdout_fd, 1, error_close, &expected_error);
224 ok(ret == expected_error, "fd_tracker_close_unsuspendable_fd() forwards the user callback's error code");
225 ret = fd_tracker_close_unsuspendable_fd(tracker,
226 &stdout_fd, 1, noop_close, &expected_error);
227 assert(!ret);
228
229 fd_tracker_destroy(tracker);
230 }
231
232 /*
233 * Validate that the tracker refuses to track two identical unsuspendable
234 * file descriptors.
235 */
236 static
237 void test_unsuspendable_duplicate(void)
238 {
239 int ret, stdout_fd = fileno(stdout), out_fd;
240 struct fd_tracker *tracker;
241
242 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
243 assert(tracker);
244
245 ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
246 NULL, 1, noop_open, &stdout_fd);
247 assert(!ret);
248 ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
249 NULL, 1, noop_open, &stdout_fd);
250 ok(ret == -EEXIST, "EEXIST reported on open of an already tracked file descriptor");
251
252 ret = fd_tracker_close_unsuspendable_fd(tracker,
253 &stdout_fd, 1, noop_close, NULL);
254 assert(!ret);
255
256 fd_tracker_destroy(tracker);
257 }
258
259 static
260 int open_pipes(void *data, int *out_fds)
261 {
262 unsigned int i;
263 const unsigned int pipe_count = TRACKER_FD_LIMIT / 2;
264
265 for (i = 0; i < pipe_count; i++) {
266 int ret = pipe(&out_fds[i * 2]);
267
268 if (ret) {
269 return -errno;
270 }
271 }
272 return 0;
273 }
274
275 static
276 int close_pipes(void *data, int *fds)
277 {
278 int i;
279 int *pipes = fds;
280
281 for (i = 0; i < TRACKER_FD_LIMIT; i++) {
282 int ret = close(pipes[i]);
283
284 if (ret) {
285 return -errno;
286 }
287 }
288 return 0;
289 }
290
291 /*
292 * Validate that the tracker enforces the open file descriptor limit
293 * when unsuspendable file descritptors are being opened.
294 */
295 static
296 void test_unsuspendable_limit(void)
297 {
298 struct fd_tracker *tracker;
299 int ret, stdout_fd = fileno(stdout), out_fd;
300 int fds[TRACKER_FD_LIMIT];
301
302 /* This test assumes TRACKER_FD_LIMIT is a multiple of 2. */
303 assert((TRACKER_FD_LIMIT % 2 == 0) && TRACKER_FD_LIMIT);
304
305 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
306 assert(tracker);
307
308 ret = fd_tracker_open_unsuspendable_fd(tracker, fds,
309 NULL, TRACKER_FD_LIMIT, open_pipes, NULL);
310 ok(ret == 0, "File descriptor tracker allowed the user to meet its limit with unsuspendable file descritptors (%d)",
311 TRACKER_FD_LIMIT);
312
313 ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
314 NULL, 1, noop_open, &stdout_fd);
315 ok(ret == -EMFILE, "EMFILE reported when exceeding the file descriptor limit while opening an unsuspendable fd");
316
317 ret = fd_tracker_close_unsuspendable_fd(tracker,
318 fds, TRACKER_FD_LIMIT, close_pipes, NULL);
319 assert(!ret);
320
321 fd_tracker_destroy(tracker);
322 }
323
324 /*
325 * Validate that the tracker refuses to track two identical unsuspendable
326 * file descriptors.
327 */
328 static
329 void test_unsuspendable_close_untracked(void)
330 {
331 int ret, stdout_fd = fileno(stdout), unknown_fds[2], out_fd;
332 struct fd_tracker *tracker;
333
334 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
335 if (!tracker) {
336 return;
337 }
338
339 ret = pipe(unknown_fds);
340 assert(!ret);
341 assert(close(unknown_fds[0]) == 0);
342 assert(close(unknown_fds[1]) == 0);
343
344 ret = fd_tracker_open_unsuspendable_fd(tracker, &out_fd,
345 NULL, 1, noop_open, &stdout_fd);
346 assert(!ret);
347
348 ret = fd_tracker_close_unsuspendable_fd(tracker,
349 unknown_fds, 1, noop_close, NULL);
350 ok(ret == -EINVAL, "EINVAL reported on close of an untracked file descriptor");
351
352 ret = fd_tracker_close_unsuspendable_fd(tracker,
353 &stdout_fd, 1, noop_close, NULL);
354 assert(!ret);
355
356 fd_tracker_destroy(tracker);
357 }
358
359 static
360 int open_files(struct fd_tracker *tracker, const char *dir, unsigned int count,
361 struct fs_handle **handles, char **file_paths)
362 {
363 int ret = 0;
364 unsigned int i;
365
366 for (i = 0; i < count; i++) {
367 int p_ret;
368 char *file_path;
369 struct fs_handle *handle;
370 mode_t mode = S_IWUSR | S_IRUSR;
371
372 p_ret = asprintf(&file_path, "%s/file-%u", dir, i);
373 assert(p_ret >= 0);
374 file_paths[i] = file_path;
375
376 handle = fd_tracker_open_fs_handle(tracker, file_path,
377 O_RDWR | O_CREAT, &mode);
378 if (!handle) {
379 ret = -1;
380 break;
381 }
382 handles[i] = handle;
383 }
384 return ret;
385 }
386
387 static
388 int open_same_file(struct fd_tracker *tracker, const char *file_path,
389 unsigned int count, struct fs_handle **handles)
390 {
391 int ret = 0;
392 unsigned int i;
393
394 for (i = 0; i < count; i++) {
395 struct fs_handle *handle;
396 mode_t mode = S_IWUSR | S_IRUSR;
397
398 handle = fd_tracker_open_fs_handle(tracker, file_path,
399 O_RDWR | O_CREAT, &mode);
400 if (!handle) {
401 ret = -1;
402 break;
403 }
404 handles[i] = handle;
405 }
406 return ret;
407 }
408
409 static
410 int cleanup_files(struct fd_tracker *tracker, const char *dir,
411 unsigned int count, struct fs_handle **handles,
412 char **file_paths)
413 {
414 int ret = 0;
415 unsigned int i;
416
417 for (i = 0; i < count; i++) {
418 char *file_path = file_paths[i];
419
420 if (!file_path) {
421 break;
422 }
423 (void) unlink(file_path);
424 free(file_path);
425 if (fs_handle_close(handles[i])) {
426 ret = -1;
427 }
428 }
429 return ret;
430 }
431
432 static
433 void test_suspendable_limit(void)
434 {
435 int ret;
436 const int files_to_create = TRACKER_FD_LIMIT * 10;
437 struct fd_tracker *tracker;
438 char tmp_path_pattern[] = TMP_DIR_PATTERN;
439 const char *output_dir;
440 char *output_files[files_to_create];
441 struct fs_handle *handles[files_to_create];
442
443 memset(output_files, 0, sizeof(output_files));
444 memset(handles, 0, sizeof(handles));
445
446 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
447 if (!tracker) {
448 return;
449 }
450
451 output_dir = mkdtemp(tmp_path_pattern);
452 if (!output_dir) {
453 diag("Failed to create temporary path of the form %s",
454 TMP_DIR_PATTERN);
455 assert(0);
456 }
457
458 ret = open_files(tracker, output_dir, files_to_create, handles,
459 output_files);
460 ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
461 files_to_create, TRACKER_FD_LIMIT);
462 check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count);
463
464 ret = cleanup_files(tracker, output_dir, files_to_create, handles,
465 output_files);
466 ok(!ret, "Close all opened filesystem handles");
467 (void) rmdir(output_dir);
468 fd_tracker_destroy(tracker);
469 }
470
471 static
472 void test_mixed_limit(void)
473 {
474 int ret;
475 const int files_to_create = TRACKER_FD_LIMIT;
476 struct fd_tracker *tracker;
477 char tmp_path_pattern[] = TMP_DIR_PATTERN;
478 const char *output_dir;
479 char *output_files[files_to_create];
480 struct fs_handle *handles[files_to_create];
481
482 memset(output_files, 0, sizeof(output_files));
483 memset(handles, 0, sizeof(handles));
484
485 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
486 if (!tracker) {
487 return;
488 }
489
490 output_dir = mkdtemp(tmp_path_pattern);
491 if (!output_dir) {
492 diag("Failed to create temporary path of the form %s",
493 TMP_DIR_PATTERN);
494 assert(0);
495 }
496
497 ret = open_files(tracker, output_dir, files_to_create, handles,
498 output_files);
499 ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
500 files_to_create, TRACKER_FD_LIMIT);
501 diag("Check file descriptor count after opening %u files", files_to_create);
502 check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count);
503
504 /*
505 * Open unsuspendable fds (stdin, stdout, stderr) and verify that the fd
506 * cap is still respected.
507 */
508 diag("Check file descriptor count after adding %d unsuspendable fds",
509 STDIO_FD_COUNT);
510 track_std_fds(tracker);
511 check_fd_count(TRACKER_FD_LIMIT + unknown_fds_count);
512 diag("Untrack unsuspendable file descriptors");
513 untrack_std_fds(tracker);
514 check_fd_count(TRACKER_FD_LIMIT + unknown_fds_count);
515
516 ret = cleanup_files(tracker, output_dir, files_to_create, handles,
517 output_files);
518 ok(!ret, "Close all opened filesystem handles");
519 (void) rmdir(output_dir);
520 fd_tracker_destroy(tracker);
521 }
522
523 /*
524 * Open more files than allowed by the fd tracker's cap and write,
525 * byte-by-byte, and in round-robin, a string. The goal is to force
526 * the fd tracker to suspend and resume the fs_handles often and
527 * verify that the fd cap is always respected.
528 *
529 * The content of the files is also verified at the end.
530 */
531 static
532 void test_suspendable_restore(void)
533 {
534 int ret;
535 const int files_to_create = TRACKER_FD_LIMIT * 10;
536 struct fd_tracker *tracker;
537 char tmp_path_pattern[] = TMP_DIR_PATTERN;
538 const char *output_dir;
539 char *output_files[files_to_create];
540 struct fs_handle *handles[files_to_create];
541 size_t content_index;
542 int handle_index;
543 bool write_success = true;
544 bool fd_cap_respected = true;
545 bool content_ok = true;
546
547 memset(output_files, 0, sizeof(output_files));
548 memset(handles, 0, sizeof(handles));
549
550 tracker = fd_tracker_create(TRACKER_FD_LIMIT);
551 if (!tracker) {
552 return;
553 }
554
555 output_dir = mkdtemp(tmp_path_pattern);
556 if (!output_dir) {
557 diag("Failed to create temporary path of the form %s",
558 TMP_DIR_PATTERN);
559 assert(0);
560 }
561
562 ret = open_files(tracker, output_dir, files_to_create, handles,
563 output_files);
564 ok(!ret, "Created %d files with a limit of %d simultaneously-opened file descriptor",
565 files_to_create, TRACKER_FD_LIMIT);
566 diag("Check file descriptor count after opening %u files", files_to_create);
567 check_fd_count(TRACKER_FD_LIMIT + STDIO_FD_COUNT + unknown_fds_count);
568
569 for (content_index = 0; content_index < sizeof(file_contents); content_index++) {
570 for (handle_index = 0; handle_index < files_to_create; handle_index++) {
571 int fd;
572 struct fs_handle *handle = handles[handle_index];
573 const char *path = output_files[handle_index];
574
575 fd = fs_handle_get_fd(handle);
576 if (fd < 0) {
577 write_success = false;
578 diag("Failed to restore fs_handle to %s",
579 path);
580 goto skip_write;
581 }
582
583 do {
584 ret = write(fd, file_contents + content_index, 1);
585 } while (ret < 0 && errno == EINTR);
586
587 if (ret != 1) {
588 write_success = false;
589 PERROR("write() to %s failed", path);
590 goto skip_write;
591 }
592
593 if (fd_count() >
594 (TRACKER_FD_LIMIT + STDIO_FD_COUNT +
595 unknown_fds_count)) {
596 fd_cap_respected = false;
597 }
598
599 fs_handle_put_fd(handle);
600 }
601 }
602 skip_write:
603 ok(write_success, "Wrote reference string to %d files",
604 files_to_create);
605 ok(fd_cap_respected, "FD tracker enforced the file descriptor cap");
606
607 /* Validate the contents of the files. */
608 for (handle_index = 0; handle_index < files_to_create; handle_index++) {
609 struct stat fd_stat;
610 const char *path = output_files[handle_index];
611 char read_buf[sizeof(file_contents)];
612 char *read_pos;
613 size_t to_read = sizeof(read_buf);
614 int fd;
615
616 fd = open(path, O_RDONLY);
617 assert(fd >= 0);
618 ret = fstat(fd, &fd_stat);
619 assert(!ret);
620 if (fd_stat.st_size != sizeof(file_contents)) {
621 diag("Content size of file %s doesn't match, got %" PRId64 ", expected %zu",
622 path, (int64_t) fd_stat.st_size,
623 sizeof(file_contents));
624 content_ok = false;
625 (void) close(fd);
626 break;
627 }
628
629 read_pos = read_buf;
630 do {
631 ret = read(fd, read_pos, to_read);
632 if (ret > 0) {
633 to_read -= ret;
634 read_pos += ret;
635 }
636 } while (to_read && (ret < 0 && errno == EINTR));
637 if (ret < 0) {
638 content_ok = false;
639 PERROR("Failed to read file %s", path);
640 (void) close(fd);
641 break;
642 }
643
644 if (strcmp(file_contents, read_buf)) {
645 content_ok = false;
646 diag("File content doesn't match the expectated string");
647 (void) close(fd);
648 break;
649 }
650 (void) close(fd);
651 }
652 ok(content_ok, "Files contain the expected content");
653 ret = cleanup_files(tracker, output_dir, files_to_create, handles,
654 output_files);
655 ok(!ret, "Close all opened filesystem handles");
656 (void) rmdir(output_dir);
657 fd_tracker_destroy(tracker);
658 }
659
660 static
661 void test_unlink(void)
662 {
663 int ret;
664 struct fd_tracker *tracker;
665 const int handles_to_open = 2;
666 char tmp_path_pattern[] = TMP_DIR_PATTERN;
667 const char *output_dir;
668 struct fs_handle *handles[handles_to_open];
669 struct fs_handle *new_handle = NULL;
670 char *file_path;
671 char *unlinked_file_path;
672 char *unlinked_file_path_suffix;
673 struct stat statbuf;
674
675 tracker = fd_tracker_create(1);
676 if (!tracker) {
677 return;
678 }
679 output_dir = mkdtemp(tmp_path_pattern);
680 if (!output_dir) {
681 diag("Failed to create temporary path of the form %s",
682 TMP_DIR_PATTERN);
683 return;
684 }
685 ret = asprintf(&file_path, "%s/my_file", output_dir);
686 if (ret < 0) {
687 diag("Failed to allocate path string");
688 return;
689 }
690 ret = asprintf(&unlinked_file_path, "%s-deleted", file_path);
691 if (ret < 0) {
692 diag("Failed to allocate path string");
693 return;
694 }
695 ret = asprintf(&unlinked_file_path_suffix, "%s-1", unlinked_file_path);
696 if (ret < 0) {
697 diag("Failed to allocate path string");
698 return;
699 }
700
701 /* Open two handles to the same file. */
702 ret = open_same_file(tracker, file_path, handles_to_open, handles);
703 ok(!ret, "Successfully %i handles to %s", handles_to_open);
704 if (ret) {
705 return;
706 }
707
708 /*
709 * Unlinking the first handle should cause the file to be renamed
710 * to 'my_file-deleted'.
711 */
712 ret = fs_handle_unlink(handles[0]);
713 ok(!ret, "Successfully unlinked the first handle to %s", file_path);
714
715 /*
716 * The original file should no longer exist on the file system, and a
717 * new file, with the '-deleted' suffix should exist.
718 */
719 ok(stat(file_path, &statbuf) == -1 && errno == ENOENT, "%s no longer present on file system after unlink", file_path);
720 ok(stat(unlinked_file_path, &statbuf) == 0, "%s exists on file system after unlink", unlinked_file_path);
721
722 /* The second unlink should fail with -ENOENT. */
723 ret = fs_handle_unlink(handles[1]);
724 ok(ret == -ENOENT, "ENOENT is reported when attempting to unlink the second handle to %s", file_path);
725
726 /*
727 * Opening a new handle to 'my_file' should succeed.
728 */
729 ret = open_same_file(tracker, file_path, 1, &new_handle);
730 ok(!ret, "Successfully opened a new handle to previously unlinked file %s", file_path);
731 assert(new_handle);
732
733 /*
734 * Unlinking the new handle should cause the file to be renamed
735 * to 'my_file-deleted-1' since 'my_file-deleted' already exists.
736 */
737 ret = fs_handle_unlink(new_handle);
738 ok(!ret, "Successfully unlinked the new handle handle to %s", file_path);
739 ok(stat(unlinked_file_path_suffix, &statbuf) == 0, "%s exists on file system after unlink", unlinked_file_path_suffix);
740
741 ret = fs_handle_close(handles[0]);
742 ok(!ret, "Successfully closed the first handle");
743 ret = fs_handle_close(handles[1]);
744 ok(!ret, "Successfully closed the second handle");
745 ret = fs_handle_close(new_handle);
746 ok(!ret, "Successfully closed the third handle");
747
748 ok(stat(file_path, &statbuf) == -1 && errno == ENOENT, "%s no longer present on file system after handle close", file_path);
749 ok(stat(unlinked_file_path, &statbuf) == -1 && errno == ENOENT, "%s no longer present on file system after handle close", unlinked_file_path);
750 ok(stat(unlinked_file_path_suffix, &statbuf) == -1 && errno == ENOENT, "%s no longer present on file system after handle close", unlinked_file_path_suffix);
751
752 (void) rmdir(output_dir);
753 fd_tracker_destroy(tracker);
754 }
755
756 int main(int argc, char **argv)
757 {
758 plan_tests(NUM_TESTS);
759 diag("File descriptor tracker unit tests");
760
761 rcu_register_thread();
762
763 unknown_fds_count = fd_count() - STDIO_FD_COUNT;
764 assert(unknown_fds_count >= 0);
765
766 diag("Unsuspendable - basic");
767 test_unsuspendable_basic();
768 diag("Unsuspendable - callback return values");
769 test_unsuspendable_cb_return();
770 diag("Unsuspendable - duplicate file descriptors");
771 test_unsuspendable_duplicate();
772 diag("Unsuspendable - closing an untracked file descriptor");
773 test_unsuspendable_close_untracked();
774 diag("Unsuspendable - check that file descritptor limit is enforced");
775 test_unsuspendable_limit();
776
777 diag("Suspendable - check that file descritptor limit is enforced");
778 test_suspendable_limit();
779 diag("Suspendable - restoration test");
780 test_suspendable_restore();
781
782 diag("Mixed - check that file descritptor limit is enforced");
783 test_mixed_limit();
784
785 diag("Suspendable - Unlinking test");
786 test_unlink();
787
788 rcu_unregister_thread();
789 return exit_status();
790 }
This page took 0.046038 seconds and 3 git commands to generate.