From: Mike Snitzer Date: Thu, 20 Mar 2014 14:11:15 +0000 (-0400) Subject: dm cache: prevent corruption caused by discard_block_size > cache_block_size X-Git-Url: https://git.fsl.cs.stonybrook.edu/?a=commitdiff_plain;h=ab1f4c35b7e0b189d5bec8b17669f92a4d7153bd;p=linux-dmdedup.git dm cache: prevent corruption caused by discard_block_size > cache_block_size If the discard block size is larger than the cache block size we will not properly quiesce IO to a region that is about to be discarded. This results in a race between a cache migration where no copy is needed, and a write to an adjacent cache block that's within the same large discard block. Workaround this by limiting the discard_block_size to cache_block_size. Also limit the max_discard_sectors to cache_block_size. A more comprehensive fix that introduces range locking support in the bio_prison and proper quiescing of a discard range that spans multiple cache blocks is already in development. Reported-by: Morgan Mears Signed-off-by: Mike Snitzer Acked-by: Joe Thornber Acked-by: Heinz Mauelshagen Cc: stable@vger.kernel.org --- diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 1af70145fab..4a608ea3771 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -2188,6 +2188,7 @@ static bool too_many_discard_blocks(sector_t discard_block_size, static sector_t calculate_discard_block_size(sector_t cache_block_size, sector_t origin_size) { +#if 0 sector_t discard_block_size; discard_block_size = roundup_pow_of_two(cache_block_size); @@ -2197,6 +2198,13 @@ static sector_t calculate_discard_block_size(sector_t cache_block_size, discard_block_size *= 2; return discard_block_size; +#else + /* + * FIXME: stop-gap workaround for corruption that is + * induced by discard_block_size > cache_block_size. + */ + return cache_block_size; +#endif } #define DEFAULT_MIGRATION_THRESHOLD 2048 @@ -3121,7 +3129,7 @@ static void set_discard_limits(struct cache *cache, struct queue_limits *limits) /* * FIXME: these limits may be incompatible with the cache device */ - limits->max_discard_sectors = cache->discard_block_size * 1024; + limits->max_discard_sectors = cache->discard_block_size; limits->discard_granularity = cache->discard_block_size << SECTOR_SHIFT; }