[CRIU] [PATCH 1/2] mount: support mandatory locked mountpoints
Dmitry Safonov
dsafonov at virtuozzo.com
Tue Jul 12 07:51:29 PDT 2016
To dump mountpoints in namespaces we need to read them.
It's complicated if process took exclusive lock on a file.
In case of binfmt fs will block on read call, in case of
tmpfs tar will return error:
(00.171924) Dumping mountpoints
(00.171930) 53: 23:/ @ ./tmp
(00.171939) Path `/tmp' resolved to `./tmp' mountpoint
tar: ./plop: Read error at byte 0, while reading 4 bytes: Resource temporarily unavailable
tar: Exiting with failure status due to previous errors
(00.174515) Error (util.c:596): exited, status=2
(00.174529) Error (mount.c:1187): Can't dump tmpfs content
I solved this with remounting mountpoint with `nomand` option.
Processes at that moment are freezed, we can dump all interesting
stuff and remount the mountpoint back with `mand` option again.
Cc: Andrey Vagin <avagin at openvz.org>
Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
criu/mount.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
criu/proc_parse.c | 2 +-
2 files changed, 127 insertions(+), 5 deletions(-)
diff --git a/criu/mount.c b/criu/mount.c
index 5c2a252fcf10..c0fc1898f89c 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -30,6 +30,7 @@
#include "sysfs_parse.h"
#include "path.h"
#include "autofs.h"
+#include "string.h"
#include "images/mnt.pb-c.h"
#include "images/binfmt-misc.pb-c.h"
@@ -88,8 +89,6 @@ static void mntinfo_add_list(struct mount_info *new)
}
}
-static int open_mountpoint(struct mount_info *pm);
-
static struct mount_info *mnt_build_tree(struct mount_info *list, struct mount_info *roots_mp);
static int validate_mounts(struct mount_info *info, bool for_dump);
@@ -1052,6 +1051,101 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_
return mnt_path;
}
+static int open_mand_mount(struct mount_info *pm, char *mnt_path)
+{
+ unsigned long remount_flags =
+ (pm->flags | pm->sb_flags | MS_REMOUNT) & ~MS_MANDLOCK;
+ size_t mnt_len = strlen(mnt_path) + 1;
+ int fd;
+
+ if (mount(NULL, mnt_path, NULL, remount_flags, NULL)) {
+ pr_perror("Can't remount with `nomad` %s", mnt_path);
+ goto err_rmdir;
+ }
+
+ fd = open(mnt_path, O_RDONLY | O_DIRECTORY, 0);
+ if (fd < 0) {
+ pr_perror("Can't open directory %s: %d", mnt_path, fd);
+ goto err_umount;
+ }
+
+ pm->ns_mountpoint = xmalloc(mnt_len);
+ if (!pm->ns_mountpoint) {
+ pr_err("Failed to allocate ns_mountpoint for temp nomad mount\n");
+ goto err_close;
+ }
+ strlcpy(pm->ns_mountpoint, mnt_path, mnt_len);
+
+ return fd;
+
+err_close:
+ close_safe(&fd);
+err_umount:
+ if (umount2(mnt_path, MNT_DETACH))
+ pr_perror("Can't detach mount %s", mnt_path);
+err_rmdir:
+ if (rmdir(mnt_path))
+ pr_perror("Can't remove tmp dir %s", mnt_path);
+ return -1;
+}
+
+static int close_mountpoint(struct mount_info *pm)
+{
+ int cwd_fd;
+ int ns_old = -1;
+ unsigned long remount_flags = pm->flags | pm->sb_flags | MS_REMOUNT;
+
+ if (!(pm->sb_flags & MS_MANDLOCK))
+ return 0;
+
+ cwd_fd = open(".", O_DIRECTORY);
+ if (cwd_fd < 0) {
+ pr_perror("Unable to open cwd");
+ return -1;
+ }
+
+ if (switch_ns(pm->nsid->ns_pid, &mnt_ns_desc, &ns_old) < 0)
+ goto err_close;
+
+ if (mount(NULL, pm->ns_mountpoint, NULL, remount_flags, NULL)) {
+ pr_perror("Can't remount with `mad` %s", pm->ns_mountpoint);
+ goto err_restore_ns;
+ }
+
+ if (umount2(pm->ns_mountpoint, MNT_DETACH)) {
+ pr_perror("Can't detach mount %s", pm->ns_mountpoint);
+ goto err_restore_ns;
+ }
+
+ if (rmdir(pm->ns_mountpoint)) {
+ pr_perror("Can't remove tmp dir %s", pm->ns_mountpoint);
+ goto err_restore_ns;
+ }
+
+ if (restore_ns(ns_old, &mnt_ns_desc)) {
+ ns_old = -1;
+ goto err_restore_ns;
+ }
+ if (fchdir(cwd_fd)) {
+ pr_perror("Unable to restore cwd");
+ goto err_close;
+ }
+ xfree(pm->ns_mountpoint);
+ pm->ns_mountpoint = pm->mountpoint;
+ return 0;
+
+err_restore_ns:
+ if (ns_old >= 0)
+ restore_ns(ns_old, &mnt_ns_desc);
+ if (fchdir(cwd_fd))
+ pr_perror("Unable to restore cwd");
+err_close:
+ close(cwd_fd);
+ xfree(pm->ns_mountpoint);
+ pm->ns_mountpoint = pm->mountpoint;
+ return -1;
+}
+
#define MNT_UNREACHABLE INT_MIN
static int open_mountpoint(struct mount_info *pm)
{
@@ -1065,8 +1159,10 @@ static int open_mountpoint(struct mount_info *pm)
/*
* If a mount doesn't have children, we can open a mount point,
* otherwise we need to create a "private" copy.
+ * For mandatory mounts, we need temporary bind-mount without
+ * MS_MANDLOCK, so we could dump mountpoint contents.
*/
- if (list_empty(&pm->children))
+ if (list_empty(&pm->children) && !(pm->sb_flags & MS_MANDLOCK))
return __open_mountpoint(pm, -1);
pr_info("Something is mounted on top of %s\n", pm->mountpoint);
@@ -1099,7 +1195,17 @@ static int open_mountpoint(struct mount_info *pm)
if (mnt_path == NULL)
goto out;
- fd = open_detach_mount(mnt_path);
+ /*
+ * We don't umount, rmdir on temporary mapping in case of
+ * mandatory locking mount. This is done in close_mountpoint().
+ * The reason -- we temporary remount it with `nomand`, so
+ * the caller of open_mountpoint() could read/dump content
+ * even if it's under exclusive locks.
+ */
+ if (pm->sb_flags & MS_MANDLOCK)
+ fd = open_mand_mount(pm, mnt_path);
+ else
+ fd = open_detach_mount(mnt_path);
if (fd < 0)
goto out;
@@ -1111,6 +1217,8 @@ static int open_mountpoint(struct mount_info *pm)
pr_perror("Unable to restore cwd");
close(cwd_fd);
close(fd);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
return -1;
}
close(cwd_fd);
@@ -1123,6 +1231,8 @@ out:
if (fchdir(cwd_fd))
pr_perror("Unable to restore cwd");
close(cwd_fd);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
return -1;
}
@@ -1201,6 +1311,8 @@ static int tmpfs_dump(struct mount_info *pm)
close_image(img);
out:
close_safe(&fd);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
return ret;
}
@@ -1376,6 +1488,8 @@ static int binfmt_misc_dump(struct mount_info *pm)
fdir = fdopendir(fd);
if (fdir == NULL) {
close(fd);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
return -1;
}
@@ -1401,6 +1515,8 @@ out:
if (img)
close_image(img);
closedir(fdir);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
return ret;
}
@@ -1547,6 +1663,8 @@ static int fusectl_dump(struct mount_info *pm)
fdir = fdopendir(fd);
if (fdir == NULL) {
close(fd);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
return -1;
}
@@ -1574,6 +1692,8 @@ static int fusectl_dump(struct mount_info *pm)
ret = 0;
out:
closedir(fdir);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
return ret;
}
@@ -1619,6 +1739,8 @@ static int dump_empty_fs(struct mount_info *pm)
ret = is_empty_dir(fd);
close(fd);
+ if (close_mountpoint(pm))
+ pr_err("Can't close mountpoint %s\n", pm->mountpoint);
if (ret < 0) {
pr_err("%s isn't empty\n", pm->fstype->name);
return -1;
diff --git a/criu/proc_parse.c b/criu/proc_parse.c
index c25077d181b7..5583e75ecf1c 100644
--- a/criu/proc_parse.c
+++ b/criu/proc_parse.c
@@ -1182,7 +1182,7 @@ static int parse_sb_opt(char *opt, unsigned *flags, char *uopt)
{ "ro", MS_RDONLY, },
{ "sync", MS_SYNC, },
{ "dirsync", MS_DIRSYNC, },
- { "mad", MS_MANDLOCK, },
+ { "mand", MS_MANDLOCK, },
{ },
};
--
2.9.0
More information about the CRIU
mailing list