Re: [PATCH] block_dev: fix crash on chained bios with O_DIRECT

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 3/20/19 9:45 AM, Johannes Thumshirn wrote:
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 <jthumshirn@xxxxxxx>
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 <jthumshirn@xxxxxxx>
---
  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 */

Yeah, should work, too.
But we should be calling bio_uninit() for all bios.

Will you be sending an updated patch?

Cheers,

Hannes
--
Dr. Hannes Reinecke		               zSeries & Storage
hare@xxxxxxxx			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux