patch-2.4.19 linux-2.4.19/fs/super.c

Next file: linux-2.4.19/fs/udf/balloc.c
Previous file: linux-2.4.19/fs/smbfs/proc.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/fs/super.c linux-2.4.19/fs/super.c
@@ -21,36 +21,19 @@
  */
 
 #include <linux/config.h>
-#include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <linux/devfs_fs_kernel.h>
-#include <linux/fd.h>
-#include <linux/init.h>
 #include <linux/major.h>
-#include <linux/quotaops.h>
 #include <linux/acct.h>
 
 #include <asm/uaccess.h>
 
-#include <linux/nfs_fs.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/nfs_mount.h>
-
 #include <linux/kmod.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
-extern void wait_for_keypress(void);
-
-extern int root_mountflags;
-
-int do_remount_sb(struct super_block *sb, int flags, void * data);
-
-/* this is initialized in init/main.c */
-kdev_t ROOT_DEV;
-
 LIST_HEAD(super_blocks);
 spinlock_t sb_lock = SPIN_LOCK_UNLOCKED;
 
@@ -392,7 +375,7 @@
 	get_filesystem(type);
 }
 
-void put_unnamed_dev(kdev_t dev);	/* should become static */
+static void put_anon_dev(kdev_t dev);
 
 /**
  *	remove_super	-	makes superblock unreachable
@@ -422,16 +405,11 @@
 	if (bdev)
 		blkdev_put(bdev, BDEV_FS);
 	else
-		put_unnamed_dev(dev);
+		put_anon_dev(dev);
 }
 
-struct vfsmount *alloc_vfsmnt(void);
+struct vfsmount *alloc_vfsmnt(char *name);
 void free_vfsmnt(struct vfsmount *mnt);
-void set_devname(struct vfsmount *mnt, const char *name);
-
-/* Will go away */
-extern struct vfsmount *root_vfsmnt;
-extern int graft_tree(struct vfsmount *mnt, struct nameidata *nd);
 
 static inline struct super_block * find_super(kdev_t dev)
 {
@@ -549,35 +527,38 @@
 	return err;
 }
 
-static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
-				       struct file_system_type *type, int flags,
-				       void *data)
+/**
+ *	do_remount_sb	-	asks filesystem to change mount options.
+ *	@sb:	superblock in question
+ *	@flags:	numeric part of options
+ *	@data:	the rest of options
+ *
+ *	Alters the mount options of a mounted file system.
+ */
+int do_remount_sb(struct super_block *sb, int flags, void *data)
 {
-	struct super_block * s;
-	s = alloc_super();
-	if (!s)
-		goto out;
-	s->s_dev = dev;
-	s->s_bdev = bdev;
-	s->s_flags = flags;
-	spin_lock(&sb_lock);
-	insert_super(s, type);
-	lock_super(s);
-	if (!type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
-		goto out_fail;
-	s->s_flags |= MS_ACTIVE;
-	unlock_super(s);
-	/* tell bdcache that we are going to keep this one */
-	if (bdev)
-		atomic_inc(&bdev->bd_count);
-out:
-	return s;
-
-out_fail:
-	unlock_super(s);
-	deactivate_super(s);
-	remove_super(s);
-	return NULL;
+	int retval;
+	
+	if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
+		return -EACCES;
+		/*flags |= MS_RDONLY;*/
+	if (flags & MS_RDONLY)
+		acct_auto_close(sb->s_dev);
+	shrink_dcache_sb(sb);
+	fsync_super(sb);
+	/* If we are remounting RDONLY, make sure there are no rw files open */
+	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
+		if (!fs_may_remount_ro(sb))
+			return -EBUSY;
+	if (sb->s_op && sb->s_op->remount_fs) {
+		lock_super(sb);
+		retval = sb->s_op->remount_fs(sb, &flags, data);
+		unlock_super(sb);
+		if (retval)
+			return retval;
+	}
+	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+	return 0;
 }
 
 /*
@@ -585,31 +566,84 @@
  * filesystems which don't use real block-devices.  -- jrs
  */
 
-static unsigned long unnamed_dev_in_use[256/(8*sizeof(unsigned long))];
+enum {Max_anon = 256};
+static unsigned long unnamed_dev_in_use[Max_anon/(8*sizeof(unsigned long))];
+static spinlock_t unnamed_dev_lock = SPIN_LOCK_UNLOCKED;/* protects the above */
 
-kdev_t get_unnamed_dev(void)
+/**
+ *	put_anon_dev	-	release anonymous device number.
+ *	@dev:	device in question
+ */
+static void put_anon_dev(kdev_t dev)
 {
-	int i;
-
-	for (i = 1; i < 256; i++) {
-		if (!test_and_set_bit(i,unnamed_dev_in_use))
-			return MKDEV(UNNAMED_MAJOR, i);
-	}
-	return 0;
+	spin_lock(&unnamed_dev_lock);
+	clear_bit(MINOR(dev), unnamed_dev_in_use);
+	spin_unlock(&unnamed_dev_lock);
 }
 
-void put_unnamed_dev(kdev_t dev)
+/**
+ *	get_anon_super	-	allocate a superblock for non-device fs
+ *	@type:		filesystem type
+ *	@compare:	check if existing superblock is what we want
+ *	@data:		argument for @compare.
+ *
+ *	get_anon_super is a helper for non-blockdevice filesystems.
+ *	It either finds and returns one of the superblocks of given type
+ *	(if it can find one that would satisfy caller) or creates a new
+ *	one.  In the either case we return an active reference to superblock
+ *	with ->s_umount locked.  If superblock is new it gets a new
+ *	anonymous device allocated for it and is inserted into lists -
+ *	other initialization is left to caller.
+ *
+ *	Rather than duplicating all that logics every time when
+ *	we want something that doesn't fit "nodev" and "single" we pull
+ *	the relevant code into common helper and let get_sb_...() call
+ *	it.
+ *
+ *	NB: get_sb_...() is going to become an fs type method, with
+ *	current ->read_super() becoming a callback used by common instances.
+ */
+struct super_block *get_anon_super(struct file_system_type *type,
+	int (*compare)(struct super_block *,void *), void *data)
 {
-	if (!dev || MAJOR(dev) != UNNAMED_MAJOR)
-		return;
-	if (test_and_clear_bit(MINOR(dev), unnamed_dev_in_use))
-		return;
-	printk("VFS: put_unnamed_dev: freeing unused device %s\n",
-			kdevname(dev));
+	struct super_block *s = alloc_super();
+	kdev_t dev;
+	struct list_head *p;
+
+	if (!s)
+		return ERR_PTR(-ENOMEM);
+
+retry:
+	spin_lock(&sb_lock);
+	if (compare) list_for_each(p, &type->fs_supers) {
+		struct super_block *old;
+		old = list_entry(p, struct super_block, s_instances);
+		if (!compare(old, data))
+			continue;
+		if (!grab_super(old))
+			goto retry;
+		destroy_super(s);
+		return old;
+	}
+
+	spin_lock(&unnamed_dev_lock);
+	dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon);
+	if (dev == Max_anon) {
+		spin_unlock(&unnamed_dev_lock);
+		spin_unlock(&sb_lock);
+		destroy_super(s);
+		return ERR_PTR(-EMFILE);
+	}
+	set_bit(dev, unnamed_dev_in_use);
+	spin_unlock(&unnamed_dev_lock);
+
+	s->s_dev = dev;
+	insert_super(s, type);
+	return s;
 }
 
 static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
-	char *dev_name, int flags, void * data)
+	int flags, char *dev_name, void * data)
 {
 	struct inode *inode;
 	struct block_device *bdev;
@@ -651,17 +685,13 @@
 		goto out;
 	check_disk_change(dev);
 	error = -EACCES;
-	if (!(flags & MS_RDONLY) && is_read_only(dev)) {
-		blkdev_put(bdev, BDEV_FS);
-		goto out;
-	}
+	if (!(flags & MS_RDONLY) && is_read_only(dev))
+		goto out1;
 
 	error = -ENOMEM;
 	s = alloc_super();
-	if (!s) {
-		blkdev_put(bdev, BDEV_FS);
-		goto out;
-	}
+	if (!s)
+		goto out1;
 
 	error = -EBUSY;
 restart:
@@ -675,8 +705,7 @@
 		    ((flags ^ old->s_flags) & MS_RDONLY)) {
 			spin_unlock(&sb_lock);
 			destroy_super(s);
-			blkdev_put(bdev, BDEV_FS);
-			goto out;
+			goto out1;
 		}
 		if (!grab_super(old))
 			goto restart;
