[dm-devel] [PATCH 10/12] Limit bio_endio recursion

Shaun Tancheff shaun at tancheff.com
Mon Apr 4 05:06:14 UTC 2016


Recursive endio calls can exceed 16k stack. Tested with
32k stack and observed:

            Depth    Size   Location    (293 entries)
            -----    ----   --------
      0)    21520      16   __module_text_address+0x12/0x60
      1)    21504       8   __module_address+0x5/0x140
      2)    21496      24   __module_text_address+0x12/0x60
      3)    21472      16   is_module_text_address+0xe/0x20
      4)    21456       8   __kernel_text_address+0x50/0x80
      5)    21448     136   print_context_stack+0x5a/0xf0
      6)    21312     144   dump_trace+0x14c/0x300
      7)    21168       8   save_stack_trace+0x2f/0x50
      8)    21160      88   set_track+0x64/0x130
      9)    21072      96   free_debug_processing+0x200/0x290
     10)    20976     176   __slab_free+0x164/0x290
     11)    20800      48   kmem_cache_free+0x1b0/0x1e0
     12)    20752      16   mempool_free_slab+0x17/0x20
     13)    20736      48   mempool_free+0x2f/0x90
     14)    20688      16   bvec_free+0x36/0x40
     15)    20672      32   bio_free+0x3b/0x60
     16)    20640      16   bio_put+0x23/0x30
     17)    20624      64   end_bio_extent_writepage+0xcf/0xe0
     18)    20560      48   bio_endio+0x57/0x90
     19)    20512      48   btrfs_end_bio+0xa8/0x160
     20)    20464      48   bio_endio+0x57/0x90
     21)    20416     112   dec_pending+0x121/0x270
     22)    20304      64   clone_endio+0x7a/0x100
     23)    20240      48   bio_endio+0x57/0x90
    ...
    277)     1264      64   clone_endio+0x7a/0x100
    278)     1200      48   bio_endio+0x57/0x90
    279)     1152     112   dec_pending+0x121/0x270
    280)     1040      64   clone_endio+0x7a/0x100
    281)      976      48   bio_endio+0x57/0x90
    282)      928      80   blk_update_request+0x8f/0x340
    283)      848      80   scsi_end_request+0x33/0x1c0
    284)      768     112   scsi_io_completion+0xb5/0x620
    285)      656      48   scsi_finish_command+0xcf/0x120
    286)      608      48   scsi_softirq_done+0x126/0x150
    287)      560      24   blk_done_softirq+0x78/0x90
    288)      536     136   __do_softirq+0xfd/0x280
    289)      400      16   run_ksoftirqd+0x28/0x50
    290)      384      64   smpboot_thread_fn+0x105/0x160
    291)      320     144   kthread+0xc9/0xe0
    292)      176     176   ret_from_fork+0x3f/0x70

Based on earlier patch by Mikulas Patocka <mpatocka at redhat.com>.
https://lkml.org/lkml/2008/6/24/18

Signed-off-by: Shaun Tancheff <shaun.tancheff at seagate.com>
---
 block/bio.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 54 insertions(+), 3 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index d42e69c..4ac19f6 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1733,6 +1733,59 @@ static inline bool bio_remaining_done(struct bio *bio)
 	return false;
 }
 
+static DEFINE_PER_CPU(struct bio **, bio_end_queue) = { NULL };
+
+static struct bio *unwind_bio_endio(struct bio *bio)
+{
+	struct bio ***bio_end_queue_ptr;
+	struct bio *bio_queue;
+	struct bio *chain_bio = NULL;
+	int error = bio->bi_error;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	bio_end_queue_ptr = this_cpu_ptr(&bio_end_queue);
+
+	if (*bio_end_queue_ptr) {
+		**bio_end_queue_ptr = bio;
+		*bio_end_queue_ptr = &bio->bi_next;
+		bio->bi_next = NULL;
+	} else {
+		bio_queue = NULL;
+		*bio_end_queue_ptr = &bio_queue;
+
+next_bio:
+		if (bio->bi_end_io == bio_chain_endio) {
+			struct bio *parent = bio->bi_private;
+
+			bio_put(bio);
+			chain_bio = parent;
+			goto out;
+		}
+
+		if (bio->bi_end_io) {
+			if (!bio->bi_error)
+				bio->bi_error = error;
+			bio->bi_end_io(bio);
+		}
+
+		if (bio_queue) {
+			bio = bio_queue;
+			bio_queue = bio->bi_next;
+			if (!bio_queue)
+				*bio_end_queue_ptr = &bio_queue;
+			goto next_bio;
+		}
+		*bio_end_queue_ptr = NULL;
+	}
+
+out:
+
+	local_irq_restore(flags);
+
+	return chain_bio;
+}
+
 /**
  * bio_endio - end I/O on a bio
  * @bio:	bio
@@ -1762,9 +1815,7 @@ void bio_endio(struct bio *bio)
 			bio_put(bio);
 			bio = parent;
 		} else {
-			if (bio->bi_end_io)
-				bio->bi_end_io(bio);
-			bio = NULL;
+			bio = unwind_bio_endio(bio);
 		}
 	}
 }
-- 
1.9.1




More information about the dm-devel mailing list