diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/dm.c | 32 |
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 | ||
67 | struct mapped_device { | 68 | struct 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 | |
238 | out: | ||
239 | spin_unlock(&_minor_lock); | ||
240 | |||
241 | return md ? 0 : -ENXIO; | ||
227 | } | 242 | } |
228 | 243 | ||
229 | static int dm_blk_close(struct inode *inode, struct file *file) | 244 | static 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 | ||
1053 | out: | ||
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); |