Messages in this thread Patch in this message | | | Date | Tue, 24 Jun 2008 01:22:33 -0400 (EDT) | From | Mikulas Patocka <> | Subject | [PATCH 1/2] Avoid bio_endio recursion |
| |
Hi
bio_endio calls bi_end_io callback. In case of stacked devices (raid, dm), bio_end_io may call bio_endio again, up to an unspecified length.
The crash because of stack overflow was really observed on sparc64. And this recursion was one of the contributing factors (using 9 stack frames --- that is 1728 bytes).
This patch removes the recursion.
Mikulas
--
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 <mpatocka@redhat.com>
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)
| |