| From 3aea6722a91a0fb5da8960013548ed979ed20a5d Mon Sep 17 00:00:00 2001 |
| From: Mikulas Patocka <mpatocka@redhat.com> |
| Date: Mon, 13 Jan 2020 15:04:37 -0500 |
| Subject: [PATCH] dm thin: don't allow changing data device during thin-pool |
| reload |
| |
| commit 873937e75f9a8ea231a502c3d29d9cb6ad91b3ef upstream. |
| |
| 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c |
| index 69201bdf7f4c..1b2c98b43519 100644 |
| --- a/drivers/md/dm-thin.c |
| +++ b/drivers/md/dm-thin.c |
| @@ -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; |
| |
| @@ -2945,6 +2946,7 @@ static struct kmem_cache *_new_mapping_cache; |
| |
| 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) |
| { |
| @@ -3052,6 +3054,7 @@ static struct pool *pool_create(struct mapped_device *pool_md, |
| 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; |
| @@ -3093,6 +3096,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) |
| { |
| @@ -3103,19 +3107,23 @@ static struct pool *__pool_find(struct mapped_device *pool_md, |
| *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 { |
| pool = __pool_table_lookup(pool_md); |
| 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"; |
| 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; |
| } |
| } |
| @@ -3368,7 +3376,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) |
| 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); |
| @@ -4114,7 +4122,7 @@ static struct target_type pool_target = { |
| .name = "thin-pool", |
| .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | |
| DM_TARGET_IMMUTABLE, |
| - .version = {1, 21, 0}, |
| + .version = {1, 22, 0}, |
| .module = THIS_MODULE, |
| .ctr = pool_ctr, |
| .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 = { |
| .name = "thin", |
| - .version = {1, 21, 0}, |
| + .version = {1, 22, 0}, |
| .module = THIS_MODULE, |
| .ctr = thin_ctr, |
| .dtr = thin_dtr, |
| -- |
| 2.7.4 |
| |