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

Cyrill Gorcunov gorcunov at gmail.com
Mon Oct 19 09:57:52 PDT 2015


Take a look on attached please.
-------------- next part --------------
>From 0c6ea73b5baf5602fe8d3de756d22294bf5e8a54 Mon Sep 17 00:00:00 2001
From: Cyrill Gorcunov <gorcunov at openvz.org>
Date: Tue, 13 Oct 2015 19:58:22 +0300
Subject: [PATCH] fsnotify: Always provide the path for inotify watchees

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 for tmpfs and devtmps which do not
save inodes between remounts. 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 | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 89 insertions(+), 11 deletions(-)

diff --git a/fsnotify.c b/fsnotify.c
index a7acc9672927..9629977de8bc 100644
--- a/fsnotify.c
+++ b/fsnotify.c
@@ -107,6 +107,90 @@ static int open_by_handle(void *arg, int fd, int pid)
 	return sys_open_by_handle_at(fd, arg, O_PATH);
 }
 
+static char *alloc_openable(unsigned int s_dev, unsigned long i_ino, FhEntry *f_handle)
+{
+	struct mount_info *m;
+	fh_t handle;
+	int fd = -1;
+	char *path;
+
+	decode_handle(&handle, f_handle);
+
+	/*
+	 * We gonna try to open the handle and then
+	 * depending on command line options and type
+	 * of the filesystem (tmpfs/devtmpfs do not
+	 * preserve their inodes between mounts) we
+	 * might need to find out an openable path
+	 * get used on restore as a watch destination.
+	 */
+	for (m = mntinfo; m; m = m->next) {
+		char buf[PATH_MAX], *__path;
+		int mntfd, openable_fd;
+		struct stat st;
+
+		if (m->s_dev != s_dev)
+			continue;
+
+		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(fd);
+			goto err;
+		}
+		close(fd);
+
+		/*
+		 * Convert into a relative path.
+		 */
+		__path = (buf[1] != '\0') ? buf + 1 : ".";
+		pr_debug("\t\t\tlink as %s\n", __path);
+
+		mntfd = mntns_get_root_fd(m->nsid);
+		if (mntfd < 0)
+			goto err;
+
+		openable_fd = openat(mntfd, __path, O_PATH);
+		if (openable_fd >= 0) {
+			if (fstat(openable_fd, &st)) {
+				pr_perror("Can't stat on %s\n", __path);
+				close(openable_fd);
+				return ERR_PTR(-errno);
+			}
+			close(openable_fd);
+
+			pr_debug("\t\t\topenable (inode %s) as %s\n",
+				 st.st_ino == i_ino ?
+				 "match" : "don't match", __path);
+
+			if (st.st_ino == i_ino) {
+				path = xstrdup(buf);
+				if (path == NULL)
+					goto err;
+
+				f_handle->has_mnt_id = true;
+				f_handle->mnt_id = m->mnt_id;
+				return path;
+			}
+		} else
+			pr_debug("\t\t\tnot openable as %s (%m)\n", __path);
+	}
+
+	return ERR_PTR(-ENOENT);
+err:
+	return ERR_PTR(-1);
+}
+
 static int open_handle(unsigned int s_dev, unsigned long i_ino,
 		FhEntry *f_handle)
 {
@@ -160,18 +244,12 @@ int check_open_handle(unsigned int s_dev, unsigned long i_ino,
 		 */
 		if ((mi->fstype->code == FSTYPE__TMPFS) ||
 				(mi->fstype->code == FSTYPE__DEVTMPFS)) {
-			char p[PATH_MAX];
-
-			if (read_fd_link(fd, p, sizeof(p)) < 0)
-				goto err;
-
-			path = xstrdup(p);
-			if (path == NULL)
+			path = alloc_openable(s_dev, i_ino, f_handle);
+			if (IS_ERR_OR_NULL(path)) {
+				pr_err("Can't find suitable path for handle (%d)\n",
+				       (int)PTR_ERR(path));
 				goto err;
-
-			f_handle->has_mnt_id = true;
-			f_handle->mnt_id = mi->mnt_id;
-
+			}
 			goto out;
 		}
 
-- 
2.4.3



More information about the CRIU mailing list