162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file is released under the GPL. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "dm-cache-metadata.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "persistent-data/dm-array.h" 1162306a36Sopenharmony_ci#include "persistent-data/dm-bitset.h" 1262306a36Sopenharmony_ci#include "persistent-data/dm-space-map.h" 1362306a36Sopenharmony_ci#include "persistent-data/dm-space-map-disk.h" 1462306a36Sopenharmony_ci#include "persistent-data/dm-transaction-manager.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/device-mapper.h> 1762306a36Sopenharmony_ci#include <linux/refcount.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define DM_MSG_PREFIX "cache metadata" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define CACHE_SUPERBLOCK_MAGIC 06142003 2462306a36Sopenharmony_ci#define CACHE_SUPERBLOCK_LOCATION 0 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * defines a range of metadata versions that this module can handle. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci#define MIN_CACHE_VERSION 1 3062306a36Sopenharmony_ci#define MAX_CACHE_VERSION 2 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * 3 for btree insert + 3462306a36Sopenharmony_ci * 2 for btree lookup used within space map 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci#define CACHE_MAX_CONCURRENT_LOCKS 5 3762306a36Sopenharmony_ci#define SPACE_MAP_ROOT_SIZE 128 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cienum superblock_flag_bits { 4062306a36Sopenharmony_ci /* for spotting crashes that would invalidate the dirty bitset */ 4162306a36Sopenharmony_ci CLEAN_SHUTDOWN, 4262306a36Sopenharmony_ci /* metadata must be checked using the tools */ 4362306a36Sopenharmony_ci NEEDS_CHECK, 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * Each mapping from cache block -> origin block carries a set of flags. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cienum mapping_bits { 5062306a36Sopenharmony_ci /* 5162306a36Sopenharmony_ci * A valid mapping. Because we're using an array we clear this 5262306a36Sopenharmony_ci * flag for an non existant mapping. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci M_VALID = 1, 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* 5762306a36Sopenharmony_ci * The data on the cache is different from that on the origin. 5862306a36Sopenharmony_ci * This flag is only used by metadata format 1. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci M_DIRTY = 2 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct cache_disk_superblock { 6462306a36Sopenharmony_ci __le32 csum; 6562306a36Sopenharmony_ci __le32 flags; 6662306a36Sopenharmony_ci __le64 blocknr; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci __u8 uuid[16]; 6962306a36Sopenharmony_ci __le64 magic; 7062306a36Sopenharmony_ci __le32 version; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci __u8 policy_name[CACHE_POLICY_NAME_SIZE]; 7362306a36Sopenharmony_ci __le32 policy_hint_size; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; 7662306a36Sopenharmony_ci __le64 mapping_root; 7762306a36Sopenharmony_ci __le64 hint_root; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci __le64 discard_root; 8062306a36Sopenharmony_ci __le64 discard_block_size; 8162306a36Sopenharmony_ci __le64 discard_nr_blocks; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci __le32 data_block_size; 8462306a36Sopenharmony_ci __le32 metadata_block_size; 8562306a36Sopenharmony_ci __le32 cache_blocks; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci __le32 compat_flags; 8862306a36Sopenharmony_ci __le32 compat_ro_flags; 8962306a36Sopenharmony_ci __le32 incompat_flags; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci __le32 read_hits; 9262306a36Sopenharmony_ci __le32 read_misses; 9362306a36Sopenharmony_ci __le32 write_hits; 9462306a36Sopenharmony_ci __le32 write_misses; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci __le32 policy_version[CACHE_POLICY_VERSION_SIZE]; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* 9962306a36Sopenharmony_ci * Metadata format 2 fields. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci __le64 dirty_root; 10262306a36Sopenharmony_ci} __packed; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct dm_cache_metadata { 10562306a36Sopenharmony_ci refcount_t ref_count; 10662306a36Sopenharmony_ci struct list_head list; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci unsigned int version; 10962306a36Sopenharmony_ci struct block_device *bdev; 11062306a36Sopenharmony_ci struct dm_block_manager *bm; 11162306a36Sopenharmony_ci struct dm_space_map *metadata_sm; 11262306a36Sopenharmony_ci struct dm_transaction_manager *tm; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci struct dm_array_info info; 11562306a36Sopenharmony_ci struct dm_array_info hint_info; 11662306a36Sopenharmony_ci struct dm_disk_bitset discard_info; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci struct rw_semaphore root_lock; 11962306a36Sopenharmony_ci unsigned long flags; 12062306a36Sopenharmony_ci dm_block_t root; 12162306a36Sopenharmony_ci dm_block_t hint_root; 12262306a36Sopenharmony_ci dm_block_t discard_root; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci sector_t discard_block_size; 12562306a36Sopenharmony_ci dm_dblock_t discard_nr_blocks; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci sector_t data_block_size; 12862306a36Sopenharmony_ci dm_cblock_t cache_blocks; 12962306a36Sopenharmony_ci bool changed:1; 13062306a36Sopenharmony_ci bool clean_when_opened:1; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci char policy_name[CACHE_POLICY_NAME_SIZE]; 13362306a36Sopenharmony_ci unsigned int policy_version[CACHE_POLICY_VERSION_SIZE]; 13462306a36Sopenharmony_ci size_t policy_hint_size; 13562306a36Sopenharmony_ci struct dm_cache_statistics stats; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * Reading the space map root can fail, so we read it into this 13962306a36Sopenharmony_ci * buffer before the superblock is locked and updated. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * Set if a transaction has to be aborted but the attempt to roll 14562306a36Sopenharmony_ci * back to the previous (good) transaction failed. The only 14662306a36Sopenharmony_ci * metadata operation permissible in this state is the closing of 14762306a36Sopenharmony_ci * the device. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci bool fail_io:1; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * Metadata format 2 fields. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci dm_block_t dirty_root; 15562306a36Sopenharmony_ci struct dm_disk_bitset dirty_info; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * These structures are used when loading metadata. They're too 15962306a36Sopenharmony_ci * big to put on the stack. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci struct dm_array_cursor mapping_cursor; 16262306a36Sopenharmony_ci struct dm_array_cursor hint_cursor; 16362306a36Sopenharmony_ci struct dm_bitset_cursor dirty_cursor; 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci *----------------------------------------------------------------- 16862306a36Sopenharmony_ci * superblock validator 16962306a36Sopenharmony_ci *----------------------------------------------------------------- 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci#define SUPERBLOCK_CSUM_XOR 9031977 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic void sb_prepare_for_write(struct dm_block_validator *v, 17462306a36Sopenharmony_ci struct dm_block *b, 17562306a36Sopenharmony_ci size_t sb_block_size) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct cache_disk_superblock *disk_super = dm_block_data(b); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci disk_super->blocknr = cpu_to_le64(dm_block_location(b)); 18062306a36Sopenharmony_ci disk_super->csum = cpu_to_le32(dm_bm_checksum(&disk_super->flags, 18162306a36Sopenharmony_ci sb_block_size - sizeof(__le32), 18262306a36Sopenharmony_ci SUPERBLOCK_CSUM_XOR)); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int check_metadata_version(struct cache_disk_superblock *disk_super) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci uint32_t metadata_version = le32_to_cpu(disk_super->version); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (metadata_version < MIN_CACHE_VERSION || metadata_version > MAX_CACHE_VERSION) { 19062306a36Sopenharmony_ci DMERR("Cache metadata version %u found, but only versions between %u and %u supported.", 19162306a36Sopenharmony_ci metadata_version, MIN_CACHE_VERSION, MAX_CACHE_VERSION); 19262306a36Sopenharmony_ci return -EINVAL; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int sb_check(struct dm_block_validator *v, 19962306a36Sopenharmony_ci struct dm_block *b, 20062306a36Sopenharmony_ci size_t sb_block_size) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct cache_disk_superblock *disk_super = dm_block_data(b); 20362306a36Sopenharmony_ci __le32 csum_le; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (dm_block_location(b) != le64_to_cpu(disk_super->blocknr)) { 20662306a36Sopenharmony_ci DMERR("%s failed: blocknr %llu: wanted %llu", 20762306a36Sopenharmony_ci __func__, le64_to_cpu(disk_super->blocknr), 20862306a36Sopenharmony_ci (unsigned long long)dm_block_location(b)); 20962306a36Sopenharmony_ci return -ENOTBLK; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (le64_to_cpu(disk_super->magic) != CACHE_SUPERBLOCK_MAGIC) { 21362306a36Sopenharmony_ci DMERR("%s failed: magic %llu: wanted %llu", 21462306a36Sopenharmony_ci __func__, le64_to_cpu(disk_super->magic), 21562306a36Sopenharmony_ci (unsigned long long)CACHE_SUPERBLOCK_MAGIC); 21662306a36Sopenharmony_ci return -EILSEQ; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci csum_le = cpu_to_le32(dm_bm_checksum(&disk_super->flags, 22062306a36Sopenharmony_ci sb_block_size - sizeof(__le32), 22162306a36Sopenharmony_ci SUPERBLOCK_CSUM_XOR)); 22262306a36Sopenharmony_ci if (csum_le != disk_super->csum) { 22362306a36Sopenharmony_ci DMERR("%s failed: csum %u: wanted %u", 22462306a36Sopenharmony_ci __func__, le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum)); 22562306a36Sopenharmony_ci return -EILSEQ; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return check_metadata_version(disk_super); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic struct dm_block_validator sb_validator = { 23262306a36Sopenharmony_ci .name = "superblock", 23362306a36Sopenharmony_ci .prepare_for_write = sb_prepare_for_write, 23462306a36Sopenharmony_ci .check = sb_check 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int superblock_read_lock(struct dm_cache_metadata *cmd, 24062306a36Sopenharmony_ci struct dm_block **sblock) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci return dm_bm_read_lock(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 24362306a36Sopenharmony_ci &sb_validator, sblock); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int superblock_lock_zero(struct dm_cache_metadata *cmd, 24762306a36Sopenharmony_ci struct dm_block **sblock) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci return dm_bm_write_lock_zero(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 25062306a36Sopenharmony_ci &sb_validator, sblock); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int superblock_lock(struct dm_cache_metadata *cmd, 25462306a36Sopenharmony_ci struct dm_block **sblock) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci return dm_bm_write_lock(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 25762306a36Sopenharmony_ci &sb_validator, sblock); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int __superblock_all_zeroes(struct dm_block_manager *bm, bool *result) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci int r; 26562306a36Sopenharmony_ci unsigned int i; 26662306a36Sopenharmony_ci struct dm_block *b; 26762306a36Sopenharmony_ci __le64 *data_le, zero = cpu_to_le64(0); 26862306a36Sopenharmony_ci unsigned int sb_block_size = dm_bm_block_size(bm) / sizeof(__le64); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* 27162306a36Sopenharmony_ci * We can't use a validator here - it may be all zeroes. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci r = dm_bm_read_lock(bm, CACHE_SUPERBLOCK_LOCATION, NULL, &b); 27462306a36Sopenharmony_ci if (r) 27562306a36Sopenharmony_ci return r; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci data_le = dm_block_data(b); 27862306a36Sopenharmony_ci *result = true; 27962306a36Sopenharmony_ci for (i = 0; i < sb_block_size; i++) { 28062306a36Sopenharmony_ci if (data_le[i] != zero) { 28162306a36Sopenharmony_ci *result = false; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci dm_bm_unlock(b); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic void __setup_mapping_info(struct dm_cache_metadata *cmd) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct dm_btree_value_type vt; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci vt.context = NULL; 29662306a36Sopenharmony_ci vt.size = sizeof(__le64); 29762306a36Sopenharmony_ci vt.inc = NULL; 29862306a36Sopenharmony_ci vt.dec = NULL; 29962306a36Sopenharmony_ci vt.equal = NULL; 30062306a36Sopenharmony_ci dm_array_info_init(&cmd->info, cmd->tm, &vt); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (cmd->policy_hint_size) { 30362306a36Sopenharmony_ci vt.size = sizeof(__le32); 30462306a36Sopenharmony_ci dm_array_info_init(&cmd->hint_info, cmd->tm, &vt); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int __save_sm_root(struct dm_cache_metadata *cmd) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci int r; 31162306a36Sopenharmony_ci size_t metadata_len; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci r = dm_sm_root_size(cmd->metadata_sm, &metadata_len); 31462306a36Sopenharmony_ci if (r < 0) 31562306a36Sopenharmony_ci return r; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return dm_sm_copy_root(cmd->metadata_sm, &cmd->metadata_space_map_root, 31862306a36Sopenharmony_ci metadata_len); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void __copy_sm_root(struct dm_cache_metadata *cmd, 32262306a36Sopenharmony_ci struct cache_disk_superblock *disk_super) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci memcpy(&disk_super->metadata_space_map_root, 32562306a36Sopenharmony_ci &cmd->metadata_space_map_root, 32662306a36Sopenharmony_ci sizeof(cmd->metadata_space_map_root)); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic bool separate_dirty_bits(struct dm_cache_metadata *cmd) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci return cmd->version >= 2; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int __write_initial_superblock(struct dm_cache_metadata *cmd) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int r; 33762306a36Sopenharmony_ci struct dm_block *sblock; 33862306a36Sopenharmony_ci struct cache_disk_superblock *disk_super; 33962306a36Sopenharmony_ci sector_t bdev_size = bdev_nr_sectors(cmd->bdev); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* FIXME: see if we can lose the max sectors limit */ 34262306a36Sopenharmony_ci if (bdev_size > DM_CACHE_METADATA_MAX_SECTORS) 34362306a36Sopenharmony_ci bdev_size = DM_CACHE_METADATA_MAX_SECTORS; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci r = dm_tm_pre_commit(cmd->tm); 34662306a36Sopenharmony_ci if (r < 0) 34762306a36Sopenharmony_ci return r; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * dm_sm_copy_root() can fail. So we need to do it before we start 35162306a36Sopenharmony_ci * updating the superblock. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci r = __save_sm_root(cmd); 35462306a36Sopenharmony_ci if (r) 35562306a36Sopenharmony_ci return r; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci r = superblock_lock_zero(cmd, &sblock); 35862306a36Sopenharmony_ci if (r) 35962306a36Sopenharmony_ci return r; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci disk_super = dm_block_data(sblock); 36262306a36Sopenharmony_ci disk_super->flags = 0; 36362306a36Sopenharmony_ci memset(disk_super->uuid, 0, sizeof(disk_super->uuid)); 36462306a36Sopenharmony_ci disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC); 36562306a36Sopenharmony_ci disk_super->version = cpu_to_le32(cmd->version); 36662306a36Sopenharmony_ci memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); 36762306a36Sopenharmony_ci memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); 36862306a36Sopenharmony_ci disk_super->policy_hint_size = cpu_to_le32(0); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci __copy_sm_root(cmd, disk_super); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci disk_super->mapping_root = cpu_to_le64(cmd->root); 37362306a36Sopenharmony_ci disk_super->hint_root = cpu_to_le64(cmd->hint_root); 37462306a36Sopenharmony_ci disk_super->discard_root = cpu_to_le64(cmd->discard_root); 37562306a36Sopenharmony_ci disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size); 37662306a36Sopenharmony_ci disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks)); 37762306a36Sopenharmony_ci disk_super->metadata_block_size = cpu_to_le32(DM_CACHE_METADATA_BLOCK_SIZE); 37862306a36Sopenharmony_ci disk_super->data_block_size = cpu_to_le32(cmd->data_block_size); 37962306a36Sopenharmony_ci disk_super->cache_blocks = cpu_to_le32(0); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci disk_super->read_hits = cpu_to_le32(0); 38262306a36Sopenharmony_ci disk_super->read_misses = cpu_to_le32(0); 38362306a36Sopenharmony_ci disk_super->write_hits = cpu_to_le32(0); 38462306a36Sopenharmony_ci disk_super->write_misses = cpu_to_le32(0); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) 38762306a36Sopenharmony_ci disk_super->dirty_root = cpu_to_le64(cmd->dirty_root); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return dm_tm_commit(cmd->tm, sblock); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int __format_metadata(struct dm_cache_metadata *cmd) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci int r; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci r = dm_tm_create_with_sm(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 39762306a36Sopenharmony_ci &cmd->tm, &cmd->metadata_sm); 39862306a36Sopenharmony_ci if (r < 0) { 39962306a36Sopenharmony_ci DMERR("tm_create_with_sm failed"); 40062306a36Sopenharmony_ci return r; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci __setup_mapping_info(cmd); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci r = dm_array_empty(&cmd->info, &cmd->root); 40662306a36Sopenharmony_ci if (r < 0) 40762306a36Sopenharmony_ci goto bad; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) { 41062306a36Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->dirty_info); 41162306a36Sopenharmony_ci r = dm_bitset_empty(&cmd->dirty_info, &cmd->dirty_root); 41262306a36Sopenharmony_ci if (r < 0) 41362306a36Sopenharmony_ci goto bad; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->discard_info); 41762306a36Sopenharmony_ci r = dm_bitset_empty(&cmd->discard_info, &cmd->discard_root); 41862306a36Sopenharmony_ci if (r < 0) 41962306a36Sopenharmony_ci goto bad; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci cmd->discard_block_size = 0; 42262306a36Sopenharmony_ci cmd->discard_nr_blocks = 0; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci r = __write_initial_superblock(cmd); 42562306a36Sopenharmony_ci if (r) 42662306a36Sopenharmony_ci goto bad; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci cmd->clean_when_opened = true; 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cibad: 43262306a36Sopenharmony_ci dm_tm_destroy(cmd->tm); 43362306a36Sopenharmony_ci dm_sm_destroy(cmd->metadata_sm); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return r; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int __check_incompat_features(struct cache_disk_superblock *disk_super, 43962306a36Sopenharmony_ci struct dm_cache_metadata *cmd) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci uint32_t incompat_flags, features; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci incompat_flags = le32_to_cpu(disk_super->incompat_flags); 44462306a36Sopenharmony_ci features = incompat_flags & ~DM_CACHE_FEATURE_INCOMPAT_SUPP; 44562306a36Sopenharmony_ci if (features) { 44662306a36Sopenharmony_ci DMERR("could not access metadata due to unsupported optional features (%lx).", 44762306a36Sopenharmony_ci (unsigned long)features); 44862306a36Sopenharmony_ci return -EINVAL; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* 45262306a36Sopenharmony_ci * Check for read-only metadata to skip the following RDWR checks. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci if (bdev_read_only(cmd->bdev)) 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci features = le32_to_cpu(disk_super->compat_ro_flags) & ~DM_CACHE_FEATURE_COMPAT_RO_SUPP; 45862306a36Sopenharmony_ci if (features) { 45962306a36Sopenharmony_ci DMERR("could not access metadata RDWR due to unsupported optional features (%lx).", 46062306a36Sopenharmony_ci (unsigned long)features); 46162306a36Sopenharmony_ci return -EINVAL; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int __open_metadata(struct dm_cache_metadata *cmd) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci int r; 47062306a36Sopenharmony_ci struct dm_block *sblock; 47162306a36Sopenharmony_ci struct cache_disk_superblock *disk_super; 47262306a36Sopenharmony_ci unsigned long sb_flags; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci r = superblock_read_lock(cmd, &sblock); 47562306a36Sopenharmony_ci if (r < 0) { 47662306a36Sopenharmony_ci DMERR("couldn't read lock superblock"); 47762306a36Sopenharmony_ci return r; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci disk_super = dm_block_data(sblock); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Verify the data block size hasn't changed */ 48362306a36Sopenharmony_ci if (le32_to_cpu(disk_super->data_block_size) != cmd->data_block_size) { 48462306a36Sopenharmony_ci DMERR("changing the data block size (from %u to %llu) is not supported", 48562306a36Sopenharmony_ci le32_to_cpu(disk_super->data_block_size), 48662306a36Sopenharmony_ci (unsigned long long)cmd->data_block_size); 48762306a36Sopenharmony_ci r = -EINVAL; 48862306a36Sopenharmony_ci goto bad; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci r = __check_incompat_features(disk_super, cmd); 49262306a36Sopenharmony_ci if (r < 0) 49362306a36Sopenharmony_ci goto bad; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci r = dm_tm_open_with_sm(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 49662306a36Sopenharmony_ci disk_super->metadata_space_map_root, 49762306a36Sopenharmony_ci sizeof(disk_super->metadata_space_map_root), 49862306a36Sopenharmony_ci &cmd->tm, &cmd->metadata_sm); 49962306a36Sopenharmony_ci if (r < 0) { 50062306a36Sopenharmony_ci DMERR("tm_open_with_sm failed"); 50162306a36Sopenharmony_ci goto bad; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci __setup_mapping_info(cmd); 50562306a36Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->dirty_info); 50662306a36Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->discard_info); 50762306a36Sopenharmony_ci sb_flags = le32_to_cpu(disk_super->flags); 50862306a36Sopenharmony_ci cmd->clean_when_opened = test_bit(CLEAN_SHUTDOWN, &sb_flags); 50962306a36Sopenharmony_ci dm_bm_unlock(sblock); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return 0; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cibad: 51462306a36Sopenharmony_ci dm_bm_unlock(sblock); 51562306a36Sopenharmony_ci return r; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic int __open_or_format_metadata(struct dm_cache_metadata *cmd, 51962306a36Sopenharmony_ci bool format_device) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci int r; 52262306a36Sopenharmony_ci bool unformatted = false; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci r = __superblock_all_zeroes(cmd->bm, &unformatted); 52562306a36Sopenharmony_ci if (r) 52662306a36Sopenharmony_ci return r; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (unformatted) 52962306a36Sopenharmony_ci return format_device ? __format_metadata(cmd) : -EPERM; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return __open_metadata(cmd); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int __create_persistent_data_objects(struct dm_cache_metadata *cmd, 53562306a36Sopenharmony_ci bool may_format_device) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci int r; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci cmd->bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, 54062306a36Sopenharmony_ci CACHE_MAX_CONCURRENT_LOCKS); 54162306a36Sopenharmony_ci if (IS_ERR(cmd->bm)) { 54262306a36Sopenharmony_ci DMERR("could not create block manager"); 54362306a36Sopenharmony_ci r = PTR_ERR(cmd->bm); 54462306a36Sopenharmony_ci cmd->bm = NULL; 54562306a36Sopenharmony_ci return r; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci r = __open_or_format_metadata(cmd, may_format_device); 54962306a36Sopenharmony_ci if (r) { 55062306a36Sopenharmony_ci dm_block_manager_destroy(cmd->bm); 55162306a36Sopenharmony_ci cmd->bm = NULL; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return r; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd, 55862306a36Sopenharmony_ci bool destroy_bm) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci dm_sm_destroy(cmd->metadata_sm); 56162306a36Sopenharmony_ci dm_tm_destroy(cmd->tm); 56262306a36Sopenharmony_ci if (destroy_bm) 56362306a36Sopenharmony_ci dm_block_manager_destroy(cmd->bm); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_citypedef unsigned long (*flags_mutator)(unsigned long); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic void update_flags(struct cache_disk_superblock *disk_super, 56962306a36Sopenharmony_ci flags_mutator mutator) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci uint32_t sb_flags = mutator(le32_to_cpu(disk_super->flags)); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci disk_super->flags = cpu_to_le32(sb_flags); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic unsigned long set_clean_shutdown(unsigned long flags) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci set_bit(CLEAN_SHUTDOWN, &flags); 57962306a36Sopenharmony_ci return flags; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic unsigned long clear_clean_shutdown(unsigned long flags) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci clear_bit(CLEAN_SHUTDOWN, &flags); 58562306a36Sopenharmony_ci return flags; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic void read_superblock_fields(struct dm_cache_metadata *cmd, 58962306a36Sopenharmony_ci struct cache_disk_superblock *disk_super) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci cmd->version = le32_to_cpu(disk_super->version); 59262306a36Sopenharmony_ci cmd->flags = le32_to_cpu(disk_super->flags); 59362306a36Sopenharmony_ci cmd->root = le64_to_cpu(disk_super->mapping_root); 59462306a36Sopenharmony_ci cmd->hint_root = le64_to_cpu(disk_super->hint_root); 59562306a36Sopenharmony_ci cmd->discard_root = le64_to_cpu(disk_super->discard_root); 59662306a36Sopenharmony_ci cmd->discard_block_size = le64_to_cpu(disk_super->discard_block_size); 59762306a36Sopenharmony_ci cmd->discard_nr_blocks = to_dblock(le64_to_cpu(disk_super->discard_nr_blocks)); 59862306a36Sopenharmony_ci cmd->data_block_size = le32_to_cpu(disk_super->data_block_size); 59962306a36Sopenharmony_ci cmd->cache_blocks = to_cblock(le32_to_cpu(disk_super->cache_blocks)); 60062306a36Sopenharmony_ci strncpy(cmd->policy_name, disk_super->policy_name, sizeof(cmd->policy_name)); 60162306a36Sopenharmony_ci cmd->policy_version[0] = le32_to_cpu(disk_super->policy_version[0]); 60262306a36Sopenharmony_ci cmd->policy_version[1] = le32_to_cpu(disk_super->policy_version[1]); 60362306a36Sopenharmony_ci cmd->policy_version[2] = le32_to_cpu(disk_super->policy_version[2]); 60462306a36Sopenharmony_ci cmd->policy_hint_size = le32_to_cpu(disk_super->policy_hint_size); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci cmd->stats.read_hits = le32_to_cpu(disk_super->read_hits); 60762306a36Sopenharmony_ci cmd->stats.read_misses = le32_to_cpu(disk_super->read_misses); 60862306a36Sopenharmony_ci cmd->stats.write_hits = le32_to_cpu(disk_super->write_hits); 60962306a36Sopenharmony_ci cmd->stats.write_misses = le32_to_cpu(disk_super->write_misses); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) 61262306a36Sopenharmony_ci cmd->dirty_root = le64_to_cpu(disk_super->dirty_root); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci cmd->changed = false; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/* 61862306a36Sopenharmony_ci * The mutator updates the superblock flags. 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_cistatic int __begin_transaction_flags(struct dm_cache_metadata *cmd, 62162306a36Sopenharmony_ci flags_mutator mutator) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci int r; 62462306a36Sopenharmony_ci struct cache_disk_superblock *disk_super; 62562306a36Sopenharmony_ci struct dm_block *sblock; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci r = superblock_lock(cmd, &sblock); 62862306a36Sopenharmony_ci if (r) 62962306a36Sopenharmony_ci return r; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci disk_super = dm_block_data(sblock); 63262306a36Sopenharmony_ci update_flags(disk_super, mutator); 63362306a36Sopenharmony_ci read_superblock_fields(cmd, disk_super); 63462306a36Sopenharmony_ci dm_bm_unlock(sblock); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci return dm_bm_flush(cmd->bm); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic int __begin_transaction(struct dm_cache_metadata *cmd) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci int r; 64262306a36Sopenharmony_ci struct cache_disk_superblock *disk_super; 64362306a36Sopenharmony_ci struct dm_block *sblock; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* 64662306a36Sopenharmony_ci * We re-read the superblock every time. Shouldn't need to do this 64762306a36Sopenharmony_ci * really. 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_ci r = superblock_read_lock(cmd, &sblock); 65062306a36Sopenharmony_ci if (r) 65162306a36Sopenharmony_ci return r; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci disk_super = dm_block_data(sblock); 65462306a36Sopenharmony_ci read_superblock_fields(cmd, disk_super); 65562306a36Sopenharmony_ci dm_bm_unlock(sblock); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int __commit_transaction(struct dm_cache_metadata *cmd, 66162306a36Sopenharmony_ci flags_mutator mutator) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci int r; 66462306a36Sopenharmony_ci struct cache_disk_superblock *disk_super; 66562306a36Sopenharmony_ci struct dm_block *sblock; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * We need to know if the cache_disk_superblock exceeds a 512-byte sector. 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cache_disk_superblock) > 512); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) { 67362306a36Sopenharmony_ci r = dm_bitset_flush(&cmd->dirty_info, cmd->dirty_root, 67462306a36Sopenharmony_ci &cmd->dirty_root); 67562306a36Sopenharmony_ci if (r) 67662306a36Sopenharmony_ci return r; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root, 68062306a36Sopenharmony_ci &cmd->discard_root); 68162306a36Sopenharmony_ci if (r) 68262306a36Sopenharmony_ci return r; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci r = dm_tm_pre_commit(cmd->tm); 68562306a36Sopenharmony_ci if (r < 0) 68662306a36Sopenharmony_ci return r; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci r = __save_sm_root(cmd); 68962306a36Sopenharmony_ci if (r) 69062306a36Sopenharmony_ci return r; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci r = superblock_lock(cmd, &sblock); 69362306a36Sopenharmony_ci if (r) 69462306a36Sopenharmony_ci return r; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci disk_super = dm_block_data(sblock); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci disk_super->flags = cpu_to_le32(cmd->flags); 69962306a36Sopenharmony_ci if (mutator) 70062306a36Sopenharmony_ci update_flags(disk_super, mutator); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci disk_super->mapping_root = cpu_to_le64(cmd->root); 70362306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) 70462306a36Sopenharmony_ci disk_super->dirty_root = cpu_to_le64(cmd->dirty_root); 70562306a36Sopenharmony_ci disk_super->hint_root = cpu_to_le64(cmd->hint_root); 70662306a36Sopenharmony_ci disk_super->discard_root = cpu_to_le64(cmd->discard_root); 70762306a36Sopenharmony_ci disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size); 70862306a36Sopenharmony_ci disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks)); 70962306a36Sopenharmony_ci disk_super->cache_blocks = cpu_to_le32(from_cblock(cmd->cache_blocks)); 71062306a36Sopenharmony_ci strncpy(disk_super->policy_name, cmd->policy_name, sizeof(disk_super->policy_name)); 71162306a36Sopenharmony_ci disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]); 71262306a36Sopenharmony_ci disk_super->policy_version[1] = cpu_to_le32(cmd->policy_version[1]); 71362306a36Sopenharmony_ci disk_super->policy_version[2] = cpu_to_le32(cmd->policy_version[2]); 71462306a36Sopenharmony_ci disk_super->policy_hint_size = cpu_to_le32(cmd->policy_hint_size); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits); 71762306a36Sopenharmony_ci disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); 71862306a36Sopenharmony_ci disk_super->write_hits = cpu_to_le32(cmd->stats.write_hits); 71962306a36Sopenharmony_ci disk_super->write_misses = cpu_to_le32(cmd->stats.write_misses); 72062306a36Sopenharmony_ci __copy_sm_root(cmd, disk_super); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return dm_tm_commit(cmd->tm, sblock); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/* 72862306a36Sopenharmony_ci * The mappings are held in a dm-array that has 64-bit values stored in 72962306a36Sopenharmony_ci * little-endian format. The index is the cblock, the high 48bits of the 73062306a36Sopenharmony_ci * value are the oblock and the low 16 bit the flags. 73162306a36Sopenharmony_ci */ 73262306a36Sopenharmony_ci#define FLAGS_MASK ((1 << 16) - 1) 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic __le64 pack_value(dm_oblock_t block, unsigned int flags) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci uint64_t value = from_oblock(block); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci value <<= 16; 73962306a36Sopenharmony_ci value = value | (flags & FLAGS_MASK); 74062306a36Sopenharmony_ci return cpu_to_le64(value); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned int *flags) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci uint64_t value = le64_to_cpu(value_le); 74662306a36Sopenharmony_ci uint64_t b = value >> 16; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci *block = to_oblock(b); 74962306a36Sopenharmony_ci *flags = value & FLAGS_MASK; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic struct dm_cache_metadata *metadata_open(struct block_device *bdev, 75562306a36Sopenharmony_ci sector_t data_block_size, 75662306a36Sopenharmony_ci bool may_format_device, 75762306a36Sopenharmony_ci size_t policy_hint_size, 75862306a36Sopenharmony_ci unsigned int metadata_version) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci int r; 76162306a36Sopenharmony_ci struct dm_cache_metadata *cmd; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 76462306a36Sopenharmony_ci if (!cmd) { 76562306a36Sopenharmony_ci DMERR("could not allocate metadata struct"); 76662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci cmd->version = metadata_version; 77062306a36Sopenharmony_ci refcount_set(&cmd->ref_count, 1); 77162306a36Sopenharmony_ci init_rwsem(&cmd->root_lock); 77262306a36Sopenharmony_ci cmd->bdev = bdev; 77362306a36Sopenharmony_ci cmd->data_block_size = data_block_size; 77462306a36Sopenharmony_ci cmd->cache_blocks = 0; 77562306a36Sopenharmony_ci cmd->policy_hint_size = policy_hint_size; 77662306a36Sopenharmony_ci cmd->changed = true; 77762306a36Sopenharmony_ci cmd->fail_io = false; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci r = __create_persistent_data_objects(cmd, may_format_device); 78062306a36Sopenharmony_ci if (r) { 78162306a36Sopenharmony_ci kfree(cmd); 78262306a36Sopenharmony_ci return ERR_PTR(r); 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci r = __begin_transaction_flags(cmd, clear_clean_shutdown); 78662306a36Sopenharmony_ci if (r < 0) { 78762306a36Sopenharmony_ci dm_cache_metadata_close(cmd); 78862306a36Sopenharmony_ci return ERR_PTR(r); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return cmd; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci/* 79562306a36Sopenharmony_ci * We keep a little list of ref counted metadata objects to prevent two 79662306a36Sopenharmony_ci * different target instances creating separate bufio instances. This is 79762306a36Sopenharmony_ci * an issue if a table is reloaded before the suspend. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_cistatic DEFINE_MUTEX(table_lock); 80062306a36Sopenharmony_cistatic LIST_HEAD(table); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic struct dm_cache_metadata *lookup(struct block_device *bdev) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct dm_cache_metadata *cmd; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci list_for_each_entry(cmd, &table, list) 80762306a36Sopenharmony_ci if (cmd->bdev == bdev) { 80862306a36Sopenharmony_ci refcount_inc(&cmd->ref_count); 80962306a36Sopenharmony_ci return cmd; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return NULL; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, 81662306a36Sopenharmony_ci sector_t data_block_size, 81762306a36Sopenharmony_ci bool may_format_device, 81862306a36Sopenharmony_ci size_t policy_hint_size, 81962306a36Sopenharmony_ci unsigned int metadata_version) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct dm_cache_metadata *cmd, *cmd2; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci mutex_lock(&table_lock); 82462306a36Sopenharmony_ci cmd = lookup(bdev); 82562306a36Sopenharmony_ci mutex_unlock(&table_lock); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (cmd) 82862306a36Sopenharmony_ci return cmd; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci cmd = metadata_open(bdev, data_block_size, may_format_device, 83162306a36Sopenharmony_ci policy_hint_size, metadata_version); 83262306a36Sopenharmony_ci if (!IS_ERR(cmd)) { 83362306a36Sopenharmony_ci mutex_lock(&table_lock); 83462306a36Sopenharmony_ci cmd2 = lookup(bdev); 83562306a36Sopenharmony_ci if (cmd2) { 83662306a36Sopenharmony_ci mutex_unlock(&table_lock); 83762306a36Sopenharmony_ci __destroy_persistent_data_objects(cmd, true); 83862306a36Sopenharmony_ci kfree(cmd); 83962306a36Sopenharmony_ci return cmd2; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci list_add(&cmd->list, &table); 84262306a36Sopenharmony_ci mutex_unlock(&table_lock); 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return cmd; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci if (cmd->data_block_size != data_block_size) { 85162306a36Sopenharmony_ci DMERR("data_block_size (%llu) different from that in metadata (%llu)", 85262306a36Sopenharmony_ci (unsigned long long) data_block_size, 85362306a36Sopenharmony_ci (unsigned long long) cmd->data_block_size); 85462306a36Sopenharmony_ci return false; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return true; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistruct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, 86162306a36Sopenharmony_ci sector_t data_block_size, 86262306a36Sopenharmony_ci bool may_format_device, 86362306a36Sopenharmony_ci size_t policy_hint_size, 86462306a36Sopenharmony_ci unsigned int metadata_version) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, may_format_device, 86762306a36Sopenharmony_ci policy_hint_size, metadata_version); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) { 87062306a36Sopenharmony_ci dm_cache_metadata_close(cmd); 87162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci return cmd; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_civoid dm_cache_metadata_close(struct dm_cache_metadata *cmd) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci if (refcount_dec_and_test(&cmd->ref_count)) { 88062306a36Sopenharmony_ci mutex_lock(&table_lock); 88162306a36Sopenharmony_ci list_del(&cmd->list); 88262306a36Sopenharmony_ci mutex_unlock(&table_lock); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (!cmd->fail_io) 88562306a36Sopenharmony_ci __destroy_persistent_data_objects(cmd, true); 88662306a36Sopenharmony_ci kfree(cmd); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/* 89162306a36Sopenharmony_ci * Checks that the given cache block is either unmapped or clean. 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_cistatic int block_clean_combined_dirty(struct dm_cache_metadata *cmd, dm_cblock_t b, 89462306a36Sopenharmony_ci bool *result) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci int r; 89762306a36Sopenharmony_ci __le64 value; 89862306a36Sopenharmony_ci dm_oblock_t ob; 89962306a36Sopenharmony_ci unsigned int flags; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value); 90262306a36Sopenharmony_ci if (r) 90362306a36Sopenharmony_ci return r; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci unpack_value(value, &ob, &flags); 90662306a36Sopenharmony_ci *result = !((flags & M_VALID) && (flags & M_DIRTY)); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return 0; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic int blocks_are_clean_combined_dirty(struct dm_cache_metadata *cmd, 91262306a36Sopenharmony_ci dm_cblock_t begin, dm_cblock_t end, 91362306a36Sopenharmony_ci bool *result) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci int r; 91662306a36Sopenharmony_ci *result = true; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci while (begin != end) { 91962306a36Sopenharmony_ci r = block_clean_combined_dirty(cmd, begin, result); 92062306a36Sopenharmony_ci if (r) { 92162306a36Sopenharmony_ci DMERR("block_clean_combined_dirty failed"); 92262306a36Sopenharmony_ci return r; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (!*result) { 92662306a36Sopenharmony_ci DMERR("cache block %llu is dirty", 92762306a36Sopenharmony_ci (unsigned long long) from_cblock(begin)); 92862306a36Sopenharmony_ci return 0; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci begin = to_cblock(from_cblock(begin) + 1); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return 0; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic int blocks_are_clean_separate_dirty(struct dm_cache_metadata *cmd, 93862306a36Sopenharmony_ci dm_cblock_t begin, dm_cblock_t end, 93962306a36Sopenharmony_ci bool *result) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci int r; 94262306a36Sopenharmony_ci bool dirty_flag; 94362306a36Sopenharmony_ci *result = true; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (from_cblock(cmd->cache_blocks) == 0) 94662306a36Sopenharmony_ci /* Nothing to do */ 94762306a36Sopenharmony_ci return 0; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci r = dm_bitset_cursor_begin(&cmd->dirty_info, cmd->dirty_root, 95062306a36Sopenharmony_ci from_cblock(cmd->cache_blocks), &cmd->dirty_cursor); 95162306a36Sopenharmony_ci if (r) { 95262306a36Sopenharmony_ci DMERR("%s: dm_bitset_cursor_begin for dirty failed", __func__); 95362306a36Sopenharmony_ci return r; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci r = dm_bitset_cursor_skip(&cmd->dirty_cursor, from_cblock(begin)); 95762306a36Sopenharmony_ci if (r) { 95862306a36Sopenharmony_ci DMERR("%s: dm_bitset_cursor_skip for dirty failed", __func__); 95962306a36Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 96062306a36Sopenharmony_ci return r; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci while (begin != end) { 96462306a36Sopenharmony_ci /* 96562306a36Sopenharmony_ci * We assume that unmapped blocks have their dirty bit 96662306a36Sopenharmony_ci * cleared. 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ci dirty_flag = dm_bitset_cursor_get_value(&cmd->dirty_cursor); 96962306a36Sopenharmony_ci if (dirty_flag) { 97062306a36Sopenharmony_ci DMERR("%s: cache block %llu is dirty", __func__, 97162306a36Sopenharmony_ci (unsigned long long) from_cblock(begin)); 97262306a36Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 97362306a36Sopenharmony_ci *result = false; 97462306a36Sopenharmony_ci return 0; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci begin = to_cblock(from_cblock(begin) + 1); 97862306a36Sopenharmony_ci if (begin == end) 97962306a36Sopenharmony_ci break; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci r = dm_bitset_cursor_next(&cmd->dirty_cursor); 98262306a36Sopenharmony_ci if (r) { 98362306a36Sopenharmony_ci DMERR("%s: dm_bitset_cursor_next for dirty failed", __func__); 98462306a36Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 98562306a36Sopenharmony_ci return r; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, 99562306a36Sopenharmony_ci dm_cblock_t begin, dm_cblock_t end, 99662306a36Sopenharmony_ci bool *result) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) 99962306a36Sopenharmony_ci return blocks_are_clean_separate_dirty(cmd, begin, end, result); 100062306a36Sopenharmony_ci else 100162306a36Sopenharmony_ci return blocks_are_clean_combined_dirty(cmd, begin, end, result); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic bool cmd_write_lock(struct dm_cache_metadata *cmd) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci down_write(&cmd->root_lock); 100762306a36Sopenharmony_ci if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { 100862306a36Sopenharmony_ci up_write(&cmd->root_lock); 100962306a36Sopenharmony_ci return false; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci return true; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci#define WRITE_LOCK(cmd) \ 101562306a36Sopenharmony_ci do { \ 101662306a36Sopenharmony_ci if (!cmd_write_lock((cmd))) \ 101762306a36Sopenharmony_ci return -EINVAL; \ 101862306a36Sopenharmony_ci } while (0) 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci#define WRITE_LOCK_VOID(cmd) \ 102162306a36Sopenharmony_ci do { \ 102262306a36Sopenharmony_ci if (!cmd_write_lock((cmd))) \ 102362306a36Sopenharmony_ci return; \ 102462306a36Sopenharmony_ci } while (0) 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci#define WRITE_UNLOCK(cmd) \ 102762306a36Sopenharmony_ci up_write(&(cmd)->root_lock) 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic bool cmd_read_lock(struct dm_cache_metadata *cmd) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci down_read(&cmd->root_lock); 103262306a36Sopenharmony_ci if (cmd->fail_io) { 103362306a36Sopenharmony_ci up_read(&cmd->root_lock); 103462306a36Sopenharmony_ci return false; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci return true; 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci#define READ_LOCK(cmd) \ 104062306a36Sopenharmony_ci do { \ 104162306a36Sopenharmony_ci if (!cmd_read_lock((cmd))) \ 104262306a36Sopenharmony_ci return -EINVAL; \ 104362306a36Sopenharmony_ci } while (0) 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci#define READ_LOCK_VOID(cmd) \ 104662306a36Sopenharmony_ci do { \ 104762306a36Sopenharmony_ci if (!cmd_read_lock((cmd))) \ 104862306a36Sopenharmony_ci return; \ 104962306a36Sopenharmony_ci } while (0) 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci#define READ_UNLOCK(cmd) \ 105262306a36Sopenharmony_ci up_read(&(cmd)->root_lock) 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ciint dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci int r; 105762306a36Sopenharmony_ci bool clean; 105862306a36Sopenharmony_ci __le64 null_mapping = pack_value(0, 0); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci WRITE_LOCK(cmd); 106162306a36Sopenharmony_ci __dm_bless_for_disk(&null_mapping); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (from_cblock(new_cache_size) < from_cblock(cmd->cache_blocks)) { 106462306a36Sopenharmony_ci r = blocks_are_unmapped_or_clean(cmd, new_cache_size, cmd->cache_blocks, &clean); 106562306a36Sopenharmony_ci if (r) { 106662306a36Sopenharmony_ci __dm_unbless_for_disk(&null_mapping); 106762306a36Sopenharmony_ci goto out; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (!clean) { 107162306a36Sopenharmony_ci DMERR("unable to shrink cache due to dirty blocks"); 107262306a36Sopenharmony_ci r = -EINVAL; 107362306a36Sopenharmony_ci __dm_unbless_for_disk(&null_mapping); 107462306a36Sopenharmony_ci goto out; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), 107962306a36Sopenharmony_ci from_cblock(new_cache_size), 108062306a36Sopenharmony_ci &null_mapping, &cmd->root); 108162306a36Sopenharmony_ci if (r) 108262306a36Sopenharmony_ci goto out; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) { 108562306a36Sopenharmony_ci r = dm_bitset_resize(&cmd->dirty_info, cmd->dirty_root, 108662306a36Sopenharmony_ci from_cblock(cmd->cache_blocks), from_cblock(new_cache_size), 108762306a36Sopenharmony_ci false, &cmd->dirty_root); 108862306a36Sopenharmony_ci if (r) 108962306a36Sopenharmony_ci goto out; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci cmd->cache_blocks = new_cache_size; 109362306a36Sopenharmony_ci cmd->changed = true; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ciout: 109662306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci return r; 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ciint dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd, 110262306a36Sopenharmony_ci sector_t discard_block_size, 110362306a36Sopenharmony_ci dm_dblock_t new_nr_entries) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci int r; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci WRITE_LOCK(cmd); 110862306a36Sopenharmony_ci r = dm_bitset_resize(&cmd->discard_info, 110962306a36Sopenharmony_ci cmd->discard_root, 111062306a36Sopenharmony_ci from_dblock(cmd->discard_nr_blocks), 111162306a36Sopenharmony_ci from_dblock(new_nr_entries), 111262306a36Sopenharmony_ci false, &cmd->discard_root); 111362306a36Sopenharmony_ci if (!r) { 111462306a36Sopenharmony_ci cmd->discard_block_size = discard_block_size; 111562306a36Sopenharmony_ci cmd->discard_nr_blocks = new_nr_entries; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci cmd->changed = true; 111962306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return r; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic int __set_discard(struct dm_cache_metadata *cmd, dm_dblock_t b) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci return dm_bitset_set_bit(&cmd->discard_info, cmd->discard_root, 112762306a36Sopenharmony_ci from_dblock(b), &cmd->discard_root); 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic int __clear_discard(struct dm_cache_metadata *cmd, dm_dblock_t b) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci return dm_bitset_clear_bit(&cmd->discard_info, cmd->discard_root, 113362306a36Sopenharmony_ci from_dblock(b), &cmd->discard_root); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cistatic int __discard(struct dm_cache_metadata *cmd, 113762306a36Sopenharmony_ci dm_dblock_t dblock, bool discard) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci int r; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci r = (discard ? __set_discard : __clear_discard)(cmd, dblock); 114262306a36Sopenharmony_ci if (r) 114362306a36Sopenharmony_ci return r; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci cmd->changed = true; 114662306a36Sopenharmony_ci return 0; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ciint dm_cache_set_discard(struct dm_cache_metadata *cmd, 115062306a36Sopenharmony_ci dm_dblock_t dblock, bool discard) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci int r; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci WRITE_LOCK(cmd); 115562306a36Sopenharmony_ci r = __discard(cmd, dblock, discard); 115662306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci return r; 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_cistatic int __load_discards(struct dm_cache_metadata *cmd, 116262306a36Sopenharmony_ci load_discard_fn fn, void *context) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci int r = 0; 116562306a36Sopenharmony_ci uint32_t b; 116662306a36Sopenharmony_ci struct dm_bitset_cursor c; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (from_dblock(cmd->discard_nr_blocks) == 0) 116962306a36Sopenharmony_ci /* nothing to do */ 117062306a36Sopenharmony_ci return 0; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (cmd->clean_when_opened) { 117362306a36Sopenharmony_ci r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root, &cmd->discard_root); 117462306a36Sopenharmony_ci if (r) 117562306a36Sopenharmony_ci return r; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci r = dm_bitset_cursor_begin(&cmd->discard_info, cmd->discard_root, 117862306a36Sopenharmony_ci from_dblock(cmd->discard_nr_blocks), &c); 117962306a36Sopenharmony_ci if (r) 118062306a36Sopenharmony_ci return r; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci for (b = 0; ; b++) { 118362306a36Sopenharmony_ci r = fn(context, cmd->discard_block_size, to_dblock(b), 118462306a36Sopenharmony_ci dm_bitset_cursor_get_value(&c)); 118562306a36Sopenharmony_ci if (r) 118662306a36Sopenharmony_ci break; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (b >= (from_dblock(cmd->discard_nr_blocks) - 1)) 118962306a36Sopenharmony_ci break; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci r = dm_bitset_cursor_next(&c); 119262306a36Sopenharmony_ci if (r) 119362306a36Sopenharmony_ci break; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci dm_bitset_cursor_end(&c); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci } else { 119962306a36Sopenharmony_ci for (b = 0; b < from_dblock(cmd->discard_nr_blocks); b++) { 120062306a36Sopenharmony_ci r = fn(context, cmd->discard_block_size, to_dblock(b), false); 120162306a36Sopenharmony_ci if (r) 120262306a36Sopenharmony_ci return r; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return r; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ciint dm_cache_load_discards(struct dm_cache_metadata *cmd, 121062306a36Sopenharmony_ci load_discard_fn fn, void *context) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci int r; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci READ_LOCK(cmd); 121562306a36Sopenharmony_ci r = __load_discards(cmd, fn, context); 121662306a36Sopenharmony_ci READ_UNLOCK(cmd); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci return r; 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ciint dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci READ_LOCK(cmd); 122462306a36Sopenharmony_ci *result = cmd->cache_blocks; 122562306a36Sopenharmony_ci READ_UNLOCK(cmd); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci return 0; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cistatic int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci int r; 123362306a36Sopenharmony_ci __le64 value = pack_value(0, 0); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci __dm_bless_for_disk(&value); 123662306a36Sopenharmony_ci r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), 123762306a36Sopenharmony_ci &value, &cmd->root); 123862306a36Sopenharmony_ci if (r) 123962306a36Sopenharmony_ci return r; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci cmd->changed = true; 124262306a36Sopenharmony_ci return 0; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ciint dm_cache_remove_mapping(struct dm_cache_metadata *cmd, dm_cblock_t cblock) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci int r; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci WRITE_LOCK(cmd); 125062306a36Sopenharmony_ci r = __remove(cmd, cblock); 125162306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci return r; 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic int __insert(struct dm_cache_metadata *cmd, 125762306a36Sopenharmony_ci dm_cblock_t cblock, dm_oblock_t oblock) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci int r; 126062306a36Sopenharmony_ci __le64 value = pack_value(oblock, M_VALID); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci __dm_bless_for_disk(&value); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), 126562306a36Sopenharmony_ci &value, &cmd->root); 126662306a36Sopenharmony_ci if (r) 126762306a36Sopenharmony_ci return r; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci cmd->changed = true; 127062306a36Sopenharmony_ci return 0; 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ciint dm_cache_insert_mapping(struct dm_cache_metadata *cmd, 127462306a36Sopenharmony_ci dm_cblock_t cblock, dm_oblock_t oblock) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci int r; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci WRITE_LOCK(cmd); 127962306a36Sopenharmony_ci r = __insert(cmd, cblock, oblock); 128062306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci return r; 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_cistruct thunk { 128662306a36Sopenharmony_ci load_mapping_fn fn; 128762306a36Sopenharmony_ci void *context; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci struct dm_cache_metadata *cmd; 129062306a36Sopenharmony_ci bool respect_dirty_flags; 129162306a36Sopenharmony_ci bool hints_valid; 129262306a36Sopenharmony_ci}; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic bool policy_unchanged(struct dm_cache_metadata *cmd, 129562306a36Sopenharmony_ci struct dm_cache_policy *policy) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci const char *policy_name = dm_cache_policy_get_name(policy); 129862306a36Sopenharmony_ci const unsigned int *policy_version = dm_cache_policy_get_version(policy); 129962306a36Sopenharmony_ci size_t policy_hint_size = dm_cache_policy_get_hint_size(policy); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* 130262306a36Sopenharmony_ci * Ensure policy names match. 130362306a36Sopenharmony_ci */ 130462306a36Sopenharmony_ci if (strncmp(cmd->policy_name, policy_name, sizeof(cmd->policy_name))) 130562306a36Sopenharmony_ci return false; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* 130862306a36Sopenharmony_ci * Ensure policy major versions match. 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_ci if (cmd->policy_version[0] != policy_version[0]) 131162306a36Sopenharmony_ci return false; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci /* 131462306a36Sopenharmony_ci * Ensure policy hint sizes match. 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_ci if (cmd->policy_hint_size != policy_hint_size) 131762306a36Sopenharmony_ci return false; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci return true; 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_cistatic bool hints_array_initialized(struct dm_cache_metadata *cmd) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci return cmd->hint_root && cmd->policy_hint_size; 132562306a36Sopenharmony_ci} 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_cistatic bool hints_array_available(struct dm_cache_metadata *cmd, 132862306a36Sopenharmony_ci struct dm_cache_policy *policy) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci return cmd->clean_when_opened && policy_unchanged(cmd, policy) && 133162306a36Sopenharmony_ci hints_array_initialized(cmd); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic int __load_mapping_v1(struct dm_cache_metadata *cmd, 133562306a36Sopenharmony_ci uint64_t cb, bool hints_valid, 133662306a36Sopenharmony_ci struct dm_array_cursor *mapping_cursor, 133762306a36Sopenharmony_ci struct dm_array_cursor *hint_cursor, 133862306a36Sopenharmony_ci load_mapping_fn fn, void *context) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci int r = 0; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci __le64 mapping; 134362306a36Sopenharmony_ci __le32 hint = 0; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci __le64 *mapping_value_le; 134662306a36Sopenharmony_ci __le32 *hint_value_le; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci dm_oblock_t oblock; 134962306a36Sopenharmony_ci unsigned int flags; 135062306a36Sopenharmony_ci bool dirty = true; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le); 135362306a36Sopenharmony_ci memcpy(&mapping, mapping_value_le, sizeof(mapping)); 135462306a36Sopenharmony_ci unpack_value(mapping, &oblock, &flags); 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (flags & M_VALID) { 135762306a36Sopenharmony_ci if (hints_valid) { 135862306a36Sopenharmony_ci dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le); 135962306a36Sopenharmony_ci memcpy(&hint, hint_value_le, sizeof(hint)); 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci if (cmd->clean_when_opened) 136262306a36Sopenharmony_ci dirty = flags & M_DIRTY; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci r = fn(context, oblock, to_cblock(cb), dirty, 136562306a36Sopenharmony_ci le32_to_cpu(hint), hints_valid); 136662306a36Sopenharmony_ci if (r) { 136762306a36Sopenharmony_ci DMERR("policy couldn't load cache block %llu", 136862306a36Sopenharmony_ci (unsigned long long) from_cblock(to_cblock(cb))); 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci return r; 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic int __load_mapping_v2(struct dm_cache_metadata *cmd, 137662306a36Sopenharmony_ci uint64_t cb, bool hints_valid, 137762306a36Sopenharmony_ci struct dm_array_cursor *mapping_cursor, 137862306a36Sopenharmony_ci struct dm_array_cursor *hint_cursor, 137962306a36Sopenharmony_ci struct dm_bitset_cursor *dirty_cursor, 138062306a36Sopenharmony_ci load_mapping_fn fn, void *context) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci int r = 0; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci __le64 mapping; 138562306a36Sopenharmony_ci __le32 hint = 0; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci __le64 *mapping_value_le; 138862306a36Sopenharmony_ci __le32 *hint_value_le; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci dm_oblock_t oblock; 139162306a36Sopenharmony_ci unsigned int flags; 139262306a36Sopenharmony_ci bool dirty = true; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le); 139562306a36Sopenharmony_ci memcpy(&mapping, mapping_value_le, sizeof(mapping)); 139662306a36Sopenharmony_ci unpack_value(mapping, &oblock, &flags); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci if (flags & M_VALID) { 139962306a36Sopenharmony_ci if (hints_valid) { 140062306a36Sopenharmony_ci dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le); 140162306a36Sopenharmony_ci memcpy(&hint, hint_value_le, sizeof(hint)); 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci if (cmd->clean_when_opened) 140462306a36Sopenharmony_ci dirty = dm_bitset_cursor_get_value(dirty_cursor); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci r = fn(context, oblock, to_cblock(cb), dirty, 140762306a36Sopenharmony_ci le32_to_cpu(hint), hints_valid); 140862306a36Sopenharmony_ci if (r) { 140962306a36Sopenharmony_ci DMERR("policy couldn't load cache block %llu", 141062306a36Sopenharmony_ci (unsigned long long) from_cblock(to_cblock(cb))); 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci return r; 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_cistatic int __load_mappings(struct dm_cache_metadata *cmd, 141862306a36Sopenharmony_ci struct dm_cache_policy *policy, 141962306a36Sopenharmony_ci load_mapping_fn fn, void *context) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci int r; 142262306a36Sopenharmony_ci uint64_t cb; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci bool hints_valid = hints_array_available(cmd, policy); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (from_cblock(cmd->cache_blocks) == 0) 142762306a36Sopenharmony_ci /* Nothing to do */ 142862306a36Sopenharmony_ci return 0; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci r = dm_array_cursor_begin(&cmd->info, cmd->root, &cmd->mapping_cursor); 143162306a36Sopenharmony_ci if (r) 143262306a36Sopenharmony_ci return r; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (hints_valid) { 143562306a36Sopenharmony_ci r = dm_array_cursor_begin(&cmd->hint_info, cmd->hint_root, &cmd->hint_cursor); 143662306a36Sopenharmony_ci if (r) { 143762306a36Sopenharmony_ci dm_array_cursor_end(&cmd->mapping_cursor); 143862306a36Sopenharmony_ci return r; 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) { 144362306a36Sopenharmony_ci r = dm_bitset_cursor_begin(&cmd->dirty_info, cmd->dirty_root, 144462306a36Sopenharmony_ci from_cblock(cmd->cache_blocks), 144562306a36Sopenharmony_ci &cmd->dirty_cursor); 144662306a36Sopenharmony_ci if (r) { 144762306a36Sopenharmony_ci dm_array_cursor_end(&cmd->hint_cursor); 144862306a36Sopenharmony_ci dm_array_cursor_end(&cmd->mapping_cursor); 144962306a36Sopenharmony_ci return r; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci for (cb = 0; ; cb++) { 145462306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) 145562306a36Sopenharmony_ci r = __load_mapping_v2(cmd, cb, hints_valid, 145662306a36Sopenharmony_ci &cmd->mapping_cursor, 145762306a36Sopenharmony_ci &cmd->hint_cursor, 145862306a36Sopenharmony_ci &cmd->dirty_cursor, 145962306a36Sopenharmony_ci fn, context); 146062306a36Sopenharmony_ci else 146162306a36Sopenharmony_ci r = __load_mapping_v1(cmd, cb, hints_valid, 146262306a36Sopenharmony_ci &cmd->mapping_cursor, &cmd->hint_cursor, 146362306a36Sopenharmony_ci fn, context); 146462306a36Sopenharmony_ci if (r) 146562306a36Sopenharmony_ci goto out; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* 146862306a36Sopenharmony_ci * We need to break out before we move the cursors. 146962306a36Sopenharmony_ci */ 147062306a36Sopenharmony_ci if (cb >= (from_cblock(cmd->cache_blocks) - 1)) 147162306a36Sopenharmony_ci break; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci r = dm_array_cursor_next(&cmd->mapping_cursor); 147462306a36Sopenharmony_ci if (r) { 147562306a36Sopenharmony_ci DMERR("dm_array_cursor_next for mapping failed"); 147662306a36Sopenharmony_ci goto out; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci if (hints_valid) { 148062306a36Sopenharmony_ci r = dm_array_cursor_next(&cmd->hint_cursor); 148162306a36Sopenharmony_ci if (r) { 148262306a36Sopenharmony_ci dm_array_cursor_end(&cmd->hint_cursor); 148362306a36Sopenharmony_ci hints_valid = false; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) { 148862306a36Sopenharmony_ci r = dm_bitset_cursor_next(&cmd->dirty_cursor); 148962306a36Sopenharmony_ci if (r) { 149062306a36Sopenharmony_ci DMERR("dm_bitset_cursor_next for dirty failed"); 149162306a36Sopenharmony_ci goto out; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ciout: 149662306a36Sopenharmony_ci dm_array_cursor_end(&cmd->mapping_cursor); 149762306a36Sopenharmony_ci if (hints_valid) 149862306a36Sopenharmony_ci dm_array_cursor_end(&cmd->hint_cursor); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) 150162306a36Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci return r; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ciint dm_cache_load_mappings(struct dm_cache_metadata *cmd, 150762306a36Sopenharmony_ci struct dm_cache_policy *policy, 150862306a36Sopenharmony_ci load_mapping_fn fn, void *context) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci int r; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci READ_LOCK(cmd); 151362306a36Sopenharmony_ci r = __load_mappings(cmd, policy, fn, context); 151462306a36Sopenharmony_ci READ_UNLOCK(cmd); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci return r; 151762306a36Sopenharmony_ci} 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_cistatic int __dump_mapping(void *context, uint64_t cblock, void *leaf) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci __le64 value; 152262306a36Sopenharmony_ci dm_oblock_t oblock; 152362306a36Sopenharmony_ci unsigned int flags; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci memcpy(&value, leaf, sizeof(value)); 152662306a36Sopenharmony_ci unpack_value(value, &oblock, &flags); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci return 0; 152962306a36Sopenharmony_ci} 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_cistatic int __dump_mappings(struct dm_cache_metadata *cmd) 153262306a36Sopenharmony_ci{ 153362306a36Sopenharmony_ci return dm_array_walk(&cmd->info, cmd->root, __dump_mapping, NULL); 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_civoid dm_cache_dump(struct dm_cache_metadata *cmd) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci READ_LOCK_VOID(cmd); 153962306a36Sopenharmony_ci __dump_mappings(cmd); 154062306a36Sopenharmony_ci READ_UNLOCK(cmd); 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ciint dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci int r; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci READ_LOCK(cmd); 154862306a36Sopenharmony_ci r = cmd->changed; 154962306a36Sopenharmony_ci READ_UNLOCK(cmd); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci return r; 155262306a36Sopenharmony_ci} 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_cistatic int __dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci int r; 155762306a36Sopenharmony_ci unsigned int flags; 155862306a36Sopenharmony_ci dm_oblock_t oblock; 155962306a36Sopenharmony_ci __le64 value; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(cblock), &value); 156262306a36Sopenharmony_ci if (r) 156362306a36Sopenharmony_ci return r; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci unpack_value(value, &oblock, &flags); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (((flags & M_DIRTY) && dirty) || (!(flags & M_DIRTY) && !dirty)) 156862306a36Sopenharmony_ci /* nothing to be done */ 156962306a36Sopenharmony_ci return 0; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci value = pack_value(oblock, (flags & ~M_DIRTY) | (dirty ? M_DIRTY : 0)); 157262306a36Sopenharmony_ci __dm_bless_for_disk(&value); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), 157562306a36Sopenharmony_ci &value, &cmd->root); 157662306a36Sopenharmony_ci if (r) 157762306a36Sopenharmony_ci return r; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci cmd->changed = true; 158062306a36Sopenharmony_ci return 0; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci} 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_cistatic int __set_dirty_bits_v1(struct dm_cache_metadata *cmd, unsigned int nr_bits, unsigned long *bits) 158562306a36Sopenharmony_ci{ 158662306a36Sopenharmony_ci int r; 158762306a36Sopenharmony_ci unsigned int i; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci for (i = 0; i < nr_bits; i++) { 159062306a36Sopenharmony_ci r = __dirty(cmd, to_cblock(i), test_bit(i, bits)); 159162306a36Sopenharmony_ci if (r) 159262306a36Sopenharmony_ci return r; 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci return 0; 159662306a36Sopenharmony_ci} 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cistatic int is_dirty_callback(uint32_t index, bool *value, void *context) 159962306a36Sopenharmony_ci{ 160062306a36Sopenharmony_ci unsigned long *bits = context; 160162306a36Sopenharmony_ci *value = test_bit(index, bits); 160262306a36Sopenharmony_ci return 0; 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic int __set_dirty_bits_v2(struct dm_cache_metadata *cmd, unsigned int nr_bits, unsigned long *bits) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci int r = 0; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci /* nr_bits is really just a sanity check */ 161062306a36Sopenharmony_ci if (nr_bits != from_cblock(cmd->cache_blocks)) { 161162306a36Sopenharmony_ci DMERR("dirty bitset is wrong size"); 161262306a36Sopenharmony_ci return -EINVAL; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci r = dm_bitset_del(&cmd->dirty_info, cmd->dirty_root); 161662306a36Sopenharmony_ci if (r) 161762306a36Sopenharmony_ci return r; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci cmd->changed = true; 162062306a36Sopenharmony_ci return dm_bitset_new(&cmd->dirty_info, &cmd->dirty_root, nr_bits, is_dirty_callback, bits); 162162306a36Sopenharmony_ci} 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ciint dm_cache_set_dirty_bits(struct dm_cache_metadata *cmd, 162462306a36Sopenharmony_ci unsigned int nr_bits, 162562306a36Sopenharmony_ci unsigned long *bits) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci int r; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci WRITE_LOCK(cmd); 163062306a36Sopenharmony_ci if (separate_dirty_bits(cmd)) 163162306a36Sopenharmony_ci r = __set_dirty_bits_v2(cmd, nr_bits, bits); 163262306a36Sopenharmony_ci else 163362306a36Sopenharmony_ci r = __set_dirty_bits_v1(cmd, nr_bits, bits); 163462306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci return r; 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_civoid dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd, 164062306a36Sopenharmony_ci struct dm_cache_statistics *stats) 164162306a36Sopenharmony_ci{ 164262306a36Sopenharmony_ci READ_LOCK_VOID(cmd); 164362306a36Sopenharmony_ci *stats = cmd->stats; 164462306a36Sopenharmony_ci READ_UNLOCK(cmd); 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_civoid dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd, 164862306a36Sopenharmony_ci struct dm_cache_statistics *stats) 164962306a36Sopenharmony_ci{ 165062306a36Sopenharmony_ci WRITE_LOCK_VOID(cmd); 165162306a36Sopenharmony_ci cmd->stats = *stats; 165262306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ciint dm_cache_commit(struct dm_cache_metadata *cmd, bool clean_shutdown) 165662306a36Sopenharmony_ci{ 165762306a36Sopenharmony_ci int r = -EINVAL; 165862306a36Sopenharmony_ci flags_mutator mutator = (clean_shutdown ? set_clean_shutdown : 165962306a36Sopenharmony_ci clear_clean_shutdown); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci WRITE_LOCK(cmd); 166262306a36Sopenharmony_ci if (cmd->fail_io) 166362306a36Sopenharmony_ci goto out; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci r = __commit_transaction(cmd, mutator); 166662306a36Sopenharmony_ci if (r) 166762306a36Sopenharmony_ci goto out; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci r = __begin_transaction(cmd); 167062306a36Sopenharmony_ciout: 167162306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 167262306a36Sopenharmony_ci return r; 167362306a36Sopenharmony_ci} 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ciint dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd, 167662306a36Sopenharmony_ci dm_block_t *result) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci int r = -EINVAL; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci READ_LOCK(cmd); 168162306a36Sopenharmony_ci if (!cmd->fail_io) 168262306a36Sopenharmony_ci r = dm_sm_get_nr_free(cmd->metadata_sm, result); 168362306a36Sopenharmony_ci READ_UNLOCK(cmd); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci return r; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ciint dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd, 168962306a36Sopenharmony_ci dm_block_t *result) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci int r = -EINVAL; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci READ_LOCK(cmd); 169462306a36Sopenharmony_ci if (!cmd->fail_io) 169562306a36Sopenharmony_ci r = dm_sm_get_nr_blocks(cmd->metadata_sm, result); 169662306a36Sopenharmony_ci READ_UNLOCK(cmd); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci return r; 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cistatic int get_hint(uint32_t index, void *value_le, void *context) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci uint32_t value; 170662306a36Sopenharmony_ci struct dm_cache_policy *policy = context; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci value = policy_get_hint(policy, to_cblock(index)); 170962306a36Sopenharmony_ci *((__le32 *) value_le) = cpu_to_le32(value); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci return 0; 171262306a36Sopenharmony_ci} 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci/* 171562306a36Sopenharmony_ci * It's quicker to always delete the hint array, and recreate with 171662306a36Sopenharmony_ci * dm_array_new(). 171762306a36Sopenharmony_ci */ 171862306a36Sopenharmony_cistatic int write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci int r; 172162306a36Sopenharmony_ci size_t hint_size; 172262306a36Sopenharmony_ci const char *policy_name = dm_cache_policy_get_name(policy); 172362306a36Sopenharmony_ci const unsigned int *policy_version = dm_cache_policy_get_version(policy); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci if (!policy_name[0] || 172662306a36Sopenharmony_ci (strlen(policy_name) > sizeof(cmd->policy_name) - 1)) 172762306a36Sopenharmony_ci return -EINVAL; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name)); 173062306a36Sopenharmony_ci memcpy(cmd->policy_version, policy_version, sizeof(cmd->policy_version)); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci hint_size = dm_cache_policy_get_hint_size(policy); 173362306a36Sopenharmony_ci if (!hint_size) 173462306a36Sopenharmony_ci return 0; /* short-circuit hints initialization */ 173562306a36Sopenharmony_ci cmd->policy_hint_size = hint_size; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (cmd->hint_root) { 173862306a36Sopenharmony_ci r = dm_array_del(&cmd->hint_info, cmd->hint_root); 173962306a36Sopenharmony_ci if (r) 174062306a36Sopenharmony_ci return r; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci return dm_array_new(&cmd->hint_info, &cmd->hint_root, 174462306a36Sopenharmony_ci from_cblock(cmd->cache_blocks), 174562306a36Sopenharmony_ci get_hint, policy); 174662306a36Sopenharmony_ci} 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ciint dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy) 174962306a36Sopenharmony_ci{ 175062306a36Sopenharmony_ci int r; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci WRITE_LOCK(cmd); 175362306a36Sopenharmony_ci r = write_hints(cmd, policy); 175462306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci return r; 175762306a36Sopenharmony_ci} 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ciint dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci int r; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci READ_LOCK(cmd); 176462306a36Sopenharmony_ci r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); 176562306a36Sopenharmony_ci READ_UNLOCK(cmd); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci return r; 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_civoid dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) 177162306a36Sopenharmony_ci{ 177262306a36Sopenharmony_ci WRITE_LOCK_VOID(cmd); 177362306a36Sopenharmony_ci dm_bm_set_read_only(cmd->bm); 177462306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_civoid dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci WRITE_LOCK_VOID(cmd); 178062306a36Sopenharmony_ci dm_bm_set_read_write(cmd->bm); 178162306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 178262306a36Sopenharmony_ci} 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ciint dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd) 178562306a36Sopenharmony_ci{ 178662306a36Sopenharmony_ci int r; 178762306a36Sopenharmony_ci struct dm_block *sblock; 178862306a36Sopenharmony_ci struct cache_disk_superblock *disk_super; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci WRITE_LOCK(cmd); 179162306a36Sopenharmony_ci set_bit(NEEDS_CHECK, &cmd->flags); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci r = superblock_lock(cmd, &sblock); 179462306a36Sopenharmony_ci if (r) { 179562306a36Sopenharmony_ci DMERR("couldn't read superblock"); 179662306a36Sopenharmony_ci goto out; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci disk_super = dm_block_data(sblock); 180062306a36Sopenharmony_ci disk_super->flags = cpu_to_le32(cmd->flags); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci dm_bm_unlock(sblock); 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ciout: 180562306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 180662306a36Sopenharmony_ci return r; 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ciint dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result) 181062306a36Sopenharmony_ci{ 181162306a36Sopenharmony_ci READ_LOCK(cmd); 181262306a36Sopenharmony_ci *result = !!test_bit(NEEDS_CHECK, &cmd->flags); 181362306a36Sopenharmony_ci READ_UNLOCK(cmd); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci return 0; 181662306a36Sopenharmony_ci} 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ciint dm_cache_metadata_abort(struct dm_cache_metadata *cmd) 181962306a36Sopenharmony_ci{ 182062306a36Sopenharmony_ci int r = -EINVAL; 182162306a36Sopenharmony_ci struct dm_block_manager *old_bm = NULL, *new_bm = NULL; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci /* fail_io is double-checked with cmd->root_lock held below */ 182462306a36Sopenharmony_ci if (unlikely(cmd->fail_io)) 182562306a36Sopenharmony_ci return r; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci /* 182862306a36Sopenharmony_ci * Replacement block manager (new_bm) is created and old_bm destroyed outside of 182962306a36Sopenharmony_ci * cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of 183062306a36Sopenharmony_ci * shrinker associated with the block manager's bufio client vs cmd root_lock). 183162306a36Sopenharmony_ci * - must take shrinker_rwsem without holding cmd->root_lock 183262306a36Sopenharmony_ci */ 183362306a36Sopenharmony_ci new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, 183462306a36Sopenharmony_ci CACHE_MAX_CONCURRENT_LOCKS); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci WRITE_LOCK(cmd); 183762306a36Sopenharmony_ci if (cmd->fail_io) { 183862306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 183962306a36Sopenharmony_ci goto out; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci __destroy_persistent_data_objects(cmd, false); 184362306a36Sopenharmony_ci old_bm = cmd->bm; 184462306a36Sopenharmony_ci if (IS_ERR(new_bm)) { 184562306a36Sopenharmony_ci DMERR("could not create block manager during abort"); 184662306a36Sopenharmony_ci cmd->bm = NULL; 184762306a36Sopenharmony_ci r = PTR_ERR(new_bm); 184862306a36Sopenharmony_ci goto out_unlock; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci cmd->bm = new_bm; 185262306a36Sopenharmony_ci r = __open_or_format_metadata(cmd, false); 185362306a36Sopenharmony_ci if (r) { 185462306a36Sopenharmony_ci cmd->bm = NULL; 185562306a36Sopenharmony_ci goto out_unlock; 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci new_bm = NULL; 185862306a36Sopenharmony_ciout_unlock: 185962306a36Sopenharmony_ci if (r) 186062306a36Sopenharmony_ci cmd->fail_io = true; 186162306a36Sopenharmony_ci WRITE_UNLOCK(cmd); 186262306a36Sopenharmony_ci dm_block_manager_destroy(old_bm); 186362306a36Sopenharmony_ciout: 186462306a36Sopenharmony_ci if (new_bm && !IS_ERR(new_bm)) 186562306a36Sopenharmony_ci dm_block_manager_destroy(new_bm); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci return r; 186862306a36Sopenharmony_ci} 1869