[Devel] [PATCH rh7 6/6] devtmpfs: lightweight virtualization

Vladimir Davydov vdavydov at parallels.com
Thu Jul 23 08:10:03 PDT 2015


All this patch does is provides each VE with its own empty single tmpfs
mount, which appears on an attempt to mount "devtmpfs". It's up to the
userspace to populate this fs on container start, all kernel requests to
create a device node inside a VE are ignored.

Signed-off-by: Vladimir Davydov <vdavydov at parallels.com>
---
 drivers/base/devtmpfs.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/ve.h      |  1 +
 kernel/ve/ve.c          |  4 ++++
 3 files changed, 68 insertions(+)

diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index f59b7986ce08..2fdcd2a6bf55 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -23,6 +23,7 @@
 #include <linux/ramfs.h>
 #include <linux/slab.h>
 #include <linux/kthread.h>
+#include <linux/ve.h>
 #include "base.h"
 
 static struct task_struct *thread;
@@ -53,9 +54,61 @@ static int __init mount_param(char *str)
 }
 __setup("devtmpfs.mount=", mount_param);
 
+#ifdef CONFIG_VE
+static int ve_test_dev_sb(struct super_block *s, void *p)
+{
+	return get_exec_env()->dev_sb == s;
+}
+
+static int ve_set_dev_sb(struct super_block *s, void *p)
+{
+	struct ve_struct *ve = get_exec_env();
+	int error;
+
+	error = set_anon_super(s, p);
+	if (!error) {
+		BUG_ON(ve->dev_sb);
+		ve->dev_sb = s;
+		atomic_inc(&s->s_active);
+	}
+	return error;
+}
+
+static struct dentry *ve_dev_mount(struct file_system_type *fs_type, int flags,
+		      const char *dev_name, void *data)
+{
+	int (*fill_super)(struct super_block *, void *, int);
+	struct super_block *s;
+	int error;
+
+#ifdef CONFIG_TMPFS
+	fill_super = shmem_fill_super;
+#else
+	fill_super = ramfs_fill_super;
+#endif
+	s = sget(fs_type, ve_test_dev_sb, ve_set_dev_sb, flags, NULL);
+	if (IS_ERR(s))
+		return ERR_CAST(s);
+
+	if (!s->s_root) {
+		error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+		if (error) {
+			deactivate_locked_super(s);
+			return ERR_PTR(error);
+		}
+		s->s_flags |= MS_ACTIVE;
+	}
+	return dget(s->s_root);
+}
+#endif /* CONFIG_VE */
+
 static struct dentry *dev_mount(struct file_system_type *fs_type, int flags,
 		      const char *dev_name, void *data)
 {
+#ifdef CONFIG_VE
+	if (!ve_is_super(get_exec_env()))
+		return ve_dev_mount(fs_type, flags, dev_name, data);
+#endif
 #ifdef CONFIG_TMPFS
 	return mount_single(fs_type, flags, data, shmem_fill_super);
 #else
@@ -86,6 +139,11 @@ int devtmpfs_create_node(struct device *dev)
 
 	if (!thread)
 		return 0;
+#ifdef CONFIG_VE
+	if (dev->class->namespace == ve_namespace &&
+	    ve_namespace(dev) != get_ve0())
+		return 0;
+#endif
 
 	req.mode = 0;
 	req.uid = GLOBAL_ROOT_UID;
@@ -125,6 +183,11 @@ int devtmpfs_delete_node(struct device *dev)
 
 	if (!thread)
 		return 0;
+#ifdef CONFIG_VE
+	if (dev->class->namespace == ve_namespace &&
+	    ve_namespace(dev) != get_ve0())
+		return 0;
+#endif
 
 	req.name = device_get_devnode(dev, NULL, NULL, NULL, &tmp);
 	if (!req.name)
diff --git a/include/linux/ve.h b/include/linux/ve.h
index 84be82303c39..82a840a988b7 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -60,6 +60,7 @@ struct ve_struct {
 /* VE's root */
 	struct path		root_path;
 
+	struct super_block	*dev_sb;
 	struct super_block	*devpts_sb;
 
 #if IS_ENABLED(CONFIG_BINFMT_MISC)
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 6699b83734b5..c2495acf9546 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -532,6 +532,10 @@ void ve_exit_ns(struct pid_namespace *pid_ns)
 	 * At this point all userspace tasks in container are dead.
 	 */
 
+	if (ve->dev_sb) {
+		deactivate_super(ve->dev_sb);
+		ve->dev_sb = NULL;
+	}
 	if (ve->devpts_sb) {
 		deactivate_super(ve->devpts_sb);
 		ve->devpts_sb = NULL;
-- 
2.1.4




More information about the Devel mailing list