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 <mpato...@redhat.com>.
https://lkml.org/lkml/2008/6/24/18

Signed-off-by: Shaun Tancheff <shaun.tanch...@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

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to