Loading drivers/md/dm-cache-metadata.c +66 −0 Original line number Original line Diff line number Diff line Loading @@ -667,19 +667,85 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd) kfree(cmd); kfree(cmd); } } /* * Checks that the given cache block is either unmapped or clean. */ static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b, bool *result) { int r; __le64 value; dm_oblock_t ob; unsigned flags; r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value); if (r) { DMERR("block_unmapped_or_clean failed"); return r; } unpack_value(value, &ob, &flags); *result = !((flags & M_VALID) && (flags & M_DIRTY)); return 0; } static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t begin, dm_cblock_t end, bool *result) { int r; *result = true; while (begin != end) { r = block_unmapped_or_clean(cmd, begin, result); if (r) return r; if (!*result) { DMERR("cache block %llu is dirty", (unsigned long long) from_cblock(begin)); return 0; } begin = to_cblock(from_cblock(begin) + 1); } return 0; } int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) { { int r; int r; bool clean; __le64 null_mapping = pack_value(0, 0); __le64 null_mapping = pack_value(0, 0); down_write(&cmd->root_lock); down_write(&cmd->root_lock); __dm_bless_for_disk(&null_mapping); __dm_bless_for_disk(&null_mapping); if (from_cblock(new_cache_size) < from_cblock(cmd->cache_blocks)) { r = blocks_are_unmapped_or_clean(cmd, new_cache_size, cmd->cache_blocks, &clean); if (r) { __dm_unbless_for_disk(&null_mapping); goto out; } if (!clean) { DMERR("unable to shrink cache due to dirty blocks"); r = -EINVAL; __dm_unbless_for_disk(&null_mapping); goto out; } } r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), from_cblock(new_cache_size), from_cblock(new_cache_size), &null_mapping, &cmd->root); &null_mapping, &cmd->root); if (!r) if (!r) cmd->cache_blocks = new_cache_size; cmd->cache_blocks = new_cache_size; cmd->changed = true; cmd->changed = true; out: up_write(&cmd->root_lock); up_write(&cmd->root_lock); return r; return r; Loading drivers/md/dm-cache-target.c +54 −9 Original line number Original line Diff line number Diff line Loading @@ -2502,18 +2502,36 @@ static int load_discard(void *context, sector_t discard_block_size, return 0; return 0; } } static int cache_preresume(struct dm_target *ti) static dm_cblock_t get_cache_dev_size(struct cache *cache) { { int r = 0; sector_t size = get_dev_size(cache->cache_dev); struct cache *cache = ti->private; (void) sector_div(size, cache->sectors_per_block); sector_t actual_cache_size = get_dev_size(cache->cache_dev); return to_cblock(size); (void) sector_div(actual_cache_size, cache->sectors_per_block); } static bool can_resize(struct cache *cache, dm_cblock_t new_size) { if (from_cblock(new_size) > from_cblock(cache->cache_size)) return true; /* /* * Check to see if the cache has resized. * We can't drop a dirty block when shrinking the cache. */ */ if (from_cblock(cache->cache_size) != actual_cache_size || !cache->sized) { while (from_cblock(new_size) < from_cblock(cache->cache_size)) { cache->cache_size = to_cblock(actual_cache_size); new_size = to_cblock(from_cblock(new_size) + 1); if (is_dirty(cache, new_size)) { DMERR("unable to shrink cache; cache block %llu is dirty", (unsigned long long) from_cblock(new_size)); return false; } } return true; } static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) { int r; r = dm_cache_resize(cache->cmd, cache->cache_size); r = dm_cache_resize(cache->cmd, cache->cache_size); if (r) { if (r) { Loading @@ -2521,7 +2539,34 @@ static int cache_preresume(struct dm_target *ti) return r; return r; } } cache->cache_size = new_size; return 0; } static int cache_preresume(struct dm_target *ti) { int r = 0; struct cache *cache = ti->private; dm_cblock_t csize = get_cache_dev_size(cache); /* * Check to see if the cache has resized. */ if (!cache->sized) { r = resize_cache_dev(cache, csize); if (r) return r; cache->sized = true; cache->sized = true; } else if (csize != cache->cache_size) { if (!can_resize(cache, csize)) return -EINVAL; r = resize_cache_dev(cache, csize); if (r) return r; } } if (!cache->loaded_mappings) { if (!cache->loaded_mappings) { Loading Loading
drivers/md/dm-cache-metadata.c +66 −0 Original line number Original line Diff line number Diff line Loading @@ -667,19 +667,85 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd) kfree(cmd); kfree(cmd); } } /* * Checks that the given cache block is either unmapped or clean. */ static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b, bool *result) { int r; __le64 value; dm_oblock_t ob; unsigned flags; r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value); if (r) { DMERR("block_unmapped_or_clean failed"); return r; } unpack_value(value, &ob, &flags); *result = !((flags & M_VALID) && (flags & M_DIRTY)); return 0; } static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t begin, dm_cblock_t end, bool *result) { int r; *result = true; while (begin != end) { r = block_unmapped_or_clean(cmd, begin, result); if (r) return r; if (!*result) { DMERR("cache block %llu is dirty", (unsigned long long) from_cblock(begin)); return 0; } begin = to_cblock(from_cblock(begin) + 1); } return 0; } int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) { { int r; int r; bool clean; __le64 null_mapping = pack_value(0, 0); __le64 null_mapping = pack_value(0, 0); down_write(&cmd->root_lock); down_write(&cmd->root_lock); __dm_bless_for_disk(&null_mapping); __dm_bless_for_disk(&null_mapping); if (from_cblock(new_cache_size) < from_cblock(cmd->cache_blocks)) { r = blocks_are_unmapped_or_clean(cmd, new_cache_size, cmd->cache_blocks, &clean); if (r) { __dm_unbless_for_disk(&null_mapping); goto out; } if (!clean) { DMERR("unable to shrink cache due to dirty blocks"); r = -EINVAL; __dm_unbless_for_disk(&null_mapping); goto out; } } r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), from_cblock(new_cache_size), from_cblock(new_cache_size), &null_mapping, &cmd->root); &null_mapping, &cmd->root); if (!r) if (!r) cmd->cache_blocks = new_cache_size; cmd->cache_blocks = new_cache_size; cmd->changed = true; cmd->changed = true; out: up_write(&cmd->root_lock); up_write(&cmd->root_lock); return r; return r; Loading
drivers/md/dm-cache-target.c +54 −9 Original line number Original line Diff line number Diff line Loading @@ -2502,18 +2502,36 @@ static int load_discard(void *context, sector_t discard_block_size, return 0; return 0; } } static int cache_preresume(struct dm_target *ti) static dm_cblock_t get_cache_dev_size(struct cache *cache) { { int r = 0; sector_t size = get_dev_size(cache->cache_dev); struct cache *cache = ti->private; (void) sector_div(size, cache->sectors_per_block); sector_t actual_cache_size = get_dev_size(cache->cache_dev); return to_cblock(size); (void) sector_div(actual_cache_size, cache->sectors_per_block); } static bool can_resize(struct cache *cache, dm_cblock_t new_size) { if (from_cblock(new_size) > from_cblock(cache->cache_size)) return true; /* /* * Check to see if the cache has resized. * We can't drop a dirty block when shrinking the cache. */ */ if (from_cblock(cache->cache_size) != actual_cache_size || !cache->sized) { while (from_cblock(new_size) < from_cblock(cache->cache_size)) { cache->cache_size = to_cblock(actual_cache_size); new_size = to_cblock(from_cblock(new_size) + 1); if (is_dirty(cache, new_size)) { DMERR("unable to shrink cache; cache block %llu is dirty", (unsigned long long) from_cblock(new_size)); return false; } } return true; } static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size) { int r; r = dm_cache_resize(cache->cmd, cache->cache_size); r = dm_cache_resize(cache->cmd, cache->cache_size); if (r) { if (r) { Loading @@ -2521,7 +2539,34 @@ static int cache_preresume(struct dm_target *ti) return r; return r; } } cache->cache_size = new_size; return 0; } static int cache_preresume(struct dm_target *ti) { int r = 0; struct cache *cache = ti->private; dm_cblock_t csize = get_cache_dev_size(cache); /* * Check to see if the cache has resized. */ if (!cache->sized) { r = resize_cache_dev(cache, csize); if (r) return r; cache->sized = true; cache->sized = true; } else if (csize != cache->cache_size) { if (!can_resize(cache, csize)) return -EINVAL; r = resize_cache_dev(cache, csize); if (r) return r; } } if (!cache->loaded_mappings) { if (!cache->loaded_mappings) { Loading