diff options
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r-- | drivers/md/dm-ioctl.c | 65 |
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 { | |||
48 | static struct list_head _name_buckets[NUM_BUCKETS]; | 48 | static struct list_head _name_buckets[NUM_BUCKETS]; |
49 | static struct list_head _uuid_buckets[NUM_BUCKETS]; | 49 | static struct list_head _uuid_buckets[NUM_BUCKETS]; |
50 | 50 | ||
51 | static void dm_hash_remove_all(void); | 51 | static 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 | ||
74 | static void dm_hash_exit(void) | 74 | static 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 | ||
263 | static void dm_hash_remove_all(void) | 263 | static 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 | |||
271 | retry: | ||
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 | ||
356 | static int remove_all(struct dm_ioctl *param, size_t param_size) | 378 | static 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); |