aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/kernfs/kernfs-internal.h22
-rw-r--r--fs/kernfs/mount.c156
-rw-r--r--fs/sysfs/mount.c152
-rw-r--r--fs/sysfs/sysfs.h18
4 files changed, 178 insertions, 170 deletions
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 0d949885389d..ced0d6dadc7d 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -134,6 +134,28 @@ struct sysfs_addrm_cxt {
134#include "../sysfs/sysfs.h" 134#include "../sysfs/sysfs.h"
135 135
136/* 136/*
137 * mount.c
138 */
139struct sysfs_super_info {
140 /*
141 * The root associated with this super_block. Each super_block is
142 * identified by the root and ns it's associated with.
143 */
144 struct kernfs_root *root;
145
146 /*
147 * Each sb is associated with one namespace tag, currently the network
148 * namespace of the task which mounted this sysfs instance. If multiple
149 * tags become necessary, make the following an array and compare
150 * sysfs_dirent tag against every entry.
151 */
152 const void *ns;
153};
154#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
155
156extern struct kmem_cache *sysfs_dir_cachep;
157
158/*
137 * inode.c 159 * inode.c
138 */ 160 */
139struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); 161struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd);
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index 872e262e5166..84c83e24bf25 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -7,3 +7,159 @@
7 * 7 *
8 * This file is released under the GPLv2. 8 * This file is released under the GPLv2.
9 */ 9 */
10
11#include <linux/fs.h>
12#include <linux/mount.h>
13#include <linux/init.h>
14#include <linux/magic.h>
15#include <linux/slab.h>
16#include <linux/pagemap.h>
17
18#include "kernfs-internal.h"
19
20struct kmem_cache *sysfs_dir_cachep;
21
22static const struct super_operations sysfs_ops = {
23 .statfs = simple_statfs,
24 .drop_inode = generic_delete_inode,
25 .evict_inode = sysfs_evict_inode,
26};
27
28static int sysfs_fill_super(struct super_block *sb)
29{
30 struct sysfs_super_info *info = sysfs_info(sb);
31 struct inode *inode;
32 struct dentry *root;
33
34 sb->s_blocksize = PAGE_CACHE_SIZE;
35 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
36 sb->s_magic = SYSFS_MAGIC;
37 sb->s_op = &sysfs_ops;
38 sb->s_time_gran = 1;
39
40 /* get root inode, initialize and unlock it */
41 mutex_lock(&sysfs_mutex);
42 inode = sysfs_get_inode(sb, info->root->sd);
43 mutex_unlock(&sysfs_mutex);
44 if (!inode) {
45 pr_debug("sysfs: could not get root inode\n");
46 return -ENOMEM;
47 }
48
49 /* instantiate and link root dentry */
50 root = d_make_root(inode);
51 if (!root) {
52 pr_debug("%s: could not get root dentry!\n", __func__);
53 return -ENOMEM;
54 }
55 kernfs_get(info->root->sd);
56 root->d_fsdata = info->root->sd;
57 sb->s_root = root;
58 sb->s_d_op = &sysfs_dentry_ops;
59 return 0;
60}
61
62static int sysfs_test_super(struct super_block *sb, void *data)
63{
64 struct sysfs_super_info *sb_info = sysfs_info(sb);
65 struct sysfs_super_info *info = data;
66
67 return sb_info->root == info->root && sb_info->ns == info->ns;
68}
69
70static int sysfs_set_super(struct super_block *sb, void *data)
71{
72 int error;
73 error = set_anon_super(sb, data);
74 if (!error)
75 sb->s_fs_info = data;
76 return error;
77}
78
79/**
80 * kernfs_super_ns - determine the namespace tag of a kernfs super_block
81 * @sb: super_block of interest
82 *
83 * Return the namespace tag associated with kernfs super_block @sb.
84 */
85const void *kernfs_super_ns(struct super_block *sb)
86{
87 struct sysfs_super_info *info = sysfs_info(sb);
88
89 return info->ns;
90}
91
92/**
93 * kernfs_mount_ns - kernfs mount helper
94 * @fs_type: file_system_type of the fs being mounted
95 * @flags: mount flags specified for the mount
96 * @root: kernfs_root of the hierarchy being mounted
97 * @ns: optional namespace tag of the mount
98 *
99 * This is to be called from each kernfs user's file_system_type->mount()
100 * implementation, which should pass through the specified @fs_type and
101 * @flags, and specify the hierarchy and namespace tag to mount via @root
102 * and @ns, respectively.
103 *
104 * The return value can be passed to the vfs layer verbatim.
105 */
106struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
107 struct kernfs_root *root, const void *ns)
108{
109 struct super_block *sb;
110 struct sysfs_super_info *info;
111 int error;
112
113 info = kzalloc(sizeof(*info), GFP_KERNEL);
114 if (!info)
115 return ERR_PTR(-ENOMEM);
116
117 info->root = root;
118 info->ns = ns;
119
120 sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);
121 if (IS_ERR(sb) || sb->s_fs_info != info)
122 kfree(info);
123 if (IS_ERR(sb))
124 return ERR_CAST(sb);
125 if (!sb->s_root) {
126 error = sysfs_fill_super(sb);
127 if (error) {
128 deactivate_locked_super(sb);
129 return ERR_PTR(error);
130 }
131 sb->s_flags |= MS_ACTIVE;
132 }
133
134 return dget(sb->s_root);
135}
136
137/**
138 * kernfs_kill_sb - kill_sb for kernfs
139 * @sb: super_block being killed
140 *
141 * This can be used directly for file_system_type->kill_sb(). If a kernfs
142 * user needs extra cleanup, it can implement its own kill_sb() and call
143 * this function at the end.
144 */
145void kernfs_kill_sb(struct super_block *sb)
146{
147 struct sysfs_super_info *info = sysfs_info(sb);
148 struct sysfs_dirent *root_sd = sb->s_root->d_fsdata;
149
150 /*
151 * Remove the superblock from fs_supers/s_instances
152 * so we can't find it, before freeing sysfs_super_info.
153 */
154 kill_anon_super(sb);
155 kfree(info);
156 kernfs_put(root_sd);
157}
158
159void __init kernfs_init(void)
160{
161 sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
162 sizeof(struct sysfs_dirent),
163 0, SLAB_PANIC, NULL);
164 sysfs_inode_init();
165}
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 5384732700ba..e7e3aa8e7b78 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -14,91 +14,14 @@
14 14
15#include <linux/fs.h> 15#include <linux/fs.h>
16#include <linux/mount.h> 16#include <linux/mount.h>
17#include <linux/pagemap.h>
18#include <linux/init.h> 17#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/magic.h>
21#include <linux/slab.h>
22#include <linux/user_namespace.h> 18#include <linux/user_namespace.h>
23 19
24#include "sysfs.h" 20#include "sysfs.h"
25 21
26
27struct kmem_cache *sysfs_dir_cachep;
28
29static const struct super_operations sysfs_ops = {
30 .statfs = simple_statfs,
31 .drop_inode = generic_delete_inode,
32 .evict_inode = sysfs_evict_inode,
33};
34
35static struct kernfs_root *sysfs_root; 22static struct kernfs_root *sysfs_root;
36struct sysfs_dirent *sysfs_root_sd; 23struct sysfs_dirent *sysfs_root_sd;
37 24
38static int sysfs_fill_super(struct super_block *sb)
39{
40 struct sysfs_super_info *info = sysfs_info(sb);
41 struct inode *inode;
42 struct dentry *root;
43
44 sb->s_blocksize = PAGE_CACHE_SIZE;
45 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
46 sb->s_magic = SYSFS_MAGIC;
47 sb->s_op = &sysfs_ops;
48 sb->s_time_gran = 1;
49
50 /* get root inode, initialize and unlock it */
51 mutex_lock(&sysfs_mutex);
52 inode = sysfs_get_inode(sb, info->root->sd);
53 mutex_unlock(&sysfs_mutex);
54 if (!inode) {
55 pr_debug("sysfs: could not get root inode\n");
56 return -ENOMEM;
57 }
58
59 /* instantiate and link root dentry */
60 root = d_make_root(inode);
61 if (!root) {
62 pr_debug("%s: could not get root dentry!\n", __func__);
63 return -ENOMEM;
64 }
65 kernfs_get(info->root->sd);
66 root->d_fsdata = info->root->sd;
67 sb->s_root = root;
68 sb->s_d_op = &sysfs_dentry_ops;
69 return 0;
70}
71
72static int sysfs_test_super(struct super_block *sb, void *data)
73{
74 struct sysfs_super_info *sb_info = sysfs_info(sb);
75 struct sysfs_super_info *info = data;
76
77 return sb_info->root == info->root && sb_info->ns == info->ns;
78}
79
80static int sysfs_set_super(struct super_block *sb, void *data)
81{
82 int error;
83 error = set_anon_super(sb, data);
84 if (!error)
85 sb->s_fs_info = data;
86 return error;
87}
88
89/**
90 * kernfs_super_ns - determine the namespace tag of a kernfs super_block
91 * @sb: super_block of interest
92 *
93 * Return the namespace tag associated with kernfs super_block @sb.
94 */
95const void *kernfs_super_ns(struct super_block *sb)
96{
97 struct sysfs_super_info *info = sysfs_info(sb);
98
99 return info->ns;
100}
101
102static struct dentry *sysfs_mount(struct file_system_type *fs_type, 25static struct dentry *sysfs_mount(struct file_system_type *fs_type,
103 int flags, const char *dev_name, void *data) 26 int flags, const char *dev_name, void *data)
104{ 27{
@@ -120,79 +43,12 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
120 return root; 43 return root;
121} 44}
122 45
123/**
124 * kernfs_mount_ns - kernfs mount helper
125 * @fs_type: file_system_type of the fs being mounted
126 * @flags: mount flags specified for the mount
127 * @root: kernfs_root of the hierarchy being mounted
128 * @ns: optional namespace tag of the mount
129 *
130 * This is to be called from each kernfs user's file_system_type->mount()
131 * implementation, which should pass through the specified @fs_type and
132 * @flags, and specify the hierarchy and namespace tag to mount via @root
133 * and @ns, respectively.
134 *
135 * The return value can be passed to the vfs layer verbatim.
136 */
137struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
138 struct kernfs_root *root, const void *ns)
139{
140 struct super_block *sb;
141 struct sysfs_super_info *info;
142 int error;
143
144 info = kzalloc(sizeof(*info), GFP_KERNEL);
145 if (!info)
146 return ERR_PTR(-ENOMEM);
147
148 info->root = root;
149 info->ns = ns;
150
151 sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);
152 if (IS_ERR(sb) || sb->s_fs_info != info)
153 kfree(info);
154 if (IS_ERR(sb))
155 return ERR_CAST(sb);
156 if (!sb->s_root) {
157 error = sysfs_fill_super(sb);
158 if (error) {
159 deactivate_locked_super(sb);
160 return ERR_PTR(error);
161 }
162 sb->s_flags |= MS_ACTIVE;
163 }
164
165 return dget(sb->s_root);
166}
167
168static void sysfs_kill_sb(struct super_block *sb) 46static void sysfs_kill_sb(struct super_block *sb)
169{ 47{
170 kernfs_kill_sb(sb); 48 kernfs_kill_sb(sb);
171 kobj_ns_drop(KOBJ_NS_TYPE_NET, (void *)kernfs_super_ns(sb)); 49 kobj_ns_drop(KOBJ_NS_TYPE_NET, (void *)kernfs_super_ns(sb));
172} 50}
173 51
174/**
175 * kernfs_kill_sb - kill_sb for kernfs
176 * @sb: super_block being killed
177 *
178 * This can be used directly for file_system_type->kill_sb(). If a kernfs
179 * user needs extra cleanup, it can implement its own kill_sb() and call
180 * this function at the end.
181 */
182void kernfs_kill_sb(struct super_block *sb)
183{
184 struct sysfs_super_info *info = sysfs_info(sb);
185 struct sysfs_dirent *root_sd = sb->s_root->d_fsdata;
186
187 /*
188 * Remove the superblock from fs_supers/s_instances
189 * so we can't find it, before freeing sysfs_super_info.
190 */
191 kill_anon_super(sb);
192 kfree(info);
193 kernfs_put(root_sd);
194}
195
196static struct file_system_type sysfs_fs_type = { 52static struct file_system_type sysfs_fs_type = {
197 .name = "sysfs", 53 .name = "sysfs",
198 .mount = sysfs_mount, 54 .mount = sysfs_mount,
@@ -200,14 +56,6 @@ static struct file_system_type sysfs_fs_type = {
200 .fs_flags = FS_USERNS_MOUNT, 56 .fs_flags = FS_USERNS_MOUNT,
201}; 57};
202 58
203void __init kernfs_init(void)
204{
205 sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
206 sizeof(struct sysfs_dirent),
207 0, SLAB_PANIC, NULL);
208 sysfs_inode_init();
209}
210
211int __init sysfs_init(void) 59int __init sysfs_init(void)
212{ 60{
213 int err; 61 int err;
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 93b4b68458ad..6a82311a50fe 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -17,25 +17,7 @@
17/* 17/*
18 * mount.c 18 * mount.c
19 */ 19 */
20
21struct sysfs_super_info {
22 /*
23 * The root associated with this super_block. Each super_block is
24 * identified by the root and ns it's associated with.
25 */
26 struct kernfs_root *root;
27
28 /*
29 * Each sb is associated with one namespace tag, currently the network
30 * namespace of the task which mounted this sysfs instance. If multiple
31 * tags become necessary, make the following an array and compare
32 * sysfs_dirent tag against every entry.
33 */
34 const void *ns;
35};
36#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
37extern struct sysfs_dirent *sysfs_root_sd; 20extern struct sysfs_dirent *sysfs_root_sd;
38extern struct kmem_cache *sysfs_dir_cachep;
39 21
40/* 22/*
41 * dir.c 23 * dir.c