aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r--drivers/md/dm-ioctl.c65
1 files changed, 45 insertions, 20 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index c826b3e1799a..c6ce13b18747 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -48,7 +48,7 @@ struct vers_iter {
48static struct list_head _name_buckets[NUM_BUCKETS]; 48static struct list_head _name_buckets[NUM_BUCKETS];
49static struct list_head _uuid_buckets[NUM_BUCKETS]; 49static struct list_head _uuid_buckets[NUM_BUCKETS];
50 50
51static void dm_hash_remove_all(void); 51static void dm_hash_remove_all(int keep_open_devices);
52 52
53/* 53/*
54 * Guards access to both hash tables. 54 * Guards access to both hash tables.
@@ -73,7 +73,7 @@ static int dm_hash_init(void)
73 73
74static void dm_hash_exit(void) 74static void dm_hash_exit(void)
75{ 75{
76 dm_hash_remove_all(); 76 dm_hash_remove_all(0);
77 devfs_remove(DM_DIR); 77 devfs_remove(DM_DIR);
78} 78}
79 79
@@ -260,19 +260,41 @@ static void __hash_remove(struct hash_cell *hc)
260 free_cell(hc); 260 free_cell(hc);
261} 261}
262 262
263static void dm_hash_remove_all(void) 263static void dm_hash_remove_all(int keep_open_devices)
264{ 264{
265 int i; 265 int i, dev_skipped, dev_removed;
266 struct hash_cell *hc; 266 struct hash_cell *hc;
267 struct list_head *tmp, *n; 267 struct list_head *tmp, *n;
268 268
269 down_write(&_hash_lock); 269 down_write(&_hash_lock);
270
271retry:
272 dev_skipped = dev_removed = 0;
270 for (i = 0; i < NUM_BUCKETS; i++) { 273 for (i = 0; i < NUM_BUCKETS; i++) {
271 list_for_each_safe (tmp, n, _name_buckets + i) { 274 list_for_each_safe (tmp, n, _name_buckets + i) {
272 hc = list_entry(tmp, struct hash_cell, name_list); 275 hc = list_entry(tmp, struct hash_cell, name_list);
276
277 if (keep_open_devices &&
278 dm_lock_for_deletion(hc->md)) {
279 dev_skipped++;
280 continue;
281 }
273 __hash_remove(hc); 282 __hash_remove(hc);
283 dev_removed = 1;
274 } 284 }
275 } 285 }
286
287 /*
288 * Some mapped devices may be using other mapped devices, so if any
289 * still exist, repeat until we make no further progress.
290 */
291 if (dev_skipped) {
292 if (dev_removed)
293 goto retry;
294
295 DMWARN("remove_all left %d open device(s)", dev_skipped);
296 }
297
276 up_write(&_hash_lock); 298 up_write(&_hash_lock);
277} 299}
278 300
@@ -355,7 +377,7 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
355 377
356static int remove_all(struct dm_ioctl *param, size_t param_size) 378static int remove_all(struct dm_ioctl *param, size_t param_size)
357{ 379{
358 dm_hash_remove_all(); 380 dm_hash_remove_all(1);
359 param->data_size = 0; 381 param->data_size = 0;
360 return 0; 382 return 0;
361} 383}
@@ -535,7 +557,6 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
535{ 557{
536 struct gendisk *disk = dm_disk(md); 558 struct gendisk *disk = dm_disk(md);
537 struct dm_table *table; 559 struct dm_table *table;
538 struct block_device *bdev;
539 560
540 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG | 561 param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
541 DM_ACTIVE_PRESENT_FLAG); 562 DM_ACTIVE_PRESENT_FLAG);
@@ -545,20 +566,12 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
545 566
546 param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor)); 567 param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
547 568
548 if (!(param->flags & DM_SKIP_BDGET_FLAG)) { 569 /*
549 bdev = bdget_disk(disk, 0); 570 * Yes, this will be out of date by the time it gets back
550 if (!bdev) 571 * to userland, but it is still very useful for
551 return -ENXIO; 572 * debugging.
552 573 */
553 /* 574 param->open_count = dm_open_count(md);
554 * Yes, this will be out of date by the time it gets back
555 * to userland, but it is still very useful for
556 * debugging.
557 */
558 param->open_count = bdev->bd_openers;
559 bdput(bdev);
560 } else
561 param->open_count = -1;
562 575
563 if (disk->policy) 576 if (disk->policy)
564 param->flags |= DM_READONLY_FLAG; 577 param->flags |= DM_READONLY_FLAG;
@@ -661,6 +674,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
661{ 674{
662 struct hash_cell *hc; 675 struct hash_cell *hc;
663 struct mapped_device *md; 676 struct mapped_device *md;
677 int r;
664 678
665 down_write(&_hash_lock); 679 down_write(&_hash_lock);
666 hc = __find_device_hash_cell(param); 680 hc = __find_device_hash_cell(param);
@@ -673,6 +687,17 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
673 687
674 md = hc->md; 688 md = hc->md;
675 689
690 /*
691 * Ensure the device is not open and nothing further can open it.
692 */
693 r = dm_lock_for_deletion(md);
694 if (r) {
695 DMWARN("unable to remove open device %s", hc->name);
696 up_write(&_hash_lock);
697 dm_put(md);
698 return r;
699 }
700
676 __hash_remove(hc); 701 __hash_remove(hc);
677 up_write(&_hash_lock); 702 up_write(&_hash_lock);
678 dm_put(md); 703 dm_put(md);