1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
3 #define _GNU_SOURCE
4 #include <stdio.h>
5 #include <sched.h>
6 #include <sys/mount.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <test_progs.h>
10
11 /* TDIR must be in a location we can create a directory in. */
12 #define TDIR "/tmp/test_bpffs_testdir"
13
read_iter(char * file)14 static int read_iter(char *file)
15 {
16 /* 1024 should be enough to get contiguous 4 "iter" letters at some point */
17 char buf[1024];
18 int fd, len;
19
20 fd = open(file, 0);
21 if (fd < 0)
22 return -1;
23 while ((len = read(fd, buf, sizeof(buf))) > 0) {
24 buf[sizeof(buf) - 1] = '\0';
25 if (strstr(buf, "iter")) {
26 close(fd);
27 return 0;
28 }
29 }
30 close(fd);
31 return -1;
32 }
33
fn(void)34 static int fn(void)
35 {
36 struct stat a, b, c;
37 int err, map;
38
39 err = unshare(CLONE_NEWNS);
40 if (!ASSERT_OK(err, "unshare"))
41 goto out;
42
43 err = mount("", "/", "", MS_REC | MS_PRIVATE, NULL);
44 if (!ASSERT_OK(err, "mount /"))
45 goto out;
46
47 err = mkdir(TDIR, 0777);
48 /* If the directory already exists we can carry on. It may be left over
49 * from a previous run.
50 */
51 if ((err && errno != EEXIST) && !ASSERT_OK(err, "mkdir " TDIR))
52 goto out;
53
54 err = mount("none", TDIR, "tmpfs", 0, NULL);
55 if (!ASSERT_OK(err, "mount tmpfs"))
56 goto out;
57
58 err = mkdir(TDIR "/fs1", 0777);
59 if (!ASSERT_OK(err, "mkdir " TDIR "/fs1"))
60 goto out;
61 err = mkdir(TDIR "/fs2", 0777);
62 if (!ASSERT_OK(err, "mkdir " TDIR "/fs2"))
63 goto out;
64
65 err = mount("bpf", TDIR "/fs1", "bpf", 0, NULL);
66 if (!ASSERT_OK(err, "mount bpffs " TDIR "/fs1"))
67 goto out;
68 err = mount("bpf", TDIR "/fs2", "bpf", 0, NULL);
69 if (!ASSERT_OK(err, "mount bpffs " TDIR "/fs2"))
70 goto out;
71
72 err = read_iter(TDIR "/fs1/maps.debug");
73 if (!ASSERT_OK(err, "reading " TDIR "/fs1/maps.debug"))
74 goto out;
75 err = read_iter(TDIR "/fs2/progs.debug");
76 if (!ASSERT_OK(err, "reading " TDIR "/fs2/progs.debug"))
77 goto out;
78
79 err = mkdir(TDIR "/fs1/a", 0777);
80 if (!ASSERT_OK(err, "creating " TDIR "/fs1/a"))
81 goto out;
82 err = mkdir(TDIR "/fs1/a/1", 0777);
83 if (!ASSERT_OK(err, "creating " TDIR "/fs1/a/1"))
84 goto out;
85 err = mkdir(TDIR "/fs1/b", 0777);
86 if (!ASSERT_OK(err, "creating " TDIR "/fs1/b"))
87 goto out;
88
89 map = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 4, 1, NULL);
90 if (!ASSERT_GT(map, 0, "create_map(ARRAY)"))
91 goto out;
92 err = bpf_obj_pin(map, TDIR "/fs1/c");
93 if (!ASSERT_OK(err, "pin map"))
94 goto out;
95 close(map);
96
97 /* Check that RENAME_EXCHANGE works for directories. */
98 err = stat(TDIR "/fs1/a", &a);
99 if (!ASSERT_OK(err, "stat(" TDIR "/fs1/a)"))
100 goto out;
101 err = renameat2(0, TDIR "/fs1/a", 0, TDIR "/fs1/b", RENAME_EXCHANGE);
102 if (!ASSERT_OK(err, "renameat2(/fs1/a, /fs1/b, RENAME_EXCHANGE)"))
103 goto out;
104 err = stat(TDIR "/fs1/b", &b);
105 if (!ASSERT_OK(err, "stat(" TDIR "/fs1/b)"))
106 goto out;
107 if (!ASSERT_EQ(a.st_ino, b.st_ino, "b should have a's inode"))
108 goto out;
109 err = access(TDIR "/fs1/b/1", F_OK);
110 if (!ASSERT_OK(err, "access(" TDIR "/fs1/b/1)"))
111 goto out;
112
113 /* Check that RENAME_EXCHANGE works for mixed file types. */
114 err = stat(TDIR "/fs1/c", &c);
115 if (!ASSERT_OK(err, "stat(" TDIR "/fs1/map)"))
116 goto out;
117 err = renameat2(0, TDIR "/fs1/c", 0, TDIR "/fs1/b", RENAME_EXCHANGE);
118 if (!ASSERT_OK(err, "renameat2(/fs1/c, /fs1/b, RENAME_EXCHANGE)"))
119 goto out;
120 err = stat(TDIR "/fs1/b", &b);
121 if (!ASSERT_OK(err, "stat(" TDIR "/fs1/b)"))
122 goto out;
123 if (!ASSERT_EQ(c.st_ino, b.st_ino, "b should have c's inode"))
124 goto out;
125 err = access(TDIR "/fs1/c/1", F_OK);
126 if (!ASSERT_OK(err, "access(" TDIR "/fs1/c/1)"))
127 goto out;
128
129 /* Check that RENAME_NOREPLACE works. */
130 err = renameat2(0, TDIR "/fs1/b", 0, TDIR "/fs1/a", RENAME_NOREPLACE);
131 if (!ASSERT_ERR(err, "renameat2(RENAME_NOREPLACE)")) {
132 err = -EINVAL;
133 goto out;
134 }
135 err = access(TDIR "/fs1/b", F_OK);
136 if (!ASSERT_OK(err, "access(" TDIR "/fs1/b)"))
137 goto out;
138
139 out:
140 umount(TDIR "/fs1");
141 umount(TDIR "/fs2");
142 rmdir(TDIR "/fs1");
143 rmdir(TDIR "/fs2");
144 umount(TDIR);
145 rmdir(TDIR);
146 exit(err);
147 }
148
test_test_bpffs(void)149 void test_test_bpffs(void)
150 {
151 int err, duration = 0, status = 0;
152 pid_t pid;
153
154 pid = fork();
155 if (CHECK(pid == -1, "clone", "clone failed %d", errno))
156 return;
157 if (pid == 0)
158 fn();
159 err = waitpid(pid, &status, 0);
160 if (CHECK(err == -1 && errno != ECHILD, "waitpid", "failed %d", errno))
161 return;
162 if (CHECK(WEXITSTATUS(status), "bpffs test ", "failed %d", WEXITSTATUS(status)))
163 return;
164 }
165