diff options
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r-- | drivers/md/dm.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 952c49c3b9aa..6982f86db6dc 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -64,12 +64,14 @@ union map_info *dm_get_mapinfo(struct bio *bio) | |||
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 | #define DMF_FREEING 3 |
67 | #define DMF_DELETING 4 | ||
67 | 68 | ||
68 | struct mapped_device { | 69 | struct mapped_device { |
69 | struct rw_semaphore io_lock; | 70 | struct rw_semaphore io_lock; |
70 | struct semaphore suspend_lock; | 71 | struct semaphore suspend_lock; |
71 | rwlock_t map_lock; | 72 | rwlock_t map_lock; |
72 | atomic_t holders; | 73 | atomic_t holders; |
74 | atomic_t open_count; | ||
73 | 75 | ||
74 | unsigned long flags; | 76 | unsigned long flags; |
75 | 77 | ||
@@ -228,12 +230,14 @@ static int dm_blk_open(struct inode *inode, struct file *file) | |||
228 | if (!md) | 230 | if (!md) |
229 | goto out; | 231 | goto out; |
230 | 232 | ||
231 | if (test_bit(DMF_FREEING, &md->flags)) { | 233 | if (test_bit(DMF_FREEING, &md->flags) || |
234 | test_bit(DMF_DELETING, &md->flags)) { | ||
232 | md = NULL; | 235 | md = NULL; |
233 | goto out; | 236 | goto out; |
234 | } | 237 | } |
235 | 238 | ||
236 | dm_get(md); | 239 | dm_get(md); |
240 | atomic_inc(&md->open_count); | ||
237 | 241 | ||
238 | out: | 242 | out: |
239 | spin_unlock(&_minor_lock); | 243 | spin_unlock(&_minor_lock); |
@@ -246,10 +250,35 @@ static int dm_blk_close(struct inode *inode, struct file *file) | |||
246 | struct mapped_device *md; | 250 | struct mapped_device *md; |
247 | 251 | ||
248 | md = inode->i_bdev->bd_disk->private_data; | 252 | md = inode->i_bdev->bd_disk->private_data; |
253 | atomic_dec(&md->open_count); | ||
249 | dm_put(md); | 254 | dm_put(md); |
250 | return 0; | 255 | return 0; |
251 | } | 256 | } |
252 | 257 | ||
258 | int dm_open_count(struct mapped_device *md) | ||
259 | { | ||
260 | return atomic_read(&md->open_count); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Guarantees nothing is using the device before it's deleted. | ||
265 | */ | ||
266 | int dm_lock_for_deletion(struct mapped_device *md) | ||
267 | { | ||
268 | int r = 0; | ||
269 | |||
270 | spin_lock(&_minor_lock); | ||
271 | |||
272 | if (dm_open_count(md)) | ||
273 | r = -EBUSY; | ||
274 | else | ||
275 | set_bit(DMF_DELETING, &md->flags); | ||
276 | |||
277 | spin_unlock(&_minor_lock); | ||
278 | |||
279 | return r; | ||
280 | } | ||
281 | |||
253 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) | 282 | static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
254 | { | 283 | { |
255 | struct mapped_device *md = bdev->bd_disk->private_data; | 284 | struct mapped_device *md = bdev->bd_disk->private_data; |
@@ -867,6 +896,7 @@ static struct mapped_device *alloc_dev(int minor) | |||
867 | init_MUTEX(&md->suspend_lock); | 896 | init_MUTEX(&md->suspend_lock); |
868 | rwlock_init(&md->map_lock); | 897 | rwlock_init(&md->map_lock); |
869 | atomic_set(&md->holders, 1); | 898 | atomic_set(&md->holders, 1); |
899 | atomic_set(&md->open_count, 0); | ||
870 | atomic_set(&md->event_nr, 0); | 900 | atomic_set(&md->event_nr, 0); |
871 | 901 | ||
872 | md->queue = blk_alloc_queue(GFP_KERNEL); | 902 | md->queue = blk_alloc_queue(GFP_KERNEL); |