| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * fs/kernfs/mount.c - kernfs mount implementation | 
|---|
| 4 | * | 
|---|
| 5 | * Copyright (c) 2001-3 Patrick Mochel | 
|---|
| 6 | * Copyright (c) 2007 SUSE Linux Products GmbH | 
|---|
| 7 | * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org> | 
|---|
| 8 | */ | 
|---|
| 9 |  | 
|---|
| 10 | #include <linux/fs.h> | 
|---|
| 11 | #include <linux/mount.h> | 
|---|
| 12 | #include <linux/init.h> | 
|---|
| 13 | #include <linux/magic.h> | 
|---|
| 14 | #include <linux/slab.h> | 
|---|
| 15 | #include <linux/pagemap.h> | 
|---|
| 16 | #include <linux/namei.h> | 
|---|
| 17 | #include <linux/seq_file.h> | 
|---|
| 18 | #include <linux/exportfs.h> | 
|---|
| 19 | #include <linux/uuid.h> | 
|---|
| 20 | #include <linux/statfs.h> | 
|---|
| 21 |  | 
|---|
| 22 | #include "kernfs-internal.h" | 
|---|
| 23 |  | 
|---|
| 24 | struct kmem_cache *kernfs_node_cache __ro_after_init; | 
|---|
| 25 | struct kmem_cache *kernfs_iattrs_cache __ro_after_init; | 
|---|
| 26 | struct kernfs_global_locks *kernfs_locks __ro_after_init; | 
|---|
| 27 |  | 
|---|
| 28 | static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry) | 
|---|
| 29 | { | 
|---|
| 30 | struct kernfs_root *root = kernfs_root(kn: kernfs_dentry_node(dentry)); | 
|---|
| 31 | struct kernfs_syscall_ops *scops = root->syscall_ops; | 
|---|
| 32 |  | 
|---|
| 33 | if (scops && scops->show_options) | 
|---|
| 34 | return scops->show_options(sf, root); | 
|---|
| 35 | return 0; | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry) | 
|---|
| 39 | { | 
|---|
| 40 | struct kernfs_node *node = kernfs_dentry_node(dentry); | 
|---|
| 41 | struct kernfs_root *root = kernfs_root(kn: node); | 
|---|
| 42 | struct kernfs_syscall_ops *scops = root->syscall_ops; | 
|---|
| 43 |  | 
|---|
| 44 | if (scops && scops->show_path) | 
|---|
| 45 | return scops->show_path(sf, node, root); | 
|---|
| 46 |  | 
|---|
| 47 | seq_dentry(sf, dentry, " \t\n\\"); | 
|---|
| 48 | return 0; | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|
| 51 | static int kernfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 
|---|
| 52 | { | 
|---|
| 53 | simple_statfs(dentry, buf); | 
|---|
| 54 | buf->f_fsid = uuid_to_fsid(uuid: dentry->d_sb->s_uuid.b); | 
|---|
| 55 | return 0; | 
|---|
| 56 | } | 
|---|
| 57 |  | 
|---|
| 58 | const struct super_operations kernfs_sops = { | 
|---|
| 59 | .statfs		= kernfs_statfs, | 
|---|
| 60 | .drop_inode	= inode_just_drop, | 
|---|
| 61 | .evict_inode	= kernfs_evict_inode, | 
|---|
| 62 |  | 
|---|
| 63 | .show_options	= kernfs_sop_show_options, | 
|---|
| 64 | .show_path	= kernfs_sop_show_path, | 
|---|
| 65 |  | 
|---|
| 66 | /* | 
|---|
| 67 | * sysfs is built on top of kernfs and sysfs provides the power | 
|---|
| 68 | * management infrastructure to support suspend/hibernate by | 
|---|
| 69 | * writing to various files in /sys/power/. As filesystems may | 
|---|
| 70 | * be automatically frozen during suspend/hibernate implementing | 
|---|
| 71 | * freeze/thaw support for kernfs generically will cause | 
|---|
| 72 | * deadlocks as the suspending/hibernation initiating task will | 
|---|
| 73 | * hold a VFS lock that it will then wait upon to be released. | 
|---|
| 74 | * If freeze/thaw for kernfs is needed talk to the VFS. | 
|---|
| 75 | */ | 
|---|
| 76 | .freeze_fs	= NULL, | 
|---|
| 77 | .unfreeze_fs	= NULL, | 
|---|
| 78 | .freeze_super	= NULL, | 
|---|
| 79 | .thaw_super	= NULL, | 
|---|
| 80 | }; | 
|---|
| 81 |  | 
|---|
| 82 | static int kernfs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, | 
|---|
| 83 | struct inode *parent) | 
|---|
| 84 | { | 
|---|
| 85 | struct kernfs_node *kn = inode->i_private; | 
|---|
| 86 |  | 
|---|
| 87 | if (*max_len < 2) { | 
|---|
| 88 | *max_len = 2; | 
|---|
| 89 | return FILEID_INVALID; | 
|---|
| 90 | } | 
|---|
| 91 |  | 
|---|
| 92 | *max_len = 2; | 
|---|
| 93 | *(u64 *)fh = kn->id; | 
|---|
| 94 | return FILEID_KERNFS; | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | static struct dentry *__kernfs_fh_to_dentry(struct super_block *sb, | 
|---|
| 98 | struct fid *fid, int fh_len, | 
|---|
| 99 | int fh_type, bool get_parent) | 
|---|
| 100 | { | 
|---|
| 101 | struct kernfs_super_info *info = kernfs_info(sb); | 
|---|
| 102 | struct kernfs_node *kn; | 
|---|
| 103 | struct inode *inode; | 
|---|
| 104 | u64 id; | 
|---|
| 105 |  | 
|---|
| 106 | if (fh_len < 2) | 
|---|
| 107 | return NULL; | 
|---|
| 108 |  | 
|---|
| 109 | switch (fh_type) { | 
|---|
| 110 | case FILEID_KERNFS: | 
|---|
| 111 | id = *(u64 *)fid; | 
|---|
| 112 | break; | 
|---|
| 113 | case FILEID_INO32_GEN: | 
|---|
| 114 | case FILEID_INO32_GEN_PARENT: | 
|---|
| 115 | /* | 
|---|
| 116 | * blk_log_action() exposes "LOW32,HIGH32" pair without | 
|---|
| 117 | * type and userland can call us with generic fid | 
|---|
| 118 | * constructed from them.  Combine it back to ID.  See | 
|---|
| 119 | * blk_log_action(). | 
|---|
| 120 | */ | 
|---|
| 121 | id = ((u64)fid->i32.gen << 32) | fid->i32.ino; | 
|---|
| 122 | break; | 
|---|
| 123 | default: | 
|---|
| 124 | return NULL; | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 | kn = kernfs_find_and_get_node_by_id(root: info->root, id); | 
|---|
| 128 | if (!kn) | 
|---|
| 129 | return ERR_PTR(error: -ESTALE); | 
|---|
| 130 |  | 
|---|
| 131 | if (get_parent) { | 
|---|
| 132 | struct kernfs_node *parent; | 
|---|
| 133 |  | 
|---|
| 134 | parent = kernfs_get_parent(kn); | 
|---|
| 135 | kernfs_put(kn); | 
|---|
| 136 | kn = parent; | 
|---|
| 137 | if (!kn) | 
|---|
| 138 | return ERR_PTR(error: -ESTALE); | 
|---|
| 139 | } | 
|---|
| 140 |  | 
|---|
| 141 | inode = kernfs_get_inode(sb, kn); | 
|---|
| 142 | kernfs_put(kn); | 
|---|
| 143 | return d_obtain_alias(inode); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | static struct dentry *kernfs_fh_to_dentry(struct super_block *sb, | 
|---|
| 147 | struct fid *fid, int fh_len, | 
|---|
| 148 | int fh_type) | 
|---|
| 149 | { | 
|---|
| 150 | return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, get_parent: false); | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 | static struct dentry *kernfs_fh_to_parent(struct super_block *sb, | 
|---|
| 154 | struct fid *fid, int fh_len, | 
|---|
| 155 | int fh_type) | 
|---|
| 156 | { | 
|---|
| 157 | return __kernfs_fh_to_dentry(sb, fid, fh_len, fh_type, get_parent: true); | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | static struct dentry *kernfs_get_parent_dentry(struct dentry *child) | 
|---|
| 161 | { | 
|---|
| 162 | struct kernfs_node *kn = kernfs_dentry_node(dentry: child); | 
|---|
| 163 | struct kernfs_root *root = kernfs_root(kn); | 
|---|
| 164 |  | 
|---|
| 165 | guard(rwsem_read)(T: &root->kernfs_rwsem); | 
|---|
| 166 | return d_obtain_alias(kernfs_get_inode(sb: child->d_sb, kn: kernfs_parent(kn))); | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | static const struct export_operations kernfs_export_ops = { | 
|---|
| 170 | .encode_fh	= kernfs_encode_fh, | 
|---|
| 171 | .fh_to_dentry	= kernfs_fh_to_dentry, | 
|---|
| 172 | .fh_to_parent	= kernfs_fh_to_parent, | 
|---|
| 173 | .get_parent	= kernfs_get_parent_dentry, | 
|---|
| 174 | }; | 
|---|
| 175 |  | 
|---|
| 176 | /** | 
|---|
| 177 | * kernfs_root_from_sb - determine kernfs_root associated with a super_block | 
|---|
| 178 | * @sb: the super_block in question | 
|---|
| 179 | * | 
|---|
| 180 | * Return: the kernfs_root associated with @sb.  If @sb is not a kernfs one, | 
|---|
| 181 | * %NULL is returned. | 
|---|
| 182 | */ | 
|---|
| 183 | struct kernfs_root *kernfs_root_from_sb(struct super_block *sb) | 
|---|
| 184 | { | 
|---|
| 185 | if (sb->s_op == &kernfs_sops) | 
|---|
| 186 | return kernfs_info(sb)->root; | 
|---|
| 187 | return NULL; | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | /* | 
|---|
| 191 | * find the next ancestor in the path down to @child, where @parent was the | 
|---|
| 192 | * ancestor whose descendant we want to find. | 
|---|
| 193 | * | 
|---|
| 194 | * Say the path is /a/b/c/d.  @child is d, @parent is %NULL.  We return the root | 
|---|
| 195 | * node.  If @parent is b, then we return the node for c. | 
|---|
| 196 | * Passing in d as @parent is not ok. | 
|---|
| 197 | */ | 
|---|
| 198 | static struct kernfs_node *find_next_ancestor(struct kernfs_node *child, | 
|---|
| 199 | struct kernfs_node *parent) | 
|---|
| 200 | { | 
|---|
| 201 | if (child == parent) { | 
|---|
| 202 | pr_crit_once( "BUG in find_next_ancestor: called with parent == child"); | 
|---|
| 203 | return NULL; | 
|---|
| 204 | } | 
|---|
| 205 |  | 
|---|
| 206 | while (kernfs_parent(kn: child) != parent) { | 
|---|
| 207 | child = kernfs_parent(kn: child); | 
|---|
| 208 | if (!child) | 
|---|
| 209 | return NULL; | 
|---|
| 210 | } | 
|---|
| 211 |  | 
|---|
| 212 | return child; | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | /** | 
|---|
| 216 | * kernfs_node_dentry - get a dentry for the given kernfs_node | 
|---|
| 217 | * @kn: kernfs_node for which a dentry is needed | 
|---|
| 218 | * @sb: the kernfs super_block | 
|---|
| 219 | * | 
|---|
| 220 | * Return: the dentry pointer | 
|---|
| 221 | */ | 
|---|
| 222 | struct dentry *kernfs_node_dentry(struct kernfs_node *kn, | 
|---|
| 223 | struct super_block *sb) | 
|---|
| 224 | { | 
|---|
| 225 | struct dentry *dentry; | 
|---|
| 226 | struct kernfs_node *knparent; | 
|---|
| 227 | struct kernfs_root *root; | 
|---|
| 228 |  | 
|---|
| 229 | BUG_ON(sb->s_op != &kernfs_sops); | 
|---|
| 230 |  | 
|---|
| 231 | dentry = dget(dentry: sb->s_root); | 
|---|
| 232 |  | 
|---|
| 233 | /* Check if this is the root kernfs_node */ | 
|---|
| 234 | if (!rcu_access_pointer(kn->__parent)) | 
|---|
| 235 | return dentry; | 
|---|
| 236 |  | 
|---|
| 237 | root = kernfs_root(kn); | 
|---|
| 238 | /* | 
|---|
| 239 | * As long as kn is valid, its parent can not vanish. This is cgroup's | 
|---|
| 240 | * kn so it can't have its parent replaced. Therefore it is safe to use | 
|---|
| 241 | * the ancestor node outside of the RCU or locked section. | 
|---|
| 242 | */ | 
|---|
| 243 | if (WARN_ON_ONCE(!(root->flags & KERNFS_ROOT_INVARIANT_PARENT))) | 
|---|
| 244 | return ERR_PTR(error: -EINVAL); | 
|---|
| 245 | scoped_guard(rcu) { | 
|---|
| 246 | knparent = find_next_ancestor(child: kn, NULL); | 
|---|
| 247 | } | 
|---|
| 248 | if (WARN_ON(!knparent)) { | 
|---|
| 249 | dput(dentry); | 
|---|
| 250 | return ERR_PTR(error: -EINVAL); | 
|---|
| 251 | } | 
|---|
| 252 |  | 
|---|
| 253 | do { | 
|---|
| 254 | struct dentry *dtmp; | 
|---|
| 255 | struct kernfs_node *kntmp; | 
|---|
| 256 | const char *name; | 
|---|
| 257 |  | 
|---|
| 258 | if (kn == knparent) | 
|---|
| 259 | return dentry; | 
|---|
| 260 |  | 
|---|
| 261 | scoped_guard(rwsem_read, &root->kernfs_rwsem) { | 
|---|
| 262 | kntmp = find_next_ancestor(child: kn, parent: knparent); | 
|---|
| 263 | if (WARN_ON(!kntmp)) { | 
|---|
| 264 | dput(dentry); | 
|---|
| 265 | return ERR_PTR(error: -EINVAL); | 
|---|
| 266 | } | 
|---|
| 267 | name = kstrdup(s: kernfs_rcu_name(kn: kntmp), GFP_KERNEL); | 
|---|
| 268 | } | 
|---|
| 269 | if (!name) { | 
|---|
| 270 | dput(dentry); | 
|---|
| 271 | return ERR_PTR(error: -ENOMEM); | 
|---|
| 272 | } | 
|---|
| 273 | dtmp = lookup_noperm_positive_unlocked(&QSTR(name), dentry); | 
|---|
| 274 | dput(dentry); | 
|---|
| 275 | kfree(objp: name); | 
|---|
| 276 | if (IS_ERR(ptr: dtmp)) | 
|---|
| 277 | return dtmp; | 
|---|
| 278 | knparent = kntmp; | 
|---|
| 279 | dentry = dtmp; | 
|---|
| 280 | } while (true); | 
|---|
| 281 | } | 
|---|
| 282 |  | 
|---|
| 283 | static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *kfc) | 
|---|
| 284 | { | 
|---|
| 285 | struct kernfs_super_info *info = kernfs_info(sb); | 
|---|
| 286 | struct kernfs_root *kf_root = kfc->root; | 
|---|
| 287 | struct inode *inode; | 
|---|
| 288 | struct dentry *root; | 
|---|
| 289 |  | 
|---|
| 290 | info->sb = sb; | 
|---|
| 291 | /* Userspace would break if executables or devices appear on sysfs */ | 
|---|
| 292 | sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; | 
|---|
| 293 | sb->s_blocksize = PAGE_SIZE; | 
|---|
| 294 | sb->s_blocksize_bits = PAGE_SHIFT; | 
|---|
| 295 | sb->s_magic = kfc->magic; | 
|---|
| 296 | sb->s_op = &kernfs_sops; | 
|---|
| 297 | sb->s_xattr = kernfs_xattr_handlers; | 
|---|
| 298 | if (info->root->flags & KERNFS_ROOT_SUPPORT_EXPORTOP) | 
|---|
| 299 | sb->s_export_op = &kernfs_export_ops; | 
|---|
| 300 | sb->s_time_gran = 1; | 
|---|
| 301 |  | 
|---|
| 302 | /* sysfs dentries and inodes don't require IO to create */ | 
|---|
| 303 | sb->s_shrink->seeks = 0; | 
|---|
| 304 |  | 
|---|
| 305 | /* get root inode, initialize and unlock it */ | 
|---|
| 306 | down_read(sem: &kf_root->kernfs_rwsem); | 
|---|
| 307 | inode = kernfs_get_inode(sb, kn: info->root->kn); | 
|---|
| 308 | up_read(sem: &kf_root->kernfs_rwsem); | 
|---|
| 309 | if (!inode) { | 
|---|
| 310 | pr_debug( "kernfs: could not get root inode\n"); | 
|---|
| 311 | return -ENOMEM; | 
|---|
| 312 | } | 
|---|
| 313 |  | 
|---|
| 314 | /* instantiate and link root dentry */ | 
|---|
| 315 | root = d_make_root(inode); | 
|---|
| 316 | if (!root) { | 
|---|
| 317 | pr_debug( "%s: could not get root dentry!\n", __func__); | 
|---|
| 318 | return -ENOMEM; | 
|---|
| 319 | } | 
|---|
| 320 | sb->s_root = root; | 
|---|
| 321 | set_default_d_op(sb, &kernfs_dops); | 
|---|
| 322 | return 0; | 
|---|
| 323 | } | 
|---|
| 324 |  | 
|---|
| 325 | static int kernfs_test_super(struct super_block *sb, struct fs_context *fc) | 
|---|
| 326 | { | 
|---|
| 327 | struct kernfs_super_info *sb_info = kernfs_info(sb); | 
|---|
| 328 | struct kernfs_super_info *info = fc->s_fs_info; | 
|---|
| 329 |  | 
|---|
| 330 | return sb_info->root == info->root && sb_info->ns == info->ns; | 
|---|
| 331 | } | 
|---|
| 332 |  | 
|---|
| 333 | static int kernfs_set_super(struct super_block *sb, struct fs_context *fc) | 
|---|
| 334 | { | 
|---|
| 335 | struct kernfs_fs_context *kfc = fc->fs_private; | 
|---|
| 336 |  | 
|---|
| 337 | kfc->ns_tag = NULL; | 
|---|
| 338 | return set_anon_super_fc(s: sb, fc); | 
|---|
| 339 | } | 
|---|
| 340 |  | 
|---|
| 341 | /** | 
|---|
| 342 | * kernfs_super_ns - determine the namespace tag of a kernfs super_block | 
|---|
| 343 | * @sb: super_block of interest | 
|---|
| 344 | * | 
|---|
| 345 | * Return: the namespace tag associated with kernfs super_block @sb. | 
|---|
| 346 | */ | 
|---|
| 347 | const void *kernfs_super_ns(struct super_block *sb) | 
|---|
| 348 | { | 
|---|
| 349 | struct kernfs_super_info *info = kernfs_info(sb); | 
|---|
| 350 |  | 
|---|
| 351 | return info->ns; | 
|---|
| 352 | } | 
|---|
| 353 |  | 
|---|
| 354 | /** | 
|---|
| 355 | * kernfs_get_tree - kernfs filesystem access/retrieval helper | 
|---|
| 356 | * @fc: The filesystem context. | 
|---|
| 357 | * | 
|---|
| 358 | * This is to be called from each kernfs user's fs_context->ops->get_tree() | 
|---|
| 359 | * implementation, which should set the specified ->@fs_type and ->@flags, and | 
|---|
| 360 | * specify the hierarchy and namespace tag to mount via ->@root and ->@ns, | 
|---|
| 361 | * respectively. | 
|---|
| 362 | * | 
|---|
| 363 | * Return: %0 on success, -errno on failure. | 
|---|
| 364 | */ | 
|---|
| 365 | int kernfs_get_tree(struct fs_context *fc) | 
|---|
| 366 | { | 
|---|
| 367 | struct kernfs_fs_context *kfc = fc->fs_private; | 
|---|
| 368 | struct super_block *sb; | 
|---|
| 369 | struct kernfs_super_info *info; | 
|---|
| 370 | int error; | 
|---|
| 371 |  | 
|---|
| 372 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 
|---|
| 373 | if (!info) | 
|---|
| 374 | return -ENOMEM; | 
|---|
| 375 |  | 
|---|
| 376 | info->root = kfc->root; | 
|---|
| 377 | info->ns = kfc->ns_tag; | 
|---|
| 378 | INIT_LIST_HEAD(list: &info->node); | 
|---|
| 379 |  | 
|---|
| 380 | fc->s_fs_info = info; | 
|---|
| 381 | sb = sget_fc(fc, test: kernfs_test_super, set: kernfs_set_super); | 
|---|
| 382 | if (IS_ERR(ptr: sb)) | 
|---|
| 383 | return PTR_ERR(ptr: sb); | 
|---|
| 384 |  | 
|---|
| 385 | if (!sb->s_root) { | 
|---|
| 386 | struct kernfs_super_info *info = kernfs_info(sb); | 
|---|
| 387 | struct kernfs_root *root = kfc->root; | 
|---|
| 388 |  | 
|---|
| 389 | kfc->new_sb_created = true; | 
|---|
| 390 |  | 
|---|
| 391 | error = kernfs_fill_super(sb, kfc); | 
|---|
| 392 | if (error) { | 
|---|
| 393 | deactivate_locked_super(sb); | 
|---|
| 394 | return error; | 
|---|
| 395 | } | 
|---|
| 396 | sb->s_flags |= SB_ACTIVE; | 
|---|
| 397 |  | 
|---|
| 398 | uuid_t uuid; | 
|---|
| 399 | uuid_gen(u: &uuid); | 
|---|
| 400 | super_set_uuid(sb, uuid: uuid.b, len: sizeof(uuid)); | 
|---|
| 401 |  | 
|---|
| 402 | down_write(sem: &root->kernfs_supers_rwsem); | 
|---|
| 403 | list_add(new: &info->node, head: &info->root->supers); | 
|---|
| 404 | up_write(sem: &root->kernfs_supers_rwsem); | 
|---|
| 405 | } | 
|---|
| 406 |  | 
|---|
| 407 | fc->root = dget(dentry: sb->s_root); | 
|---|
| 408 | return 0; | 
|---|
| 409 | } | 
|---|
| 410 |  | 
|---|
| 411 | void kernfs_free_fs_context(struct fs_context *fc) | 
|---|
| 412 | { | 
|---|
| 413 | /* Note that we don't deal with kfc->ns_tag here. */ | 
|---|
| 414 | kfree(objp: fc->s_fs_info); | 
|---|
| 415 | fc->s_fs_info = NULL; | 
|---|
| 416 | } | 
|---|
| 417 |  | 
|---|
| 418 | /** | 
|---|
| 419 | * kernfs_kill_sb - kill_sb for kernfs | 
|---|
| 420 | * @sb: super_block being killed | 
|---|
| 421 | * | 
|---|
| 422 | * This can be used directly for file_system_type->kill_sb().  If a kernfs | 
|---|
| 423 | * user needs extra cleanup, it can implement its own kill_sb() and call | 
|---|
| 424 | * this function at the end. | 
|---|
| 425 | */ | 
|---|
| 426 | void kernfs_kill_sb(struct super_block *sb) | 
|---|
| 427 | { | 
|---|
| 428 | struct kernfs_super_info *info = kernfs_info(sb); | 
|---|
| 429 | struct kernfs_root *root = info->root; | 
|---|
| 430 |  | 
|---|
| 431 | down_write(sem: &root->kernfs_supers_rwsem); | 
|---|
| 432 | list_del(entry: &info->node); | 
|---|
| 433 | up_write(sem: &root->kernfs_supers_rwsem); | 
|---|
| 434 |  | 
|---|
| 435 | /* | 
|---|
| 436 | * Remove the superblock from fs_supers/s_instances | 
|---|
| 437 | * so we can't find it, before freeing kernfs_super_info. | 
|---|
| 438 | */ | 
|---|
| 439 | kill_anon_super(sb); | 
|---|
| 440 | kfree(objp: info); | 
|---|
| 441 | } | 
|---|
| 442 |  | 
|---|
| 443 | static void __init kernfs_mutex_init(void) | 
|---|
| 444 | { | 
|---|
| 445 | int count; | 
|---|
| 446 |  | 
|---|
| 447 | for (count = 0; count < NR_KERNFS_LOCKS; count++) | 
|---|
| 448 | mutex_init(&kernfs_locks->open_file_mutex[count]); | 
|---|
| 449 | } | 
|---|
| 450 |  | 
|---|
| 451 | static void __init kernfs_lock_init(void) | 
|---|
| 452 | { | 
|---|
| 453 | kernfs_locks = kmalloc(sizeof(struct kernfs_global_locks), GFP_KERNEL); | 
|---|
| 454 | WARN_ON(!kernfs_locks); | 
|---|
| 455 |  | 
|---|
| 456 | kernfs_mutex_init(); | 
|---|
| 457 | } | 
|---|
| 458 |  | 
|---|
| 459 | void __init kernfs_init(void) | 
|---|
| 460 | { | 
|---|
| 461 | kernfs_node_cache = kmem_cache_create( "kernfs_node_cache", | 
|---|
| 462 | sizeof(struct kernfs_node), | 
|---|
| 463 | 0, SLAB_PANIC, NULL); | 
|---|
| 464 |  | 
|---|
| 465 | /* Creates slab cache for kernfs inode attributes */ | 
|---|
| 466 | kernfs_iattrs_cache  = kmem_cache_create( "kernfs_iattrs_cache", | 
|---|
| 467 | sizeof(struct kernfs_iattrs), | 
|---|
| 468 | 0, SLAB_PANIC, NULL); | 
|---|
| 469 |  | 
|---|
| 470 | kernfs_lock_init(); | 
|---|
| 471 | } | 
|---|
| 472 |  | 
|---|