Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c
26302 views
1
// SPDX-License-Identifier: GPL-2.0
2
#define _GNU_SOURCE
3
#define __SANE_USERSPACE_TYPES__ // Use ll64
4
5
#include <inttypes.h>
6
#include <unistd.h>
7
#include <stdio.h>
8
9
#include <linux/unistd.h>
10
#include <linux/types.h>
11
#include <linux/mount.h>
12
#include <sys/syscall.h>
13
#include <sys/stat.h>
14
#include <sys/mman.h>
15
#include <sched.h>
16
#include <fcntl.h>
17
18
#include "../../kselftest.h"
19
#include "log.h"
20
#include "../wrappers.h"
21
22
static long get_file_dev_and_inode(void *addr, struct statx *stx)
23
{
24
char buf[4096];
25
FILE *mapf;
26
27
mapf = fopen("/proc/self/maps", "r");
28
if (mapf == NULL)
29
return pr_perror("fopen(/proc/self/maps)");
30
31
while (fgets(buf, sizeof(buf), mapf)) {
32
unsigned long start, end;
33
uint32_t maj, min;
34
__u64 ino;
35
36
if (sscanf(buf, "%lx-%lx %*s %*s %x:%x %llu",
37
&start, &end, &maj, &min, &ino) != 5)
38
return pr_perror("unable to parse: %s", buf);
39
if (start == (unsigned long)addr) {
40
stx->stx_dev_major = maj;
41
stx->stx_dev_minor = min;
42
stx->stx_ino = ino;
43
return 0;
44
}
45
}
46
47
return pr_err("unable to find the mapping");
48
}
49
50
static int ovl_mount(void)
51
{
52
int tmpfs, fsfd, ovl;
53
54
fsfd = sys_fsopen("tmpfs", 0);
55
if (fsfd == -1)
56
return pr_perror("fsopen(tmpfs)");
57
58
if (sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) == -1)
59
return pr_perror("FSCONFIG_CMD_CREATE");
60
61
tmpfs = sys_fsmount(fsfd, 0, 0);
62
if (tmpfs == -1)
63
return pr_perror("fsmount");
64
65
close(fsfd);
66
67
/* overlayfs can't be constructed on top of a detached mount. */
68
if (sys_move_mount(tmpfs, "", AT_FDCWD, "/tmp", MOVE_MOUNT_F_EMPTY_PATH))
69
return pr_perror("move_mount");
70
close(tmpfs);
71
72
if (mkdir("/tmp/w", 0755) == -1 ||
73
mkdir("/tmp/u", 0755) == -1 ||
74
mkdir("/tmp/l", 0755) == -1)
75
return pr_perror("mkdir");
76
77
fsfd = sys_fsopen("overlay", 0);
78
if (fsfd == -1)
79
return pr_perror("fsopen(overlay)");
80
if (sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "test", 0) == -1 ||
81
sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "lowerdir", "/tmp/l", 0) == -1 ||
82
sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "upperdir", "/tmp/u", 0) == -1 ||
83
sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "workdir", "/tmp/w", 0) == -1)
84
return pr_perror("fsconfig");
85
if (sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) == -1)
86
return pr_perror("fsconfig");
87
ovl = sys_fsmount(fsfd, 0, 0);
88
if (ovl == -1)
89
return pr_perror("fsmount");
90
91
return ovl;
92
}
93
94
/*
95
* Check that the file device and inode shown in /proc/pid/maps match values
96
* returned by stat(2).
97
*/
98
static int test(void)
99
{
100
struct statx stx, mstx;
101
int ovl, fd;
102
void *addr;
103
104
ovl = ovl_mount();
105
if (ovl == -1)
106
return -1;
107
108
fd = openat(ovl, "test", O_RDWR | O_CREAT, 0644);
109
if (fd == -1)
110
return pr_perror("openat");
111
112
addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);
113
if (addr == MAP_FAILED)
114
return pr_perror("mmap");
115
116
if (get_file_dev_and_inode(addr, &mstx))
117
return -1;
118
if (statx(fd, "", AT_EMPTY_PATH | AT_STATX_SYNC_AS_STAT, STATX_INO, &stx))
119
return pr_perror("statx");
120
121
if (stx.stx_dev_major != mstx.stx_dev_major ||
122
stx.stx_dev_minor != mstx.stx_dev_minor ||
123
stx.stx_ino != mstx.stx_ino)
124
return pr_fail("unmatched dev:ino %x:%x:%llx (expected %x:%x:%llx)\n",
125
mstx.stx_dev_major, mstx.stx_dev_minor, mstx.stx_ino,
126
stx.stx_dev_major, stx.stx_dev_minor, stx.stx_ino);
127
128
ksft_test_result_pass("devices are matched\n");
129
return 0;
130
}
131
132
int main(int argc, char **argv)
133
{
134
int fsfd;
135
136
fsfd = sys_fsopen("overlay", 0);
137
if (fsfd == -1) {
138
ksft_test_result_skip("unable to create overlay mount\n");
139
return 1;
140
}
141
close(fsfd);
142
143
/* Create a new mount namespace to not care about cleaning test mounts. */
144
if (unshare(CLONE_NEWNS) == -1) {
145
ksft_test_result_skip("unable to create a new mount namespace\n");
146
return 1;
147
}
148
if (sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) == -1) {
149
pr_perror("mount");
150
return 1;
151
}
152
153
ksft_set_plan(1);
154
155
if (test())
156
return 1;
157
158
ksft_exit_pass();
159
return 0;
160
}
161
162