[CRIU] [PATCH 2/3] mount: allow to dump content even if a part of fs is overmounted (v3)
Andrey Vagin
avagin at openvz.org
Thu Aug 1 09:17:03 EDT 2013
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 at openvz.org>
---
mount.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 88 insertions(+), 20 deletions(-)
diff --git a/mount.c b/mount.c
index 68965bb..a14269d 100644
--- a/mount.c
+++ b/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;
- }
-
- 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;
+ 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;
+ }
}
- 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;
--
1.8.3.1
More information about the CRIU
mailing list