mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-29 13:28:27 +00:00
mount: allow to dump content even if a part of fs is overmounted (v3)
for that the mount point is bind-mounted in a temporary place. v2: * check, that the fs you get access to at the end is _really_ the one you wanted to * use switch_ns/restore_ns helpers v3: reuse code of __open_mountpoint and a few small cleanups Signed-off-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
2d631b4562
commit
65d3545945
108
mount.c
108
mount.c
@ -197,47 +197,48 @@ static struct mount_info *mnt_build_tree(struct mount_info *list)
|
||||
return tree;
|
||||
}
|
||||
|
||||
static DIR *open_mountpoint(struct mount_info *pm)
|
||||
/*
|
||||
* mnt_fd is a file descriptor on the mountpoint, which is closed in an error case.
|
||||
* If mnt_fd is -1, the mountpoint will be opened by this function.
|
||||
*/
|
||||
static DIR *__open_mountpoint(struct mount_info *pm, int mnt_fd)
|
||||
{
|
||||
int fd, ret;
|
||||
char path[PATH_MAX + 1];
|
||||
struct stat st;
|
||||
DIR *fdir;
|
||||
int ret;
|
||||
|
||||
if (!list_empty(&pm->children)) {
|
||||
pr_err("Something is mounted on top of %s\n", pm->fstype->name);
|
||||
return NULL;
|
||||
if (mnt_fd == -1) {
|
||||
snprintf(path, sizeof(path), ".%s", pm->mountpoint);
|
||||
mnt_fd = openat(mntns_root, path, O_RDONLY);
|
||||
if (mnt_fd < 0) {
|
||||
pr_perror("Can't open %s", pm->mountpoint);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(path, sizeof(path), ".%s", pm->mountpoint);
|
||||
fd = openat(mntns_root, path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
pr_perror("Can't open %s", pm->mountpoint);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = fstat(fd, &st);
|
||||
ret = fstat(mnt_fd, &st);
|
||||
if (ret < 0) {
|
||||
pr_perror("fstat(%s) failed", path);
|
||||
close(fd);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (st.st_dev != pm->s_dev) {
|
||||
pr_err("The file system %#x %s %s is inaccessible\n",
|
||||
pm->s_dev, pm->fstype->name, pm->mountpoint);
|
||||
close(fd);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fdir = fdopendir(fd);
|
||||
fdir = fdopendir(mnt_fd);
|
||||
if (fdir == NULL) {
|
||||
close(fd);
|
||||
pr_perror("Can't open %s", pm->mountpoint);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return fdir;
|
||||
err:
|
||||
close(mnt_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int close_mountpoint(DIR *dfd)
|
||||
@ -249,6 +250,73 @@ static int close_mountpoint(DIR *dfd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DIR *open_mountpoint(struct mount_info *pm)
|
||||
{
|
||||
int fd = -1, ns_old = -1;
|
||||
char buf[PATH_MAX];
|
||||
char mnt_path[] = "/tmp/cr-tmpfs.XXXXXX";
|
||||
|
||||
/*
|
||||
* If a mount doesn't have children, we can open a mount point,
|
||||
* otherwise we need to create a "private" copy.
|
||||
*/
|
||||
if (list_empty(&pm->children))
|
||||
return __open_mountpoint(pm, -1);
|
||||
|
||||
pr_info("Something is mounted on top of %s\n", pm->mountpoint);
|
||||
|
||||
/*
|
||||
* To create a "private" copy, the target mount is bind-mounted
|
||||
* in a temporary place w/o MS_REC (non-recursively).
|
||||
* A mount point can't be bind-mounted in criu's namespace, it will be
|
||||
* mounted in a target namespace. The sequence of actions is
|
||||
* mkdtemp, setns(tgt), mount, open, detach, setns(old).
|
||||
*/
|
||||
|
||||
if (switch_ns(root_item->pid.real, &mnt_ns_desc, &ns_old) < 0)
|
||||
return NULL;
|
||||
|
||||
if (mkdtemp(mnt_path) == NULL) {
|
||||
pr_perror("Can't create a temporary directory");
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/self/root/%s", pm->mountpoint);
|
||||
if (mount(buf, mnt_path, NULL, MS_BIND, NULL)) {
|
||||
pr_perror("Can't bind-mount %d:%s to %s",
|
||||
pm->mnt_id, pm->mountpoint, mnt_path);
|
||||
rmdir(mnt_path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = open(mnt_path, O_RDONLY | O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
pr_perror("Can't open %s\n", mnt_path);
|
||||
|
||||
if (umount2(mnt_path, MNT_DETACH)) {
|
||||
pr_perror("Can't umount %s", mnt_path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rmdir(mnt_path)) {
|
||||
pr_perror("Can't remove the directory %s", mnt_path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
goto out;
|
||||
|
||||
if (restore_ns(ns_old, &mnt_ns_desc))
|
||||
goto out;
|
||||
|
||||
return __open_mountpoint(pm, fd);;
|
||||
out:
|
||||
if (ns_old >= 0)
|
||||
restore_ns(ns_old, &mnt_ns_desc);
|
||||
close_safe(&fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tmpfs_dump(struct mount_info *pm)
|
||||
{
|
||||
int ret = -1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user