Skip to contentSkip to conversation

Fix bio_set copy

PATCH In review Jens Axboe 3 participants 6 messages Jun 7, 2018 – Jun 8, 2018

Subsystems (2)
lore
Share & tools
lore

Jens Axboe

author maintainer
#0 lore raw

cover Fix bio_set copy

After a recent change, dm ends up doing a straight copy of a bio_set. This breaks for various items in that bio_set, most notably lists. Provide a proper helper for it, and use it.

Signature · 1 line
Jens Axboe
author maintainer
#1 lore raw

PATCH 1/2 block: add bioset_init_from_src() helper

Add a helper that allows a caller to initialize a new bio_set, using the settings from an existing bio_set.

---
 block/bio.c         | 18 ++++++++++++++++++
 include/linux/bio.h |  1 +
 2 files changed, 19 insertions(+)
block/bio.c +18 -0
index 595663e0281a..bf516d873ce9 100644
@@ -1967,6 +1967,24 @@ int bioset_init(struct bio_set *bs,
 }
 EXPORT_SYMBOL(bioset_init);
 
+/*
+ * Initialize and setup a new bio_set, based on the settings from
+ * another bio_set.
+ */
+int bioset_init_from_src(struct bio_set *bs, struct bio_set *src)
+{
+	int flags;
+
+	flags = 0;
+	if (src->bvec_pool.min_nr)
+		flags |= BIOSET_NEED_BVECS;
+	if (src->rescue_workqueue)
+		flags |= BIOSET_NEED_RESCUER;
+
+	return bioset_init(bs, src->bio_pool.min_nr, src->front_pad, flags);
+}
+EXPORT_SYMBOL(bioset_init_from_src);
+
 #ifdef CONFIG_BLK_CGROUP
 
 /**
include/linux/bio.h +1 -0
index 810a8bee8f85..84abd1706dcb 100644
@@ -417,6 +417,7 @@ enum {
 extern int bioset_init(struct bio_set *, unsigned int, unsigned int, int flags);
 extern void bioset_exit(struct bio_set *);
 extern int biovec_init_pool(mempool_t *pool, int pool_entries);
+extern int bioset_init_from_src(struct bio_set *bs, struct bio_set *src);
 
 extern struct bio *bio_alloc_bioset(gfp_t, unsigned int, struct bio_set *);
 extern void bio_put(struct bio *);
Signature · 1 line
2.17.1
author maintainer
#2 lore raw

PATCH 2/2 dm: use bioset_init_from_src() to copy bio_set

In reply to Jens Axboe

We can't just copy and clear a bio_set, use the bio helper to setup a new bio_set with the settings from another one.

Fixes 6f1c819c219f ("dm: convert to bioset_init()/mempool_init()")
---
 drivers/md/dm.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/md/dm.c +16 -6
index 98dff36b89a3..20a8d63754bf 100644
@@ -1953,9 +1953,10 @@ static void free_dev(struct mapped_device *md)
 	kvfree(md);
 }
 
-static void __bind_mempools(struct mapped_device *md, struct dm_table *t)
+static int __bind_mempools(struct mapped_device *md, struct dm_table *t)
 {
 	struct dm_md_mempools *p = dm_table_get_md_mempools(t);
+	int ret = 0;
 
 	if (dm_table_bio_based(t)) {
 		/*
@@ -1982,13 +1983,16 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t)
 	       bioset_initialized(&md->bs) ||
 	       bioset_initialized(&md->io_bs));
 
-	md->bs = p->bs;
-	memset(&p->bs, 0, sizeof(p->bs));
-	md->io_bs = p->io_bs;
-	memset(&p->io_bs, 0, sizeof(p->io_bs));
+	ret = bioset_init_from_src(&md->bs, &p->bs);
+	if (ret)
+		goto out;
+	ret = bioset_init_from_src(&md->io_bs, &p->io_bs);
+	if (ret)
+		bioset_exit(&md->bs);
 out:
 	/* mempool bind completed, no longer need any mempools in the table */
 	dm_table_free_md_mempools(t);
+	return ret;
 }
 
 /*
@@ -2033,6 +2037,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
 	struct request_queue *q = md->queue;
 	bool request_based = dm_table_request_based(t);
 	sector_t size;
+	int ret;
 
 	lockdep_assert_held(&md->suspend_lock);
 
@@ -2068,7 +2073,11 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
 		md->immutable_target = dm_table_get_immutable_target(t);
 	}
 
-	__bind_mempools(md, t);
+	ret = __bind_mempools(md, t);
+	if (ret) {
+		old_map = ERR_PTR(ret);
+		goto out;
+	}
 
 	old_map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
 	rcu_assign_pointer(md->map, (void *)t);
@@ -2078,6 +2087,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
 	if (old_map)
 		dm_sync_table(md);
 
+out:
 	return old_map;
 }
 
Signature · 1 line
2.17.1
Tested-by
#4 lore raw
Quoted 7 lines · Li Wang
Quoted 3 lines · Jens Axboe

After a recent change, dm ends up doing a straight copy of a bio_set. This breaks for various items in that bio_set, most notably lists. Provide a proper helper for it, and use it.

​

I am not seeing the issue, I reported with this patch applied to latest mainline.

JOB ID : 5d6db9ad320b92b77cd92056fb4514c9afa0feea
JOB LOG : /root/avocado-korg/korg/results/job-2018-06-08T03.49-5d6db9a/job.log
(1/4) memhotplug.py:memstress.test_hotplug_loop: PASS (254.14 s) (2/4) memhotplug.py:memstress.test_hotplug_toggle: PASS (246.81 s) (3/4) memhotplug.py:memstress.test_dlpar_mem_hotplug: PASS (3.95 s) (4/4) memhotplug.py:memstress.test_hotplug_per_numa_node: PASS (223.96
s)
RESULTS : PASS 4 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
JOB TIME : 734.52 s
JOB HTML : /root/avocado-korg/korg/results/job-2018-06-08T03.49-5d6db9a/results.html

Quoted 18 lines

I can confirm that the issue[1] was gone with this patchset applied.

​
[1] https://lkml.org/lkml/2018/6/7/36 [1]​

--

Regards,

Li Wang

Links:
------
[1] https://lkml.org/lkml/2018/6/7/36

author maintainer
#5 lore raw
In reply to Li Wang
Quoted 6 lines · Li Wang

Jens Axboe <[email protected] <mailto:[email protected]>> wrote:

After a recent change, dm ends up doing a straight copy of a bio_set. This breaks for various items in that bio_set, most notably lists. Provide a proper helper for it, and use it.

Quoted 6 lines

​

I can confirm that the issue[1] was gone with this patchset applied.

Tested-by Li Wang <[email protected] <mailto:[email protected]>>

Thanks for testing, both of you, and reporting. I'll get this pushed upstream.

Signature · 1 line
Jens Axboe