@@ -689,85 +718,102 @@
 	s->s_bdev = bdev;
 	s->s_flags = flags;
 	insert_super(s, fs_type);
-
-	error = -EINVAL;
-	lock_super(s);
 	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
-		goto out_fail;
+		goto Einval;
 	s->s_flags |= MS_ACTIVE;
-	unlock_super(s);
 	path_release(&nd);
 	return s;
 
-out_fail:
-	unlock_super(s);
+Einval:
 	deactivate_super(s);
 	remove_super(s);
+	error = -EINVAL;
+	goto out;
+out1:
+	blkdev_put(bdev, BDEV_FS);
 out:
 	path_release(&nd);
 	return ERR_PTR(error);
 }
 
 static struct super_block *get_sb_nodev(struct file_system_type *fs_type,
-	int flags, void * data)
+	int flags, char *dev_name, void *data)
 {
-	kdev_t dev;
-	int error = -EMFILE;
-	dev = get_unnamed_dev();
-	if (dev) {
-		struct super_block * sb;
-		error = -EINVAL;
-		sb = read_super(dev, NULL, fs_type, flags, data);
-		if (sb)
-			return sb;
+	struct super_block *s = get_anon_super(fs_type, NULL, NULL);
+
+	if (IS_ERR(s))
+		return s;
+
+	s->s_flags = flags;
+	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
+		deactivate_super(s);
+		remove_super(s);
+		return ERR_PTR(-EINVAL);
 	}
-	return ERR_PTR(error);
+	s->s_flags |= MS_ACTIVE;
+	return s;
+}
+
+static int compare_single(struct super_block *s, void *p)
+{
+	return 1;
 }
 
 static struct super_block *get_sb_single(struct file_system_type *fs_type,
-	int flags, void *data)
+	int flags, char *dev_name, void *data)
 {
-	struct super_block * s = alloc_super();
-	if (!s)
-		return ERR_PTR(-ENOMEM);
-	/*
-	 * Get the superblock of kernel-wide instance, but
-	 * keep the reference to fs_type.
-	 */
-retry:
-	spin_lock(&sb_lock);
-	if (!list_empty(&fs_type->fs_supers)) {
-		struct super_block *old;
-		old = list_entry(fs_type->fs_supers.next, struct super_block,
-				s_instances);
-		if (!grab_super(old))
-			goto retry;
-		destroy_super(s);
-		do_remount_sb(old, flags, data);
-		return old;
-	} else {
-		kdev_t dev = get_unnamed_dev();
-		if (!dev) {
-			spin_unlock(&sb_lock);
-			destroy_super(s);
-			return ERR_PTR(-EMFILE);
-		}
-		s->s_dev = dev;
+	struct super_block *s = get_anon_super(fs_type, compare_single, NULL);
+
+	if (IS_ERR(s))
+		return s;
+	if (!s->s_root) {
 		s->s_flags = flags;
-		insert_super(s, fs_type);
-		lock_super(s);
-		if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
-			goto out_fail;
+		if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0)) {
+			deactivate_super(s);
+			remove_super(s);
+			return ERR_PTR(-EINVAL);
+		}
 		s->s_flags |= MS_ACTIVE;
-		unlock_super(s);
-		return s;
-
-	out_fail:
-		unlock_super(s);
-		deactivate_super(s);
-		remove_super(s);
-		return ERR_PTR(-EINVAL);
 	}
