dm thin: don't allow changing data device during thin-pool reload
[ Upstream commit 873937e75f
]
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: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5.4-rM2-2.2.x-imx-squashed
parent
74f42a7731
commit
7f0d9ac262
|
@ -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;
|
||||||
|
|
||||||
|
@ -2945,6 +2946,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)
|
||||||
{
|
{
|
||||||
|
@ -3052,6 +3054,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;
|
||||||
|
@ -3093,6 +3096,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)
|
||||||
{
|
{
|
||||||
|
@ -3103,19 +3107,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3368,7 +3376,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);
|
||||||
|
@ -4114,7 +4122,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,
|
||||||
|
@ -4493,7 +4501,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,
|
||||||
|
|
Loading…
Reference in New Issue