Skip to content

Commit be8a9bc

Browse files
committed
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()
2 parents 0e536e2 + 63a4f06 commit be8a9bc

File tree

1 file changed

+16
-10
lines changed

1 file changed

+16
-10
lines changed

drivers/md/dm.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
433433

434434
dm_get(md);
435435
atomic_inc(&md->open_count);
436-
437436
out:
438437
spin_unlock(&_minor_lock);
439438

@@ -442,16 +441,20 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
442441

443442
static void dm_blk_close(struct gendisk *disk, fmode_t mode)
444443
{
445-
struct mapped_device *md = disk->private_data;
444+
struct mapped_device *md;
446445

447446
spin_lock(&_minor_lock);
448447

448+
md = disk->private_data;
449+
if (WARN_ON(!md))
450+
goto out;
451+
449452
if (atomic_dec_and_test(&md->open_count) &&
450453
(test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
451454
queue_work(deferred_remove_workqueue, &deferred_remove_work);
452455

453456
dm_put(md);
454-
457+
out:
455458
spin_unlock(&_minor_lock);
456459
}
457460

@@ -2241,7 +2244,6 @@ static void free_dev(struct mapped_device *md)
22412244
int minor = MINOR(disk_devt(md->disk));
22422245

22432246
unlock_fs(md);
2244-
bdput(md->bdev);
22452247
destroy_workqueue(md->wq);
22462248

22472249
if (md->kworker_task)
@@ -2252,19 +2254,22 @@ static void free_dev(struct mapped_device *md)
22522254
mempool_destroy(md->rq_pool);
22532255
if (md->bs)
22542256
bioset_free(md->bs);
2255-
blk_integrity_unregister(md->disk);
2256-
del_gendisk(md->disk);
2257+
22572258
cleanup_srcu_struct(&md->io_barrier);
22582259
free_table_devices(&md->table_devices);
2259-
free_minor(minor);
2260+
dm_stats_cleanup(&md->stats);
22602261

22612262
spin_lock(&_minor_lock);
22622263
md->disk->private_data = NULL;
22632264
spin_unlock(&_minor_lock);
2264-
2265+
if (blk_get_integrity(md->disk))
2266+
blk_integrity_unregister(md->disk);
2267+
del_gendisk(md->disk);
22652268
put_disk(md->disk);
22662269
blk_cleanup_queue(md->queue);
2267-
dm_stats_cleanup(&md->stats);
2270+
bdput(md->bdev);
2271+
free_minor(minor);
2272+
22682273
module_put(THIS_MODULE);
22692274
kfree(md);
22702275
}
@@ -2642,8 +2647,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
26422647

26432648
might_sleep();
26442649

2645-
spin_lock(&_minor_lock);
26462650
map = dm_get_live_table(md, &srcu_idx);
2651+
2652+
spin_lock(&_minor_lock);
26472653
idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
26482654
set_bit(DMF_FREEING, &md->flags);
26492655
spin_unlock(&_minor_lock);

0 commit comments

Comments
 (0)