diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-03-26 17:53:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-03-26 17:53:47 -0400 |
commit | be8a9bc63328a8472d1a09fb151a04141aae614e (patch) | |
tree | 66d0772418484691b8263f7cfca59cfaea0adad9 | |
parent | 0e536e2516296c93a45933f540de587b4597681a (diff) | |
parent | 63a4f065ece613b6d575b538234375b0e9c23bbc (diff) |
Merge tag 'dm-4.0-fix-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper fix from Mike Snitzer:
"Fix DM core device cleanup regression -- due to a latent race that was
exposed by the bdi changes that were introduced during the 4.0 merge"
* tag 'dm-4.0-fix-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm: fix add_disk() NULL pointer due to race with free_dev()
-rw-r--r-- | drivers/md/dm.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 9b641b38b857..8001fe9e3434 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -433,7 +433,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode) | |||
433 | 433 | ||
434 | dm_get(md); | 434 | dm_get(md); |
435 | atomic_inc(&md->open_count); | 435 | atomic_inc(&md->open_count); |
436 | |||
437 | out: | 436 | out: |
438 | spin_unlock(&_minor_lock); | 437 | spin_unlock(&_minor_lock); |
439 | 438 | ||
@@ -442,16 +441,20 @@ out: | |||
442 | 441 | ||
443 | static void dm_blk_close(struct gendisk *disk, fmode_t mode) | 442 | static void dm_blk_close(struct gendisk *disk, fmode_t mode) |
444 | { | 443 | { |
445 | struct mapped_device *md = disk->private_data; | 444 | struct mapped_device *md; |
446 | 445 | ||
447 | spin_lock(&_minor_lock); | 446 | spin_lock(&_minor_lock); |
448 | 447 | ||
448 | md = disk->private_data; | ||
449 | if (WARN_ON(!md)) | ||
450 | goto out; | ||
451 | |||
449 | if (atomic_dec_and_test(&md->open_count) && | 452 | if (atomic_dec_and_test(&md->open_count) && |
450 | (test_bit(DMF_DEFERRED_REMOVE, &md->flags))) | 453 | (test_bit(DMF_DEFERRED_REMOVE, &md->flags))) |
451 | queue_work(deferred_remove_workqueue, &deferred_remove_work); | 454 | queue_work(deferred_remove_workqueue, &deferred_remove_work); |
452 | 455 | ||
453 | dm_put(md); | 456 | dm_put(md); |
454 | 457 | out: | |
455 | spin_unlock(&_minor_lock); | 458 | spin_unlock(&_minor_lock); |
456 | } | 459 | } |
457 | 460 | ||
@@ -2241,7 +2244,6 @@ static void free_dev(struct mapped_device *md) | |||
2241 | int minor = MINOR(disk_devt(md->disk)); | 2244 | int minor = MINOR(disk_devt(md->disk)); |
2242 | 2245 | ||
2243 | unlock_fs(md); | 2246 | unlock_fs(md); |
2244 | bdput(md->bdev); | ||
2245 | destroy_workqueue(md->wq); | 2247 | destroy_workqueue(md->wq); |
2246 | 2248 | ||
2247 | if (md->kworker_task) | 2249 | if (md->kworker_task) |
@@ -2252,19 +2254,22 @@ static void free_dev(struct mapped_device *md) | |||
2252 | mempool_destroy(md->rq_pool); | 2254 | mempool_destroy(md->rq_pool); |
2253 | if (md->bs) | 2255 | if (md->bs) |
2254 | bioset_free(md->bs); | 2256 | bioset_free(md->bs); |
2255 | blk_integrity_unregister(md->disk); | 2257 | |
2256 | del_gendisk(md->disk); | ||
2257 | cleanup_srcu_struct(&md->io_barrier); | 2258 | cleanup_srcu_struct(&md->io_barrier); |
2258 | free_table_devices(&md->table_devices); | 2259 | free_table_devices(&md->table_devices); |
2259 | free_minor(minor); | 2260 | dm_stats_cleanup(&md->stats); |
2260 | 2261 | ||
2261 | spin_lock(&_minor_lock); | 2262 | spin_lock(&_minor_lock); |
2262 | md->disk->private_data = NULL; | 2263 | md->disk->private_data = NULL; |
2263 | spin_unlock(&_minor_lock); | 2264 | spin_unlock(&_minor_lock); |
2264 | 2265 | if (blk_get_integrity(md->disk)) | |
2266 | blk_integrity_unregister(md->disk); | ||
2267 | del_gendisk(md->disk); | ||
2265 | put_disk(md->disk); | 2268 | put_disk(md->disk); |
2266 | blk_cleanup_queue(md->queue); | 2269 | blk_cleanup_queue(md->queue); |
2267 | dm_stats_cleanup(&md->stats); | 2270 | bdput(md->bdev); |
2271 | free_minor(minor); | ||
2272 | |||
2268 | module_put(THIS_MODULE); | 2273 | module_put(THIS_MODULE); |
2269 | kfree(md); | 2274 | kfree(md); |
2270 | } | 2275 | } |
@@ -2642,8 +2647,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait) | |||
2642 | 2647 | ||
2643 | might_sleep(); | 2648 | might_sleep(); |
2644 | 2649 | ||
2645 | spin_lock(&_minor_lock); | ||
2646 | map = dm_get_live_table(md, &srcu_idx); | 2650 | map = dm_get_live_table(md, &srcu_idx); |
2651 | |||
2652 | spin_lock(&_minor_lock); | ||
2647 | idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md)))); | 2653 | idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md)))); |
2648 | set_bit(DMF_FREEING, &md->flags); | 2654 | set_bit(DMF_FREEING, &md->flags); |
2649 | spin_unlock(&_minor_lock); | 2655 | spin_unlock(&_minor_lock); |