1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2019 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
6 * Test program to open unlinked files and leak them.
18 #include <sys/types.h>
20 #include <sys/ioctl.h>
23 static int min_fd = -1;
24 static int max_fd = -1;
25 static unsigned int nr_opened = 0;
26 static float start_time;
27 static int shutdown_fd = -1;
29 void clock_time(float *time)
31 static clockid_t clkid = CLOCK_MONOTONIC;
36 ret = clock_gettime(clkid, &ts);
38 if (clkid == CLOCK_MONOTONIC) {
39 clkid = CLOCK_REALTIME;
42 perror("clock_gettime");
45 *time = ts.tv_sec + ((float)ts.tv_nsec / 1000000000);
49 * Exit the program due to an error.
51 * If we've exhausted all the file descriptors, make sure we close all the
52 * open fds in the order we received them in order to exploit a quirk of ext4
53 * and xfs where the oldest unlinked inodes are at the /end/ of the unlinked
54 * lists, which will make removing the unlinked files maximally painful.
56 * If it's some other error, just die and let the kernel sort it out.
67 clock_time(&end_time);
68 printf("Opened %u files in %.2fs.\n", nr_opened,
69 end_time - start_time);
72 if (shutdown_fd >= 0) {
74 * Flush the log so that we have to process the
75 * unlinked inodes the next time we mount.
77 int flag = XFS_FSOP_GOING_FLAGS_LOGFLUSH;
80 ret = ioctl(shutdown_fd, XFS_IOC_GOINGDOWN, &flag);
88 clock_time(&start_time);
89 for (fd = min_fd; fd <= max_fd; fd++)
91 clock_time(&end_time);
92 printf("Closed %u files in %.2fs.\n", nr_opened,
93 end_time - start_time);
103 /* Remember how many file we open and all that. */
104 void remember_fd(int fd)
106 if (min_fd == -1 || min_fd > fd)
108 if (max_fd == -1 || max_fd < fd)
113 /* Put an opened file on the unlinked list and leak the fd. */
114 void leak_tmpfile(void)
119 static int try_o_tmpfile = 1;
122 /* Try to create an O_TMPFILE and leak the fd. */
125 fd = open(".", O_TMPFILE | O_RDWR, 0644);
131 if (errno == EOPNOTSUPP)
139 /* Oh well, create a new file, unlink it, and leak the fd. */
140 fd = open("./moo", O_CREAT | O_RDWR, 0644);
143 ret = unlink("./moo");
150 * Try to put as many files on the unlinked list and then kill them.
151 * The first argument is a directory to chdir into; the second argumennt (if
152 * provided) is a file path that will be opened and then used to shut down the
153 * fs before the program exits.
155 int main(int argc, char *argv[])
160 ret = chdir(argv[1]);
165 shutdown_fd = open(argv[2], O_RDONLY);
166 if (shutdown_fd < 0) {
172 clock_time(&start_time);