On 20/03/2019 09:12, Hannes Reinecke wrote:
> __blkdev_direct_IO_simple() is allocating a bio on the stack.
> When that bio needs to be split bio_chain_endio() invokes bio_put()
> on this bio, causing the kernel to crash in mempool_free() as the
> bio was never allocated from a mempool in the first place.
> So call bio_get() before submitting to avoid this problem.

Hmm this sounds as if we're just papering over the real issue here,
which is calling bio_free() for bios not allocated using bio_alloc_bioset().

How about the following untested patch:

>From 9c8434e5bf81595e97ea5647437d12bfce0e37b6 Mon Sep 17 00:00:00 2001
From: Johannes Thumshirn <[email protected]>
Date: Wed, 20 Mar 2019 09:40:18 +0100
Subject: [PATCH] bio: Introduce BIO_ALLOCED flag and check it in bio_free

When we're submitting a bio from stack and this ends up being split, we
call bio_put(). bio_put() will eventually call bio_free() if the reference
count drops to 0. But freeing the bio is wrong, as it was never allocated
out of the bio's mempool.

Flag each normally allocated bio as 'BIO_ALLOCATED' and skip freeing if the
flag isn't set.

Signed-off-by: Johannes Thumshirn <[email protected]>
---
 block/bio.c               | 4 ++++
 include/linux/blk_types.h | 1 +
 2 files changed, 5 insertions(+)

diff --git a/block/bio.c b/block/bio.c
index 4db1008309ed..caa8bc076377 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -253,6 +253,9 @@ static void bio_free(struct bio *bio)
        struct bio_set *bs = bio->bi_pool;
        void *p;

+       if (!bio_flagged(bio, BIO_ALLOCED))
+               return;
+
        bio_uninit(bio);

        if (bs) {
@@ -521,6 +524,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask,
unsigned int nr_iovecs,
                bvl = bio->bi_inline_vecs;
        }

+       bio_set_flag(bio, BIO_ALLOCED);
        bio->bi_pool = bs;
        bio->bi_max_vecs = nr_iovecs;
        bio->bi_io_vec = bvl;
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index d66bf5f32610..14b4f87a1eab 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -229,6 +229,7 @@ struct bio {
                                 * of this bio. */
 #define BIO_QUEUE_ENTERED 11   /* can use blk_queue_enter_live() */
 #define BIO_TRACKED 12         /* set if bio goes through the rq_qos path */
+#define BIO_ALLOCED 13         /* set if the bio was allocated by
bio_alloc_bioset */

 /* See BVEC_POOL_OFFSET below before adding new flags */

-- 
2.16.4



-- 
Johannes Thumshirn                            SUSE Labs Filesystems
[email protected]                                +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850

Reply via email to