aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 6e65d85d0829..a5cc4c8462f3 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -63,6 +63,7 @@ union map_info *dm_get_mapinfo(struct bio *bio)
63#define DMF_BLOCK_IO 0 63#define DMF_BLOCK_IO 0
64#define DMF_SUSPENDED 1 64#define DMF_SUSPENDED 1
65#define DMF_FROZEN 2 65#define DMF_FROZEN 2
66#define DMF_FREEING 3
66 67
67struct mapped_device { 68struct mapped_device {
68 struct rw_semaphore io_lock; 69 struct rw_semaphore io_lock;
@@ -221,9 +222,23 @@ static int dm_blk_open(struct inode *inode, struct file *file)
221{ 222{
222 struct mapped_device *md; 223 struct mapped_device *md;
223 224
225 spin_lock(&_minor_lock);
226
224 md = inode->i_bdev->bd_disk->private_data; 227 md = inode->i_bdev->bd_disk->private_data;
228 if (!md)
229 goto out;
230
231 if (test_bit(DMF_FREEING, &md->flags)) {
232 md = NULL;
233 goto out;
234 }
235
225 dm_get(md); 236 dm_get(md);
226 return 0; 237
238out:
239 spin_unlock(&_minor_lock);
240
241 return md ? 0 : -ENXIO;
227} 242}
228 243
229static int dm_blk_close(struct inode *inode, struct file *file) 244static int dm_blk_close(struct inode *inode, struct file *file)
@@ -919,6 +934,11 @@ static void free_dev(struct mapped_device *md)
919 mempool_destroy(md->io_pool); 934 mempool_destroy(md->io_pool);
920 del_gendisk(md->disk); 935 del_gendisk(md->disk);
921 free_minor(minor); 936 free_minor(minor);
937
938 spin_lock(&_minor_lock);
939 md->disk->private_data = NULL;
940 spin_unlock(&_minor_lock);
941
922 put_disk(md->disk); 942 put_disk(md->disk);
923 blk_cleanup_queue(md->queue); 943 blk_cleanup_queue(md->queue);
924 kfree(md); 944 kfree(md);
@@ -1023,9 +1043,14 @@ static struct mapped_device *dm_find_md(dev_t dev)
1023 spin_lock(&_minor_lock); 1043 spin_lock(&_minor_lock);
1024 1044
1025 md = idr_find(&_minor_idr, minor); 1045 md = idr_find(&_minor_idr, minor);
1026 if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor))) 1046 if (md && (md == MINOR_ALLOCED ||
1047 (dm_disk(md)->first_minor != minor) ||
1048 test_bit(DMF_FREEING, &md->flags))) {
1027 md = NULL; 1049 md = NULL;
1050 goto out;
1051 }
1028 1052
1053out:
1029 spin_unlock(&_minor_lock); 1054 spin_unlock(&_minor_lock);
1030 1055
1031 return md; 1056 return md;
@@ -1060,9 +1085,12 @@ void dm_put(struct mapped_device *md)
1060{ 1085{
1061 struct dm_table *map; 1086 struct dm_table *map;
1062 1087
1088 BUG_ON(test_bit(DMF_FREEING, &md->flags));
1089
1063 if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { 1090 if (atomic_dec_and_lock(&md->holders, &_minor_lock)) {
1064 map = dm_get_table(md); 1091 map = dm_get_table(md);
1065 idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); 1092 idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor);
1093 set_bit(DMF_FREEING, &md->flags);
1066 spin_unlock(&_minor_lock); 1094 spin_unlock(&_minor_lock);
1067 if (!dm_suspended(md)) { 1095 if (!dm_suspended(md)) {
1068 dm_table_presuspend_targets(map); 1096 dm_table_presuspend_targets(map);