+	do_remount_sb(s, flags, data);
+	return s;
+}
+
+struct vfsmount *
+do_kern_mount(const char *fstype, int flags, char *name, void *data)
+{
+	struct file_system_type *type = get_fs_type(fstype);
+	struct super_block *sb = ERR_PTR(-ENOMEM);
+	struct vfsmount *mnt;
+
+	if (!type)
+		return ERR_PTR(-ENODEV);
+
+	mnt = alloc_vfsmnt(name);
+	if (!mnt)
+		goto out;
+	if (type->fs_flags & FS_REQUIRES_DEV)
+		sb = get_sb_bdev(type, flags, name, data);
+	else if (type->fs_flags & FS_SINGLE)
+		sb = get_sb_single(type, flags, name, data);
+	else
+		sb = get_sb_nodev(type, flags, name, data);
+	if (IS_ERR(sb))
+		goto out_mnt;
+	if (type->fs_flags & FS_NOMOUNT)
+		sb->s_flags |= MS_NOUSER;
+	mnt->mnt_sb = sb;
+	mnt->mnt_root = dget(sb->s_root);
+	mnt->mnt_mountpoint = sb->s_root;
+	mnt->mnt_parent = mnt;
+	up_write(&sb->s_umount);
+	put_filesystem(type);
+	return mnt;
+out_mnt:
+	free_vfsmnt(mnt);
+out:
+	put_filesystem(type);
+	return (struct vfsmount *)sb;
 }
 
 void kill_super(struct super_block *sb)
@@ -780,7 +826,6 @@
 		return;
 
 	down_write(&sb->s_umount);
-	lock_kernel();
 	sb->s_root = NULL;
 	/* Need to clean after the sucker */
 	if (fs->fs_flags & FS_LITTER)
@@ -789,6 +834,7 @@
 	dput(root);
 	fsync_super(sb);
 	lock_super(sb);
