Commit 873937e7 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Mike Snitzer

dm thin: don't allow changing data device during thin-pool reload

The existing code allows changing the data device when the thin-pool
target is reloaded.

This capability is not required and only complicates device lifetime
guarantees. This can cause crashes like the one reported here:
	https://bugzilla.redhat.com/show_bug.cgi?id=1788596
where the kernel tries to issue a flush bio located in a structure that
was already freed.

Take the first step to simplifying the thin-pool's data device lifetime
by disallowing changing it. Like the thin-pool's metadata device, the
data device is now set in pool_create() and it cannot be changed for a
given thin-pool.
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent a4a8d286
...@@ -231,6 +231,7 @@ struct pool { ...@@ -231,6 +231,7 @@ struct pool {
struct dm_target *ti; /* Only set if a pool target is bound */ struct dm_target *ti; /* Only set if a pool target is bound */
struct mapped_device *pool_md; struct mapped_device *pool_md;
struct block_device *data_dev;
struct block_device *md_dev; struct block_device *md_dev;
struct dm_pool_metadata *pmd; struct dm_pool_metadata *pmd;
...@@ -2933,6 +2934,7 @@ static struct kmem_cache *_new_mapping_cache; ...@@ -2933,6 +2934,7 @@ static struct kmem_cache *_new_mapping_cache;
static struct pool *pool_create(struct mapped_device *pool_md, static struct pool *pool_create(struct mapped_device *pool_md,
struct block_device *metadata_dev, struct block_device *metadata_dev,
struct block_device *data_dev,
unsigned long block_size, unsigned long block_size,
int read_only, char **error) int read_only, char **error)
{ {
...@@ -3040,6 +3042,7 @@ static struct pool *pool_create(struct mapped_device *pool_md, ...@@ -3040,6 +3042,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
pool->last_commit_jiffies = jiffies; pool->last_commit_jiffies = jiffies;
pool->pool_md = pool_md; pool->pool_md = pool_md;
pool->md_dev = metadata_dev; pool->md_dev = metadata_dev;
pool->data_dev = data_dev;
__pool_table_insert(pool); __pool_table_insert(pool);
return pool; return pool;
...@@ -3081,6 +3084,7 @@ static void __pool_dec(struct pool *pool) ...@@ -3081,6 +3084,7 @@ static void __pool_dec(struct pool *pool)
static struct pool *__pool_find(struct mapped_device *pool_md, static struct pool *__pool_find(struct mapped_device *pool_md,
struct block_device *metadata_dev, struct block_device *metadata_dev,
struct block_device *data_dev,
unsigned long block_size, int read_only, unsigned long block_size, int read_only,
char **error, int *created) char **error, int *created)
{ {
...@@ -3091,19 +3095,23 @@ static struct pool *__pool_find(struct mapped_device *pool_md, ...@@ -3091,19 +3095,23 @@ static struct pool *__pool_find(struct mapped_device *pool_md,
*error = "metadata device already in use by a pool"; *error = "metadata device already in use by a pool";
return ERR_PTR(-EBUSY); return ERR_PTR(-EBUSY);
} }
if (pool->data_dev != data_dev) {
*error = "data device already in use by a pool";
return ERR_PTR(-EBUSY);
}
__pool_inc(pool); __pool_inc(pool);
} else { } else {
pool = __pool_table_lookup(pool_md); pool = __pool_table_lookup(pool_md);
if (pool) { if (pool) {
if (pool->md_dev != metadata_dev) { if (pool->md_dev != metadata_dev || pool->data_dev != data_dev) {
*error = "different pool cannot replace a pool"; *error = "different pool cannot replace a pool";
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
__pool_inc(pool); __pool_inc(pool);
} else { } else {
pool = pool_create(pool_md, metadata_dev, block_size, read_only, error); pool = pool_create(pool_md, metadata_dev, data_dev, block_size, read_only, error);
*created = 1; *created = 1;
} }
} }
...@@ -3356,7 +3364,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -3356,7 +3364,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto out; goto out;
} }
pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev, pool = __pool_find(dm_table_get_md(ti->table), metadata_dev->bdev, data_dev->bdev,
block_size, pf.mode == PM_READ_ONLY, &ti->error, &pool_created); block_size, pf.mode == PM_READ_ONLY, &ti->error, &pool_created);
if (IS_ERR(pool)) { if (IS_ERR(pool)) {
r = PTR_ERR(pool); r = PTR_ERR(pool);
...@@ -4098,7 +4106,7 @@ static struct target_type pool_target = { ...@@ -4098,7 +4106,7 @@ static struct target_type pool_target = {
.name = "thin-pool", .name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE, DM_TARGET_IMMUTABLE,
.version = {1, 21, 0}, .version = {1, 22, 0},
.module = THIS_MODULE, .module = THIS_MODULE,
.ctr = pool_ctr, .ctr = pool_ctr,
.dtr = pool_dtr, .dtr = pool_dtr,
...@@ -4475,7 +4483,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits) ...@@ -4475,7 +4483,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
static struct target_type thin_target = { static struct target_type thin_target = {
.name = "thin", .name = "thin",
.version = {1, 21, 0}, .version = {1, 22, 0},
.module = THIS_MODULE, .module = THIS_MODULE,
.ctr = thin_ctr, .ctr = thin_ctr,
.dtr = thin_dtr, .dtr = thin_dtr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment