mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-18 09:05:10 +00:00
Acked-by: Mike Rapoport <rppt@linux.ibm.com> Signed-off-by: Adrian Reber <areber@redhat.com>
303 lines
7.5 KiB
C
303 lines
7.5 KiB
C
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/stat.h>
|
|
#include <sched.h>
|
|
#include <sys/wait.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "zdtmtst.h"
|
|
|
|
const char *test_doc = "Check that mountpoints (in mount namespace) are supported";
|
|
const char *test_author = "Pavel Emelianov <xemul@parallels.com>";
|
|
|
|
#define MPTS_ROOT "/zdtm_mpts/"
|
|
|
|
#define NS_STACK_SIZE 4096
|
|
/* All arguments should be above stack, because it grows down */
|
|
struct ns_exec_args {
|
|
char stack[NS_STACK_SIZE] __stack_aligned__;
|
|
char stack_ptr[0];
|
|
int status_pipe[2];
|
|
};
|
|
|
|
task_waiter_t t;
|
|
|
|
int ns_child(void *_arg)
|
|
{
|
|
struct stat st;
|
|
pid_t pid;
|
|
int fd, ufd;
|
|
|
|
mkdir(MPTS_ROOT "/dev/mntns2", 0600);
|
|
if (mount("none", MPTS_ROOT "/dev/mntns2", "tmpfs", 0, "") < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
|
|
mkdir(MPTS_ROOT "/dev/mntns2/test", 0600);
|
|
|
|
fd = open(MPTS_ROOT "/dev/mntns2/test/test.file", O_WRONLY | O_CREAT, 0666);
|
|
if (fd < 0)
|
|
return 1;
|
|
|
|
ufd = open(MPTS_ROOT "/dev/mntns2/test/test.file.unlinked", O_WRONLY | O_CREAT, 0666);
|
|
if (ufd < 0)
|
|
return 1;
|
|
unlink(MPTS_ROOT "/dev/mntns2/test/test.file.unlinked");
|
|
|
|
pid = fork();
|
|
|
|
task_waiter_complete(&t, 1);
|
|
|
|
test_waitsig();
|
|
|
|
if (pid) {
|
|
int status = 1;
|
|
kill(pid, SIGTERM);
|
|
wait(&status);
|
|
if (status)
|
|
return 1;
|
|
}
|
|
|
|
if (stat(MPTS_ROOT "/dev/mntns2/test", &st)) {
|
|
pr_perror("Can't stat /dev/share-1/test.share/test.share");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int fd, tmpfs_fd, have_bfmtm = 0;
|
|
struct ns_exec_args args;
|
|
pid_t pid = -1;
|
|
|
|
test_init(argc, argv);
|
|
|
|
task_waiter_init(&t);
|
|
|
|
rmdir(MPTS_ROOT);
|
|
if (mkdir(MPTS_ROOT, 0600) < 0) {
|
|
fail("Can't make zdtm_sys");
|
|
return 1;
|
|
}
|
|
|
|
if (mount("none", MPTS_ROOT, "sysfs", 0, "") < 0) {
|
|
fail("Can't mount sysfs");
|
|
return 1;
|
|
}
|
|
|
|
if (mount("none", MPTS_ROOT "/dev", "tmpfs", 0, "") < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
tmpfs_fd = open(MPTS_ROOT "/dev/test", O_WRONLY | O_CREAT);
|
|
if (write(tmpfs_fd, "hello", 5) <= 0) {
|
|
pr_perror("write() failed");
|
|
return 1;
|
|
}
|
|
|
|
/* Check that over-mounted files are restored on tmpfs */
|
|
mkdir(MPTS_ROOT "/dev/overmount", 0600);
|
|
fd = open(MPTS_ROOT "/dev/overmount/test.over", O_WRONLY | O_CREAT);
|
|
if (fd == -1) {
|
|
pr_perror("Unable to open " MPTS_ROOT "/dev/overmount");
|
|
return -1;
|
|
}
|
|
close(fd);
|
|
if (mount("none", MPTS_ROOT "/dev/overmount", "tmpfs", 0, "") < 0) {
|
|
pr_perror("Can't mount " MPTS_ROOT "/dev/overmount");
|
|
return 1;
|
|
}
|
|
|
|
mkdir(MPTS_ROOT "/dev/non-root", 0600);
|
|
if (mount(MPTS_ROOT "/dev/non-root", MPTS_ROOT "/module", NULL, MS_BIND, NULL) < 0) {
|
|
pr_perror("Can't bind-mount %s -> %s", MPTS_ROOT "/dev/tdir", MPTS_ROOT "/module");
|
|
}
|
|
mkdir(MPTS_ROOT "/dev/non-root/test", 0600);
|
|
|
|
mkdir(MPTS_ROOT "/dev/share-1", 0600);
|
|
if (mount("none", MPTS_ROOT "/dev/share-1/", "tmpfs", 0, "") < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
if (mount("none", MPTS_ROOT "/dev/share-1/", NULL, MS_SHARED, NULL) < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
|
|
//#define CR_NEXT
|
|
#ifdef CR_NEXT
|
|
mkdir(MPTS_ROOT "/dev/share-1/alone", 0600);
|
|
if (mount("none", MPTS_ROOT "/dev/share-1/alone", "tmpfs", 0, "") < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
mkdir(MPTS_ROOT "/dev/share-2", 0600);
|
|
if (mount(MPTS_ROOT "/dev/share-1", MPTS_ROOT "/dev/share-2", NULL, MS_BIND, NULL) < 0) {
|
|
fail("Can't bind mount a tmpfs directory");
|
|
return 1;
|
|
}
|
|
|
|
mkdir(MPTS_ROOT "/dev/share-3", 0600);
|
|
if (mount(MPTS_ROOT "/dev/share-1", MPTS_ROOT "/dev/share-3", NULL, MS_BIND, NULL) < 0) {
|
|
fail("Can't bind mount a tmpfs directory");
|
|
return 1;
|
|
}
|
|
mkdir(MPTS_ROOT "/dev/slave", 0600);
|
|
if (mount(MPTS_ROOT "/dev/share-1", MPTS_ROOT "/dev/slave", NULL, MS_BIND, NULL) < 0) {
|
|
fail("Can't bind mount a tmpfs directory");
|
|
return 1;
|
|
}
|
|
if (mount("none", MPTS_ROOT "/dev/slave", NULL, MS_SLAVE, NULL) < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
|
|
mkdir(MPTS_ROOT "/dev/slave2", 0600);
|
|
if (mount(MPTS_ROOT "/dev/share-3", MPTS_ROOT "/dev/slave2", NULL, MS_BIND, NULL) < 0) {
|
|
fail("Can't bind mount a tmpfs directory");
|
|
return 1;
|
|
}
|
|
if (mount("none", MPTS_ROOT "/dev/slave2", NULL, MS_SLAVE, NULL) < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
|
|
mkdir(MPTS_ROOT "/dev/share-1/test.mnt.share", 0600);
|
|
if (mount("none", MPTS_ROOT "/dev/share-1/test.mnt.share", "tmpfs", 0, "size=1G") < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
|
|
mkdir(MPTS_ROOT "/dev/share-1/test.mnt.share/test.share", 0600);
|
|
if (umount(MPTS_ROOT "/dev/slave2/test.mnt.share")) {
|
|
pr_perror("Can't umount " MPTS_ROOT "/dev/slave2/test.mnt.share");
|
|
return 1;
|
|
}
|
|
|
|
mkdir(MPTS_ROOT "/dev/slave/test.mnt.slave", 0600);
|
|
if (mount("none", MPTS_ROOT "/dev/slave/test.mnt.slave", "tmpfs", 0, "") < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
mkdir(MPTS_ROOT "/dev/slave/test.mnt.slave/test.slave", 0600);
|
|
|
|
fd = open(MPTS_ROOT "/dev/bmfile", O_CREAT | O_WRONLY);
|
|
if (fd < 0) {
|
|
pr_perror("Can't create " MPTS_ROOT "/dev/share-1/bmfile");
|
|
return 1;
|
|
}
|
|
close(fd);
|
|
|
|
fd = open(MPTS_ROOT "/dev/bmfile-mount", O_CREAT | O_WRONLY);
|
|
if (fd < 0) {
|
|
pr_perror("Can't create " MPTS_ROOT "/dev/share-1/bmfile");
|
|
return 1;
|
|
}
|
|
close(fd);
|
|
|
|
if (mount(MPTS_ROOT "/dev/bmfile", MPTS_ROOT "/dev/bmfile-mount", NULL, MS_BIND, NULL) < 0) {
|
|
fail("Can't mount tmpfs");
|
|
return 1;
|
|
}
|
|
|
|
if (mount("none", MPTS_ROOT "/kernel", "proc", 0, "") < 0) {
|
|
fail("Can't mount proc");
|
|
return 1;
|
|
}
|
|
|
|
if (mount("none", MPTS_ROOT "/kernel/sys/fs/binfmt_misc", "binfmt_misc", 0, "") == 0)
|
|
have_bfmtm = 1;
|
|
|
|
fd = open(MPTS_ROOT "/kernel/meminfo", O_RDONLY);
|
|
if (fd == -1)
|
|
return 1;
|
|
|
|
if (getenv("ZDTM_NOSUBNS") == NULL) {
|
|
pid = clone(ns_child, args.stack_ptr, CLONE_NEWNS | SIGCHLD, &args);
|
|
if (pid < 0) {
|
|
pr_perror("Unable to fork child");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
task_waiter_wait4(&t, 1);
|
|
|
|
test_daemon();
|
|
test_waitsig();
|
|
|
|
/* this checks both -- sys and proc presence */
|
|
if (access(MPTS_ROOT "/kernel/meminfo", F_OK)) {
|
|
fail("No proc after restore");
|
|
return 1;
|
|
}
|
|
|
|
if (have_bfmtm && access(MPTS_ROOT "/kernel/sys/fs/binfmt_misc/register", F_OK)) {
|
|
fail("No binfmt_misc after restore");
|
|
return 1;
|
|
}
|
|
|
|
if (umount(MPTS_ROOT "/dev/overmount") == -1) {
|
|
pr_perror("Can't umount " MPTS_ROOT "/dev/overmount");
|
|
return -1;
|
|
}
|
|
if (access(MPTS_ROOT "/dev/overmount/test.over", F_OK)) {
|
|
fail(MPTS_ROOT "/dev/overmount/test.over");
|
|
return -1;
|
|
}
|
|
|
|
{
|
|
struct stat st1, st2;
|
|
if (stat(MPTS_ROOT "/dev/share-1/test.mnt.share/test.share", &st1)) {
|
|
pr_perror("Can't stat /dev/share-1/test.share/test.share");
|
|
return 1;
|
|
}
|
|
if (stat(MPTS_ROOT "/dev/share-2/test.mnt.share/test.share", &st2)) {
|
|
pr_perror("Can't stat /dev/share-2/test.mnt.share/test.share");
|
|
return 1;
|
|
}
|
|
if (st1.st_ino != st2.st_ino) {
|
|
fail("/dev/share-1 and /dev/share-1 is not shared");
|
|
return 1;
|
|
}
|
|
if (stat(MPTS_ROOT "/dev/slave/test.mnt.share/test.share", &st2)) {
|
|
pr_perror("Can't stat /dev/slave/test.mnt.share/test.share");
|
|
return 1;
|
|
}
|
|
if (st1.st_ino != st2.st_ino) {
|
|
fail("/dev/slave is not slave of /dev/share-1");
|
|
return 1;
|
|
}
|
|
if (stat(MPTS_ROOT "/dev/share-1/test.mnt.slave/test.slave", &st1) != -1 || errno != ENOENT) {
|
|
pr_perror("/dev/share-1/test.mnt.slave/test.slave exists");
|
|
return 1;
|
|
}
|
|
if (stat(MPTS_ROOT "/dev/slave/test.mnt.slave/test.slave", &st2)) {
|
|
pr_perror("Can't stat /dev/slave/test.mnt.slave/test.slave");
|
|
return 1;
|
|
}
|
|
if (stat(MPTS_ROOT "/dev/non-root/test", &st1)) {
|
|
pr_perror("Can't stat /dev/non-root/test");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (pid > 0) {
|
|
int status = 1;
|
|
kill(pid, SIGTERM);
|
|
wait(&status);
|
|
if (status)
|
|
return 1;
|
|
}
|
|
|
|
pass();
|
|
return 0;
|
|
}
|