Tree has invariant part + two subtrees that get replaced upon each policy load. Invariant parts stay for the lifetime of filesystem, these two subdirs - from policy load to policy load (serialized on lock_rename(root, ...)).
All object creations are via d_alloc_name()+d_add() inside selinuxfs, all removals are via simple_recursive_removal(). Turn those d_add() into d_make_persistent()+dput() and that's mostly it. Don't bother to store the dentry of /policy_capabilities - it belongs to invariant part of tree and we only use it to populate that directory, so there's no reason to keep it around afterwards. Signed-off-by: Al Viro <[email protected]> --- security/selinux/selinuxfs.c | 52 +++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 9aa1d03ab612..dc1bb49664f2 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -75,7 +75,6 @@ struct selinux_fs_info { struct dentry *class_dir; unsigned long last_class_ino; bool policy_opened; - struct dentry *policycap_dir; unsigned long last_ino; struct super_block *sb; }; @@ -1404,7 +1403,8 @@ static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_ isec->initialized = LABEL_INITIALIZED; inode->i_fop = &sel_bool_ops; inode->i_ino = i|SEL_BOOL_INO_OFFSET; - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); } out: free_page((unsigned long)page); @@ -1614,7 +1614,8 @@ static int sel_make_avc_files(struct dentry *dir) inode->i_fop = files[i].ops; inode->i_ino = ++fsi->last_ino; - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); } return 0; @@ -1645,7 +1646,8 @@ static int sel_make_ss_files(struct dentry *dir) inode->i_fop = files[i].ops; inode->i_ino = ++fsi->last_ino; - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); } return 0; @@ -1696,7 +1698,8 @@ static int sel_make_initcon_files(struct dentry *dir) inode->i_fop = &sel_initcon_ops; inode->i_ino = i|SEL_INITCON_INO_OFFSET; - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); } return 0; @@ -1800,7 +1803,8 @@ static int sel_make_perm_files(struct selinux_policy *newpolicy, inode->i_fop = &sel_perm_ops; /* i+1 since perm values are 1-indexed */ inode->i_ino = sel_perm_to_ino(classvalue, i + 1); - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); } rc = 0; out: @@ -1831,7 +1835,8 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy, inode->i_fop = &sel_class_ops; inode->i_ino = sel_class_to_ino(index); - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); dentry = sel_make_dir(dir, "perms", &fsi->last_class_ino); if (IS_ERR(dentry)) @@ -1879,7 +1884,7 @@ static int sel_make_classes(struct selinux_policy *newpolicy, return rc; } -static int sel_make_policycap(struct selinux_fs_info *fsi) +static int sel_make_policycap(struct selinux_fs_info *fsi, struct dentry *dir) { unsigned int iter; struct dentry *dentry = NULL; @@ -1887,10 +1892,10 @@ static int sel_make_policycap(struct selinux_fs_info *fsi) for (iter = 0; iter <= POLICYDB_CAP_MAX; iter++) { if (iter < ARRAY_SIZE(selinux_policycap_names)) - dentry = d_alloc_name(fsi->policycap_dir, + dentry = d_alloc_name(dir, selinux_policycap_names[iter]); else - dentry = d_alloc_name(fsi->policycap_dir, "unknown"); + dentry = d_alloc_name(dir, "unknown"); if (dentry == NULL) return -ENOMEM; @@ -1903,7 +1908,8 @@ static int sel_make_policycap(struct selinux_fs_info *fsi) inode->i_fop = &sel_policycap_ops; inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET; - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); } return 0; @@ -1929,11 +1935,12 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name, inode->i_ino = ++(*ino); /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); - d_add(dentry, inode); + d_make_persistent(dentry, inode); /* bump link count on parent directory, too */ inc_nlink(d_inode(dir)); - return dentry; + dput(dentry); + return dentry; // borrowed } static int reject_all(struct mnt_idmap *idmap, struct inode *inode, int mask) @@ -1966,10 +1973,11 @@ static struct dentry *sel_make_swapover_dir(struct super_block *sb, /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); inode_lock(sb->s_root->d_inode); - d_add(dentry, inode); + d_make_persistent(dentry, inode); inc_nlink(sb->s_root->d_inode); inode_unlock(sb->s_root->d_inode); - return dentry; + dput(dentry); + return dentry; // borrowed } #define NULL_FILE_NAME "null" @@ -2040,7 +2048,8 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) isec->initialized = LABEL_INITIALIZED; init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3)); - d_add(dentry, inode); + d_make_persistent(dentry, inode); + dput(dentry); dentry = sel_make_dir(sb->s_root, "avc", &fsi->last_ino); if (IS_ERR(dentry)) { @@ -2079,15 +2088,14 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) goto err; } - fsi->policycap_dir = sel_make_dir(sb->s_root, POLICYCAP_DIR_NAME, + dentry = sel_make_dir(sb->s_root, POLICYCAP_DIR_NAME, &fsi->last_ino); - if (IS_ERR(fsi->policycap_dir)) { - ret = PTR_ERR(fsi->policycap_dir); - fsi->policycap_dir = NULL; + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); goto err; } - ret = sel_make_policycap(fsi); + ret = sel_make_policycap(fsi, dentry); if (ret) { pr_err("SELinux: failed to load policy capabilities\n"); goto err; @@ -2119,7 +2127,7 @@ static int sel_init_fs_context(struct fs_context *fc) static void sel_kill_sb(struct super_block *sb) { selinux_fs_info_free(sb); - kill_litter_super(sb); + kill_anon_super(sb); } static struct file_system_type sel_fs_type = { -- 2.47.3
