diff options
Diffstat (limited to 'fs/kernfs/mount.c')
-rw-r--r-- | fs/kernfs/mount.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 95dcd1d558bb..f973ae9b05f1 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c | |||
@@ -68,6 +68,7 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic) | |||
68 | struct inode *inode; | 68 | struct inode *inode; |
69 | struct dentry *root; | 69 | struct dentry *root; |
70 | 70 | ||
71 | info->sb = sb; | ||
71 | sb->s_blocksize = PAGE_CACHE_SIZE; | 72 | sb->s_blocksize = PAGE_CACHE_SIZE; |
72 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 73 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
73 | sb->s_magic = magic; | 74 | sb->s_magic = magic; |
@@ -167,12 +168,18 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, | |||
167 | *new_sb_created = !sb->s_root; | 168 | *new_sb_created = !sb->s_root; |
168 | 169 | ||
169 | if (!sb->s_root) { | 170 | if (!sb->s_root) { |
171 | struct kernfs_super_info *info = kernfs_info(sb); | ||
172 | |||
170 | error = kernfs_fill_super(sb, magic); | 173 | error = kernfs_fill_super(sb, magic); |
171 | if (error) { | 174 | if (error) { |
172 | deactivate_locked_super(sb); | 175 | deactivate_locked_super(sb); |
173 | return ERR_PTR(error); | 176 | return ERR_PTR(error); |
174 | } | 177 | } |
175 | sb->s_flags |= MS_ACTIVE; | 178 | sb->s_flags |= MS_ACTIVE; |
179 | |||
180 | mutex_lock(&kernfs_mutex); | ||
181 | list_add(&info->node, &root->supers); | ||
182 | mutex_unlock(&kernfs_mutex); | ||
176 | } | 183 | } |
177 | 184 | ||
178 | return dget(sb->s_root); | 185 | return dget(sb->s_root); |
@@ -191,6 +198,10 @@ void kernfs_kill_sb(struct super_block *sb) | |||
191 | struct kernfs_super_info *info = kernfs_info(sb); | 198 | struct kernfs_super_info *info = kernfs_info(sb); |
192 | struct kernfs_node *root_kn = sb->s_root->d_fsdata; | 199 | struct kernfs_node *root_kn = sb->s_root->d_fsdata; |
193 | 200 | ||
201 | mutex_lock(&kernfs_mutex); | ||
202 | list_del(&info->node); | ||
203 | mutex_unlock(&kernfs_mutex); | ||
204 | |||
194 | /* | 205 | /* |
195 | * Remove the superblock from fs_supers/s_instances | 206 | * Remove the superblock from fs_supers/s_instances |
196 | * so we can't find it, before freeing kernfs_super_info. | 207 | * so we can't find it, before freeing kernfs_super_info. |
@@ -200,6 +211,36 @@ void kernfs_kill_sb(struct super_block *sb) | |||
200 | kernfs_put(root_kn); | 211 | kernfs_put(root_kn); |
201 | } | 212 | } |
202 | 213 | ||
214 | /** | ||
215 | * kernfs_pin_sb: try to pin the superblock associated with a kernfs_root | ||
216 | * @kernfs_root: the kernfs_root in question | ||
217 | * @ns: the namespace tag | ||
218 | * | ||
219 | * Pin the superblock so the superblock won't be destroyed in subsequent | ||
220 | * operations. This can be used to block ->kill_sb() which may be useful | ||
221 | * for kernfs users which dynamically manage superblocks. | ||
222 | * | ||
223 | * Returns NULL if there's no superblock associated to this kernfs_root, or | ||
224 | * -EINVAL if the superblock is being freed. | ||
225 | */ | ||
226 | struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns) | ||
227 | { | ||
228 | struct kernfs_super_info *info; | ||
229 | struct super_block *sb = NULL; | ||
230 | |||
231 | mutex_lock(&kernfs_mutex); | ||
232 | list_for_each_entry(info, &root->supers, node) { | ||
233 | if (info->ns == ns) { | ||
234 | sb = info->sb; | ||
235 | if (!atomic_inc_not_zero(&info->sb->s_active)) | ||
236 | sb = ERR_PTR(-EINVAL); | ||
237 | break; | ||
238 | } | ||
239 | } | ||
240 | mutex_unlock(&kernfs_mutex); | ||
241 | return sb; | ||
242 | } | ||
243 | |||
203 | void __init kernfs_init(void) | 244 | void __init kernfs_init(void) |
204 | { | 245 | { |
205 | kernfs_node_cache = kmem_cache_create("kernfs_node_cache", | 246 | kernfs_node_cache = kmem_cache_create("kernfs_node_cache", |