aboutsummaryrefslogtreecommitdiffstats
path: root/fs/super.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-06-23 05:02:57 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:42:45 -0400
commit454e2398be9b9fa30433fccc548db34d19aa9958 (patch)
tree1f61cb0c3716a33b661cfc8977e9beeb480a322c /fs/super.c
parent1ad5544098a69d7dc1fa508cbb17e13a7a952fd8 (diff)
[PATCH] VFS: Permit filesystem to override root dentry on mount
Extend the get_sb() filesystem operation to take an extra argument that permits the VFS to pass in the target vfsmount that defines the mountpoint. The filesystem is then required to manually set the superblock and root dentry pointers. For most filesystems, this should be done with simple_set_mnt() which will set the superblock pointer and then set the root dentry to the superblock's s_root (as per the old default behaviour). The get_sb() op now returns an integer as there's now no need to return the superblock pointer. This patch permits a superblock to be implicitly shared amongst several mount points, such as can be done with NFS to avoid potential inode aliasing. In such a case, simple_set_mnt() would not be called, and instead the mnt_root and mnt_sb would be set directly. The patch also makes the following changes: (*) the get_sb_*() convenience functions in the core kernel now take a vfsmount pointer argument and return an integer, so most filesystems have to change very little. (*) If one of the convenience function is not used, then get_sb() should normally call simple_set_mnt() to instantiate the vfsmount. This will always return 0, and so can be tail-called from get_sb(). (*) generic_shutdown_super() now calls shrink_dcache_sb() to clean up the dcache upon superblock destruction rather than shrink_dcache_anon(). This is required because the superblock may now have multiple trees that aren't actually bound to s_root, but that still need to be cleaned up. The currently called functions assume that the whole tree is rooted at s_root, and that anonymous dentries are not the roots of trees which results in dentries being left unculled. However, with the way NFS superblock sharing are currently set to be implemented, these assumptions are violated: the root of the filesystem is simply a dummy dentry and inode (the real inode for '/' may well be inaccessible), and all the vfsmounts are rooted on anonymous[*] dentries with child trees. [*] Anonymous until discovered from another tree. (*) The documentation has been adjusted, including the additional bit of changing ext2_* into foo_* in the documentation. [akpm@osdl.org: convert ipath_fs, do other stuff] Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Al Viro <viro@zeniv.linux.org.uk> Cc: Nathan Scott <nathans@sgi.com> Cc: Roland Dreier <rolandd@cisco.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/super.c')
-rw-r--r--fs/super.c109
1 files changed, 62 insertions, 47 deletions
diff --git a/fs/super.c b/fs/super.c
index 9d5c2add7228..324c2d232f54 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -231,7 +231,7 @@ void generic_shutdown_super(struct super_block *sb)
231 if (root) { 231 if (root) {
232 sb->s_root = NULL; 232 sb->s_root = NULL;
233 shrink_dcache_parent(root); 233 shrink_dcache_parent(root);
234 shrink_dcache_anon(sb); 234 shrink_dcache_sb(sb);
235 dput(root); 235 dput(root);
236 fsync_super(sb); 236 fsync_super(sb);
237 lock_super(sb); 237 lock_super(sb);
@@ -676,9 +676,10 @@ static void bdev_uevent(struct block_device *bdev, enum kobject_action action)
676 } 676 }
677} 677}
678 678
679struct super_block *get_sb_bdev(struct file_system_type *fs_type, 679int get_sb_bdev(struct file_system_type *fs_type,
680 int flags, const char *dev_name, void *data, 680 int flags, const char *dev_name, void *data,
681 int (*fill_super)(struct super_block *, void *, int)) 681 int (*fill_super)(struct super_block *, void *, int),
682 struct vfsmount *mnt)
682{ 683{
683 struct block_device *bdev; 684 struct block_device *bdev;
684 struct super_block *s; 685 struct super_block *s;
@@ -686,7 +687,7 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
686 687
687 bdev = open_bdev_excl(dev_name, flags, fs_type); 688 bdev = open_bdev_excl(dev_name, flags, fs_type);
688 if (IS_ERR(bdev)) 689 if (IS_ERR(bdev))
689 return (struct super_block *)bdev; 690 return PTR_ERR(bdev);
690 691
691 /* 692 /*
692 * once the super is inserted into the list by sget, s_umount 693 * once the super is inserted into the list by sget, s_umount
@@ -697,15 +698,17 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
697 s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); 698 s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
698 mutex_unlock(&bdev->bd_mount_mutex); 699 mutex_unlock(&bdev->bd_mount_mutex);
699 if (IS_ERR(s)) 700 if (IS_ERR(s))
700 goto out; 701 goto error_s;
701 702
702 if (s->s_root) { 703 if (s->s_root) {
703 if ((flags ^ s->s_flags) & MS_RDONLY) { 704 if ((flags ^ s->s_flags) & MS_RDONLY) {
704 up_write(&s->s_umount); 705 up_write(&s->s_umount);
705 deactivate_super(s); 706 deactivate_super(s);
706 s = ERR_PTR(-EBUSY); 707 error = -EBUSY;
708 goto error_bdev;
707 } 709 }
708 goto out; 710
711 close_bdev_excl(bdev);
709 } else { 712 } else {
710 char b[BDEVNAME_SIZE]; 713 char b[BDEVNAME_SIZE];
711 714
@@ -716,18 +719,21 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
716 if (error) { 719 if (error) {
717 up_write(&s->s_umount); 720 up_write(&s->s_umount);
718 deactivate_super(s); 721 deactivate_super(s);
719 s = ERR_PTR(error); 722 goto error;
720 } else {
721 s->s_flags |= MS_ACTIVE;
722 bdev_uevent(bdev, KOBJ_MOUNT);
723 } 723 }
724
725 s->s_flags |= MS_ACTIVE;
726 bdev_uevent(bdev, KOBJ_MOUNT);
724 } 727 }
725 728
726 return s; 729 return simple_set_mnt(mnt, s);
727 730
728out: 731error_s:
732 error = PTR_ERR(s);
733error_bdev:
729 close_bdev_excl(bdev); 734 close_bdev_excl(bdev);
730 return s; 735error:
736 return error;
731} 737}
732 738
733EXPORT_SYMBOL(get_sb_bdev); 739EXPORT_SYMBOL(get_sb_bdev);
@@ -744,15 +750,16 @@ void kill_block_super(struct super_block *sb)
744 750
745EXPORT_SYMBOL(kill_block_super); 751EXPORT_SYMBOL(kill_block_super);
746 752
747struct super_block *get_sb_nodev(struct file_system_type *fs_type, 753int get_sb_nodev(struct file_system_type *fs_type,
748 int flags, void *data, 754 int flags, void *data,
749 int (*fill_super)(struct super_block *, void *, int)) 755 int (*fill_super)(struct super_block *, void *, int),
756 struct vfsmount *mnt)
750{ 757{
751 int error; 758 int error;
752 struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); 759 struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
753 760
754 if (IS_ERR(s)) 761 if (IS_ERR(s))
755 return s; 762 return PTR_ERR(s);
756 763
757 s->s_flags = flags; 764 s->s_flags = flags;
758 765
@@ -760,10 +767,10 @@ struct super_block *get_sb_nodev(struct file_system_type *fs_type,
760 if (error) { 767 if (error) {
761 up_write(&s->s_umount); 768 up_write(&s->s_umount);
762 deactivate_super(s); 769 deactivate_super(s);
763 return ERR_PTR(error); 770 return error;
764 } 771 }
765 s->s_flags |= MS_ACTIVE; 772 s->s_flags |= MS_ACTIVE;
766 return s; 773 return simple_set_mnt(mnt, s);
767} 774}
768 775
769EXPORT_SYMBOL(get_sb_nodev); 776EXPORT_SYMBOL(get_sb_nodev);
@@ -773,94 +780,102 @@ static int compare_single(struct super_block *s, void *p)
773 return 1; 780 return 1;
774} 781}
775 782
776struct super_block *get_sb_single(struct file_system_type *fs_type, 783int get_sb_single(struct file_system_type *fs_type,
777 int flags, void *data, 784 int flags, void *data,
778 int (*fill_super)(struct super_block *, void *, int)) 785 int (*fill_super)(struct super_block *, void *, int),
786 struct vfsmount *mnt)
779{ 787{
780 struct super_block *s; 788 struct super_block *s;
781 int error; 789 int error;
782 790
783 s = sget(fs_type, compare_single, set_anon_super, NULL); 791 s = sget(fs_type, compare_single, set_anon_super, NULL);
784 if (IS_ERR(s)) 792 if (IS_ERR(s))
785 return s; 793 return PTR_ERR(s);
786 if (!s->s_root) { 794 if (!s->s_root) {
787 s->s_flags = flags; 795 s->s_flags = flags;
788 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); 796 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
789 if (error) { 797 if (error) {
790 up_write(&s->s_umount); 798 up_write(&s->s_umount);
791 deactivate_super(s); 799 deactivate_super(s);
792 return ERR_PTR(error); 800 return error;
793 } 801 }
794 s->s_flags |= MS_ACTIVE; 802 s->s_flags |= MS_ACTIVE;
795 } 803 }
796 do_remount_sb(s, flags, data, 0); 804 do_remount_sb(s, flags, data, 0);
797 return s; 805 return simple_set_mnt(mnt, s);
798} 806}
799 807
800EXPORT_SYMBOL(get_sb_single); 808EXPORT_SYMBOL(get_sb_single);
801 809
802struct vfsmount * 810struct vfsmount *
803do_kern_mount(const char *fstype, int flags, const char *name, void *data) 811vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
804{ 812{
805 struct file_system_type *type = get_fs_type(fstype);
806 struct super_block *sb = ERR_PTR(-ENOMEM);
807 struct vfsmount *mnt; 813 struct vfsmount *mnt;
808 int error;
809 char *secdata = NULL; 814 char *secdata = NULL;
815 int error;
810 816
811 if (!type) 817 if (!type)
812 return ERR_PTR(-ENODEV); 818 return ERR_PTR(-ENODEV);
813 819
820 error = -ENOMEM;
814 mnt = alloc_vfsmnt(name); 821 mnt = alloc_vfsmnt(name);
815 if (!mnt) 822 if (!mnt)
816 goto out; 823 goto out;
817 824
818 if (data) { 825 if (data) {
819 secdata = alloc_secdata(); 826 secdata = alloc_secdata();
820 if (!secdata) { 827 if (!secdata)
821 sb = ERR_PTR(-ENOMEM);
822 goto out_mnt; 828 goto out_mnt;
823 }
824 829
825 error = security_sb_copy_data(type, data, secdata); 830 error = security_sb_copy_data(type, data, secdata);
826 if (error) { 831 if (error)
827 sb = ERR_PTR(error);
828 goto out_free_secdata; 832 goto out_free_secdata;
829 }
830 } 833 }
831 834
832 sb = type->get_sb(type, flags, name, data); 835 error = type->get_sb(type, flags, name, data, mnt);
833 if (IS_ERR(sb)) 836 if (error < 0)
834 goto out_free_secdata; 837 goto out_free_secdata;
835 error = security_sb_kern_mount(sb, secdata); 838
839 error = security_sb_kern_mount(mnt->mnt_sb, secdata);
836 if (error) 840 if (error)
837 goto out_sb; 841 goto out_sb;
838 mnt->mnt_sb = sb; 842
839 mnt->mnt_root = dget(sb->s_root); 843 mnt->mnt_mountpoint = mnt->mnt_root;
840 mnt->mnt_mountpoint = sb->s_root;
841 mnt->mnt_parent = mnt; 844 mnt->mnt_parent = mnt;
842 up_write(&sb->s_umount); 845 up_write(&mnt->mnt_sb->s_umount);
843 free_secdata(secdata); 846 free_secdata(secdata);
844 put_filesystem(type);
845 return mnt; 847 return mnt;
846out_sb: 848out_sb:
847 up_write(&sb->s_umount); 849 dput(mnt->mnt_root);
848 deactivate_super(sb); 850 up_write(&mnt->mnt_sb->s_umount);
849 sb = ERR_PTR(error); 851 deactivate_super(mnt->mnt_sb);
850out_free_secdata: 852out_free_secdata:
851 free_secdata(secdata); 853 free_secdata(secdata);
852out_mnt: 854out_mnt:
853 free_vfsmnt(mnt); 855 free_vfsmnt(mnt);
854out: 856out:
857 return ERR_PTR(error);
858}
859
860EXPORT_SYMBOL_GPL(vfs_kern_mount);
861
862struct vfsmount *
863do_kern_mount(const char *fstype, int flags, const char *name, void *data)
864{
865 struct file_system_type *type = get_fs_type(fstype);
866 struct vfsmount *mnt;
867 if (!type)
868 return ERR_PTR(-ENODEV);
869 mnt = vfs_kern_mount(type, flags, name, data);
855 put_filesystem(type); 870 put_filesystem(type);
856 return (struct vfsmount *)sb; 871 return mnt;
857} 872}
858 873
859EXPORT_SYMBOL_GPL(do_kern_mount); 874EXPORT_SYMBOL_GPL(do_kern_mount);
860 875
861struct vfsmount *kern_mount(struct file_system_type *type) 876struct vfsmount *kern_mount(struct file_system_type *type)
862{ 877{
863 return do_kern_mount(type->name, 0, type->name, NULL); 878 return vfs_kern_mount(type, 0, type->name, NULL);
864} 879}
865 880
866EXPORT_SYMBOL(kern_mount); 881EXPORT_SYMBOL(kern_mount);