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; if (!fs_may_mount(new_root_dev)) { printk(KERN_CRIT "New root is busy. Staying in initrd.\n"); return -EBUSY; } 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; }
static int do_umount(kdev_t dev,int unmount_root) { struct super_block * sb; int retval; if (dev==ROOT_DEV && !unmount_root) { /* * Special case for "unmounting" root. We just try to remount * it readonly, and sync() the device. */ if (!(sb=get_super(dev))) return -ENOENT; if (!(sb->s_flags & MS_RDONLY)) { /* * Make sure all quotas are turned off on this device we need to mount * it readonly so no more writes by the quotasystem. * If later on the remount fails too bad there are no quotas running * anymore. Turn them on again by hand. */ quota_off(dev, -1); fsync_dev(dev); retval = do_remount_sb(sb, MS_RDONLY, 0); if (retval) return retval; } return 0; } if (!(sb=get_super(dev)) || !(sb->s_covered)) return -ENOENT; if (!sb->s_covered->i_mount) printk("VFS: umount(%s): mounted inode has i_mount=NULL\n", kdevname(dev)); /* * Before checking if the filesystem is still busy make sure the kernel * doesn't hold any quotafiles open on that device. If the umount fails * too bad there are no quotas running anymore. Turn them on again by hand. */ quota_off(dev, -1); if (!fs_may_umount(dev, sb->s_mounted)) return -EBUSY; sb->s_covered->i_mount = NULL; iput(sb->s_covered); sb->s_covered = NULL; iput(sb->s_mounted); sb->s_mounted = NULL; if (sb->s_op && sb->s_op->write_super && sb->s_dirt) sb->s_op->write_super(sb); put_super(dev); remove_vfsmnt(dev); return 0; }
int __init change_root(kdev_t new_root_dev,const char *put_old) { kdev_t old_root_dev; struct vfsmount *vfsmnt; struct dentry *old_root,*old_pwd,*dir_d = NULL; int error; old_root = current->fs->root; old_pwd = current->fs->pwd; old_root_dev = ROOT_DEV; if (!fs_may_mount(new_root_dev)) { printk(KERN_CRIT "New root is busy. Staying in initrd.\n"); return -EBUSY; } ROOT_DEV = new_root_dev; mount_root(); dput(old_root); dput(old_pwd); #if 1 shrink_dcache(); printk("change_root: old root has d_count=%d\n", old_root->d_count); #endif /* * Get the new mount directory */ dir_d = lookup_dentry(put_old, NULL, 1); if (IS_ERR(dir_d)) { error = PTR_ERR(dir_d); } else if (!dir_d->d_inode) { dput(dir_d); error = -ENOENT; } else { error = 0; } if (!error && dir_d->d_covers != dir_d) { dput(dir_d); error = -EBUSY; } if (!error && !S_ISDIR(dir_d->d_inode->i_mode)) { dput(dir_d); error = -ENOTDIR; } if (error) { int umount_error; printk(KERN_NOTICE "Trying to unmount old root ... "); umount_error = do_umount(old_root_dev,1, 0); if (!umount_error) { printk("okay\n"); /* special: the old device driver is going to be a ramdisk and the point of this call is to free its protected memory (even if dirty). */ destroy_buffers(old_root_dev); return 0; } printk(KERN_ERR "error %d\n",umount_error); return error; } remove_vfsmnt(old_root_dev); vfsmnt = add_vfsmnt(old_root->d_sb, "/dev/root.old", put_old); if (vfsmnt) { d_mount(dir_d,old_root); return 0; } printk(KERN_CRIT "Trouble: add_vfsmnt failed\n"); return -ENOMEM; }
static int do_umount(kdev_t dev, int unmount_root, int flags) { struct super_block * sb; int retval; retval = -ENOENT; sb = get_super(dev); if (!sb || !sb->s_root) goto out; /* * Before checking whether the filesystem is still busy, * make sure the kernel doesn't hold any quota files open * on the device. If the umount fails, too bad -- there * are no quotas running any more. Just turn them on again. */ DQUOT_OFF(dev); acct_auto_close(dev); /* * If we may have to abort operations to get out of this * mount, and they will themselves hold resources we must * allow the fs to do things. In the Unix tradition of * 'Gee thats tricky lets do it in userspace' the umount_begin * might fail to complete on the first run through as other tasks * must return, and the like. Thats for the mount program to worry * about for the moment. */ if( (flags&MNT_FORCE) && sb->s_op->umount_begin) sb->s_op->umount_begin(sb); /* * Shrink dcache, then fsync. This guarantees that if the * filesystem is quiescent at this point, then (a) only the * root entry should be in use and (b) that root entry is * clean. */ shrink_dcache_sb(sb); fsync_dev(dev); if (dev==ROOT_DEV && !unmount_root) { /* * Special case for "unmounting" root ... * we just try to remount it readonly. */ retval = 0; if (!(sb->s_flags & MS_RDONLY)) retval = do_remount_sb(sb, MS_RDONLY, 0); return retval; } retval = d_umount(sb); if (retval) goto out; if (sb->s_op) { if (sb->s_op->write_super && sb->s_dirt) sb->s_op->write_super(sb); } lock_super(sb); if (sb->s_op) { if (sb->s_op->put_super) sb->s_op->put_super(sb); } /* Forget any remaining inodes */ if (invalidate_inodes(sb)) { printk("VFS: Busy inodes after unmount. " "Self-destruct in 5 seconds. Have a nice day...\n"); } sb->s_dev = 0; /* Free the superblock */ unlock_super(sb); remove_vfsmnt(dev); out: return retval; }
void __init mount_root(void) { struct file_system_type * fs_type; struct super_block * sb; struct vfsmount *vfsmnt; struct inode * d_inode = NULL; struct file filp; int retval; #ifdef CONFIG_ROOT_NFS if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { ROOT_DEV = 0; if ((fs_type = get_fs_type("nfs"))) { sb = get_empty_super(); /* "can't fail" */ sb->s_dev = get_unnamed_dev(); sb->s_flags = root_mountflags; sema_init(&sb->s_vfs_rename_sem,1); vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); if (vfsmnt) { if (nfs_root_mount(sb) >= 0) { sb->s_dirt = 0; sb->s_type = fs_type; current->fs->root = dget(sb->s_root); current->fs->pwd = dget(sb->s_root); ROOT_DEV = sb->s_dev; printk (KERN_NOTICE "VFS: Mounted root (NFS filesystem)%s.\n", (sb->s_flags & MS_RDONLY) ? " readonly" : ""); return; } remove_vfsmnt(sb->s_dev); } put_unnamed_dev(sb->s_dev); sb->s_dev = 0; } if (!ROOT_DEV) { printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0); } } #endif #ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; #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 memset(&filp, 0, sizeof(filp)); d_inode = get_empty_inode(); d_inode->i_rdev = ROOT_DEV; filp.f_dentry = NULL; if ( root_mountflags & MS_RDONLY) filp.f_mode = 1; /* read only */ else filp.f_mode = 3; /* read write */ retval = blkdev_open(d_inode, &filp); if (retval == -EROFS) { root_mountflags |= MS_RDONLY; filp.f_mode = 1; retval = blkdev_open(d_inode, &filp); } iput(d_inode); 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->fs_flags & FS_REQUIRES_DEV)) continue; sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,root_mount_data,1); if (sb) { sb->s_flags = root_mountflags; current->fs->root = dget(sb->s_root); current->fs->pwd = dget(sb->s_root); printk ("VFS: Mounted root (%s filesystem)%s.\n", fs_type->name, (sb->s_flags & MS_RDONLY) ? " readonly" : ""); vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); if (vfsmnt) return; panic("VFS: add_vfsmnt failed for root fs"); } } #ifdef CONFIG_EMPEG_DISPLAY display_bootfail(); #endif panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); }