2012-06-01 03:26:10 +04:00
/*
* Many of the syscalls used in this file expect some of the arguments
* to be __user pointers not __kernel pointers . To limit the sparse
* noise , turn off sparse checking for this file .
*/
# ifdef __CHECKER__
# undef __CHECKER__
# warning "Sparse checking disabled for this file"
# endif
2005-04-17 02:20:36 +04:00
# include <linux/unistd.h>
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/minix_fs.h>
# include <linux/romfs_fs.h>
# include <linux/initrd.h>
# include <linux/sched.h>
2006-12-07 07:34:23 +03:00
# include <linux/freezer.h>
2012-10-02 23:29:10 +04:00
# include <linux/kmod.h>
2005-04-17 02:20:36 +04:00
# include "do_mounts.h"
unsigned long initrd_start , initrd_end ;
int initrd_below_start_ok ;
unsigned int real_root_dev ; /* do_proc_dointvec cannot handle kdev_t */
static int __initdata mount_initrd = 1 ;
static int __init no_initrd ( char * str )
{
mount_initrd = 0 ;
return 1 ;
}
__setup ( " noinitrd " , no_initrd ) ;
2012-10-02 23:29:10 +04:00
static int init_linuxrc ( struct subprocess_info * info , struct cred * new )
2005-04-17 02:20:36 +04:00
{
2012-10-02 23:29:10 +04:00
sys_unshare ( CLONE_FS | CLONE_FILES ) ;
2013-01-19 22:29:54 +04:00
/* stdin/stdout/stderr for /linuxrc */
sys_open ( " /dev/console " , O_RDWR , 0 ) ;
sys_dup ( 0 ) ;
sys_dup ( 0 ) ;
2012-10-02 23:29:10 +04:00
/* move initrd over / and chdir/chroot in initrd root */
sys_chdir ( " /root " ) ;
sys_mount ( " . " , " / " , NULL , MS_MOVE , NULL ) ;
sys_chroot ( " . " ) ;
2005-04-17 02:20:36 +04:00
sys_setsid ( ) ;
2012-10-02 23:29:10 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static void __init handle_initrd ( void )
{
2013-05-01 02:28:07 +04:00
struct subprocess_info * info ;
2012-10-02 23:29:10 +04:00
static char * argv [ ] = { " linuxrc " , NULL , } ;
extern char * envp_init [ ] ;
2005-04-17 02:20:36 +04:00
int error ;
real_root_dev = new_encode_dev ( ROOT_DEV ) ;
2005-06-21 08:15:16 +04:00
create_dev ( " /dev/root.old " , Root_RAM0 ) ;
2005-04-17 02:20:36 +04:00
/* mount initrd on rootfs' /root */
mount_block_root ( " /dev/root.old " , root_mountflags & ~ MS_RDONLY ) ;
sys_mkdir ( " /old " , 0700 ) ;
2012-10-02 23:29:10 +04:00
sys_chdir ( " /old " ) ;
2005-04-17 02:20:36 +04:00
2013-01-19 02:05:56 +04:00
/* try loading default modules from initrd */
load_default_modules ( ) ;
2007-11-21 04:50:17 +03:00
/*
* In case that a resume from disk is carried out by linuxrc or one of
* its children , we need to tell the freezer not to wait for us .
*/
current - > flags | = PF_FREEZER_SKIP ;
2013-05-01 02:28:07 +04:00
info = call_usermodehelper_setup ( " /linuxrc " , argv , envp_init ,
GFP_KERNEL , init_linuxrc , NULL , NULL ) ;
if ( ! info )
return ;
call_usermodehelper_exec ( info , UMH_WAIT_PROC ) ;
2007-11-21 04:50:17 +03:00
current - > flags & = ~ PF_FREEZER_SKIP ;
2005-04-17 02:20:36 +04:00
/* move initrd to rootfs' /old */
2012-10-02 23:29:10 +04:00
sys_mount ( " .. " , " . " , NULL , MS_MOVE , NULL ) ;
2005-04-17 02:20:36 +04:00
/* switch root and cwd back to / of rootfs */
2012-10-02 23:29:10 +04:00
sys_chroot ( " .. " ) ;
2005-04-17 02:20:36 +04:00
if ( new_decode_dev ( real_root_dev ) = = Root_RAM0 ) {
sys_chdir ( " /old " ) ;
return ;
}
2012-10-02 23:29:10 +04:00
sys_chdir ( " / " ) ;
2005-04-17 02:20:36 +04:00
ROOT_DEV = new_decode_dev ( real_root_dev ) ;
mount_root ( ) ;
printk ( KERN_NOTICE " Trying to move old root to /initrd ... " ) ;
error = sys_mount ( " /old " , " /root/initrd " , NULL , MS_MOVE , NULL ) ;
if ( ! error )
printk ( " okay \n " ) ;
else {
int fd = sys_open ( " /dev/root.old " , O_RDWR , 0 ) ;
2005-06-30 13:59:03 +04:00
if ( error = = - ENOENT )
printk ( " /initrd does not exist. Ignored. \n " ) ;
else
printk ( " failed \n " ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_NOTICE " Unmounting old root \n " ) ;
sys_umount ( " /old " , MNT_DETACH ) ;
printk ( KERN_NOTICE " Trying to free ramdisk memory ... " ) ;
if ( fd < 0 ) {
error = fd ;
} else {
error = sys_ioctl ( fd , BLKFLSBUF , 0 ) ;
sys_close ( fd ) ;
}
printk ( ! error ? " okay \n " : " failed \n " ) ;
}
}
2016-01-21 01:59:29 +03:00
bool __init initrd_load ( void )
2005-04-17 02:20:36 +04:00
{
if ( mount_initrd ) {
2005-06-21 08:15:16 +04:00
create_dev ( " /dev/ram " , Root_RAM0 ) ;
2005-04-17 02:20:36 +04:00
/*
* Load the initrd data into / dev / ram0 . Execute it as initrd
* unless / dev / ram0 is supposed to be our actual root device ,
* in that case the ram disk is just set up here , and gets
* mounted in the normal path .
*/
if ( rd_load_image ( " /initrd.image " ) & & ROOT_DEV ! = Root_RAM0 ) {
sys_unlink ( " /initrd.image " ) ;
handle_initrd ( ) ;
2016-01-21 01:59:29 +03:00
return true ;
2005-04-17 02:20:36 +04:00
}
}
sys_unlink ( " /initrd.image " ) ;
2016-01-21 01:59:29 +03:00
return false ;
2005-04-17 02:20:36 +04:00
}