diff options
author | Tejun Heo <tj@kernel.org> | 2013-11-28 14:54:43 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-11-29 21:16:08 -0500 |
commit | 4b93dc9b1c684d0587fe44d36bbfdf45bd3bea9d (patch) | |
tree | 99a8124d0407511d6193e286b1a5b6e7d5aafdb2 /fs/sysfs | |
parent | df394fb56c64244b30b442e9e02de1a2d9c5a98b (diff) |
sysfs, kernfs: prepare mount path for kernfs
We're in the process of separating out core sysfs functionality into
kernfs which will deal with sysfs_dirents directly. This patch
rearranges mount path so that the kernfs and sysfs parts are separate.
* As sysfs_super_info won't be visible outside kernfs proper,
kernfs_super_ns() is added to allow kernfs users to access a
super_block's namespace tag.
* Generic mount operation is separated out into kernfs_mount_ns().
sysfs_mount() now just performs sysfs-specific permission check,
acquires namespace tag, and invokes kernfs_mount_ns().
* Generic superblock release is separated out into kernfs_kill_sb()
which can be used directly as file_system_type->kill_sb(). As sysfs
needs to put the namespace tag, sysfs_kill_sb() wraps
kernfs_kill_sb() with ns tag put.
* sysfs_dir_cachep init and sysfs_inode_init() are separated out into
kernfs_init(). kernfs_init() uses only small amount of memory and
trying to handle and propagate kernfs_init() failure doesn't make
much sense. Use SLAB_PANIC for sysfs_dir_cachep and make
sysfs_inode_init() panic on failure.
After this change, kernfs_init() should be called before
sysfs_init(), fs/namespace.c::mnt_init() modified accordingly.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: linux-fsdevel@vger.kernel.org
Cc: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/mount.c | 104 |
1 files changed, 72 insertions, 32 deletions
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index f143b203a7e6..5384732700ba 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -86,18 +86,24 @@ static int sysfs_set_super(struct super_block *sb, void *data) | |||
86 | return error; | 86 | return error; |
87 | } | 87 | } |
88 | 88 | ||
89 | static void free_sysfs_super_info(struct sysfs_super_info *info) | 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 | */ | ||
95 | const void *kernfs_super_ns(struct super_block *sb) | ||
90 | { | 96 | { |
91 | kobj_ns_drop(KOBJ_NS_TYPE_NET, (void *)info->ns); | 97 | struct sysfs_super_info *info = sysfs_info(sb); |
92 | kfree(info); | 98 | |
99 | return info->ns; | ||
93 | } | 100 | } |
94 | 101 | ||
95 | static struct dentry *sysfs_mount(struct file_system_type *fs_type, | 102 | static struct dentry *sysfs_mount(struct file_system_type *fs_type, |
96 | int flags, const char *dev_name, void *data) | 103 | int flags, const char *dev_name, void *data) |
97 | { | 104 | { |
98 | struct sysfs_super_info *info; | 105 | struct dentry *root; |
99 | struct super_block *sb; | 106 | void *ns; |
100 | int error; | ||
101 | 107 | ||
102 | if (!(flags & MS_KERNMOUNT)) { | 108 | if (!(flags & MS_KERNMOUNT)) { |
103 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) | 109 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) |
@@ -107,16 +113,44 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
107 | return ERR_PTR(-EPERM); | 113 | return ERR_PTR(-EPERM); |
108 | } | 114 | } |
109 | 115 | ||
116 | ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); | ||
117 | root = kernfs_mount_ns(fs_type, flags, sysfs_root, ns); | ||
118 | if (IS_ERR(root)) | ||
119 | kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); | ||
120 | return root; | ||
121 | } | ||
122 | |||
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 | */ | ||
137 | struct 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 | |||
110 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 144 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
111 | if (!info) | 145 | if (!info) |
112 | return ERR_PTR(-ENOMEM); | 146 | return ERR_PTR(-ENOMEM); |
113 | 147 | ||
114 | info->root = sysfs_root; | 148 | info->root = root; |
115 | info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); | 149 | info->ns = ns; |
116 | 150 | ||
117 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); | 151 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); |
118 | if (IS_ERR(sb) || sb->s_fs_info != info) | 152 | if (IS_ERR(sb) || sb->s_fs_info != info) |
119 | free_sysfs_super_info(info); | 153 | kfree(info); |
120 | if (IS_ERR(sb)) | 154 | if (IS_ERR(sb)) |
121 | return ERR_CAST(sb); | 155 | return ERR_CAST(sb); |
122 | if (!sb->s_root) { | 156 | if (!sb->s_root) { |
@@ -133,6 +167,20 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
133 | 167 | ||
134 | static void sysfs_kill_sb(struct super_block *sb) | 168 | static void sysfs_kill_sb(struct super_block *sb) |
135 | { | 169 | { |
170 | kernfs_kill_sb(sb); | ||
171 | kobj_ns_drop(KOBJ_NS_TYPE_NET, (void *)kernfs_super_ns(sb)); | ||
172 | } | ||
173 | |||
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 | */ | ||
182 | void kernfs_kill_sb(struct super_block *sb) | ||
183 | { | ||
136 | struct sysfs_super_info *info = sysfs_info(sb); | 184 | struct sysfs_super_info *info = sysfs_info(sb); |
137 | struct sysfs_dirent *root_sd = sb->s_root->d_fsdata; | 185 | struct sysfs_dirent *root_sd = sb->s_root->d_fsdata; |
138 | 186 | ||
@@ -141,7 +189,7 @@ static void sysfs_kill_sb(struct super_block *sb) | |||
141 | * so we can't find it, before freeing sysfs_super_info. | 189 | * so we can't find it, before freeing sysfs_super_info. |
142 | */ | 190 | */ |
143 | kill_anon_super(sb); | 191 | kill_anon_super(sb); |
144 | free_sysfs_super_info(info); | 192 | kfree(info); |
145 | kernfs_put(root_sd); | 193 | kernfs_put(root_sd); |
146 | } | 194 | } |
147 | 195 | ||
@@ -152,37 +200,29 @@ static struct file_system_type sysfs_fs_type = { | |||
152 | .fs_flags = FS_USERNS_MOUNT, | 200 | .fs_flags = FS_USERNS_MOUNT, |
153 | }; | 201 | }; |
154 | 202 | ||
155 | int __init sysfs_init(void) | 203 | void __init kernfs_init(void) |
156 | { | 204 | { |
157 | int err; | ||
158 | |||
159 | sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", | 205 | sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", |
160 | sizeof(struct sysfs_dirent), | 206 | sizeof(struct sysfs_dirent), |
161 | 0, 0, NULL); | 207 | 0, SLAB_PANIC, NULL); |
162 | if (!sysfs_dir_cachep) | 208 | sysfs_inode_init(); |
163 | return -ENOMEM; | 209 | } |
164 | 210 | ||
165 | err = sysfs_inode_init(); | 211 | int __init sysfs_init(void) |
166 | if (err) | 212 | { |
167 | goto out_err; | 213 | int err; |
168 | 214 | ||
169 | sysfs_root = kernfs_create_root(NULL); | 215 | sysfs_root = kernfs_create_root(NULL); |
170 | if (IS_ERR(sysfs_root)) { | 216 | if (IS_ERR(sysfs_root)) |
171 | err = PTR_ERR(sysfs_root); | 217 | return PTR_ERR(sysfs_root); |
172 | goto out_err; | 218 | |
173 | } | ||
174 | sysfs_root_sd = sysfs_root->sd; | 219 | sysfs_root_sd = sysfs_root->sd; |
175 | 220 | ||
176 | err = register_filesystem(&sysfs_fs_type); | 221 | err = register_filesystem(&sysfs_fs_type); |
177 | if (err) | 222 | if (err) { |
178 | goto out_destroy_root; | 223 | kernfs_destroy_root(sysfs_root); |
224 | return err; | ||
225 | } | ||
179 | 226 | ||
180 | return 0; | 227 | return 0; |
181 | |||
182 | out_destroy_root: | ||
183 | kernfs_destroy_root(sysfs_root); | ||
184 | out_err: | ||
185 | kmem_cache_destroy(sysfs_dir_cachep); | ||
186 | sysfs_dir_cachep = NULL; | ||
187 | return err; | ||
188 | } | 228 | } |