18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fs/sysfs/symlink.c - operations for initializing and mounting sysfs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2001-3 Patrick Mochel 68c2ecf20Sopenharmony_ci * Copyright (c) 2007 SUSE Linux Products GmbH 78c2ecf20Sopenharmony_ci * Copyright (c) 2007 Tejun Heo <teheo@suse.de> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Please see Documentation/filesystems/sysfs.rst for more information. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/fs.h> 138c2ecf20Sopenharmony_ci#include <linux/magic.h> 148c2ecf20Sopenharmony_ci#include <linux/mount.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/user_namespace.h> 188c2ecf20Sopenharmony_ci#include <linux/fs_context.h> 198c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "sysfs.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic struct kernfs_root *sysfs_root; 248c2ecf20Sopenharmony_cistruct kernfs_node *sysfs_root_kn; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int sysfs_get_tree(struct fs_context *fc) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct kernfs_fs_context *kfc = fc->fs_private; 298c2ecf20Sopenharmony_ci int ret; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci ret = kernfs_get_tree(fc); 328c2ecf20Sopenharmony_ci if (ret) 338c2ecf20Sopenharmony_ci return ret; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (kfc->new_sb_created) 368c2ecf20Sopenharmony_ci fc->root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE; 378c2ecf20Sopenharmony_ci return 0; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void sysfs_fs_context_free(struct fs_context *fc) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct kernfs_fs_context *kfc = fc->fs_private; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (kfc->ns_tag) 458c2ecf20Sopenharmony_ci kobj_ns_drop(KOBJ_NS_TYPE_NET, kfc->ns_tag); 468c2ecf20Sopenharmony_ci kernfs_free_fs_context(fc); 478c2ecf20Sopenharmony_ci kfree(kfc); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const struct fs_context_operations sysfs_fs_context_ops = { 518c2ecf20Sopenharmony_ci .free = sysfs_fs_context_free, 528c2ecf20Sopenharmony_ci .get_tree = sysfs_get_tree, 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int sysfs_init_fs_context(struct fs_context *fc) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct kernfs_fs_context *kfc; 588c2ecf20Sopenharmony_ci struct net *netns; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (!(fc->sb_flags & SB_KERNMOUNT)) { 618c2ecf20Sopenharmony_ci if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) 628c2ecf20Sopenharmony_ci return -EPERM; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci kfc = kzalloc(sizeof(struct kernfs_fs_context), GFP_KERNEL); 668c2ecf20Sopenharmony_ci if (!kfc) 678c2ecf20Sopenharmony_ci return -ENOMEM; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci kfc->ns_tag = netns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 708c2ecf20Sopenharmony_ci kfc->root = sysfs_root; 718c2ecf20Sopenharmony_ci kfc->magic = SYSFS_MAGIC; 728c2ecf20Sopenharmony_ci fc->fs_private = kfc; 738c2ecf20Sopenharmony_ci fc->ops = &sysfs_fs_context_ops; 748c2ecf20Sopenharmony_ci if (netns) { 758c2ecf20Sopenharmony_ci put_user_ns(fc->user_ns); 768c2ecf20Sopenharmony_ci fc->user_ns = get_user_ns(netns->user_ns); 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci fc->global = true; 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void sysfs_kill_sb(struct super_block *sb) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci void *ns = (void *)kernfs_super_ns(sb); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci kernfs_kill_sb(sb); 878c2ecf20Sopenharmony_ci kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic struct file_system_type sysfs_fs_type = { 918c2ecf20Sopenharmony_ci .name = "sysfs", 928c2ecf20Sopenharmony_ci .init_fs_context = sysfs_init_fs_context, 938c2ecf20Sopenharmony_ci .kill_sb = sysfs_kill_sb, 948c2ecf20Sopenharmony_ci .fs_flags = FS_USERNS_MOUNT, 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciint __init sysfs_init(void) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int err; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK, 1028c2ecf20Sopenharmony_ci NULL); 1038c2ecf20Sopenharmony_ci if (IS_ERR(sysfs_root)) 1048c2ecf20Sopenharmony_ci return PTR_ERR(sysfs_root); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci sysfs_root_kn = sysfs_root->kn; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci err = register_filesystem(&sysfs_fs_type); 1098c2ecf20Sopenharmony_ci if (err) { 1108c2ecf20Sopenharmony_ci kernfs_destroy_root(sysfs_root); 1118c2ecf20Sopenharmony_ci return err; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 116