unsigned long *ino);
 
 /* declaration for sel_make_policy_nodes */
-static struct dentry *sel_make_disconnected_dir(struct super_block *sb,
+static struct dentry *sel_make_swapover_dir(struct super_block *sb,
                                                unsigned long *ino);
 
-/* declaration for sel_make_policy_nodes */
-static void sel_remove_entries(struct dentry *de);
-
 static ssize_t sel_read_mls(struct file *filp, char __user *buf,
                                size_t count, loff_t *ppos)
 {
                                struct selinux_policy *newpolicy)
 {
        int ret = 0;
-       struct dentry *tmp_parent, *tmp_bool_dir, *tmp_class_dir, *old_dentry;
-       unsigned int tmp_bool_num, old_bool_num;
-       char **tmp_bool_names, **old_bool_names;
-       int *tmp_bool_values, *old_bool_values;
+       struct dentry *tmp_parent, *tmp_bool_dir, *tmp_class_dir;
+       unsigned int bool_num = 0;
+       char **bool_names = NULL;
+       int *bool_values = NULL;
        unsigned long tmp_ino = fsi->last_ino; /* Don't increment last_ino in this function */
 
-       tmp_parent = sel_make_disconnected_dir(fsi->sb, &tmp_ino);
+       tmp_parent = sel_make_swapover_dir(fsi->sb, &tmp_ino);
        if (IS_ERR(tmp_parent))
                return PTR_ERR(tmp_parent);
 
                goto out;
        }
 
-       ret = sel_make_bools(newpolicy, tmp_bool_dir, &tmp_bool_num,
-                            &tmp_bool_names, &tmp_bool_values);
+       ret = sel_make_bools(newpolicy, tmp_bool_dir, &bool_num,
+                            &bool_names, &bool_values);
        if (ret)
                goto out;
 
        if (ret)
                goto out;
 
+       lock_rename(tmp_parent, fsi->sb->s_root);
+
        /* booleans */
-       old_dentry = fsi->bool_dir;
-       lock_rename(tmp_bool_dir, old_dentry);
        d_exchange(tmp_bool_dir, fsi->bool_dir);
 
-       old_bool_num = fsi->bool_num;
-       old_bool_names = fsi->bool_pending_names;
-       old_bool_values = fsi->bool_pending_values;
-
-       fsi->bool_num = tmp_bool_num;
-       fsi->bool_pending_names = tmp_bool_names;
-       fsi->bool_pending_values = tmp_bool_values;
-
-       sel_remove_old_bool_data(old_bool_num, old_bool_names, old_bool_values);
+       swap(fsi->bool_num, bool_num);
+       swap(fsi->bool_pending_names, bool_names);
+       swap(fsi->bool_pending_values, bool_values);
 
        fsi->bool_dir = tmp_bool_dir;
-       unlock_rename(tmp_bool_dir, old_dentry);
 
        /* classes */
-       old_dentry = fsi->class_dir;
-       lock_rename(tmp_class_dir, old_dentry);
        d_exchange(tmp_class_dir, fsi->class_dir);
        fsi->class_dir = tmp_class_dir;
-       unlock_rename(tmp_class_dir, old_dentry);
+
+       unlock_rename(tmp_parent, fsi->sb->s_root);
 
 out:
+       sel_remove_old_bool_data(bool_num, bool_names, bool_values);
        /* Since the other temporary dirs are children of tmp_parent
         * this will handle all the cleanup in the case of a failure before
         * the swapover
         */
-       sel_remove_entries(tmp_parent);
-       dput(tmp_parent); /* d_genocide() only handles the children */
+       simple_recursive_removal(tmp_parent, NULL);
 
        return ret;
 }
        .llseek         = generic_file_llseek,
 };
 
