--- /dev/null
+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);