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@xxxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx 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); -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel