2005-04-17 02:20:36 +04:00
/*
raid0 . c : Multiple Devices driver for Linux
Copyright ( C ) 1994 - 96 Marc ZYNGIER
< zyngier @ ufr - info - p7 . ibp . fr > or
< maz @ gloups . fdn . fr >
Copyright ( C ) 1999 , 2000 Ingo Molnar , Red Hat
RAID - 0 management functions .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 , or ( at your option )
any later version .
You should have received a copy of the GNU General Public License
( for example / usr / src / linux / COPYING ) ; if not , write to the Free
Software Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2009-03-31 07:33:13 +04:00
# include <linux/blkdev.h>
# include <linux/seq_file.h>
2009-03-31 07:33:13 +04:00
# include "md.h"
2009-03-31 07:27:03 +04:00
# include "raid0.h"
2005-04-17 02:20:36 +04:00
2007-07-24 11:28:11 +04:00
static void raid0_unplug ( struct request_queue * q )
2005-04-17 02:20:36 +04:00
{
mddev_t * mddev = q - > queuedata ;
2009-06-16 10:54:21 +04:00
raid0_conf_t * conf = mddev - > private ;
2009-06-16 10:50:52 +04:00
mdk_rdev_t * * devlist = conf - > devlist ;
2005-04-17 02:20:36 +04:00
int i ;
for ( i = 0 ; i < mddev - > raid_disks ; i + + ) {
2007-07-24 11:28:11 +04:00
struct request_queue * r_queue = bdev_get_queue ( devlist [ i ] - > bdev ) ;
2005-04-17 02:20:36 +04:00
2007-11-07 22:26:56 +03:00
blk_unplug ( r_queue ) ;
2005-04-17 02:20:36 +04:00
}
}
2006-10-03 12:15:53 +04:00
static int raid0_congested ( void * data , int bits )
{
mddev_t * mddev = data ;
2009-06-16 10:54:21 +04:00
raid0_conf_t * conf = mddev - > private ;
2009-06-16 10:50:52 +04:00
mdk_rdev_t * * devlist = conf - > devlist ;
2006-10-03 12:15:53 +04:00
int i , ret = 0 ;
for ( i = 0 ; i < mddev - > raid_disks & & ! ret ; i + + ) {
2007-07-24 11:28:11 +04:00
struct request_queue * q = bdev_get_queue ( devlist [ i ] - > bdev ) ;
2006-10-03 12:15:53 +04:00
ret | = bdi_congested ( & q - > backing_dev_info , bits ) ;
}
return ret ;
}
2009-06-16 11:00:54 +04:00
/*
* inform the user of the raid configuration
*/
static void dump_zones ( mddev_t * mddev )
{
int j , k , h ;
sector_t zone_size = 0 ;
sector_t zone_start = 0 ;
char b [ BDEVNAME_SIZE ] ;
raid0_conf_t * conf = mddev - > private ;
printk ( KERN_INFO " ******* %s configuration ********* \n " ,
mdname ( mddev ) ) ;
h = 0 ;
for ( j = 0 ; j < conf - > nr_strip_zones ; j + + ) {
printk ( KERN_INFO " zone%d=[ " , j ) ;
for ( k = 0 ; k < conf - > strip_zone [ j ] . nb_dev ; k + + )
printk ( " %s/ " ,
bdevname ( conf - > devlist [ j * mddev - > raid_disks
+ k ] - > bdev , b ) ) ;
printk ( " ] \n " ) ;
zone_size = conf - > strip_zone [ j ] . zone_end - zone_start ;
printk ( KERN_INFO " zone offset=%llukb "
" device offset=%llukb size=%llukb \n " ,
( unsigned long long ) zone_start > > 1 ,
( unsigned long long ) conf - > strip_zone [ j ] . dev_start > > 1 ,
( unsigned long long ) zone_size > > 1 ) ;
zone_start = conf - > strip_zone [ j ] . zone_end ;
}
printk ( KERN_INFO " ********************************** \n \n " ) ;
}
2009-06-16 10:47:36 +04:00
static int create_strip_zones ( mddev_t * mddev )
2005-04-17 02:20:36 +04:00
{
2009-06-16 10:47:36 +04:00
int i , c , j , err ;
2009-06-16 10:50:35 +04:00
sector_t curr_zone_end , sectors ;
2009-06-16 10:50:52 +04:00
mdk_rdev_t * smallest , * rdev1 , * rdev2 , * rdev , * * dev ;
2005-04-17 02:20:36 +04:00
struct strip_zone * zone ;
int cnt ;
char b [ BDEVNAME_SIZE ] ;
2009-06-16 10:47:36 +04:00
raid0_conf_t * conf = kzalloc ( sizeof ( * conf ) , GFP_KERNEL ) ;
if ( ! conf )
return - ENOMEM ;
2009-01-09 00:31:08 +03:00
list_for_each_entry ( rdev1 , & mddev - > disks , same_set ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: looking at %s \n " ,
2005-04-17 02:20:36 +04:00
bdevname ( rdev1 - > bdev , b ) ) ;
c = 0 ;
2009-06-18 02:48:55 +04:00
/* round size to chunk_size */
sectors = rdev1 - > sectors ;
sector_div ( sectors , mddev - > chunk_sectors ) ;
rdev1 - > sectors = sectors * mddev - > chunk_sectors ;
2009-01-09 00:31:08 +03:00
list_for_each_entry ( rdev2 , & mddev - > disks , same_set ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: comparing %s(%llu) " ,
2005-04-17 02:20:36 +04:00
bdevname ( rdev1 - > bdev , b ) ,
2009-03-31 07:33:13 +04:00
( unsigned long long ) rdev1 - > sectors ) ;
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " with %s(%llu) \n " ,
2005-04-17 02:20:36 +04:00
bdevname ( rdev2 - > bdev , b ) ,
2009-03-31 07:33:13 +04:00
( unsigned long long ) rdev2 - > sectors ) ;
2005-04-17 02:20:36 +04:00
if ( rdev2 = = rdev1 ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: END \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2009-03-31 07:33:13 +04:00
if ( rdev2 - > sectors = = rdev1 - > sectors ) {
2005-04-17 02:20:36 +04:00
/*
* Not unique , don ' t count it as a new
* group
*/
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: EQUAL \n " ) ;
2005-04-17 02:20:36 +04:00
c = 1 ;
break ;
}
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: NOT EQUAL \n " ) ;
2005-04-17 02:20:36 +04:00
}
if ( ! c ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: ==> UNIQUE \n " ) ;
2005-04-17 02:20:36 +04:00
conf - > nr_strip_zones + + ;
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: %d zones \n " ,
conf - > nr_strip_zones ) ;
2005-04-17 02:20:36 +04:00
}
}
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: FINAL %d zones \n " , conf - > nr_strip_zones ) ;
2009-06-16 10:47:36 +04:00
err = - ENOMEM ;
2006-01-06 11:20:32 +03:00
conf - > strip_zone = kzalloc ( sizeof ( struct strip_zone ) *
2005-04-17 02:20:36 +04:00
conf - > nr_strip_zones , GFP_KERNEL ) ;
if ( ! conf - > strip_zone )
2009-06-16 10:47:36 +04:00
goto abort ;
2006-01-06 11:20:32 +03:00
conf - > devlist = kzalloc ( sizeof ( mdk_rdev_t * ) *
2005-04-17 02:20:36 +04:00
conf - > nr_strip_zones * mddev - > raid_disks ,
GFP_KERNEL ) ;
if ( ! conf - > devlist )
2009-06-16 10:47:36 +04:00
goto abort ;
2005-04-17 02:20:36 +04:00
/* The first zone must contain all devices, so here we check that
* there is a proper alignment of slots to devices and find them all
*/
zone = & conf - > strip_zone [ 0 ] ;
cnt = 0 ;
smallest = NULL ;
2009-06-16 10:50:52 +04:00
dev = conf - > devlist ;
2009-06-16 10:47:36 +04:00
err = - EINVAL ;
2009-01-09 00:31:08 +03:00
list_for_each_entry ( rdev1 , & mddev - > disks , same_set ) {
2005-04-17 02:20:36 +04:00
int j = rdev1 - > raid_disk ;
if ( j < 0 | | j > = mddev - > raid_disks ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_ERR " raid0: bad disk number %d - "
" aborting! \n " , j ) ;
2005-04-17 02:20:36 +04:00
goto abort ;
}
2009-06-16 10:50:52 +04:00
if ( dev [ j ] ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_ERR " raid0: multiple devices for %d - "
" aborting! \n " , j ) ;
2005-04-17 02:20:36 +04:00
goto abort ;
}
2009-06-16 10:50:52 +04:00
dev [ j ] = rdev1 ;
2005-04-17 02:20:36 +04:00
blk_queue_stack_limits ( mddev - > queue ,
rdev1 - > bdev - > bd_disk - > queue ) ;
/* as we don't honour merge_bvec_fn, we must never risk
* violating it , so limit - > max_sector to one PAGE , as
* a one page request is never in violation .
*/
if ( rdev1 - > bdev - > bd_disk - > queue - > merge_bvec_fn & &
2009-05-23 01:17:50 +04:00
queue_max_sectors ( mddev - > queue ) > ( PAGE_SIZE > > 9 ) )
2005-04-17 02:20:36 +04:00
blk_queue_max_sectors ( mddev - > queue , PAGE_SIZE > > 9 ) ;
2009-03-31 07:33:13 +04:00
if ( ! smallest | | ( rdev1 - > sectors < smallest - > sectors ) )
2005-04-17 02:20:36 +04:00
smallest = rdev1 ;
cnt + + ;
}
if ( cnt ! = mddev - > raid_disks ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_ERR " raid0: too few disks (%d of %d) - "
" aborting! \n " , cnt , mddev - > raid_disks ) ;
2005-04-17 02:20:36 +04:00
goto abort ;
}
zone - > nb_dev = cnt ;
2009-06-16 10:50:35 +04:00
zone - > zone_end = smallest - > sectors * cnt ;
2005-04-17 02:20:36 +04:00
2009-06-16 10:50:35 +04:00
curr_zone_end = zone - > zone_end ;
2005-04-17 02:20:36 +04:00
/* now do the other zones */
for ( i = 1 ; i < conf - > nr_strip_zones ; i + + )
{
zone = conf - > strip_zone + i ;
2009-06-16 10:50:52 +04:00
dev = conf - > devlist + i * mddev - > raid_disks ;
2005-04-17 02:20:36 +04:00
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: zone %d \n " , i ) ;
2009-06-16 10:46:46 +04:00
zone - > dev_start = smallest - > sectors ;
2005-04-17 02:20:36 +04:00
smallest = NULL ;
c = 0 ;
for ( j = 0 ; j < cnt ; j + + ) {
char b [ BDEVNAME_SIZE ] ;
2009-06-16 10:50:52 +04:00
rdev = conf - > devlist [ j ] ;
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: checking %s ... " ,
bdevname ( rdev - > bdev , b ) ) ;
2009-06-16 10:46:46 +04:00
if ( rdev - > sectors < = zone - > dev_start ) {
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " nope. \n " ) ;
2009-03-31 07:33:13 +04:00
continue ;
}
printk ( KERN_INFO " contained as device %d \n " , c ) ;
2009-06-16 10:50:52 +04:00
dev [ c ] = rdev ;
2009-03-31 07:33:13 +04:00
c + + ;
if ( ! smallest | | rdev - > sectors < smallest - > sectors ) {
smallest = rdev ;
printk ( KERN_INFO " (%llu) is smallest!. \n " ,
( unsigned long long ) rdev - > sectors ) ;
}
2005-04-17 02:20:36 +04:00
}
zone - > nb_dev = c ;
2009-06-16 10:50:35 +04:00
sectors = ( smallest - > sectors - zone - > dev_start ) * c ;
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: zone->nb_dev: %d, sectors: %llu \n " ,
2009-06-16 10:50:35 +04:00
zone - > nb_dev , ( unsigned long long ) sectors ) ;
2005-04-17 02:20:36 +04:00
2009-06-16 10:50:35 +04:00
curr_zone_end + = sectors ;
2009-06-16 10:46:46 +04:00
zone - > zone_end = curr_zone_end ;
2005-04-17 02:20:36 +04:00
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: current zone start: %llu \n " ,
2009-06-16 10:46:46 +04:00
( unsigned long long ) smallest - > sectors ) ;
2005-04-17 02:20:36 +04:00
}
mddev - > queue - > unplug_fn = raid0_unplug ;
2006-10-03 12:15:53 +04:00
mddev - > queue - > backing_dev_info . congested_fn = raid0_congested ;
mddev - > queue - > backing_dev_info . congested_data = mddev ;
2005-04-17 02:20:36 +04:00
2009-06-16 11:00:57 +04:00
/*
* now since we have the hard sector sizes , we can make sure
* chunk size is a multiple of that sector size
*/
2009-06-18 02:45:01 +04:00
if ( ( mddev - > chunk_sectors < < 9 ) % queue_logical_block_size ( mddev - > queue ) ) {
2009-06-16 11:00:57 +04:00
printk ( KERN_ERR " %s chunk_size of %d not valid \n " ,
mdname ( mddev ) ,
2009-06-18 02:45:01 +04:00
mddev - > chunk_sectors < < 9 ) ;
2009-06-16 11:00:57 +04:00
goto abort ;
}
2009-01-09 00:31:07 +03:00
printk ( KERN_INFO " raid0: done. \n " ) ;
2009-06-16 10:47:36 +04:00
mddev - > private = conf ;
2005-04-17 02:20:36 +04:00
return 0 ;
2009-06-16 10:47:21 +04:00
abort :
2009-06-16 10:47:36 +04:00
kfree ( conf - > strip_zone ) ;
kfree ( conf - > devlist ) ;
kfree ( conf ) ;
mddev - > private = NULL ;
return err ;
2005-04-17 02:20:36 +04:00
}
/**
* raid0_mergeable_bvec - - tell bio layer if a two requests can be merged
* @ q : request queue
2008-07-03 11:53:43 +04:00
* @ bvm : properties of new bio
2005-04-17 02:20:36 +04:00
* @ biovec : the request that could be merged to it .
*
* Return amount of bytes we can accept at this offset
*/
2008-07-03 11:53:43 +04:00
static int raid0_mergeable_bvec ( struct request_queue * q ,
struct bvec_merge_data * bvm ,
struct bio_vec * biovec )
2005-04-17 02:20:36 +04:00
{
mddev_t * mddev = q - > queuedata ;
2008-07-03 11:53:43 +04:00
sector_t sector = bvm - > bi_sector + get_start_sect ( bvm - > bi_bdev ) ;
2005-04-17 02:20:36 +04:00
int max ;
2009-06-18 02:45:01 +04:00
unsigned int chunk_sectors = mddev - > chunk_sectors ;
2008-07-03 11:53:43 +04:00
unsigned int bio_sectors = bvm - > bi_size > > 9 ;
2005-04-17 02:20:36 +04:00
2009-06-18 02:47:00 +04:00
if ( is_power_of_2 ( chunk_sectors ) )
2009-06-16 11:02:05 +04:00
max = ( chunk_sectors - ( ( sector & ( chunk_sectors - 1 ) )
+ bio_sectors ) ) < < 9 ;
else
max = ( chunk_sectors - ( sector_div ( sector , chunk_sectors )
+ bio_sectors ) ) < < 9 ;
2005-04-17 02:20:36 +04:00
if ( max < 0 ) max = 0 ; /* bio_add cannot handle a negative return */
if ( max < = biovec - > bv_len & & bio_sectors = = 0 )
return biovec - > bv_len ;
else
return max ;
}
2009-03-18 04:10:40 +03:00
static sector_t raid0_size ( mddev_t * mddev , sector_t sectors , int raid_disks )
{
sector_t array_sectors = 0 ;
mdk_rdev_t * rdev ;
WARN_ONCE ( sectors | | raid_disks ,
" %s does not support generic reshape \n " , __func__ ) ;
list_for_each_entry ( rdev , & mddev - > disks , same_set )
array_sectors + = rdev - > sectors ;
return array_sectors ;
}
2009-06-16 10:47:10 +04:00
static int raid0_run ( mddev_t * mddev )
2005-04-17 02:20:36 +04:00
{
2009-06-16 10:47:21 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
2009-06-18 02:45:01 +04:00
if ( mddev - > chunk_sectors = = 0 ) {
2009-06-16 11:02:05 +04:00
printk ( KERN_ERR " md/raid0: chunk size must be set. \n " ) ;
2006-01-06 11:20:36 +03:00
return - EINVAL ;
}
2009-06-18 02:45:01 +04:00
blk_queue_max_sectors ( mddev - > queue , mddev - > chunk_sectors ) ;
2008-05-15 03:05:54 +04:00
mddev - > queue - > queue_lock = & mddev - > queue - > __queue_lock ;
2005-04-17 02:20:36 +04:00
2009-06-16 10:47:21 +04:00
ret = create_strip_zones ( mddev ) ;
if ( ret < 0 )
2009-06-16 10:47:36 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
/* calculate array device size */
2009-03-31 07:59:03 +04:00
md_set_array_sectors ( mddev , raid0_size ( mddev , 0 , 0 ) ) ;
2005-04-17 02:20:36 +04:00
2009-01-09 00:31:08 +03:00
printk ( KERN_INFO " raid0 : md_size is %llu sectors. \n " ,
( unsigned long long ) mddev - > array_sectors ) ;
2005-04-17 02:20:36 +04:00
/* calculate the max read-ahead size.
* For read - ahead of large files to be effective , we need to
* readahead at least twice a whole stripe . i . e . number of devices
* multiplied by chunk size times 2.
* If an individual device has an ra_pages greater than the
* chunk size , then we will not drive that device as hard as it
* wants . We consider this a configuration error : a larger
* chunksize should be used in that case .
*/
{
2009-06-18 02:45:01 +04:00
int stripe = mddev - > raid_disks *
( mddev - > chunk_sectors < < 9 ) / PAGE_SIZE ;
2005-04-17 02:20:36 +04:00
if ( mddev - > queue - > backing_dev_info . ra_pages < 2 * stripe )
mddev - > queue - > backing_dev_info . ra_pages = 2 * stripe ;
}
blk_queue_merge_bvec ( mddev - > queue , raid0_mergeable_bvec ) ;
2009-06-16 11:00:54 +04:00
dump_zones ( mddev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-06-16 10:48:19 +04:00
static int raid0_stop ( mddev_t * mddev )
2005-04-17 02:20:36 +04:00
{
2009-06-16 10:54:21 +04:00
raid0_conf_t * conf = mddev - > private ;
2005-04-17 02:20:36 +04:00
blk_sync_queue ( mddev - > queue ) ; /* the unplug fn references 'conf'*/
2005-06-22 04:17:30 +04:00
kfree ( conf - > strip_zone ) ;
2009-06-16 10:48:19 +04:00
kfree ( conf - > devlist ) ;
2005-06-22 04:17:30 +04:00
kfree ( conf ) ;
2005-04-17 02:20:36 +04:00
mddev - > private = NULL ;
return 0 ;
}
2009-06-16 10:50:35 +04:00
/* Find the zone which holds a particular offset
* Update * sectorp to be an offset in that zone
*/
2009-06-16 10:18:43 +04:00
static struct strip_zone * find_zone ( struct raid0_private_data * conf ,
2009-06-16 10:50:35 +04:00
sector_t * sectorp )
2009-06-16 10:18:43 +04:00
{
int i ;
struct strip_zone * z = conf - > strip_zone ;
2009-06-16 10:50:35 +04:00
sector_t sector = * sectorp ;
2009-06-16 10:18:43 +04:00
for ( i = 0 ; i < conf - > nr_strip_zones ; i + + )
2009-06-16 10:50:35 +04:00
if ( sector < z [ i ] . zone_end ) {
if ( i )
* sectorp = sector - z [ i - 1 ] . zone_end ;
2009-06-16 10:18:43 +04:00
return z + i ;
2009-06-16 10:50:35 +04:00
}
2009-06-16 10:18:43 +04:00
BUG ( ) ;
}
2009-06-16 11:02:05 +04:00
/*
* remaps the bio to the target device . we separate two flows .
* power 2 flow and a general flow for the sake of perfromance
*/
static mdk_rdev_t * map_sector ( mddev_t * mddev , struct strip_zone * zone ,
sector_t sector , sector_t * sector_offset )
2005-04-17 02:20:36 +04:00
{
2009-06-16 11:02:05 +04:00
unsigned int sect_in_chunk ;
sector_t chunk ;
2009-06-16 10:54:21 +04:00
raid0_conf_t * conf = mddev - > private ;
2009-06-18 02:45:01 +04:00
unsigned int chunk_sects = mddev - > chunk_sectors ;
2009-06-16 11:02:05 +04:00
2009-06-18 02:47:00 +04:00
if ( is_power_of_2 ( chunk_sects ) ) {
2009-06-16 11:02:05 +04:00
int chunksect_bits = ffz ( ~ chunk_sects ) ;
/* find the sector offset inside the chunk */
sect_in_chunk = sector & ( chunk_sects - 1 ) ;
sector > > = chunksect_bits ;
/* chunk in zone */
chunk = * sector_offset ;
/* quotient is the chunk in real device*/
sector_div ( chunk , zone - > nb_dev < < chunksect_bits ) ;
} else {
sect_in_chunk = sector_div ( sector , chunk_sects ) ;
chunk = * sector_offset ;
sector_div ( chunk , chunk_sects * zone - > nb_dev ) ;
}
/*
* position the bio over the real device
* real sector = chunk in device + starting of zone
* + the position in the chunk
*/
* sector_offset = ( chunk * chunk_sects ) + sect_in_chunk ;
return conf - > devlist [ ( zone - conf - > strip_zone ) * mddev - > raid_disks
+ sector_div ( sector , zone - > nb_dev ) ] ;
}
/*
* Is io distribute over 1 or more chunks ?
*/
static inline int is_io_in_chunk_boundary ( mddev_t * mddev ,
unsigned int chunk_sects , struct bio * bio )
{
2009-06-18 02:47:00 +04:00
if ( likely ( is_power_of_2 ( chunk_sects ) ) ) {
2009-06-16 11:02:05 +04:00
return chunk_sects > = ( ( bio - > bi_sector & ( chunk_sects - 1 ) )
+ ( bio - > bi_size > > 9 ) ) ;
} else {
sector_t sector = bio - > bi_sector ;
return chunk_sects > = ( sector_div ( sector , chunk_sects )
+ ( bio - > bi_size > > 9 ) ) ;
}
}
static int raid0_make_request ( struct request_queue * q , struct bio * bio )
{
mddev_t * mddev = q - > queuedata ;
unsigned int chunk_sects ;
sector_t sector_offset ;
2005-04-17 02:20:36 +04:00
struct strip_zone * zone ;
mdk_rdev_t * tmp_dev ;
2005-11-01 11:26:16 +03:00
const int rw = bio_data_dir ( bio ) ;
2008-08-25 14:47:21 +04:00
int cpu ;
2005-04-17 02:20:36 +04:00
2005-09-10 03:23:41 +04:00
if ( unlikely ( bio_barrier ( bio ) ) ) {
2007-09-27 14:47:43 +04:00
bio_endio ( bio , - EOPNOTSUPP ) ;
2005-09-10 03:23:41 +04:00
return 0 ;
}
2008-08-25 14:56:14 +04:00
cpu = part_stat_lock ( ) ;
part_stat_inc ( cpu , & mddev - > gendisk - > part0 , ios [ rw ] ) ;
part_stat_add ( cpu , & mddev - > gendisk - > part0 , sectors [ rw ] ,
bio_sectors ( bio ) ) ;
part_stat_unlock ( ) ;
2005-04-17 02:20:36 +04:00
2009-06-18 02:45:01 +04:00
chunk_sects = mddev - > chunk_sectors ;
2009-06-16 11:02:05 +04:00
if ( unlikely ( ! is_io_in_chunk_boundary ( mddev , chunk_sects , bio ) ) ) {
sector_t sector = bio - > bi_sector ;
2005-04-17 02:20:36 +04:00
struct bio_pair * bp ;
/* Sanity check -- queue functions should prevent this happening */
if ( bio - > bi_vcnt ! = 1 | |
bio - > bi_idx ! = 0 )
goto bad_map ;
/* This is a one page bio that upper layers
* refuse to split for us , so we need to split it .
*/
2009-06-18 02:47:00 +04:00
if ( likely ( is_power_of_2 ( chunk_sects ) ) )
2009-06-16 11:02:05 +04:00
bp = bio_split ( bio , chunk_sects - ( sector &
( chunk_sects - 1 ) ) ) ;
else
bp = bio_split ( bio , chunk_sects -
sector_div ( sector , chunk_sects ) ) ;
2005-04-17 02:20:36 +04:00
if ( raid0_make_request ( q , & bp - > bio1 ) )
generic_make_request ( & bp - > bio1 ) ;
if ( raid0_make_request ( q , & bp - > bio2 ) )
generic_make_request ( & bp - > bio2 ) ;
bio_pair_release ( bp ) ;
return 0 ;
}
2009-06-16 11:02:05 +04:00
sector_offset = bio - > bi_sector ;
zone = find_zone ( mddev - > private , & sector_offset ) ;
tmp_dev = map_sector ( mddev , zone , bio - > bi_sector ,
& sector_offset ) ;
2005-04-17 02:20:36 +04:00
bio - > bi_bdev = tmp_dev - > bdev ;
2009-06-16 11:02:05 +04:00
bio - > bi_sector = sector_offset + zone - > dev_start +
tmp_dev - > data_offset ;
2005-04-17 02:20:36 +04:00
/*
* Let the main block layer submit the IO and resolve recursion :
*/
return 1 ;
bad_map :
printk ( " raid0_make_request bug: can't convert block across chunks "
2009-01-09 00:31:06 +03:00
" or bigger than %dk %llu %d \n " , chunk_sects / 2 ,
2005-04-17 02:20:36 +04:00
( unsigned long long ) bio - > bi_sector , bio - > bi_size > > 10 ) ;
2007-09-27 14:47:43 +04:00
bio_io_error ( bio ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-10-17 10:30:53 +04:00
2009-06-16 10:57:40 +04:00
static void raid0_status ( struct seq_file * seq , mddev_t * mddev )
2005-04-17 02:20:36 +04:00
{
# undef MD_DEBUG
# ifdef MD_DEBUG
int j , k , h ;
char b [ BDEVNAME_SIZE ] ;
2009-06-16 10:54:21 +04:00
raid0_conf_t * conf = mddev - > private ;
2007-10-17 10:30:53 +04:00
2009-06-16 10:57:40 +04:00
sector_t zone_size ;
sector_t zone_start = 0 ;
2005-04-17 02:20:36 +04:00
h = 0 ;
2009-06-16 10:57:40 +04:00
2005-04-17 02:20:36 +04:00
for ( j = 0 ; j < conf - > nr_strip_zones ; j + + ) {
seq_printf ( seq , " z%d " , j ) ;
seq_printf ( seq , " =[ " ) ;
for ( k = 0 ; k < conf - > strip_zone [ j ] . nb_dev ; k + + )
2007-10-17 10:30:53 +04:00
seq_printf ( seq , " %s/ " , bdevname (
2009-06-16 10:57:40 +04:00
conf - > devlist [ j * mddev - > raid_disks + k ]
- > bdev , b ) ) ;
zone_size = conf - > strip_zone [ j ] . zone_end - zone_start ;
seq_printf ( seq , " ] ze=%lld ds=%lld s=%lld \n " ,
( unsigned long long ) zone_start > > 1 ,
( unsigned long long ) conf - > strip_zone [ j ] . dev_start > > 1 ,
( unsigned long long ) zone_size > > 1 ) ;
zone_start = conf - > strip_zone [ j ] . zone_end ;
2005-04-17 02:20:36 +04:00
}
# endif
2009-06-18 02:45:01 +04:00
seq_printf ( seq , " %dk chunks " , mddev - > chunk_sectors / 2 ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2006-01-06 11:20:36 +03:00
static struct mdk_personality raid0_personality =
2005-04-17 02:20:36 +04:00
{
. name = " raid0 " ,
2006-01-06 11:20:36 +03:00
. level = 0 ,
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. make_request = raid0_make_request ,
. run = raid0_run ,
. stop = raid0_stop ,
. status = raid0_status ,
2009-03-18 04:10:40 +03:00
. size = raid0_size ,
2005-04-17 02:20:36 +04:00
} ;
static int __init raid0_init ( void )
{
2006-01-06 11:20:36 +03:00
return register_md_personality ( & raid0_personality ) ;
2005-04-17 02:20:36 +04:00
}
static void raid0_exit ( void )
{
2006-01-06 11:20:36 +03:00
unregister_md_personality ( & raid0_personality ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( raid0_init ) ;
module_exit ( raid0_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " md-personality-2 " ) ; /* RAID0 */
2006-01-06 11:20:51 +03:00
MODULE_ALIAS ( " md-raid0 " ) ;
2006-01-06 11:20:36 +03:00
MODULE_ALIAS ( " md-level-0 " ) ;