aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm.c
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2013-11-01 18:27:41 -0400
committerMike Snitzer <snitzer@redhat.com>2013-11-09 18:20:22 -0500
commit2c140a246dc0bc085b98eddde978060fcec1080c (patch)
tree73d747f4422fe202868495d08ea5d189bc16bd79 /drivers/md/dm.c
parent7833b08e18241a1c35c09ef38be840cbf6c58acf (diff)
dm: allow remove to be deferred
This patch allows the removal of an open device to be deferred until it is closed. (Previously such a removal attempt would fail.) The deferred remove functionality is enabled by setting the flag DM_DEFERRED_REMOVE in the ioctl structure on DM_DEV_REMOVE or DM_REMOVE_ALL ioctl. On return from DM_DEV_REMOVE, the flag DM_DEFERRED_REMOVE indicates if the device was removed immediately or flagged to be removed on close - if the flag is clear, the device was removed. On return from DM_DEV_STATUS and other ioctls, the flag DM_DEFERRED_REMOVE is set if the device is scheduled to be removed on closure. A device that is scheduled to be deleted can be revived using the message "@cancel_deferred_remove". This message clears the DMF_DEFERRED_REMOVE flag so that the device won't be deleted on close. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r--drivers/md/dm.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index b3e26c7d1417..0704c523a76b 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -49,6 +49,11 @@ static unsigned int _major = 0;
49static DEFINE_IDR(_minor_idr); 49static DEFINE_IDR(_minor_idr);
50 50
51static DEFINE_SPINLOCK(_minor_lock); 51static DEFINE_SPINLOCK(_minor_lock);
52
53static void do_deferred_remove(struct work_struct *w);
54
55static DECLARE_WORK(deferred_remove_work, do_deferred_remove);
56
52/* 57/*
53 * For bio-based dm. 58 * For bio-based dm.
54 * One of these is allocated per bio. 59 * One of these is allocated per bio.
@@ -116,6 +121,7 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
116#define DMF_DELETING 4 121#define DMF_DELETING 4
117#define DMF_NOFLUSH_SUSPENDING 5 122#define DMF_NOFLUSH_SUSPENDING 5
118#define DMF_MERGE_IS_OPTIONAL 6 123#define DMF_MERGE_IS_OPTIONAL 6
124#define DMF_DEFERRED_REMOVE 7
119 125
120/* 126/*
121 * A dummy definition to make RCU happy. 127 * A dummy definition to make RCU happy.
@@ -299,6 +305,8 @@ out_free_io_cache:
299 305
300static void local_exit(void) 306static void local_exit(void)
301{ 307{
308 flush_scheduled_work();
309
302 kmem_cache_destroy(_rq_tio_cache); 310 kmem_cache_destroy(_rq_tio_cache);
303 kmem_cache_destroy(_io_cache); 311 kmem_cache_destroy(_io_cache);
304 unregister_blkdev(_major, _name); 312 unregister_blkdev(_major, _name);
@@ -404,7 +412,10 @@ static void dm_blk_close(struct gendisk *disk, fmode_t mode)
404 412
405 spin_lock(&_minor_lock); 413 spin_lock(&_minor_lock);
406 414
407 atomic_dec(&md->open_count); 415 if (atomic_dec_and_test(&md->open_count) &&
416 (test_bit(DMF_DEFERRED_REMOVE, &md->flags)))
417 schedule_work(&deferred_remove_work);
418
408 dm_put(md); 419 dm_put(md);
409 420
410 spin_unlock(&_minor_lock); 421 spin_unlock(&_minor_lock);
@@ -418,14 +429,18 @@ int dm_open_count(struct mapped_device *md)
418/* 429/*
419 * Guarantees nothing is using the device before it's deleted. 430 * Guarantees nothing is using the device before it's deleted.
420 */ 431 */
421int dm_lock_for_deletion(struct mapped_device *md) 432int dm_lock_for_deletion(struct mapped_device *md, bool mark_deferred, bool only_deferred)
422{ 433{
423 int r = 0; 434 int r = 0;
424 435
425 spin_lock(&_minor_lock); 436 spin_lock(&_minor_lock);
426 437
427 if (dm_open_count(md)) 438 if (dm_open_count(md)) {
428 r = -EBUSY; 439 r = -EBUSY;
440 if (mark_deferred)
441 set_bit(DMF_DEFERRED_REMOVE, &md->flags);
442 } else if (only_deferred && !test_bit(DMF_DEFERRED_REMOVE, &md->flags))
443 r = -EEXIST;
429 else 444 else
430 set_bit(DMF_DELETING, &md->flags); 445 set_bit(DMF_DELETING, &md->flags);
431 446
@@ -434,6 +449,27 @@ int dm_lock_for_deletion(struct mapped_device *md)
434 return r; 449 return r;
435} 450}
436 451
452int dm_cancel_deferred_remove(struct mapped_device *md)
453{
454 int r = 0;
455
456 spin_lock(&_minor_lock);
457
458 if (test_bit(DMF_DELETING, &md->flags))
459 r = -EBUSY;
460 else
461 clear_bit(DMF_DEFERRED_REMOVE, &md->flags);
462
463 spin_unlock(&_minor_lock);
464
465 return r;
466}
467
468static void do_deferred_remove(struct work_struct *w)
469{
470 dm_deferred_remove();
471}
472
437sector_t dm_get_size(struct mapped_device *md) 473sector_t dm_get_size(struct mapped_device *md)
438{ 474{
439 return get_capacity(md->disk); 475 return get_capacity(md->disk);
@@ -2894,6 +2930,11 @@ int dm_suspended_md(struct mapped_device *md)
2894 return test_bit(DMF_SUSPENDED, &md->flags); 2930 return test_bit(DMF_SUSPENDED, &md->flags);
2895} 2931}
2896 2932
2933int dm_test_deferred_remove_flag(struct mapped_device *md)
2934{
2935 return test_bit(DMF_DEFERRED_REMOVE, &md->flags);
2936}
2937
2897int dm_suspended(struct dm_target *ti) 2938int dm_suspended(struct dm_target *ti)
2898{ 2939{
2899 return dm_suspended_md(dm_table_get_md(ti->table)); 2940 return dm_suspended_md(dm_table_get_md(ti->table));