From 9356863c9409efc79029c01a85d015efae977e69 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 6 Feb 2017 13:41:39 +1100 Subject: md: ensure md devices are freed before module is unloaded. Commit: cbd199837750 ("md: Fix unfortunate interaction with evms") change mddev_put() so that it would not destroy an md device while ->ctime was non-zero. Unfortunately, we didn't make sure to clear ->ctime when unloading the module, so it is possible for an md device to remain after module unload. An attempt to open such a device will trigger an invalid memory reference in: get_gendisk -> kobj_lookup -> exact_lock -> get_disk when tring to access disk->fops, which was in the module that has been removed. So ensure we clear ->ctime in md_exit(), and explain how that is useful, as it isn't immediately obvious when looking at the code. Fixes: cbd199837750 ("md: Fix unfortunate interaction with evms") Tested-by: Guoqing Jiang Signed-off-by: NeilBrown Signed-off-by: Shaohua Li --- drivers/md/md.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/md/md.c') diff --git a/drivers/md/md.c b/drivers/md/md.c index 01175dac0db6..13020e5c8cc0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8980,7 +8980,14 @@ static __exit void md_exit(void) for_each_mddev(mddev, tmp) { export_array(mddev); + mddev->ctime = 0; mddev->hold_active = 0; + /* + * for_each_mddev() will call mddev_put() at the end of each + * iteration. As the mddev is now fully clear, this will + * schedule the mddev for destruction by a workqueue, and the + * destroy_workqueue() below will wait for that to complete. + */ } destroy_workqueue(md_misc_wq); destroy_workqueue(md_wq); -- cgit v1.2.3 From 10273170fd5602d8090b1312e66ad4746ab02c94 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 14 Feb 2017 23:29:00 +0800 Subject: md: fail if mddev->bio_set can't be created The current behaviour is to fall back to allocate bio from 'fs_bio_set', that isn't a correct way because it might cause deadlock. So this patch simply return failure if mddev->bio_set can't be created. Reviewed-by: Christoph Hellwig Signed-off-by: Ming Lei Signed-off-by: Shaohua Li --- drivers/md/md.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/md/md.c') diff --git a/drivers/md/md.c b/drivers/md/md.c index 13020e5c8cc0..137a1fe124e8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5228,8 +5228,11 @@ int md_run(struct mddev *mddev) sysfs_notify_dirent_safe(rdev->sysfs_state); } - if (mddev->bio_set == NULL) + if (mddev->bio_set == NULL) { mddev->bio_set = bioset_create(BIO_POOL_SIZE, 0); + if (!mddev->bio_set) + return -ENOMEM; + } spin_lock(&pers_lock); pers = find_pers(mddev->level, mddev->clevel); -- cgit v1.2.3 From ed7ef732ca9f7d6f42be8df6cc7bf4ace3534af3 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 14 Feb 2017 23:29:02 +0800 Subject: md: remove unnecessary check on mddev mddev is never NULL and neither is ->bio_set, so remove the check. Reviewed-by: Christoph Hellwig Signed-off-by: Ming Lei Signed-off-by: Shaohua Li --- drivers/md/md.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/md/md.c') diff --git a/drivers/md/md.c b/drivers/md/md.c index 137a1fe124e8..0e408bc67904 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -193,9 +193,6 @@ EXPORT_SYMBOL_GPL(bio_alloc_mddev); struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, struct mddev *mddev) { - if (!mddev || !mddev->bio_set) - return bio_clone(bio, gfp_mask); - return bio_clone_bioset(bio, gfp_mask, mddev->bio_set); } EXPORT_SYMBOL_GPL(bio_clone_mddev); -- cgit v1.2.3 From d7a1030839d35c04a620e841f406b9b2a8600041 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 14 Feb 2017 23:29:03 +0800 Subject: md: fast clone bio in bio_clone_mddev() Firstly bio_clone_mddev() is used in raid normal I/O and isn't in resync I/O path. Secondly all the direct access to bvec table in raid happens on resync I/O except for write behind of raid1, in which we still use bio_clone() for allocating new bvec table. So this patch replaces bio_clone() with bio_clone_fast() in bio_clone_mddev(). Also kill bio_clone_mddev() and call bio_clone_fast() directly, as suggested by Christoph Hellwig. Reviewed-by: Christoph Hellwig Signed-off-by: Ming Lei Signed-off-by: Shaohua Li --- drivers/md/md.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/md/md.c') diff --git a/drivers/md/md.c b/drivers/md/md.c index 0e408bc67904..55e7e7a8714e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -190,13 +190,6 @@ struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, } EXPORT_SYMBOL_GPL(bio_alloc_mddev); -struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, - struct mddev *mddev) -{ - return bio_clone_bioset(bio, gfp_mask, mddev->bio_set); -} -EXPORT_SYMBOL_GPL(bio_clone_mddev); - /* * We have a system wide 'event count' that is incremented * on any 'interesting' event, and readers of /proc/mdstat -- cgit v1.2.3