+	lock_kernel();
 	sb->s_flags &= ~MS_ACTIVE;
 	invalidate_inodes(sb);	/* bad name - it should be evict_inodes() */
 	if (sop) {
@@ -800,7 +846,7 @@
 
 	/* Forget any remaining inodes */
 	if (invalidate_inodes(sb)) {
-		printk("VFS: Busy inodes after unmount. "
+		printk(KERN_ERR "VFS: Busy inodes after unmount. "
 			"Self-destruct in 5 seconds.  Have a nice day...\n");
 	}
 
@@ -809,313 +855,7 @@
 	remove_super(sb);
 }
 
-/*
- * Alters the mount flags of a mounted file system. Only the mount point
- * is used as a reference - file system type and the device are ignored.
- */
-
-int do_remount_sb(struct super_block *sb, int flags, void *data)
-{
-	int retval;
-	
-	if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
-		return -EACCES;
-		/*flags |= MS_RDONLY;*/
-	if (flags & MS_RDONLY)
-		acct_auto_close(sb->s_dev);
-	shrink_dcache_sb(sb);
-	fsync_super(sb);
-	/* If we are remounting RDONLY, make sure there are no rw files open */
-	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
-		if (!fs_may_remount_ro(sb))
-			return -EBUSY;
-	if (sb->s_op && sb->s_op->remount_fs) {
-		lock_super(sb);
-		retval = sb->s_op->remount_fs(sb, &flags, data);
-		unlock_super(sb);
-		if (retval)
-			return retval;
-	}
-	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
-
-	/*
-	 * We can't invalidate inodes as we can loose data when remounting
-	 * (someone might manage to alter data while we are waiting in lock_super()
-	 * or in foo_remount_fs()))
-	 */
-
-	return 0;
-}
-
-struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data)
-{
-	struct file_system_type * fstype;
-	struct vfsmount *mnt = NULL;
-	struct super_block *sb;
-
-	if (!type || !memchr(type, 0, PAGE_SIZE))
-		return ERR_PTR(-EINVAL);
-
-	/* we need capabilities... */
-	if (!capable(CAP_SYS_ADMIN))
-		return ERR_PTR(-EPERM);
-
-	/* ... filesystem driver... */
-	fstype = get_fs_type(type);
-	if (!fstype)		
-		return ERR_PTR(-ENODEV);
-
-	/* ... allocated vfsmount... */
-	mnt = alloc_vfsmnt();
-	if (!mnt) {
-		mnt = ERR_PTR(-ENOMEM);
-		goto fs_out;
-	}
-	set_devname(mnt, name);
-	/* get locked superblock */
-	if (fstype->fs_flags & FS_REQUIRES_DEV)
-		sb = get_sb_bdev(fstype, name, flags, data);
-	else if (fstype->fs_flags & FS_SINGLE)
-		sb = get_sb_single(fstype, flags, data);
-	else
-		sb = get_sb_nodev(fstype, flags, data);
-
-	if (IS_ERR(sb)) {
-		free_vfsmnt(mnt);
-		mnt = (struct vfsmount *)sb;
-		goto fs_out;
-	}
-	if (fstype->fs_flags & FS_NOMOUNT)
-		sb->s_flags |= MS_NOUSER;
-
-	mnt->mnt_sb = sb;
-	mnt->mnt_root = dget(sb->s_root);
-	mnt->mnt_mountpoint = mnt->mnt_root;
-	mnt->mnt_parent = mnt;
-	up_write(&sb->s_umount);
-fs_out:
-	put_filesystem(fstype);
-	return mnt;
-}
-
 struct vfsmount *kern_mount(struct file_system_type *type)
 {
-	return do_kern_mount((char *)type->name, 0, (char *)type->name, NULL);
-}
-
-static char * __initdata root_mount_data;
-static int __init root_data_setup(char *str)
-{
-	root_mount_data = str;
-	return 1;
-}
-
-static char * __initdata root_fs_names;
-static int __init fs_names_setup(char *str)
-{
-	root_fs_names = str;
-	return 1;
-}
-
-__setup("rootflags=", root_data_setup);
-__setup("rootfstype=", fs_names_setup);
-
-static void __init get_fs_names(char *page)
-{
-	char *s = page;
-
-	if (root_fs_names) {
-		strcpy(page, root_fs_names);
-		while (*s++) {
-			if (s[-1] == ',')
-				s[-1] = '\0';
-		}
-	} else {
-		int len = get_filesystem_list(page);
-		char *p, *next;
-
-		page[len] = '\0';
-		for (p = page-1; p; p = next) {
-			next = strchr(++p, '\n');
-			if (*p++ != '\t')
-				continue;
-			while ((*s++ = *p++) != '\n')
-				;
-			s[-1] = '\0';
-		}
-	}
-	*s = '\0';
-}
-
-void __init mount_root(void)
-{
-	struct nameidata root_nd;
-	struct super_block * sb;
-	struct vfsmount *vfsmnt;
-	struct block_device *bdev = NULL;
-	mode_t mode;
-	int retval;
-	void *handle;
-	char path[64];
-	int path_start = -1;
-	char *name = "/dev/root";
-	char *fs_names, *p;
-#ifdef CONFIG_ROOT_NFS
-	void *data;
-#endif
-	root_mountflags |= MS_VERBOSE;
-
-#ifdef CONFIG_ROOT_NFS
-	if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR)
-		goto skip_nfs;
-	data = nfs_root_data();
-	if (!data)
-		goto no_nfs;
-	vfsmnt = do_kern_mount("nfs", root_mountflags, "/dev/root", data);
-	if (!IS_ERR(vfsmnt)) {
-		printk ("VFS: Mounted root (%s filesystem).\n", "nfs");
-		ROOT_DEV = vfsmnt->mnt_sb->s_dev;
-		goto attach_it;
-	}
-no_nfs:
-	printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
-	ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
-skip_nfs:
-#endif
-
-#ifdef CONFIG_BLK_DEV_FD
-	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
-#ifdef CONFIG_BLK_DEV_RAM
-		extern int rd_doload;
-		extern void rd_load_secondary(void);
-#endif
-		floppy_eject();
-#ifndef CONFIG_BLK_DEV_RAM
-		printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
-#else
-		/* rd_doload is 2 for a dual initrd/ramload setup */
-		if(rd_doload==2)
-			rd_load_secondary();
-		else
-#endif
-		{
-			printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
-			wait_for_keypress();
-		}
-	}
-#endif
-
-	fs_names = __getname();
-	get_fs_names(fs_names);
-
-	devfs_make_root (root_device_name);
-	handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME,
-	                            MAJOR (ROOT_DEV), MINOR (ROOT_DEV),
-				    DEVFS_SPECIAL_BLK, 1);
-	if (handle)  /*  Sigh: bd*() functions only paper over the cracks  */
-	{
-	    unsigned major, minor;
-
-	    devfs_get_maj_min (handle, &major, &minor);
-	    ROOT_DEV = MKDEV (major, minor);
-	}
-
-	/*
-	 * Probably pure paranoia, but I'm less than happy about delving into
-	 * devfs crap and checking it right now. Later.
-	 */
-	if (!ROOT_DEV)
-		panic("I have no root and I want to scream");
-
-retry:
-	bdev = bdget(kdev_t_to_nr(ROOT_DEV));
-	if (!bdev)
-		panic(__FUNCTION__ ": unable to allocate root device");
-	bdev->bd_op = devfs_get_ops (handle); /* Increments module use count */
-	path_start = devfs_generate_path (handle, path + 5, sizeof (path) - 5);
-	mode = FMODE_READ;
-	if (!(root_mountflags & MS_RDONLY))
-		mode |= FMODE_WRITE;
-	retval = blkdev_get(bdev, mode, 0, BDEV_FS);
-	devfs_put_ops (handle); /* Decrement module use count now we're safe */
-	if (retval == -EROFS) {
-		root_mountflags |= MS_RDONLY;
-		goto retry;
-	}
-	if (retval) {
-	        /*
-		 * Allow the user to distinguish between failed open
-		 * and bad superblock on root device.
-		 */
-Eio:
-		printk ("VFS: Cannot open root device \"%s\" or %s\n",
-			root_device_name, kdevname (ROOT_DEV));
-		printk ("Please append a correct \"root=\" boot option\n");
-		panic("VFS: Unable to mount root fs on %s",
-			kdevname(ROOT_DEV));
-	}
-
-	check_disk_change(ROOT_DEV);
-	sb = get_super(ROOT_DEV);
-	if (sb) {
-		/* FIXME */
-		p = (char *)sb->s_type->name;
-		atomic_inc(&sb->s_active);
-		up_read(&sb->s_umount);
-		down_write(&sb->s_umount);
-		goto mount_it;
-	}
-
-	for (p = fs_names; *p; p += strlen(p)+1) {
-		struct file_system_type * fs_type = get_fs_type(p);
-		if (!fs_type)
-  			continue;
-		atomic_inc(&bdev->bd_count);
-		retval = blkdev_get(bdev, mode, 0, BDEV_FS);
-		if (retval)
-			goto Eio;
-  		sb = read_super(ROOT_DEV, bdev, fs_type,
-				root_mountflags, root_mount_data);
-		put_filesystem(fs_type);
-		if (sb) {
-			blkdev_put(bdev, BDEV_FS);
-			goto mount_it;
-		}
-	}
-	panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
-
-mount_it:
-	/* FIXME */
-	up_write(&sb->s_umount);
-	printk ("VFS: Mounted root (%s filesystem)%s.\n", p,
-		(sb->s_flags & MS_RDONLY) ? " readonly" : "");
-	putname(fs_names);
-	if (path_start >= 0) {
-		name = path + path_start;
-		devfs_unregister (devfs_find_handle(NULL, "root", 0, 0, 0, 0));
-		devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT,
-				  name + 5, NULL, NULL);
-		memcpy (name, "/dev/", 5);
-	}
-	vfsmnt = alloc_vfsmnt();
-	if (!vfsmnt)
-		panic("VFS: alloc_vfsmnt failed for root fs");
-
-	set_devname(vfsmnt, name);
-	vfsmnt->mnt_sb = sb;
-	vfsmnt->mnt_root = dget(sb->s_root);
-	bdput(bdev); /* sb holds a reference */
-
-
-#ifdef CONFIG_ROOT_NFS
-attach_it:
-#endif
-	root_nd.mnt = root_vfsmnt;
-	root_nd.dentry = root_vfsmnt->mnt_sb->s_root;
-	graft_tree(vfsmnt, &root_nd);
-
-	set_fs_root(current->fs, vfsmnt, vfsmnt->mnt_root);
-	set_fs_pwd(current->fs, vfsmnt, vfsmnt->mnt_root);
-
-	mntput(vfsmnt);
+	return do_kern_mount(type->name, 0, (char *)type->name, NULL);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)