Merge IO requests to try and get larger requests on underlying drives. Index: linux-2.6.9/drivers/md/raid5.c =================================================================== --- linux-2.6.9.orig/drivers/md/raid5.c 2006-05-22 00:10:04.000000000 +0400 +++ linux-2.6.9/drivers/md/raid5.c 2006-05-22 00:10:06.000000000 +0400 @@ -934,6 +934,26 @@ static void add_stripe_bio (struct strip } } +/* + * The whole idea is to collect all bio's and then issue them + * disk by disk to assist merging a bit -bzzz + */ +static void raid5_flush_bios(raid5_conf_t *conf, struct bio *bios[], int raid_disks) +{ + struct bio *bio, *nbio; + int i; + + for (i = 0; i < raid_disks; i++) { + bio = bios[i]; + while (bio) { + nbio = bio->bi_next; + bio->bi_next = NULL; + generic_make_request(bio); + bio = nbio; + } + bios[i] = NULL; + } +} /* * handle_stripe - do things to a stripe. @@ -953,7 +973,7 @@ static void add_stripe_bio (struct strip * */ -static void handle_stripe(struct stripe_head *sh) +static void handle_stripe(struct stripe_head *sh, struct bio *bios[]) { raid5_conf_t *conf = sh->raid_conf; int disks = conf->raid_disks; @@ -1376,7 +1396,11 @@ static void handle_stripe(struct stripe_ bi->bi_size = STRIPE_SIZE; bi->bi_next = NULL; atomic_inc(&conf->out_reqs_in_queue); - generic_make_request(bi); + if (bios) { + bi->bi_next = bios[i]; + bios[i] = bi; + } else + generic_make_request(bi); } else { PRINTK("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector); @@ -1501,6 +1525,7 @@ static int make_request (request_queue_t int sectors_per_chunk = conf->chunk_size >> 9; int stripes_per_chunk, sectors_per_block; int sectors_per_stripe; + struct bio *bios[MD_SB_DISKS]; int i, j; atomic_inc(&conf->in_reqs_in_queue); @@ -1530,6 +1555,7 @@ static int make_request (request_queue_t sector_div(block, sectors_per_block); sectors = bi->bi_size >> 9; + memset(&bios, 0, sizeof(bios)); repeat: stripe = block * sectors_per_block / data_disks; b_sector = stripe * data_disks; @@ -1549,9 +1575,17 @@ repeat: 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 == NULL) { + /* first, try to get stripe w/o blocking + * if we can't, then it's time to submit + * all collected bio's in order to free + * some space in the cache -bzzz */ + sh = get_active_stripe(conf, new_sector, pd_idx, 1); + if (!sh && !(bi->bi_rw&RWA_MASK)) { + raid5_flush_bios(conf, bios, raid_disks); + sh = get_active_stripe(conf, new_sector, pd_idx, 0); + } + } if (sh) { add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK)); } else { @@ -1571,7 +1605,7 @@ repeat: } if (sh) { raid5_plug_device(conf); - handle_stripe(sh); + handle_stripe(sh, bios); release_stripe(sh); sh = NULL; } @@ -1581,6 +1615,9 @@ repeat: if (sectors > 0) goto repeat; + /* now flush all bio's */ + raid5_flush_bios(conf, bios, raid_disks); + spin_lock_irq(&conf->device_lock); if (--bi->bi_phys_segments == 0) { int bytes = bi->bi_size; @@ -1636,7 +1673,7 @@ static int sync_request (mddev_t *mddev, clear_bit(STRIPE_INSYNC, &sh->state); spin_unlock(&sh->lock); - handle_stripe(sh); + handle_stripe(sh, NULL); release_stripe(sh); return STRIPE_SECTORS; @@ -1685,7 +1722,7 @@ static void raid5d (mddev_t *mddev) handled++; atomic_inc(&conf->handled_in_raid5d); - handle_stripe(sh); + handle_stripe(sh, NULL); release_stripe(sh); spin_lock_irq(&conf->device_lock);