summaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2018-09-25 20:56:02 -0400
committerMike Snitzer <snitzer@redhat.com>2018-10-04 15:20:52 -0400
commit5d07384a666d4b2f781dc056bfeec2c27fbdf383 (patch)
tree74d8d0932b0abc02137d00d989418f7711a745d7 /drivers/md
parent4561ffca88c546f96367f94b8f1e4715a9c62314 (diff)
downloadlinux-stable-5d07384a666d4b2f781dc056bfeec2c27fbdf383.tar.gz
linux-stable-5d07384a666d4b2f781dc056bfeec2c27fbdf383.tar.bz2
linux-stable-5d07384a666d4b2f781dc056bfeec2c27fbdf383.zip
dm cache: fix resize crash if user doesn't reload cache table
A reload of the cache's DM table is needed during resize because otherwise a crash will occur when attempting to access smq policy entries associated with the portion of the cache that was recently extended. The reason is cache-size based data structures in the policy will not be resized, the only way to safely extend the cache is to allow for a proper cache policy initialization that occurs when the cache table is loaded. For example the smq policy's space_init(), init_allocator(), calc_hotspot_params() must be sized based on the extended cache size. The fix for this is to disallow cache resizes of this pattern: 1) suspend "cache" target's device 2) resize the fast device used for the cache 3) resume "cache" target's device Instead, the last step must be a full reload of the cache's DM table. Fixes: 66a636356 ("dm cache: add stochastic-multi-queue (smq) policy") Cc: stable@vger.kernel.org Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-cache-target.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index a53413371725..e13d991e9fb5 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -3009,8 +3009,13 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache)
static bool can_resize(struct cache *cache, dm_cblock_t new_size)
{
- if (from_cblock(new_size) > from_cblock(cache->cache_size))
- return true;
+ if (from_cblock(new_size) > from_cblock(cache->cache_size)) {
+ if (cache->sized) {
+ DMERR("%s: unable to extend cache due to missing cache table reload",
+ cache_device_name(cache));
+ return false;
+ }
+ }
/*
* We can't drop a dirty block when shrinking the cache.