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