Helps to avoid unnesessary reads if request covers full stripe. Note that reads needed to update parity hurt performance badly Index: linux-2.6.9/drivers/md/raid5.c =================================================================== --- linux-2.6.9.orig/drivers/md/raid5.c 2006-05-22 00:09:56.000000000 +0400 +++ linux-2.6.9/drivers/md/raid5.c 2006-05-22 00:10:01.000000000 +0400 @@ -1412,6 +1412,11 @@ static int make_request (request_queue_t sector_t new_sector; sector_t logical_sector, last_sector; struct stripe_head *sh; + sector_t stripe, sectors, block, r_sector, b_sector; + int sectors_per_chunk = conf->chunk_size >> 9; + int stripes_per_chunk, sectors_per_block; + int sectors_per_stripe; + int i, j; atomic_inc(&conf->in_reqs_in_queue); @@ -1431,30 +1436,66 @@ static int make_request (request_queue_t bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ if ( bio_data_dir(bi) == WRITE ) md_write_start(mddev); - for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { - - new_sector = raid5_compute_sector(logical_sector, - raid_disks, data_disks, &dd_idx, &pd_idx, conf); - - PRINTK("raid5: make_request, sector %Lu logical %Lu\n", - (unsigned long long)new_sector, - (unsigned long long)logical_sector); - sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); + stripes_per_chunk = conf->chunk_size / STRIPE_SIZE; + sectors_per_stripe = STRIPE_SECTORS * data_disks; + sectors_per_block = stripes_per_chunk * sectors_per_stripe; + + block = logical_sector & ~((sector_t)sectors_per_block - 1); + sector_div(block, sectors_per_block); + sectors = bi->bi_size >> 9; + +repeat: + stripe = block * (sectors_per_block / data_disks); + b_sector = stripe * data_disks; + /* iterate through all stripes in this block, + * where block is a set of internal stripes + * which covers chunk */ + for (i = 0; i < stripes_per_chunk && sectors > 0; i++) { + r_sector = b_sector + (i * STRIPE_SECTORS); + sh = NULL; + /* iterrate through all pages in the stripe */ + for (j = 0; j < data_disks && sectors > 0; j++) { + if (r_sector + STRIPE_SECTORS <= bi->bi_sector || + r_sector >= last_sector) { + r_sector += sectors_per_chunk; + continue; + } + new_sector = raid5_compute_sector(r_sector, raid_disks, + data_disks, &dd_idx, + &pd_idx, conf); + if (sh == NULL) + sh = get_active_stripe(conf, new_sector, pd_idx, + (bi->bi_rw&RWA_MASK)); + if (sh) { + add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK)); + } else { + /* cannot get stripe for read-ahead, just give-up */ + clear_bit(BIO_UPTODATE, &bi->bi_flags); + sectors = 0; + break; + } + + BUG_ON (new_sector != stripe); + sectors -= STRIPE_SECTORS; + if (bi->bi_sector > r_sector) + sectors += bi->bi_sector - r_sector; + if (r_sector + STRIPE_SECTORS > last_sector) + sectors += r_sector + STRIPE_SECTORS - last_sector; + r_sector += sectors_per_chunk; + } if (sh) { - - add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK)); - raid5_plug_device(conf); handle_stripe(sh); release_stripe(sh); - } else { - /* cannot get stripe for read-ahead, just give-up */ - clear_bit(BIO_UPTODATE, &bi->bi_flags); - break; + sh = NULL; } - + stripe += STRIPE_SECTORS; } + block++; + if (sectors > 0) + goto repeat; + spin_lock_irq(&conf->device_lock); if (--bi->bi_phys_segments == 0) { int bytes = bi->bi_size;