[CRIU] [PATCH 2/2] fsnotify: Always provide the path for inotify watchees

Cyrill Gorcunov gorcunov at openvz.org
Tue Oct 13 11:27:10 PDT 2015


In debian-8 container we faced the problem -- systemd creates nested
mount namespaces and inotify watchee are resolved into a path which
is inaccessbile on restore, the same happens when pathes where
watchees are living are bind-overmounted. Thus when we try to
restore such watchees we can't open the paths.

Lets do a trick here (thanks a huge to Andrew Vagin for idea and
overall help) -- walk over all mount points which device match
the handle's device and open handle first and test if the path
provided is openable as well. After all the inotify objects are
bound to inode so it's irrelevean via which path it's assigned.

https://jira.sw.ru/browse/PSBM-39957

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 fsnotify.c | 83 +++++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 53 insertions(+), 30 deletions(-)

diff --git a/fsnotify.c b/fsnotify.c
index 931e76785b41..ac5f3c857a7e 100644
--- a/fsnotify.c
+++ b/fsnotify.c
@@ -139,53 +139,76 @@ out:
 int check_open_handle(unsigned int s_dev, unsigned long i_ino,
 		FhEntry *f_handle)
 {
+	struct mount_info *m;
+	fh_t handle;
 	int fd = -1;
 	char *path;
 
-	fd = open_handle(s_dev, i_ino, f_handle);
-	if (fd >= 0) {
-		struct mount_info *mi;
+	decode_handle(&handle, f_handle);
+
+	for (m = mntinfo; m; m = m->next) {
+		char buf[PATH_MAX], *__path;
+		int mntfd, new;
 
-		pr_debug("\tHandle 0x%x:0x%lx is openable\n", s_dev, i_ino);
+		if (m->s_dev != s_dev)
+			continue;
 
-		mi = lookup_mnt_sdev(s_dev);
-		if (mi == NULL) {
-			pr_err("Unable to lookup a mount by dev 0x%x\n", s_dev);
-			goto err;
+		mntfd = __open_mountpoint(m, -1);
+		pr_debug("\t\tTrying via mntid %d root %s ns_mountpoint @%s (%d)\n",
+			 m->mnt_id, m->root, m->ns_mountpoint, mntfd);
+		if (mntfd < 0)
+			continue;
+
+		fd = userns_call(open_by_handle, UNS_FDOUT, &handle,
+				 sizeof(handle), mntfd);
+		close(mntfd);
+		if (fd < 0)
+			continue;
+
+		if (read_fd_link(fd, buf, sizeof(buf)) < 0) {
+			close_safe(&fd);
+			continue;
 		}
+		close_safe(&fd);
 
 		/*
-		 * Inode numbers are not restored for tmpfs content, but we can
-		 * get file names, becasue tmpfs cache is not pruned.
+		 * Convert to relative path.
 		 */
-		if ((mi->fstype->code == FSTYPE__TMPFS) ||
-				(mi->fstype->code == FSTYPE__DEVTMPFS)) {
-			char p[PATH_MAX];
+		__path = (buf[1] != '\0') ? buf + 1 : buf;
+		pr_debug("\t\t\tlink as %s\n", __path);
 
-			if (read_fd_link(fd, p, sizeof(p)) < 0)
-				goto err;
+		mntfd = mntns_get_root_by_mnt_id(m->mnt_id);
+		if (mntfd < 0)
+			continue;
 
-			path = xstrdup(p);
+		new = openat(mntfd, __path, O_PATH);
+		close(new);
+
+		if (new >= 0) {
+			pr_debug("\t\t\topenable as %s\n", __path);
+			path = xstrdup(buf);
 			if (path == NULL)
 				goto err;
 
 			f_handle->has_mnt_id = true;
-			f_handle->mnt_id = mi->mnt_id;
-
+			f_handle->mnt_id = m->mnt_id;
 			goto out;
-		}
+		} else
+			pr_debug("\t\t\tnot openable as %s (%m)\n", __path);
+	}
 
-		if (!opts.force_irmap)
-			/*
-			 * If we're not forced to do irmap, then
-			 * say we have no path for watch. Otherwise
-			 * do irmap scan even if the handle is
-			 * working.
-			 *
-			 * FIXME -- no need to open-by-handle if
-			 * we are in force-irmap and not on tempfs
-			 */
-			goto out_nopath;
+	if (!opts.force_irmap) {
+		/*
+		 * If we're not forced to do irmap, then
+		 * say we have no path for watch. Otherwise
+		 * do irmap scan even if the handle is
+		 * working.
+		 *
+		 * FIXME -- no need to open-by-handle if
+		 * we are in force-irmap and not on tempfs
+		 */
+		pr_warn("\tHandle 0x%x:0x%lx cannot be opened\n", s_dev, i_ino);
+		goto out_nopath;
 	}
 
 	pr_warn("\tHandle 0x%x:0x%lx cannot be opened\n", s_dev, i_ino);
-- 
2.4.3



More information about the CRIU mailing list