-static void sel_remove_entries(struct dentry *de)
-{
-       d_genocide(de);
-       shrink_dcache_parent(de);
-}
-
 static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir,
                          unsigned int *bool_num, char ***bool_pending_names,
                          int **bool_pending_values)
 {
        int ret;
-       ssize_t len;
-       struct dentry *dentry = NULL;
-       struct inode *inode = NULL;
-       struct inode_security_struct *isec;
-       char **names = NULL, *page;
+       char **names, *page;
        u32 i, num;
-       int *values = NULL;
-       u32 sid;
 
-       ret = -ENOMEM;
        page = (char *)get_zeroed_page(GFP_KERNEL);
        if (!page)
-               goto out;
+               return -ENOMEM;
 
-       ret = security_get_bools(newpolicy, &num, &names, &values);
+       ret = security_get_bools(newpolicy, &num, &names, bool_pending_values);
        if (ret)
                goto out;
 
+       *bool_num = num;
+       *bool_pending_names = names;
+
        for (i = 0; i < num; i++) {
-               ret = -ENOMEM;
+               struct dentry *dentry;
+               struct inode *inode;
+               struct inode_security_struct *isec;
+               ssize_t len;
+               u32 sid;
+
+               len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
+               if (len >= PAGE_SIZE) {
+                       ret = -ENAMETOOLONG;
+                       break;
+               }
                dentry = d_alloc_name(bool_dir, names[i]);
-               if (!dentry)
-                       goto out;
+               if (!dentry) {
+                       ret = -ENOMEM;
+                       break;
+               }
 
-               ret = -ENOMEM;
                inode = sel_make_inode(bool_dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
                if (!inode) {
                        dput(dentry);
-                       goto out;
-               }
-
-               ret = -ENAMETOOLONG;
-               len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
-               if (len >= PAGE_SIZE) {
-                       dput(dentry);
-                       iput(inode);
-                       goto out;
+                       ret = -ENOMEM;
+                       break;
                }
 
                isec = selinux_inode(inode);
                inode->i_ino = i|SEL_BOOL_INO_OFFSET;
                d_add(dentry, inode);
        }
-       *bool_num = num;
-       *bool_pending_names = names;
-       *bool_pending_values = values;
-
-       free_page((unsigned long)page);
-       return 0;
 out:
        free_page((unsigned long)page);
-
-       if (names) {
-               for (i = 0; i < num; i++)
-                       kfree(names[i]);
-               kfree(names);
-       }
-       kfree(values);
-       sel_remove_entries(bool_dir);
-
        return ret;
 }
 
        return dentry;
 }
 
-static struct dentry *sel_make_disconnected_dir(struct super_block *sb,
+static int reject_all(struct mnt_idmap *idmap, struct inode *inode, int mask)
+{
+       return -EPERM;  // no access for anyone, root or no root.
+}
+
+static const struct inode_operations swapover_dir_inode_operations = {
+       .lookup         = simple_lookup,
+       .permission     = reject_all,
+};
+
+static struct dentry *sel_make_swapover_dir(struct super_block *sb,
                                                unsigned long *ino)
 {
-       struct inode *inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
+       struct dentry *dentry = d_alloc_name(sb->s_root, ".swapover");
+       struct inode *inode;
 
-       if (!inode)
+       if (!dentry)
                return ERR_PTR(-ENOMEM);
 
-       inode->i_op = &simple_dir_inode_operations;
-       inode->i_fop = &simple_dir_operations;
+       inode = sel_make_inode(sb, S_IFDIR);
+       if (!inode) {
+               dput(dentry);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       inode->i_op = &swapover_dir_inode_operations;
        inode->i_ino = ++(*ino);
        /* directory inodes start off with i_nlink == 2 (for "." entry) */
        inc_nlink(inode);
-       return d_obtain_alias(inode);
+       inode_lock(sb->s_root->d_inode);
+       d_add(dentry, inode);
+       inc_nlink(sb->s_root->d_inode);
+       inode_unlock(sb->s_root->d_inode);
+       return dentry;
 }
 
 #define NULL_FILE_NAME "null"