d2b3e5
From 27034e7c64b00a1f2467afb5ebb1d5b9b1a06ce1 Mon Sep 17 00:00:00 2001
d2b3e5
From: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
d2b3e5
Date: Wed, 11 Jul 2018 13:43:33 +0300
d2b3e5
Subject: [PATCH] mount: fix regression where open_mountpoint failed on
d2b3e5
 readonly fs
d2b3e5
d2b3e5
If we fail to create temporary directory for doing a clean mount we can
d2b3e5
make mount clean reusing the code which enters new mountns to umount
d2b3e5
overmounts. As when last process exits mntns all mounts are implicitly
d2b3e5
cleaned from children, see in kernel source - sys_exit->do_exit
d2b3e5
->exit_task_namespaces->switch_task_namespaces->free_nsproxy
d2b3e5
->put_mnt_ns->umount_tree->drop_collected_mounts->umount_tree:
d2b3e5
d2b3e5
    /* Hide the mounts from mnt_mounts */
d2b3e5
    list_for_each_entry(p, &tmp_list, mnt_list) {
d2b3e5
            list_del_init(&p->mnt_child);
d2b3e5
    }
d2b3e5
d2b3e5
Fixes commit b6cfb1ce2948 ("mount: make open_mountpoint handle overmouts
d2b3e5
properly")
d2b3e5
d2b3e5
https://github.com/checkpoint-restore/criu/issues/520
d2b3e5
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
d2b3e5
Acked-by: Adrian Reber <areber@redhat.com>
d2b3e5
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
d2b3e5
---
d2b3e5
 criu/mount.c | 28 ++++++++++++++++++++--------
d2b3e5
 1 file changed, 20 insertions(+), 8 deletions(-)
d2b3e5
d2b3e5
diff --git a/criu/mount.c b/criu/mount.c
d2b3e5
index b56164e953..9cc8f6e940 100644
d2b3e5
--- a/criu/mount.c
d2b3e5
+++ b/criu/mount.c
d2b3e5
@@ -1325,10 +1325,18 @@ int ns_open_mountpoint(void *arg)
d2b3e5
 	if (umount_overmounts(mi))
d2b3e5
 		goto err;
d2b3e5
 
d2b3e5
-	/* Save fd which we opened for parent due to CLONE_FILES flag */
d2b3e5
-	*fd = get_clean_fd(mi);
d2b3e5
-	if (*fd < 0)
d2b3e5
+	/*
d2b3e5
+	 * Save fd which we opened for parent due to CLONE_FILES flag
d2b3e5
+	 *
d2b3e5
+	 * Mount can still have children in it, but we don't need to clean it
d2b3e5
+	 * explicitly as when last process exits mntns all mounts in it are
d2b3e5
+	 * cleaned from their children, and we are exactly the last process.
d2b3e5
+	 */
d2b3e5
+	*fd = open(mi->mountpoint, O_DIRECTORY|O_RDONLY);
d2b3e5
+	if (*fd < 0) {
d2b3e5
+		pr_perror("Unable to open %s", mi->mountpoint);
d2b3e5
 		goto err;
d2b3e5
+	}
d2b3e5
 
d2b3e5
 	return 0;
d2b3e5
 err:
d2b3e5
@@ -1367,18 +1375,22 @@ int open_mountpoint(struct mount_info *pm)
d2b3e5
 
d2b3e5
 	if (!mnt_is_overmounted(pm)) {
d2b3e5
 		pr_info("\tmount has children %s\n", pm->mountpoint);
d2b3e5
-
d2b3e5
 		fd = get_clean_fd(pm);
d2b3e5
-		if (fd < 0)
d2b3e5
-			goto err;
d2b3e5
-	} else {
d2b3e5
+	}
d2b3e5
+
d2b3e5
+	/*
d2b3e5
+	 * Mount is overmounted or probably we can't create a temporary
d2b3e5
+	 * direcotry for a cleaned mount
d2b3e5
+	 */
d2b3e5
+	if (fd < 0) {
d2b3e5
 		int pid, status;
d2b3e5
 		struct clone_arg ca = {
d2b3e5
 			.mi = pm,
d2b3e5
 			.fd = &fd
d2b3e5
 		};
d2b3e5
 
d2b3e5
-		pr_info("\tmount is overmounted %s\n", pm->mountpoint);
d2b3e5
+		pr_info("\tmount is overmounted or has children %s\n",
d2b3e5
+				pm->mountpoint);
d2b3e5
 
d2b3e5
 		/*
d2b3e5
 		 * We are overmounted - not accessible in a regular way. We