Skip to content

Commit 80e96c5

Browse files
committed
dm thin: do not allow thin device activation while pool is suspended
Otherwise IO could be issued to the pool while it is suspended. Care was taken to properly interlock between the thin and thin-pool targets when accessing the pool's 'suspended' flag. The thin_ctr will not add a new thin device to the pool's active_thins list if the pool is susepended. Signed-off-by: Mike Snitzer <[email protected]> Acked-by: Joe Thornber <[email protected]>
1 parent d67ee21 commit 80e96c5

File tree

1 file changed

+45
-10
lines changed

1 file changed

+45
-10
lines changed

drivers/md/dm-thin.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ struct pool {
224224

225225
struct pool_features pf;
226226
bool low_water_triggered:1; /* A dm event has been sent */
227+
bool suspended:1;
227228

228229
struct dm_bio_prison *prison;
229230
struct dm_kcopyd_client *copier;
@@ -2575,6 +2576,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
25752576
INIT_LIST_HEAD(&pool->prepared_discards);
25762577
INIT_LIST_HEAD(&pool->active_thins);
25772578
pool->low_water_triggered = false;
2579+
pool->suspended = true;
25782580

25792581
pool->shared_read_ds = dm_deferred_set_create();
25802582
if (!pool->shared_read_ds) {
@@ -3119,12 +3121,36 @@ static void pool_resume(struct dm_target *ti)
31193121

31203122
spin_lock_irqsave(&pool->lock, flags);
31213123
pool->low_water_triggered = false;
3124+
pool->suspended = false;
31223125
spin_unlock_irqrestore(&pool->lock, flags);
3126+
31233127
requeue_bios(pool);
31243128

31253129
do_waker(&pool->waker.work);
31263130
}
31273131

3132+
static void pool_presuspend(struct dm_target *ti)
3133+
{
3134+
struct pool_c *pt = ti->private;
3135+
struct pool *pool = pt->pool;
3136+
unsigned long flags;
3137+
3138+
spin_lock_irqsave(&pool->lock, flags);
3139+
pool->suspended = true;
3140+
spin_unlock_irqrestore(&pool->lock, flags);
3141+
}
3142+
3143+
static void pool_presuspend_undo(struct dm_target *ti)
3144+
{
3145+
struct pool_c *pt = ti->private;
3146+
struct pool *pool = pt->pool;
3147+
unsigned long flags;
3148+
3149+
spin_lock_irqsave(&pool->lock, flags);
3150+
pool->suspended = false;
3151+
spin_unlock_irqrestore(&pool->lock, flags);
3152+
}
3153+
31283154
static void pool_postsuspend(struct dm_target *ti)
31293155
{
31303156
struct pool_c *pt = ti->private;
@@ -3592,6 +3618,8 @@ static struct target_type pool_target = {
35923618
.ctr = pool_ctr,
35933619
.dtr = pool_dtr,
35943620
.map = pool_map,
3621+
.presuspend = pool_presuspend,
3622+
.presuspend_undo = pool_presuspend_undo,
35953623
.postsuspend = pool_postsuspend,
35963624
.preresume = pool_preresume,
35973625
.resume = pool_resume,
@@ -3721,18 +3749,18 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
37213749
if (get_pool_mode(tc->pool) == PM_FAIL) {
37223750
ti->error = "Couldn't open thin device, Pool is in fail mode";
37233751
r = -EINVAL;
3724-
goto bad_thin_open;
3752+
goto bad_pool;
37253753
}
37263754

37273755
r = dm_pool_open_thin_device(tc->pool->pmd, tc->dev_id, &tc->td);
37283756
if (r) {
37293757
ti->error = "Couldn't open thin internal device";
3730-
goto bad_thin_open;
3758+
goto bad_pool;
37313759
}
37323760

37333761
r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
37343762
if (r)
3735-
goto bad_target_max_io_len;
3763+
goto bad;
37363764

37373765
ti->num_flush_bios = 1;
37383766
ti->flush_supported = true;
@@ -3747,14 +3775,16 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
37473775
ti->split_discard_bios = true;
37483776
}
37493777

3750-
dm_put(pool_md);
3751-
37523778
mutex_unlock(&dm_thin_pool_table.mutex);
37533779

3754-
atomic_set(&tc->refcount, 1);
3755-
init_completion(&tc->can_destroy);
3756-
37573780
spin_lock_irqsave(&tc->pool->lock, flags);
3781+
if (tc->pool->suspended) {
3782+
spin_unlock_irqrestore(&tc->pool->lock, flags);
3783+
mutex_lock(&dm_thin_pool_table.mutex); /* reacquire for __pool_dec */
3784+
ti->error = "Unable to activate thin device while pool is suspended";
3785+
r = -EINVAL;
3786+
goto bad;
3787+
}
37583788
list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
37593789
spin_unlock_irqrestore(&tc->pool->lock, flags);
37603790
/*
@@ -3765,11 +3795,16 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
37653795
*/
37663796
synchronize_rcu();
37673797

3798+
dm_put(pool_md);
3799+
3800+
atomic_set(&tc->refcount, 1);
3801+
init_completion(&tc->can_destroy);
3802+
37683803
return 0;
37693804

3770-
bad_target_max_io_len:
3805+
bad:
37713806
dm_pool_close_thin_device(tc->td);
3772-
bad_thin_open:
3807+
bad_pool:
37733808
__pool_dec(tc->pool);
37743809
bad_pool_lookup:
37753810
dm_put(pool_md);

0 commit comments

Comments
 (0)