[Devel] [PATCH] Filesystems visibility control group

Pavel Emelyanov xemul at openvz.org
Thu Feb 7 07:04:52 PST 2008


After making the devices visibility cg, I thought, that it might
be useful to have a filesystem visibility control group.

The patch is rather simple - all the code is in fs/filesystems.c

The main idea is in file_system_proxy object. This coincides in
its three first fields with file_system_type (name, flags and next)
and is used to lookup the file system. To distinguish between
them I use a FS_IS_PROXY flag.

Having this proxy is the easiest way to keep the global list and
file_system_type structure (almost) untouched and simplify the code.

The filesystems.list file syntax is simple: [+-]<name> without
a '\n' at the end. Made for 2.6.24-rc8-mm1

Signed-off-by: Pavel Emelyanov <xemul at openvz.org>

---

diff --git a/fs/filesystems.c b/fs/filesystems.c
index f37f872..b8189a4 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -27,9 +27,214 @@
  *	Once the reference is obtained we can drop the spinlock.
  */
 
+/*
+ * the first three fields of it must coincide with the
+ * struct file_system_type
+ */
+
+struct file_system_proxy {
+	char *name;
+	struct file_system_proxy *next;
+	int fs_flags;
+	struct file_system_type *fs;
+};
+
 static struct file_system_type *file_systems;
 static DEFINE_RWLOCK(file_systems_lock);
 
