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
2008-10-30 00:01:05 +03:00
# include <linux/delay.h>
2009-03-31 07:33:13 +04:00
# include <linux/raid/md_u.h>
# include <linux/raid/md_p.h>
2005-04-17 02:20:36 +04:00
# include "do_mounts.h"
/*
* When md ( and any require personalities ) are compiled into the kernel
* ( not a module ) , arrays can be assembles are boot time using with AUTODETECT
* where specially marked partitions are registered with md_autodetect_dev ( ) ,
* and with MD_BOOT where devices to be collected are given on the boot line
* with md = . . . . .
* The code for that is here .
*/
2008-09-22 02:44:32 +04:00
# ifdef CONFIG_MD_AUTODETECT
static int __initdata raid_noautodetect ;
# else
static int __initdata raid_noautodetect = 1 ;
# endif
static int __initdata raid_autopart ;
2005-04-17 02:20:36 +04:00
static struct {
int minor ;
int partitioned ;
2006-01-06 11:20:36 +03:00
int level ;
2005-04-17 02:20:36 +04:00
int chunk ;
char * device_names ;
2006-10-03 12:15:59 +04:00
} md_setup_args [ 256 ] __initdata ;
2005-04-17 02:20:36 +04:00
static int md_setup_ents __initdata ;
/*
* Parse the command - line parameters given our kernel , but do not
* actually try to invoke the MD device now ; that is handled by
* md_setup_drive after the low - level disk drivers have initialised .
*
* 27 / 11 / 1999 : Fixed to work correctly with the 2.3 kernel ( which
* assigns the task of parsing integer arguments to the
* invoked program now ) . Added ability to initialise all
* the MD devices ( by specifying multiple " md= " lines )
* instead of just one . - - KTK
* 18 May2000 : Added support for persistent - superblock arrays :
* md = n , 0 , factor , fault , device - list uses RAID0 for device n
* md = n , - 1 , factor , fault , device - list uses LINEAR for device n
* md = n , device - list reads a RAID superblock from the devices
* elements in device - list are read by name_to_kdev_t so can be
* a hex number or something like / dev / hda1 / dev / sdb
* 2001 - 06 - 03 : Dave Cinege < dcinege @ psychosis . com >
* Shifted name_to_kdev_t ( ) and related operations to md_set_drive ( )
* for later execution . Rewrote section to make devfs compatible .
*/
static int __init md_setup ( char * str )
{
2006-01-06 11:20:36 +03:00
int minor , level , factor , fault , partitioned = 0 ;
2005-04-17 02:20:36 +04:00
char * pername = " " ;
char * str1 ;
int ent ;
if ( * str = = ' d ' ) {
partitioned = 1 ;
str + + ;
}
if ( get_option ( & str , & minor ) ! = 2 ) { /* MD Number */
printk ( KERN_WARNING " md: Too few arguments supplied to md=. \n " ) ;
return 0 ;
}
str1 = str ;
for ( ent = 0 ; ent < md_setup_ents ; ent + + )
if ( md_setup_args [ ent ] . minor = = minor & &
md_setup_args [ ent ] . partitioned = = partitioned ) {
printk ( KERN_WARNING " md: md=%s%d, Specified more than once. "
" Replacing previous definition. \n " , partitioned ? " d " : " " , minor ) ;
break ;
}
2006-10-03 12:15:59 +04:00
if ( ent > = ARRAY_SIZE ( md_setup_args ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " md: md=%s%d - too many md initialisations \n " , partitioned ? " d " : " " , minor ) ;
return 0 ;
}
if ( ent > = md_setup_ents )
md_setup_ents + + ;
2006-01-06 11:20:36 +03:00
switch ( get_option ( & str , & level ) ) { /* RAID level */
2005-04-17 02:20:36 +04:00
case 2 : /* could be 0 or -1.. */
if ( level = = 0 | | level = = LEVEL_LINEAR ) {
if ( get_option ( & str , & factor ) ! = 2 | | /* Chunk Size */
get_option ( & str , & fault ) ! = 2 ) {
printk ( KERN_WARNING " md: Too few arguments supplied to md=. \n " ) ;
return 0 ;
}
2006-01-06 11:20:36 +03:00
md_setup_args [ ent ] . level = level ;
2005-04-17 02:20:36 +04:00
md_setup_args [ ent ] . chunk = 1 < < ( factor + 12 ) ;
2006-01-06 11:20:36 +03:00
if ( level = = LEVEL_LINEAR )
2005-04-17 02:20:36 +04:00
pername = " linear " ;
2006-01-06 11:20:36 +03:00
else
2005-04-17 02:20:36 +04:00
pername = " raid0 " ;
break ;
}
/* FALL THROUGH */
case 1 : /* the first device is numeric */
str = str1 ;
/* FALL THROUGH */
case 0 :
2006-01-06 11:20:36 +03:00
md_setup_args [ ent ] . level = LEVEL_NONE ;
2005-04-17 02:20:36 +04:00
pername = " super-block " ;
}
printk ( KERN_INFO " md: Will configure md%d (%s) from %s, below. \n " ,
minor , pername , str ) ;
md_setup_args [ ent ] . device_names = str ;
md_setup_args [ ent ] . partitioned = partitioned ;
md_setup_args [ ent ] . minor = minor ;
return 1 ;
}
static void __init md_setup_drive ( void )
{
int minor , i , ent , partitioned ;
dev_t dev ;
dev_t devices [ MD_SB_DISKS + 1 ] ;
for ( ent = 0 ; ent < md_setup_ents ; ent + + ) {
int fd ;
int err = 0 ;
char * devname ;
mdu_disk_info_t dinfo ;
2005-06-21 08:15:16 +04:00
char name [ 16 ] ;
2005-04-17 02:20:36 +04:00
minor = md_setup_args [ ent ] . minor ;
partitioned = md_setup_args [ ent ] . partitioned ;
devname = md_setup_args [ ent ] . device_names ;
sprintf ( name , " /dev/md%s%d " , partitioned ? " _d " : " " , minor ) ;
if ( partitioned )
dev = MKDEV ( mdp_major , minor < < MdpMinorShift ) ;
else
dev = MKDEV ( MD_MAJOR , minor ) ;
2005-06-21 08:15:16 +04:00
create_dev ( name , dev ) ;
2008-04-29 01:13:14 +04:00
for ( i = 0 ; i < MD_SB_DISKS & & devname ! = NULL ; i + + ) {
2005-04-17 02:20:36 +04:00
char * p ;
char comp_name [ 64 ] ;
u32 rdev ;
p = strchr ( devname , ' , ' ) ;
if ( p )
* p + + = 0 ;
dev = name_to_dev_t ( devname ) ;
if ( strncmp ( devname , " /dev/ " , 5 ) = = 0 )
devname + = 5 ;
snprintf ( comp_name , 63 , " /dev/%s " , devname ) ;
rdev = bstat ( comp_name ) ;
if ( rdev )
dev = new_decode_dev ( rdev ) ;
if ( ! dev ) {
printk ( KERN_WARNING " md: Unknown device name: %s \n " , devname ) ;
break ;
}
devices [ i ] = dev ;
devname = p ;
}
devices [ i ] = 0 ;
if ( ! i )
continue ;
printk ( KERN_INFO " md: Loading md%s%d: %s \n " ,
partitioned ? " _d " : " " , minor ,
md_setup_args [ ent ] . device_names ) ;
fd = sys_open ( name , 0 , 0 ) ;
if ( fd < 0 ) {
printk ( KERN_ERR " md: open failed - cannot start "
" array %s \n " , name ) ;
continue ;
}
if ( sys_ioctl ( fd , SET_ARRAY_INFO , 0 ) = = - EBUSY ) {
printk ( KERN_WARNING
" md: Ignoring md=%d, already autodetected. (Use raid=noautodetect) \n " ,
minor ) ;
sys_close ( fd ) ;
continue ;
}
2006-01-06 11:20:36 +03:00
if ( md_setup_args [ ent ] . level ! = LEVEL_NONE ) {
2005-04-17 02:20:36 +04:00
/* non-persistent */
mdu_array_info_t ainfo ;
2006-01-06 11:20:36 +03:00
ainfo . level = md_setup_args [ ent ] . level ;
2005-04-17 02:20:36 +04:00
ainfo . size = 0 ;
ainfo . nr_disks = 0 ;
ainfo . raid_disks = 0 ;
while ( devices [ ainfo . raid_disks ] )
ainfo . raid_disks + + ;
ainfo . md_minor = minor ;
ainfo . not_persistent = 1 ;
ainfo . state = ( 1 < < MD_SB_CLEAN ) ;
ainfo . layout = 0 ;
ainfo . chunk_size = md_setup_args [ ent ] . chunk ;
err = sys_ioctl ( fd , SET_ARRAY_INFO , ( long ) & ainfo ) ;
for ( i = 0 ; ! err & & i < = MD_SB_DISKS ; i + + ) {
dev = devices [ i ] ;
if ( ! dev )
break ;
dinfo . number = i ;
dinfo . raid_disk = i ;
dinfo . state = ( 1 < < MD_DISK_ACTIVE ) | ( 1 < < MD_DISK_SYNC ) ;
dinfo . major = MAJOR ( dev ) ;
dinfo . minor = MINOR ( dev ) ;
err = sys_ioctl ( fd , ADD_NEW_DISK , ( long ) & dinfo ) ;
}
} else {
/* persistent */
for ( i = 0 ; i < = MD_SB_DISKS ; i + + ) {
dev = devices [ i ] ;
if ( ! dev )
break ;
dinfo . major = MAJOR ( dev ) ;
dinfo . minor = MINOR ( dev ) ;
sys_ioctl ( fd , ADD_NEW_DISK , ( long ) & dinfo ) ;
}
}
if ( ! err )
err = sys_ioctl ( fd , RUN_ARRAY , 0 ) ;
if ( err )
printk ( KERN_WARNING " md: starting md%d failed \n " , minor ) ;
else {
/* reread the partition table.
* I ( neilb ) and not sure why this is needed , but I cannot
* boot a kernel with devfs compiled in from partitioned md
* array without it
*/
sys_close ( fd ) ;
fd = sys_open ( name , 0 , 0 ) ;
sys_ioctl ( fd , BLKRRPART , 0 ) ;
}
sys_close ( fd ) ;
}
}
static int __init raid_setup ( char * str )
{
int len , pos ;
len = strlen ( str ) + 1 ;
pos = 0 ;
while ( pos < len ) {
char * comma = strchr ( str + pos , ' , ' ) ;
int wlen ;
if ( comma )
wlen = ( comma - str ) - pos ;
else wlen = ( len - 1 ) - pos ;
if ( ! strncmp ( str , " noautodetect " , wlen ) )
raid_noautodetect = 1 ;
2008-09-22 02:44:32 +04:00
if ( ! strncmp ( str , " autodetect " , wlen ) )
raid_noautodetect = 0 ;
2005-04-17 02:20:36 +04:00
if ( strncmp ( str , " partitionable " , wlen ) = = 0 )
raid_autopart = 1 ;
if ( strncmp ( str , " part " , wlen ) = = 0 )
raid_autopart = 1 ;
pos + = wlen + 1 ;
}
return 1 ;
}
__setup ( " raid= " , raid_setup ) ;
__setup ( " md= " , md_setup ) ;
2009-01-07 01:40:53 +03:00
static void __init autodetect_raid ( void )
2008-08-18 14:54:00 +04:00
{
int fd ;
/*
* Since we don ' t want to detect and use half a raid array , we need to
* wait for the known devices to complete their probing
*/
printk ( KERN_INFO " md: Waiting for all devices to be available before autodetect \n " ) ;
printk ( KERN_INFO " md: If you don't use raid, use raid=noautodetect \n " ) ;
2009-02-14 03:59:06 +03:00
wait_for_device_probe ( ) ;
2012-06-01 03:26:10 +04:00
fd = sys_open ( " /dev/md0 " , 0 , 0 ) ;
2008-08-18 14:54:00 +04:00
if ( fd > = 0 ) {
sys_ioctl ( fd , RAID_AUTORUN , raid_autopart ) ;
sys_close ( fd ) ;
}
}
2005-04-17 02:20:36 +04:00
void __init md_run_setup ( void )
{
2005-06-21 08:15:16 +04:00
create_dev ( " /dev/md0 " , MKDEV ( MD_MAJOR , 0 ) ) ;
2008-07-21 00:07:09 +04:00
2005-04-17 02:20:36 +04:00
if ( raid_noautodetect )
2008-09-22 02:44:32 +04:00
printk ( KERN_INFO " md: Skipping autodetection of RAID arrays. (raid=autodetect will force) \n " ) ;
2008-08-18 14:54:00 +04:00
else
autodetect_raid ( ) ;
2005-04-17 02:20:36 +04:00
md_setup_drive ( ) ;
}