patch-1.3.73 linux/fs/super.c
Next file: linux/fs/umsdos/inode.c
Previous file: linux/fs/nfs/inode.c
Back to the patch index
Back to the overall index
- Lines: 184
- Date:
Mon Mar 11 18:09:16 1996
- Orig file:
v1.3.72/linux/fs/super.c
- Orig date:
Tue Mar 5 10:11:08 1996
diff -u --recursive --new-file v1.3.72/linux/fs/super.c linux/fs/super.c
@@ -11,6 +11,7 @@
* GK 2/5/95 - Changed to support mounting the root fs via NFS
*
* Added kerneld support: Jacques Gelinas and Bjorn Ekwall
+ * Added change_root: Werner Almesberger & Hans Lermen, Feb '96
*/
#include <stdarg.h>
@@ -35,6 +36,10 @@
#include <linux/kerneld.h>
#endif
+#ifdef CONFIG_ROOT_NFS
+#include <linux/nfs_fs.h>
+#endif
+
extern void wait_for_keypress(void);
extern struct file_operations * get_blkfops(unsigned int major);
extern void blkdev_release (struct inode *);
@@ -43,10 +48,6 @@
static int do_remount_sb(struct super_block *sb, int flags, char * data);
-#ifdef CONFIG_ROOT_NFS
-extern int nfs_root_mount(struct super_block *sb);
-#endif
-
/* this is initialized in init/main.c */
kdev_t ROOT_DEV;
@@ -482,12 +483,12 @@
kdevname(dev));
}
-static int do_umount(kdev_t dev)
+static int do_umount(kdev_t dev,int unmount_root)
{
struct super_block * sb;
int retval;
- if (dev==ROOT_DEV) {
+ if (dev==ROOT_DEV && !unmount_root) {
/*
* Special case for "unmounting" root. We just try to remount
* it readonly, and sync() the device.
@@ -581,7 +582,7 @@
iput(inode);
return -ENXIO;
}
- if (!(retval = do_umount(dev)) && dev != ROOT_DEV) {
+ if (!(retval = do_umount(dev,0)) && dev != ROOT_DEV) {
blkdev_release (inode);
if (MAJOR(dev) == UNNAMED_MAJOR)
put_unnamed_dev(dev);
@@ -818,7 +819,7 @@
return retval;
}
-void mount_root(void)
+static void do_mount_root(void)
{
struct file_system_type * fs_type;
struct super_block * sb;
@@ -827,12 +828,18 @@
struct file filp;
int retval;
- memset(super_blocks, 0, sizeof(super_blocks));
#ifdef CONFIG_ROOT_NFS
+ if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR)
+ if (nfs_root_init(nfs_root_name, nfs_root_addrs) < 0) {
+ printk(KERN_ERR "Root-NFS: Unable to contact NFS "
+ "server for root fs, using /dev/fd0 instead\n");
+ ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
+ }
if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
ROOT_DEV = 0;
if ((fs_type = get_fs_type("nfs"))) {
sb = &super_blocks[0];
+ while (sb->s_dev) sb++;
sb->s_dev = get_unnamed_dev();
sb->s_flags = root_mountflags & ~MS_RDONLY;
if (nfs_root_mount(sb) >= 0) {
@@ -873,15 +880,19 @@
else
filp.f_mode = 3; /* read write */
retval = blkdev_open(&d_inode, &filp);
- if(retval == -EROFS){
+ if (retval == -EROFS) {
root_mountflags |= MS_RDONLY;
filp.f_mode = 1;
retval = blkdev_open(&d_inode, &filp);
}
-
- for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
- if(retval)
- break;
+ if (retval)
+ /*
+ * Allow the user to distinguish between failed open
+ * and bad superblock on root device.
+ */
+ printk("VFS: Cannot open root device %s\n",
+ kdevname(ROOT_DEV));
+ else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
if (!fs_type->requires_dev)
continue;
sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
@@ -896,10 +907,75 @@
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
vfsmnt = add_vfsmnt(ROOT_DEV, "rootfs", "/");
+ if (!vfsmnt)
+ panic("VFS: add_vfsmnt failed for root fs");
vfsmnt->mnt_sb = sb;
+ vfsmnt->mnt_flags = root_mountflags;
return;
}
}
panic("VFS: Unable to mount root fs on %s",
kdevname(ROOT_DEV));
}
+
+
+void mount_root(void)
+{
+ memset(super_blocks, 0, sizeof(super_blocks));
+ do_mount_root();
+}
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+int change_root(kdev_t new_root_dev,const char *put_old)
+{
+ kdev_t old_root_dev;
+ struct vfsmount *vfsmnt;
+ struct inode *old_root,*old_pwd,*inode;
+ unsigned long old_fs;
+ int error;
+
+ old_root = current->fs->root;
+ old_pwd = current->fs->pwd;
+ old_root_dev = ROOT_DEV;
+ ROOT_DEV = new_root_dev;
+ do_mount_root();
+ old_fs = get_fs();
+ set_fs(get_ds());
+ error = namei(put_old,&inode);
+ if (error) inode = NULL;
+ set_fs(old_fs);
+ if (!error && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY;
+ if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR;
+ iput(old_root); /* current->fs->root */
+ iput(old_pwd); /* current->fs->pwd */
+ if (error) {
+ int umount_error;
+
+ if (inode) iput(inode);
+ printk(KERN_NOTICE "Trying to unmount old root ... ");
+ old_root->i_mount = old_root;
+ /* does this belong into do_mount_root ? */
+ umount_error = do_umount(old_root_dev,1);
+ if (umount_error) printk(KERN_ERR "error %d\n",umount_error);
+ else {
+ printk(KERN_NOTICE "okay\n");
+ invalidate_buffers(old_root_dev);
+ }
+ return umount_error ? error : 0;
+ }
+ iput(old_root); /* sb->s_covered */
+ remove_vfsmnt(old_root_dev);
+ vfsmnt = add_vfsmnt(old_root_dev,"old_rootfs",put_old);
+ if (!vfsmnt) printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
+ else {
+ vfsmnt->mnt_sb = old_root->i_sb;
+ vfsmnt->mnt_sb->s_covered = inode;
+ vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags;
+ }
+ inode->i_mount = old_root;
+ return 0;
+}
+
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this