Avoid recursion on bio_endio. bio_endio calls bio->bi_end_io which may in turn call bio_endio again. When this recursion happens, put the new bio to the queue and process it later, from the top-level bio_endio. Signed-off-by: Mikulas Patocka Index: linux-2.6.26-rc5-devel/fs/bio.c =================================================================== --- linux-2.6.26-rc5-devel.orig/fs/bio.c 2008-06-18 23:48:45.000000000 +0200 +++ linux-2.6.26-rc5-devel/fs/bio.c 2008-06-19 00:15:56.000000000 +0200 @@ -1168,6 +1168,27 @@ **/ void bio_endio(struct bio *bio, int error) { + static DEFINE_PER_CPU(struct bio **, bio_end_queue) = { NULL }; + struct bio ***bio_end_queue_ptr; + struct bio *bio_queue; + + unsigned long flags; + + local_irq_save(flags); + bio_end_queue_ptr = &__get_cpu_var(bio_end_queue); + + if (*bio_end_queue_ptr) { + **bio_end_queue_ptr = bio; + *bio_end_queue_ptr = &bio->bi_next; + bio->bi_next = NULL; + goto ret; + } + + bio_queue = NULL; +queue_empty_next_bio: + *bio_end_queue_ptr = &bio_queue; +next_bio: + if (error) clear_bit(BIO_UPTODATE, &bio->bi_flags); else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) @@ -1175,6 +1196,17 @@ if (bio->bi_end_io) bio->bi_end_io(bio, error); + + if (bio_queue) { + bio = bio_queue; + bio_queue = bio->bi_next; + if (!bio_queue) goto queue_empty_next_bio; + goto next_bio; + } + *bio_end_queue_ptr = NULL; + +ret: + local_irq_restore(flags); } void bio_pair_release(struct bio_pair *bp)