[09/15] tty: Add helpers to resolve mnt_id on peers

Submitted by Cyrill Gorcunov on Sept. 7, 2018, 4:18 p.m.

Details

Message ID 20180907161836.25738-10-gorcunov@gmail.com
State New
Series "tty: Add support for multiple devtps instances"
Headers show

Commit Message

Cyrill Gorcunov Sept. 7, 2018, 4:18 p.m.
These helpers will be needed to resolve devpts mounts
thus each instance will have own peer tracking. The
patch is preparatory.

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 criu/include/mount.h |  2 +
 criu/include/util.h  | 14 +++++++
 criu/mount.c         | 99 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 115 insertions(+)

Patch hide | download patch | download mbox

diff --git a/criu/include/mount.h b/criu/include/mount.h
index ca17b059afc5..ddc111ee5546 100644
--- a/criu/include/mount.h
+++ b/criu/include/mount.h
@@ -107,6 +107,8 @@  extern struct mount_info *lookup_mnt_sdev(unsigned int s_dev);
 extern dev_t phys_stat_resolve_dev(struct ns_id *, dev_t st_dev, const char *path);
 extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev,
 				struct ns_id *, const char *path);
+extern struct mount_info *lookup_first_fstype(int code);
+extern int mount_resolve_devpts_mnt_id(const char *path, int mnt_id, int s_dev);
 
 extern int restore_task_mnt_ns(struct pstree_item *current);
 extern void fini_restore_mntns(void);
diff --git a/criu/include/util.h b/criu/include/util.h
index 5c18e69f793d..674fc76da72d 100644
--- a/criu/include/util.h
+++ b/criu/include/util.h
@@ -252,6 +252,20 @@  static inline bool issubpath(const char *path, const char *sub_path)
 		(end == '/' || end == '\0');
 }
 
+/*
+ * Check if @str ends with @sfx
+ */
+static inline bool issuffix(const char *str, const char *sfx)
+{
+	if (str && sfx) {
+		size_t str_len = strlen(str);
+		size_t sfx_len = strlen(sfx);
+		if (sfx_len <= str_len)
+			return !strcmp(&str[str_len-sfx_len], sfx);
+	}
+	return false;
+}
+
 /*
  * mkdir -p
  */
diff --git a/criu/mount.c b/criu/mount.c
index d95e60334148..739b3bbbcecd 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -289,6 +289,105 @@  bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev,
 	return phys_dev == phys_stat_resolve_dev(ns, st_dev, path);
 }
 
+struct mount_info *lookup_first_fstype(int code)
+{
+	struct mount_info *m;
+
+	for (m = mntinfo; m != NULL; m = m->next) {
+		if (m->fstype->code == code &&
+		    is_root(m->root))
+			return m;
+	}
+	return NULL;
+}
+
+static struct mount_info *lookup_mnt_sdev_on_root(unsigned int s_dev)
+{
+	struct mount_info *m;
+
+	for (m = mntinfo; m != NULL; m = m->next) {
+		if (kdev_to_odev(m->s_dev) == s_dev &&
+		    is_root(m->root))
+			return m;
+	}
+	return NULL;
+}
+
+/*
+ * Figuring out mount id is a bit tricky for PTYs: when
+ * several devpts mounted they have own superblocks
+ * thus opening /dev/<dirs>/ptmx leads to slave
+ * peers lay into /dev/<dirs>/0 and etc, but the
+ * exception is toplevel /dev/ptmx, when opened the
+ * kernel lookups for first "pts" downlevel directory mounted
+ * at /dev/pts (which of course must have DEVPTS_SUPER_MAGIC
+ * in properties). It's done for backward compatibility,
+ * see drivers/tty/pty.c:ptmx_open.
+ */
+int mount_resolve_devpts_mnt_id(const char *path, int mnt_id, int s_dev)
+{
+	struct mount_info *mi = NULL;
+	char *base = basename(path);
+
+	pr_debug("tty: resolving path %s mnt_id %d s_dev %#x\n", path, mnt_id, s_dev);
+
+	if (mnt_id != -1)
+		mi = lookup_mnt_id(mnt_id);
+	if (!mi) {
+		mi = lookup_mnt_sdev_on_root(s_dev);
+		if (!mi) {
+			pr_err("tty: No devpts mount point found for s_dev %#x\n", s_dev);
+			return -1;
+		}
+	}
+
+	pr_debug("tty: pre-resolved path %s to mnt_id %d root %s ns_mountpoint %s source %s fstype %s %d\n",
+		 path, mi->mnt_id, mi->root, mi->ns_mountpoint, mi->source,
+		 mi->fstype->name, mi->fstype->code);
+
+	/*
+	 * A special case: bindmounted ptmx, need to walk up to
+	 * a parent which most probably gonna be / where devtmps
+	 * sits.
+	 */
+	while (mi && issuffix(mi->ns_mountpoint, base)) {
+		pr_debug("tty: bindmount on mnt_id %d root %s ns_mountpoint %s source %s fstype %s %d\n",
+			 mi->mnt_id, mi->root, mi->ns_mountpoint, mi->source, mi->fstype->name, mi->fstype->code);
+		mi = mi->parent;
+		if (!mi) {
+			pr_err("tty: No devpts mount point found for s_dev %#x as a parent\n", s_dev);
+			return -1;
+		}
+	}
+
+	if (mi->fstype->code == FSTYPE__DEVPTS) {
+		pr_debug("tty: resolved path %s to mnt_id %d root %s ns_mountpoint %s source %s fstype %s %d\n",
+			 path, mi->mnt_id, mi->root, mi->ns_mountpoint, mi->source,
+			 mi->fstype->name, mi->fstype->code);
+		return mi->mnt_id;
+	} else if (mi->fstype->code == FSTYPE__DEVTMPFS) {
+		char ptmx_path[PATH_MAX];
+
+		snprintf(ptmx_path, sizeof(ptmx_path), "%s/pts/ptmx", mi->ns_mountpoint + 1);
+		pr_debug("tty: devtmps detected, try resolve as %s\n", ptmx_path);
+
+		mi = mount_resolve_path(mi, ptmx_path);
+		if (!mi) {
+			pr_err("tty: Can't resolve %s\n", ptmx_path);
+			return -1;
+		}
+		if (mi->fstype->code == FSTYPE__DEVPTS) {
+			pr_debug("tty: resolved updated path %s to mnt_id %d root %s ns_mountpoint %s source %s fstype %s %d\n",
+				 ptmx_path, mi->mnt_id, mi->root, mi->ns_mountpoint, mi->source,
+				 mi->fstype->name, mi->fstype->code);
+			return mi->mnt_id;
+		}
+	}
+
+	pr_err("tty: Can't resolve devpts for s_dev %#x\n", s_dev);
+	return -1;
+}
+
 /*
  * Compare super-blocks mounted at two places
  */