+#ifdef CONFIG_CGROUP_FS
+#include <linux/cgroup.h>
+
+struct fs_cgroup {
+	struct cgroup_subsys_state css;
+
+	struct file_system_proxy *fs;
+};
+
+static inline struct fs_cgroup *css_to_fs(struct cgroup_subsys_state *ss)
+{
+	return container_of(ss, struct fs_cgroup, css);
+}
+
+static inline struct fs_cgroup *cgroup_to_fs(struct cgroup *c)
+{
+	return css_to_fs(cgroup_subsys_state(c, fs_subsys_id));
+}
+
+static inline struct file_system_type *task_fs_types(struct task_struct *t)
+{
+	struct cgroup_subsys_state *css;
+
+	css = task_subsys_state(t, fs_subsys_id);
+	if (css->cgroup->parent == NULL)
+		return file_systems;
+	else
+		return (struct file_system_type *)css_to_fs(css)->fs;
+}
+
+static struct cgroup_subsys_state *
+fs_create(struct cgroup_subsys *ss, struct cgroup *cont)
+{
+	struct fs_cgroup *fs;
+
+	fs = kzalloc(sizeof(struct fs_cgroup), GFP_KERNEL);
+	if (fs == NULL)
+		return ERR_PTR(-ENOMEM);
+	else
+		return &fs->css;
+}
+
+static void fs_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
+{
+	struct fs_cgroup *fcg;
+	struct file_system_proxy *p, *next;
+
+	fcg = cgroup_to_fs(cont);
+
+	write_lock(&file_systems_lock);
+	for (p = fcg->fs; p != NULL; p = next) {
+		next = p->next;
+		put_filesystem(p->fs);
+		kfree(p);
+	}
+	write_unlock(&file_systems_lock);
+
+	kfree(fcg);
+}
+
+static ssize_t fs_write(struct cgroup *cont, struct cftype *cft,
+		struct file *f, const char __user *ubuf,
+		size_t nbytes, loff_t *pos)
+{
+	int err, add;
+	char buf[64];
+	struct file_system_type *fs;
+	struct file_system_proxy **p, *proxy = NULL;
+	struct fs_cgroup *fcg;
+
+	if (copy_from_user(buf, ubuf, sizeof(buf)))
+		return -EFAULT;
+
+	buf[sizeof(buf) - 1] = '\0';
+	if (buf[0] == '+')
+		add = 1;
+	else if (buf[0] == '-')
+		add = 0;
+	else
+		return -EINVAL;
+
+	if (add) {
+		err = -ENOMEM;
+		proxy = kmalloc(sizeof(*proxy) + sizeof(buf), GFP_KERNEL);
+		if (proxy == NULL)
+			goto err_alloc;
+	}
+
+	fcg = cgroup_to_fs(cont);
+	write_lock(&file_systems_lock);
+
+	for (p = &fcg->fs; *p != NULL; p = &(*p)->next)
+		if (strcmp((*p)->name, buf + 1) == 0)
+			goto fs_exists;
+
+	err = -ESRCH;
+	if (!add)
+		goto err_unlock;
+
+	for (fs = file_systems; fs != NULL; fs = fs->next)
+		if (strcmp(fs->name, buf + 1) == 0)
+			break;
+
+	if (fs == NULL)
+		goto err_srch;
+
+	if (!try_module_get(fs->owner))
+		goto err_srch;
+
+	proxy->name = (char *)(proxy + 1);
+	strcpy(proxy->name, fs->name);
+	proxy->fs_flags = fs->fs_flags | FS_IS_PROXY;
+	proxy->fs = fs;
+	proxy->next = fcg->fs;
+	fcg->fs = proxy;
+	write_unlock(&file_systems_lock);
+
+	return nbytes;
+
+fs_exists:
+	if (add) {
+		err = -EEXIST;
+		goto err_srch;
+	}
+
+	proxy = *p;
+	*p = proxy->next;
+	write_unlock(&file_systems_lock);
+	put_filesystem(proxy->fs);
+	kfree(proxy);
+	return nbytes;
+
+err_srch:
+	kfree(proxy);
+err_unlock:
+	write_unlock(&file_systems_lock);
+err_alloc:
+	return err;
+}
+
+static ssize_t fs_read(struct cgroup *cont, struct cftype *cft,
+		struct file *f, char __user *ubuf,
+		size_t nbytes, loff_t *pos)
+{
+	int len;
+	char *buf;
+	struct fs_cgroup *fcg;
+	struct file_system_proxy *p;
+
+	buf = (char *)__get_free_page(GFP_KERNEL);
+
+	len = 0;
+	fcg = cgroup_to_fs(cont);
+	read_lock(&file_systems_lock);
+	for (p = fcg->fs; p != NULL; p = p->next) {
+		if (len + strlen(p->name) > PAGE_SIZE)
+			break;
+
+		len += sprintf(buf + len, "%s\n", p->name);
+	}
+	read_unlock(&file_systems_lock);
+
+	return simple_read_from_buffer(ubuf, nbytes, pos, buf, len);
+}
+
+static struct cftype fs_files[] = {
+	{
+		.name = "list",
+		.write = fs_write,
+		.read = fs_read,
+	},
+};
+
+static int fs_populate(struct cgroup_subsys *ss, struct cgroup *cont)
+{
+	return cgroup_add_files(cont, ss,
+			fs_files, ARRAY_SIZE(fs_files));
+}
+
+struct cgroup_subsys fs_subsys = {
+	.name = "filesystems",
+	.subsys_id = fs_subsys_id,
+	.create = fs_create,
+	.destroy = fs_destroy,
+	.populate = fs_populate,
+};
+#else
+static inline struct file_system_type *task_fs_types(struct task_struct *t)
+{
+	return file_systems;
+}
+#endif
+
 /* WARNING: This can be used only if we _already_ own a reference */
 void get_filesystem(struct file_system_type *fs)
 {
@@ -41,13 +246,29 @@ void put_filesystem(struct file_system_type *fs)
 	module_put(fs->owner);
 }
 
-static struct file_system_type **find_filesystem(const char *name, unsigned len)
+static struct file_system_type **find_filesystemp(const char *name, unsigned len)
 {
 	struct file_system_type **p;
 	for (p=&file_systems; *p; p=&(*p)->next)
 		if (strlen((*p)->name) == len &&
 		    strncmp((*p)->name, name, len) == 0)
 			break;
+
+	return p;
+}
+
+static struct file_system_type *find_filesystem(const char *name, unsigned len)
+{
+	struct file_system_type *p;
+
+	for (p = task_fs_types(current); p != NULL; p = p->next)
+		if (strlen(p->name) == len &&
+		    strncmp(p->name, name, len) == 0)
+			break;
+
+	if (p && (p->fs_flags & FS_IS_PROXY))
+		p = ((struct file_system_proxy *)p)->fs;
+
 	return p;
 }
 
@@ -74,7 +295,7 @@ int register_filesystem(struct file_system_type * fs)
 		return -EBUSY;
 	INIT_LIST_HEAD(&fs->fs_supers);
 	write_lock(&file_systems_lock);
-	p = find_filesystem(fs->name, strlen(fs->name));
+	p = find_filesystemp(fs->name, strlen(fs->name));
 	if (*p)
 		res = -EBUSY;
 	else
@@ -131,7 +352,8 @@ static int fs_index(const char __user * __name)
 
 	err = -EINVAL;
 	read_lock(&file_systems_lock);
