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