VFS : mount lock scalability for internal mounts
authorTim Chen <tim.c.chen@linux.intel.com>
Tue, 19 Jul 2011 16:32:38 +0000 (09:32 -0700)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 24 Jul 2011 14:08:32 +0000 (10:08 -0400)
For a number of file systems that don't have a mount point (e.g. sockfs
and pipefs), they are not marked as long term. Therefore in
mntput_no_expire, all locks in vfs_mount lock are taken instead of just
local cpu's lock to aggregate reference counts when we release
reference to file objects.  In fact, only local lock need to have been
taken to update ref counts as these file systems are in no danger of
going away until we are ready to unregister them.

The attached patch marks file systems using kern_mount without
mount point as long term.  The contentions of vfs_mount lock
is now eliminated.  Before un-registering such file system,
kern_unmount should be called to remove the long term flag and
make the mount point ready to be freed.

Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
drivers/mtd/mtdchar.c
fs/anon_inodes.c
fs/hugetlbfs/inode.c
fs/namespace.c
fs/pipe.c
include/linux/fs.h
security/selinux/selinuxfs.c

index 3f92731a5b9ebf288ed83602c36972e5d32dee8d..f1af2228a1b1ec2e90ee2cb19958a68f0d7bb0da 100644 (file)
@@ -1192,7 +1192,7 @@ err_unregister_chdev:
 static void __exit cleanup_mtdchar(void)
 {
        unregister_mtd_user(&mtdchar_notifier);
-       mntput(mtd_inode_mnt);
+       kern_unmount(mtd_inode_mnt);
        unregister_filesystem(&mtd_inodefs_type);
        __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
 }
index c5567cb784325a7fa6f745c63e473edea592c4fb..4d433d34736f2e45784142012e1969f712443c93 100644 (file)
@@ -233,7 +233,7 @@ static int __init anon_inode_init(void)
        return 0;
 
 err_mntput:
-       mntput(anon_inode_mnt);
+       kern_unmount(anon_inode_mnt);
 err_unregister_filesystem:
        unregister_filesystem(&anon_inode_fs_type);
 err_exit:
index 7aafeb8fa3005eb14fd09f75d94c17dbeefe8481..0b686cec9976b39bfd50f37b4a5ad8d7690d4e29 100644 (file)
@@ -1030,6 +1030,7 @@ static int __init init_hugetlbfs_fs(void)
 static void __exit exit_hugetlbfs_fs(void)
 {
        kmem_cache_destroy(hugetlbfs_inode_cachep);
+       kern_unmount(hugetlbfs_vfsmount);
        unregister_filesystem(&hugetlbfs_fs_type);
        bdi_destroy(&hugetlbfs_backing_dev_info);
 }
index cda50fe9250ac3e7eb52d6a56143731505ef732f..22bfe8273c680b441f43a0191c7bd0e805a51ec2 100644 (file)
@@ -2721,6 +2721,25 @@ EXPORT_SYMBOL(put_mnt_ns);
 
 struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
 {
-       return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
+       struct vfsmount *mnt;
+       mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
+       if (!IS_ERR(mnt)) {
+               /*
+                * it is a longterm mount, don't release mnt until
+                * we unmount before file sys is unregistered
+               */
+               mnt_make_longterm(mnt);
+       }
+       return mnt;
 }
 EXPORT_SYMBOL_GPL(kern_mount_data);
+
+void kern_unmount(struct vfsmount *mnt)
+{
+       /* release long term mount so mount point can be released */
+       if (!IS_ERR_OR_NULL(mnt)) {
+               mnt_make_shortterm(mnt);
+               mntput(mnt);
+       }
+}
+EXPORT_SYMBOL(kern_unmount);
index da42f7db50de42640a7fa56df21e21bbb48cf588..1b7f9af67ccfff8ca6aaacb9ecdd8ddc87fa99a0 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1291,8 +1291,8 @@ static int __init init_pipe_fs(void)
 
 static void __exit exit_pipe_fs(void)
 {
+       kern_unmount(pipe_mnt);
        unregister_filesystem(&pipe_fs_type);
-       mntput(pipe_mnt);
 }
 
 fs_initcall(init_pipe_fs);
index b224dc468a232e30b752d7e2815d3dd8a975af89..7a757a48a5c6acbb8b2bca1c9d52c3ad09d46d7a 100644 (file)
@@ -1885,6 +1885,7 @@ extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
 extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data);
 #define kern_mount(type) kern_mount_data(type, NULL)
+extern void kern_unmount(struct vfsmount *mnt);
 extern int may_umount_tree(struct vfsmount *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(char *, char *, char *, unsigned long, void *);
index 35459340019e44399775c2f96aa9b5871f8d566c..de7900ef53da6257ab610629fd8ef65368526d62 100644 (file)
@@ -1984,6 +1984,7 @@ __initcall(init_sel_fs);
 void exit_sel_fs(void)
 {
        kobject_put(selinuxfs_kobj);
+       kern_unmount(selinuxfs_mount);
        unregister_filesystem(&sel_fs_type);
 }
 #endif