-	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
+	for (tmp = task_fs_types(current), index = 0; tmp;
+			tmp = tmp->next, index++) {
 		if (strcmp(tmp->name,name) == 0) {
 			err = index;
 			break;
@@ -148,8 +370,9 @@ static int fs_name(unsigned int index, char __user * buf)
 	int len, res;
 
 	read_lock(&file_systems_lock);
-	for (tmp = file_systems; tmp; tmp = tmp->next, index--)
-		if (index <= 0 && try_module_get(tmp->owner))
+	for (tmp = task_fs_types(current); tmp; tmp = tmp->next, index--)
+		if (index <= 0 && ((tmp->fs_flags & FS_IS_PROXY) ||
+					try_module_get(tmp->owner)))
 			break;
 	read_unlock(&file_systems_lock);
 	if (!tmp)
@@ -158,7 +381,8 @@ static int fs_name(unsigned int index, char __user * buf)
 	/* OK, we got the reference, so we can safely block */
 	len = strlen(tmp->name) + 1;
 	res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
-	put_filesystem(tmp);
+	if (!(tmp->fs_flags & FS_IS_PROXY))
+		put_filesystem(tmp);
 	return res;
 }
 
@@ -168,7 +392,8 @@ static int fs_maxindex(void)
 	int index;
 
 	read_lock(&file_systems_lock);
-	for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
+	for (tmp = task_fs_types(current), index = 0; tmp;
+			tmp = tmp->next, index++)
 		;
 	read_unlock(&file_systems_lock);
 	return index;
@@ -203,7 +428,7 @@ int get_filesystem_list(char * buf)
 	struct file_system_type * tmp;
 
 	read_lock(&file_systems_lock);
-	tmp = file_systems;
+	tmp = task_fs_types(current);
 	while (tmp && len < PAGE_SIZE - 80) {
 		len += sprintf(buf+len, "%s\t%s\n",
 			(tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
@@ -221,13 +446,13 @@ struct file_system_type *get_fs_type(const char *name)
 	unsigned len = dot ? dot - name : strlen(name);
 
 	read_lock(&file_systems_lock);
-	fs = *(find_filesystem(name, len));
+	fs = find_filesystem(name, len);
 	if (fs && !try_module_get(fs->owner))
 		fs = NULL;
 	read_unlock(&file_systems_lock);
 	if (!fs && (request_module("%.*s", len, name) == 0)) {
 		read_lock(&file_systems_lock);
-		fs = *(find_filesystem(name, len));
+		fs = find_filesystem(name, len);
 		if (fs && !try_module_get(fs->owner))
 			fs = NULL;
 		read_unlock(&file_systems_lock);
diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h
index 228235c..cda4be7 100644
--- a/include/linux/cgroup_subsys.h
+++ b/include/linux/cgroup_subsys.h
@@ -42,3 +42,9 @@ SUBSYS(mem_cgroup)
 #endif
 
 /* */
+
+#ifdef CONFIG_CGROUP_FS
+SUBSYS(fs)
+#endif
+
+/* */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a456afe..19b6e0e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -93,6 +93,7 @@ extern int dir_notify_enable;
 #define FS_REQUIRES_DEV 1 
 #define FS_BINARY_MOUNTDATA 2
 #define FS_HAS_SUBTYPE 4
+#define FS_IS_PROXY 4096 /* This is a proxy for control groups */
 #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move()
 					 * during rename() internally.
@@ -1426,12 +1427,12 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc);
 
 struct file_system_type {
 	const char *name;
+	struct file_system_type * next;
 	int fs_flags;
 	int (*get_sb) (struct file_system_type *, int,
 		       const char *, void *, struct vfsmount *);
 	void (*kill_sb) (struct super_block *);
 	struct module *owner;
-	struct file_system_type * next;
 	struct list_head fs_supers;
 
 	struct lock_class_key s_lock_key;
diff --git a/init/Kconfig b/init/Kconfig
index 732a1c2..60d5f08 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -292,6 +292,12 @@ config CGROUP_NS
           for instance virtual servers and checkpoint/restart
           jobs.
 
+config CGROUP_FS
+	bool "Filesystems control group"
+	depends on CGROUPS
+	help
+	  Tune the filesystems visibility
+
 config CPUSETS
 	bool "Cpuset support"
 	depends on SMP && CGROUPS
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the Devel mailing list