[dm-devel] [PATCH 1/2] dm-thin: don't allow changing the data device
Mikulas Patocka
mpatocka at redhat.com
Mon Jan 13 20:15:00 UTC 2020
The existing code allow changing the data device when the dm-thin-pool
target is reloaded.
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.
Locking the data device would be quite tricky, so a better solution is to
disallow changing it - it is set in pool_create and it can never be
changed for the given pool.
Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
Cc: stable at vger.kernel.org
Fixes: 694cfe7f31db ("dm thin: Flush data device before committing metadata")
---
drivers/md/dm-thin.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
Index: linux-2.6/drivers/md/dm-thin.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-thin.c 2020-01-13 16:13:42.000000000 +0100
+++ linux-2.6/drivers/md/dm-thin.c 2020-01-13 18:47:50.000000000 +0100
@@ -231,6 +231,7 @@ struct pool {
struct dm_target *ti; /* Only set if a pool target is bound */
struct mapped_device *pool_md;
+ struct block_device *data_dev;
struct block_device *md_dev;
struct dm_pool_metadata *pmd;
@@ -2933,6 +2934,7 @@ static struct kmem_cache *_new_mapping_c
static struct pool *pool_create(struct mapped_device *pool_md,
struct block_device *metadata_dev,
+ struct block_device *data_dev,
unsigned long block_size,
int read_only, char **error)
{
@@ -3040,6 +3042,7 @@ static struct pool *pool_create(struct m
pool->last_commit_jiffies = jiffies;
pool->pool_md = pool_md;
pool->md_dev = metadata_dev;
+ pool->data_dev = data_dev;
__pool_table_insert(pool);
return pool;
@@ -3081,6 +3084,7 @@ static void __pool_dec(struct pool *pool
static struct pool *__pool_find(struct mapped_device *pool_md,
struct block_device *metadata_dev,
+ struct block_device *data_dev,
unsigned long block_size, int read_only,
char **error, int *created)
{
@@ -3091,6 +3095,10 @@ static struct pool *__pool_find(struct m
*error = "metadata device already in use by a pool";
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);
} else {
@@ -3100,10 +3108,14 @@ static struct pool *__pool_find(struct m
*error = "different pool cannot replace a pool";
return ERR_PTR(-EINVAL);
}
+ if (pool->data_dev != data_dev) {
+ *error = "different pool cannot replace a pool";
+ return ERR_PTR(-EINVAL);
+ }
__pool_inc(pool);
} 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;
}
}
@@ -3356,7 +3368,7 @@ static int pool_ctr(struct dm_target *ti
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);
if (IS_ERR(pool)) {
r = PTR_ERR(pool);
More information about the dm-devel
mailing list