Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
 22static 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
 50static 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 */
 98static 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
132int 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}