Skip to content

Commit

Permalink
dm thin: do not allow thin device activation while pool is suspended
Browse files Browse the repository at this point in the history
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 <snitzer@redhat.com>
Acked-by: Joe Thornber <ejt@redhat.com>
  • Loading branch information
snitm committed Nov 19, 2014
1 parent d67ee21 commit 80e96c5
Showing 1 changed file with 45 additions and 10 deletions.
55 changes: 45 additions & 10 deletions drivers/md/dm-thin.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ struct pool {

struct pool_features pf;
bool low_water_triggered:1; /* A dm event has been sent */
bool suspended:1;

struct dm_bio_prison *prison;
struct dm_kcopyd_client *copier;
Expand Down Expand Up @@ -2575,6 +2576,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
INIT_LIST_HEAD(&pool->prepared_discards);
INIT_LIST_HEAD(&pool->active_thins);
pool->low_water_triggered = false;
pool->suspended = true;

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

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);
}

static void pool_presuspend(struct dm_target *ti)
{
struct pool_c *pt = ti->private;
struct pool *pool = pt->pool;
unsigned long flags;

spin_lock_irqsave(&pool->lock, flags);
pool->suspended = true;
spin_unlock_irqrestore(&pool->lock, flags);
}

static void pool_presuspend_undo(struct dm_target *ti)
{
struct pool_c *pt = ti->private;
struct pool *pool = pt->pool;
unsigned long flags;

spin_lock_irqsave(&pool->lock, flags);
pool->suspended = false;
spin_unlock_irqrestore(&pool->lock, flags);
}

static void pool_postsuspend(struct dm_target *ti)
{
struct pool_c *pt = ti->private;
Expand Down Expand Up @@ -3592,6 +3618,8 @@ static struct target_type pool_target = {
.ctr = pool_ctr,
.dtr = pool_dtr,
.map = pool_map,
.presuspend = pool_presuspend,
.presuspend_undo = pool_presuspend_undo,
.postsuspend = pool_postsuspend,
.preresume = pool_preresume,
.resume = pool_resume,
Expand Down Expand Up @@ -3721,18 +3749,18 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (get_pool_mode(tc->pool) == PM_FAIL) {
ti->error = "Couldn't open thin device, Pool is in fail mode";
r = -EINVAL;
goto bad_thin_open;
goto bad_pool;
}

r = dm_pool_open_thin_device(tc->pool->pmd, tc->dev_id, &tc->td);
if (r) {
ti->error = "Couldn't open thin internal device";
goto bad_thin_open;
goto bad_pool;
}

r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
if (r)
goto bad_target_max_io_len;
goto bad;

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

dm_put(pool_md);

mutex_unlock(&dm_thin_pool_table.mutex);

atomic_set(&tc->refcount, 1);
init_completion(&tc->can_destroy);

spin_lock_irqsave(&tc->pool->lock, flags);
if (tc->pool->suspended) {
spin_unlock_irqrestore(&tc->pool->lock, flags);
mutex_lock(&dm_thin_pool_table.mutex); /* reacquire for __pool_dec */
ti->error = "Unable to activate thin device while pool is suspended";
r = -EINVAL;
goto bad;
}
list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
spin_unlock_irqrestore(&tc->pool->lock, flags);
/*
Expand All @@ -3765,11 +3795,16 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
*/
synchronize_rcu();

dm_put(pool_md);

atomic_set(&tc->refcount, 1);
init_completion(&tc->can_destroy);

return 0;

bad_target_max_io_len:
bad:
dm_pool_close_thin_device(tc->td);
bad_thin_open:
bad_pool:
__pool_dec(tc->pool);
bad_pool_lookup:
dm_put(pool_md);
Expand Down

0 comments on commit 80e96c5

Please sign in to comment.