diff options
author | Mike Snitzer <snitzer@redhat.com> | 2014-10-28 20:58:45 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2014-11-19 12:34:08 -0500 |
commit | 583024d248f486e21479d1912aa2093565455770 (patch) | |
tree | 1bd3b82b4a6db8fff1fb6fa4aa58e5a6596263a0 | |
parent | ffcc39364160663cda1a3c358f4537302a92459b (diff) | |
download | linux-583024d248f486e21479d1912aa2093565455770.tar.bz2 |
dm thin: suspend/resume active thin devices when reloading thin-pool
Before this change it was expected that userspace would first suspend
all active thin devices, reload/resize the thin-pool target, then resume
all active thin devices. Now the thin-pool suspend/resume will trigger
the suspend/resume of all active thins via appropriate calls to
dm_internal_suspend and dm_internal_resume.
Store the mapped_device for each thin device in struct thin_c to make
these calls possible.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Acked-by: Joe Thornber <ejt@redhat.com>
-rw-r--r-- | drivers/md/dm-thin.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index f1b53e31d868..e9e9584fe769 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -292,6 +292,8 @@ struct thin_c { struct pool *pool; struct dm_thin_device *td; + struct mapped_device *thin_md; + bool requeue_mode:1; spinlock_t lock; struct list_head deferred_cells; @@ -3113,19 +3115,48 @@ static int pool_preresume(struct dm_target *ti) return 0; } +static void pool_suspend_active_thins(struct pool *pool) +{ + struct thin_c *tc; + + /* Suspend all active thin devices */ + tc = get_first_thin(pool); + while (tc) { + dm_internal_suspend_noflush(tc->thin_md); + tc = get_next_thin(pool, tc); + } +} + +static void pool_resume_active_thins(struct pool *pool) +{ + struct thin_c *tc; + + /* Resume all active thin devices */ + tc = get_first_thin(pool); + while (tc) { + dm_internal_resume(tc->thin_md); + tc = get_next_thin(pool, tc); + } +} + static void pool_resume(struct dm_target *ti) { struct pool_c *pt = ti->private; struct pool *pool = pt->pool; unsigned long flags; + /* + * Must requeue active_thins' bios and then resume + * active_thins _before_ clearing 'suspend' flag. + */ + requeue_bios(pool); + pool_resume_active_thins(pool); + spin_lock_irqsave(&pool->lock, flags); pool->low_water_triggered = false; pool->suspended = false; spin_unlock_irqrestore(&pool->lock, flags); - requeue_bios(pool); - do_waker(&pool->waker.work); } @@ -3138,6 +3169,8 @@ static void pool_presuspend(struct dm_target *ti) spin_lock_irqsave(&pool->lock, flags); pool->suspended = true; spin_unlock_irqrestore(&pool->lock, flags); + + pool_suspend_active_thins(pool); } static void pool_presuspend_undo(struct dm_target *ti) @@ -3146,6 +3179,8 @@ static void pool_presuspend_undo(struct dm_target *ti) struct pool *pool = pt->pool; unsigned long flags; + pool_resume_active_thins(pool); + spin_lock_irqsave(&pool->lock, flags); pool->suspended = false; spin_unlock_irqrestore(&pool->lock, flags); @@ -3703,6 +3738,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) r = -ENOMEM; goto out_unlock; } + tc->thin_md = dm_table_get_md(ti->table); spin_lock_init(&tc->lock); INIT_LIST_HEAD(&tc->deferred_cells); bio_list_init(&tc->deferred_bio_list); |