18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is released under the GPL. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "dm-cache-metadata.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "persistent-data/dm-array.h" 108c2ecf20Sopenharmony_ci#include "persistent-data/dm-bitset.h" 118c2ecf20Sopenharmony_ci#include "persistent-data/dm-space-map.h" 128c2ecf20Sopenharmony_ci#include "persistent-data/dm-space-map-disk.h" 138c2ecf20Sopenharmony_ci#include "persistent-data/dm-transaction-manager.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/device-mapper.h> 168c2ecf20Sopenharmony_ci#include <linux/refcount.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "cache metadata" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define CACHE_SUPERBLOCK_MAGIC 06142003 238c2ecf20Sopenharmony_ci#define CACHE_SUPERBLOCK_LOCATION 0 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * defines a range of metadata versions that this module can handle. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#define MIN_CACHE_VERSION 1 298c2ecf20Sopenharmony_ci#define MAX_CACHE_VERSION 2 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * 3 for btree insert + 338c2ecf20Sopenharmony_ci * 2 for btree lookup used within space map 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci#define CACHE_MAX_CONCURRENT_LOCKS 5 368c2ecf20Sopenharmony_ci#define SPACE_MAP_ROOT_SIZE 128 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cienum superblock_flag_bits { 398c2ecf20Sopenharmony_ci /* for spotting crashes that would invalidate the dirty bitset */ 408c2ecf20Sopenharmony_ci CLEAN_SHUTDOWN, 418c2ecf20Sopenharmony_ci /* metadata must be checked using the tools */ 428c2ecf20Sopenharmony_ci NEEDS_CHECK, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Each mapping from cache block -> origin block carries a set of flags. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_cienum mapping_bits { 498c2ecf20Sopenharmony_ci /* 508c2ecf20Sopenharmony_ci * A valid mapping. Because we're using an array we clear this 518c2ecf20Sopenharmony_ci * flag for an non existant mapping. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci M_VALID = 1, 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* 568c2ecf20Sopenharmony_ci * The data on the cache is different from that on the origin. 578c2ecf20Sopenharmony_ci * This flag is only used by metadata format 1. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci M_DIRTY = 2 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct cache_disk_superblock { 638c2ecf20Sopenharmony_ci __le32 csum; 648c2ecf20Sopenharmony_ci __le32 flags; 658c2ecf20Sopenharmony_ci __le64 blocknr; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci __u8 uuid[16]; 688c2ecf20Sopenharmony_ci __le64 magic; 698c2ecf20Sopenharmony_ci __le32 version; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci __u8 policy_name[CACHE_POLICY_NAME_SIZE]; 728c2ecf20Sopenharmony_ci __le32 policy_hint_size; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; 758c2ecf20Sopenharmony_ci __le64 mapping_root; 768c2ecf20Sopenharmony_ci __le64 hint_root; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci __le64 discard_root; 798c2ecf20Sopenharmony_ci __le64 discard_block_size; 808c2ecf20Sopenharmony_ci __le64 discard_nr_blocks; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci __le32 data_block_size; 838c2ecf20Sopenharmony_ci __le32 metadata_block_size; 848c2ecf20Sopenharmony_ci __le32 cache_blocks; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci __le32 compat_flags; 878c2ecf20Sopenharmony_ci __le32 compat_ro_flags; 888c2ecf20Sopenharmony_ci __le32 incompat_flags; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci __le32 read_hits; 918c2ecf20Sopenharmony_ci __le32 read_misses; 928c2ecf20Sopenharmony_ci __le32 write_hits; 938c2ecf20Sopenharmony_ci __le32 write_misses; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci __le32 policy_version[CACHE_POLICY_VERSION_SIZE]; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * Metadata format 2 fields. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci __le64 dirty_root; 1018c2ecf20Sopenharmony_ci} __packed; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct dm_cache_metadata { 1048c2ecf20Sopenharmony_ci refcount_t ref_count; 1058c2ecf20Sopenharmony_ci struct list_head list; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci unsigned version; 1088c2ecf20Sopenharmony_ci struct block_device *bdev; 1098c2ecf20Sopenharmony_ci struct dm_block_manager *bm; 1108c2ecf20Sopenharmony_ci struct dm_space_map *metadata_sm; 1118c2ecf20Sopenharmony_ci struct dm_transaction_manager *tm; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci struct dm_array_info info; 1148c2ecf20Sopenharmony_ci struct dm_array_info hint_info; 1158c2ecf20Sopenharmony_ci struct dm_disk_bitset discard_info; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci struct rw_semaphore root_lock; 1188c2ecf20Sopenharmony_ci unsigned long flags; 1198c2ecf20Sopenharmony_ci dm_block_t root; 1208c2ecf20Sopenharmony_ci dm_block_t hint_root; 1218c2ecf20Sopenharmony_ci dm_block_t discard_root; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci sector_t discard_block_size; 1248c2ecf20Sopenharmony_ci dm_dblock_t discard_nr_blocks; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci sector_t data_block_size; 1278c2ecf20Sopenharmony_ci dm_cblock_t cache_blocks; 1288c2ecf20Sopenharmony_ci bool changed:1; 1298c2ecf20Sopenharmony_ci bool clean_when_opened:1; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci char policy_name[CACHE_POLICY_NAME_SIZE]; 1328c2ecf20Sopenharmony_ci unsigned policy_version[CACHE_POLICY_VERSION_SIZE]; 1338c2ecf20Sopenharmony_ci size_t policy_hint_size; 1348c2ecf20Sopenharmony_ci struct dm_cache_statistics stats; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * Reading the space map root can fail, so we read it into this 1388c2ecf20Sopenharmony_ci * buffer before the superblock is locked and updated. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * Set if a transaction has to be aborted but the attempt to roll 1448c2ecf20Sopenharmony_ci * back to the previous (good) transaction failed. The only 1458c2ecf20Sopenharmony_ci * metadata operation permissible in this state is the closing of 1468c2ecf20Sopenharmony_ci * the device. 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_ci bool fail_io:1; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* 1518c2ecf20Sopenharmony_ci * Metadata format 2 fields. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci dm_block_t dirty_root; 1548c2ecf20Sopenharmony_ci struct dm_disk_bitset dirty_info; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* 1578c2ecf20Sopenharmony_ci * These structures are used when loading metadata. They're too 1588c2ecf20Sopenharmony_ci * big to put on the stack. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci struct dm_array_cursor mapping_cursor; 1618c2ecf20Sopenharmony_ci struct dm_array_cursor hint_cursor; 1628c2ecf20Sopenharmony_ci struct dm_bitset_cursor dirty_cursor; 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/*------------------------------------------------------------------- 1668c2ecf20Sopenharmony_ci * superblock validator 1678c2ecf20Sopenharmony_ci *-----------------------------------------------------------------*/ 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci#define SUPERBLOCK_CSUM_XOR 9031977 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void sb_prepare_for_write(struct dm_block_validator *v, 1728c2ecf20Sopenharmony_ci struct dm_block *b, 1738c2ecf20Sopenharmony_ci size_t sb_block_size) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super = dm_block_data(b); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci disk_super->blocknr = cpu_to_le64(dm_block_location(b)); 1788c2ecf20Sopenharmony_ci disk_super->csum = cpu_to_le32(dm_bm_checksum(&disk_super->flags, 1798c2ecf20Sopenharmony_ci sb_block_size - sizeof(__le32), 1808c2ecf20Sopenharmony_ci SUPERBLOCK_CSUM_XOR)); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int check_metadata_version(struct cache_disk_superblock *disk_super) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci uint32_t metadata_version = le32_to_cpu(disk_super->version); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (metadata_version < MIN_CACHE_VERSION || metadata_version > MAX_CACHE_VERSION) { 1888c2ecf20Sopenharmony_ci DMERR("Cache metadata version %u found, but only versions between %u and %u supported.", 1898c2ecf20Sopenharmony_ci metadata_version, MIN_CACHE_VERSION, MAX_CACHE_VERSION); 1908c2ecf20Sopenharmony_ci return -EINVAL; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int sb_check(struct dm_block_validator *v, 1978c2ecf20Sopenharmony_ci struct dm_block *b, 1988c2ecf20Sopenharmony_ci size_t sb_block_size) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super = dm_block_data(b); 2018c2ecf20Sopenharmony_ci __le32 csum_le; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (dm_block_location(b) != le64_to_cpu(disk_super->blocknr)) { 2048c2ecf20Sopenharmony_ci DMERR("sb_check failed: blocknr %llu: wanted %llu", 2058c2ecf20Sopenharmony_ci le64_to_cpu(disk_super->blocknr), 2068c2ecf20Sopenharmony_ci (unsigned long long)dm_block_location(b)); 2078c2ecf20Sopenharmony_ci return -ENOTBLK; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (le64_to_cpu(disk_super->magic) != CACHE_SUPERBLOCK_MAGIC) { 2118c2ecf20Sopenharmony_ci DMERR("sb_check failed: magic %llu: wanted %llu", 2128c2ecf20Sopenharmony_ci le64_to_cpu(disk_super->magic), 2138c2ecf20Sopenharmony_ci (unsigned long long)CACHE_SUPERBLOCK_MAGIC); 2148c2ecf20Sopenharmony_ci return -EILSEQ; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci csum_le = cpu_to_le32(dm_bm_checksum(&disk_super->flags, 2188c2ecf20Sopenharmony_ci sb_block_size - sizeof(__le32), 2198c2ecf20Sopenharmony_ci SUPERBLOCK_CSUM_XOR)); 2208c2ecf20Sopenharmony_ci if (csum_le != disk_super->csum) { 2218c2ecf20Sopenharmony_ci DMERR("sb_check failed: csum %u: wanted %u", 2228c2ecf20Sopenharmony_ci le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum)); 2238c2ecf20Sopenharmony_ci return -EILSEQ; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return check_metadata_version(disk_super); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic struct dm_block_validator sb_validator = { 2308c2ecf20Sopenharmony_ci .name = "superblock", 2318c2ecf20Sopenharmony_ci .prepare_for_write = sb_prepare_for_write, 2328c2ecf20Sopenharmony_ci .check = sb_check 2338c2ecf20Sopenharmony_ci}; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int superblock_read_lock(struct dm_cache_metadata *cmd, 2388c2ecf20Sopenharmony_ci struct dm_block **sblock) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci return dm_bm_read_lock(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 2418c2ecf20Sopenharmony_ci &sb_validator, sblock); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int superblock_lock_zero(struct dm_cache_metadata *cmd, 2458c2ecf20Sopenharmony_ci struct dm_block **sblock) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci return dm_bm_write_lock_zero(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 2488c2ecf20Sopenharmony_ci &sb_validator, sblock); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int superblock_lock(struct dm_cache_metadata *cmd, 2528c2ecf20Sopenharmony_ci struct dm_block **sblock) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci return dm_bm_write_lock(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 2558c2ecf20Sopenharmony_ci &sb_validator, sblock); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int __superblock_all_zeroes(struct dm_block_manager *bm, bool *result) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int r; 2638c2ecf20Sopenharmony_ci unsigned i; 2648c2ecf20Sopenharmony_ci struct dm_block *b; 2658c2ecf20Sopenharmony_ci __le64 *data_le, zero = cpu_to_le64(0); 2668c2ecf20Sopenharmony_ci unsigned sb_block_size = dm_bm_block_size(bm) / sizeof(__le64); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * We can't use a validator here - it may be all zeroes. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci r = dm_bm_read_lock(bm, CACHE_SUPERBLOCK_LOCATION, NULL, &b); 2728c2ecf20Sopenharmony_ci if (r) 2738c2ecf20Sopenharmony_ci return r; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci data_le = dm_block_data(b); 2768c2ecf20Sopenharmony_ci *result = true; 2778c2ecf20Sopenharmony_ci for (i = 0; i < sb_block_size; i++) { 2788c2ecf20Sopenharmony_ci if (data_le[i] != zero) { 2798c2ecf20Sopenharmony_ci *result = false; 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci dm_bm_unlock(b); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void __setup_mapping_info(struct dm_cache_metadata *cmd) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct dm_btree_value_type vt; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci vt.context = NULL; 2948c2ecf20Sopenharmony_ci vt.size = sizeof(__le64); 2958c2ecf20Sopenharmony_ci vt.inc = NULL; 2968c2ecf20Sopenharmony_ci vt.dec = NULL; 2978c2ecf20Sopenharmony_ci vt.equal = NULL; 2988c2ecf20Sopenharmony_ci dm_array_info_init(&cmd->info, cmd->tm, &vt); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (cmd->policy_hint_size) { 3018c2ecf20Sopenharmony_ci vt.size = sizeof(__le32); 3028c2ecf20Sopenharmony_ci dm_array_info_init(&cmd->hint_info, cmd->tm, &vt); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int __save_sm_root(struct dm_cache_metadata *cmd) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci int r; 3098c2ecf20Sopenharmony_ci size_t metadata_len; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci r = dm_sm_root_size(cmd->metadata_sm, &metadata_len); 3128c2ecf20Sopenharmony_ci if (r < 0) 3138c2ecf20Sopenharmony_ci return r; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return dm_sm_copy_root(cmd->metadata_sm, &cmd->metadata_space_map_root, 3168c2ecf20Sopenharmony_ci metadata_len); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void __copy_sm_root(struct dm_cache_metadata *cmd, 3208c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci memcpy(&disk_super->metadata_space_map_root, 3238c2ecf20Sopenharmony_ci &cmd->metadata_space_map_root, 3248c2ecf20Sopenharmony_ci sizeof(cmd->metadata_space_map_root)); 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic bool separate_dirty_bits(struct dm_cache_metadata *cmd) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci return cmd->version >= 2; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int __write_initial_superblock(struct dm_cache_metadata *cmd) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci int r; 3358c2ecf20Sopenharmony_ci struct dm_block *sblock; 3368c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super; 3378c2ecf20Sopenharmony_ci sector_t bdev_size = i_size_read(cmd->bdev->bd_inode) >> SECTOR_SHIFT; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* FIXME: see if we can lose the max sectors limit */ 3408c2ecf20Sopenharmony_ci if (bdev_size > DM_CACHE_METADATA_MAX_SECTORS) 3418c2ecf20Sopenharmony_ci bdev_size = DM_CACHE_METADATA_MAX_SECTORS; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci r = dm_tm_pre_commit(cmd->tm); 3448c2ecf20Sopenharmony_ci if (r < 0) 3458c2ecf20Sopenharmony_ci return r; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * dm_sm_copy_root() can fail. So we need to do it before we start 3498c2ecf20Sopenharmony_ci * updating the superblock. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci r = __save_sm_root(cmd); 3528c2ecf20Sopenharmony_ci if (r) 3538c2ecf20Sopenharmony_ci return r; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci r = superblock_lock_zero(cmd, &sblock); 3568c2ecf20Sopenharmony_ci if (r) 3578c2ecf20Sopenharmony_ci return r; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci disk_super = dm_block_data(sblock); 3608c2ecf20Sopenharmony_ci disk_super->flags = 0; 3618c2ecf20Sopenharmony_ci memset(disk_super->uuid, 0, sizeof(disk_super->uuid)); 3628c2ecf20Sopenharmony_ci disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC); 3638c2ecf20Sopenharmony_ci disk_super->version = cpu_to_le32(cmd->version); 3648c2ecf20Sopenharmony_ci memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); 3658c2ecf20Sopenharmony_ci memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); 3668c2ecf20Sopenharmony_ci disk_super->policy_hint_size = cpu_to_le32(0); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci __copy_sm_root(cmd, disk_super); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci disk_super->mapping_root = cpu_to_le64(cmd->root); 3718c2ecf20Sopenharmony_ci disk_super->hint_root = cpu_to_le64(cmd->hint_root); 3728c2ecf20Sopenharmony_ci disk_super->discard_root = cpu_to_le64(cmd->discard_root); 3738c2ecf20Sopenharmony_ci disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size); 3748c2ecf20Sopenharmony_ci disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks)); 3758c2ecf20Sopenharmony_ci disk_super->metadata_block_size = cpu_to_le32(DM_CACHE_METADATA_BLOCK_SIZE); 3768c2ecf20Sopenharmony_ci disk_super->data_block_size = cpu_to_le32(cmd->data_block_size); 3778c2ecf20Sopenharmony_ci disk_super->cache_blocks = cpu_to_le32(0); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci disk_super->read_hits = cpu_to_le32(0); 3808c2ecf20Sopenharmony_ci disk_super->read_misses = cpu_to_le32(0); 3818c2ecf20Sopenharmony_ci disk_super->write_hits = cpu_to_le32(0); 3828c2ecf20Sopenharmony_ci disk_super->write_misses = cpu_to_le32(0); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) 3858c2ecf20Sopenharmony_ci disk_super->dirty_root = cpu_to_le64(cmd->dirty_root); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return dm_tm_commit(cmd->tm, sblock); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int __format_metadata(struct dm_cache_metadata *cmd) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int r; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci r = dm_tm_create_with_sm(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 3958c2ecf20Sopenharmony_ci &cmd->tm, &cmd->metadata_sm); 3968c2ecf20Sopenharmony_ci if (r < 0) { 3978c2ecf20Sopenharmony_ci DMERR("tm_create_with_sm failed"); 3988c2ecf20Sopenharmony_ci return r; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci __setup_mapping_info(cmd); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci r = dm_array_empty(&cmd->info, &cmd->root); 4048c2ecf20Sopenharmony_ci if (r < 0) 4058c2ecf20Sopenharmony_ci goto bad; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) { 4088c2ecf20Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->dirty_info); 4098c2ecf20Sopenharmony_ci r = dm_bitset_empty(&cmd->dirty_info, &cmd->dirty_root); 4108c2ecf20Sopenharmony_ci if (r < 0) 4118c2ecf20Sopenharmony_ci goto bad; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->discard_info); 4158c2ecf20Sopenharmony_ci r = dm_bitset_empty(&cmd->discard_info, &cmd->discard_root); 4168c2ecf20Sopenharmony_ci if (r < 0) 4178c2ecf20Sopenharmony_ci goto bad; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci cmd->discard_block_size = 0; 4208c2ecf20Sopenharmony_ci cmd->discard_nr_blocks = 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci r = __write_initial_superblock(cmd); 4238c2ecf20Sopenharmony_ci if (r) 4248c2ecf20Sopenharmony_ci goto bad; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci cmd->clean_when_opened = true; 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cibad: 4308c2ecf20Sopenharmony_ci dm_tm_destroy(cmd->tm); 4318c2ecf20Sopenharmony_ci dm_sm_destroy(cmd->metadata_sm); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return r; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int __check_incompat_features(struct cache_disk_superblock *disk_super, 4378c2ecf20Sopenharmony_ci struct dm_cache_metadata *cmd) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci uint32_t incompat_flags, features; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci incompat_flags = le32_to_cpu(disk_super->incompat_flags); 4428c2ecf20Sopenharmony_ci features = incompat_flags & ~DM_CACHE_FEATURE_INCOMPAT_SUPP; 4438c2ecf20Sopenharmony_ci if (features) { 4448c2ecf20Sopenharmony_ci DMERR("could not access metadata due to unsupported optional features (%lx).", 4458c2ecf20Sopenharmony_ci (unsigned long)features); 4468c2ecf20Sopenharmony_ci return -EINVAL; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * Check for read-only metadata to skip the following RDWR checks. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci if (get_disk_ro(cmd->bdev->bd_disk)) 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci features = le32_to_cpu(disk_super->compat_ro_flags) & ~DM_CACHE_FEATURE_COMPAT_RO_SUPP; 4568c2ecf20Sopenharmony_ci if (features) { 4578c2ecf20Sopenharmony_ci DMERR("could not access metadata RDWR due to unsupported optional features (%lx).", 4588c2ecf20Sopenharmony_ci (unsigned long)features); 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int __open_metadata(struct dm_cache_metadata *cmd) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int r; 4688c2ecf20Sopenharmony_ci struct dm_block *sblock; 4698c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super; 4708c2ecf20Sopenharmony_ci unsigned long sb_flags; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci r = superblock_read_lock(cmd, &sblock); 4738c2ecf20Sopenharmony_ci if (r < 0) { 4748c2ecf20Sopenharmony_ci DMERR("couldn't read lock superblock"); 4758c2ecf20Sopenharmony_ci return r; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci disk_super = dm_block_data(sblock); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Verify the data block size hasn't changed */ 4818c2ecf20Sopenharmony_ci if (le32_to_cpu(disk_super->data_block_size) != cmd->data_block_size) { 4828c2ecf20Sopenharmony_ci DMERR("changing the data block size (from %u to %llu) is not supported", 4838c2ecf20Sopenharmony_ci le32_to_cpu(disk_super->data_block_size), 4848c2ecf20Sopenharmony_ci (unsigned long long)cmd->data_block_size); 4858c2ecf20Sopenharmony_ci r = -EINVAL; 4868c2ecf20Sopenharmony_ci goto bad; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci r = __check_incompat_features(disk_super, cmd); 4908c2ecf20Sopenharmony_ci if (r < 0) 4918c2ecf20Sopenharmony_ci goto bad; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci r = dm_tm_open_with_sm(cmd->bm, CACHE_SUPERBLOCK_LOCATION, 4948c2ecf20Sopenharmony_ci disk_super->metadata_space_map_root, 4958c2ecf20Sopenharmony_ci sizeof(disk_super->metadata_space_map_root), 4968c2ecf20Sopenharmony_ci &cmd->tm, &cmd->metadata_sm); 4978c2ecf20Sopenharmony_ci if (r < 0) { 4988c2ecf20Sopenharmony_ci DMERR("tm_open_with_sm failed"); 4998c2ecf20Sopenharmony_ci goto bad; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci __setup_mapping_info(cmd); 5038c2ecf20Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->dirty_info); 5048c2ecf20Sopenharmony_ci dm_disk_bitset_init(cmd->tm, &cmd->discard_info); 5058c2ecf20Sopenharmony_ci sb_flags = le32_to_cpu(disk_super->flags); 5068c2ecf20Sopenharmony_ci cmd->clean_when_opened = test_bit(CLEAN_SHUTDOWN, &sb_flags); 5078c2ecf20Sopenharmony_ci dm_bm_unlock(sblock); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cibad: 5128c2ecf20Sopenharmony_ci dm_bm_unlock(sblock); 5138c2ecf20Sopenharmony_ci return r; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int __open_or_format_metadata(struct dm_cache_metadata *cmd, 5178c2ecf20Sopenharmony_ci bool format_device) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci int r; 5208c2ecf20Sopenharmony_ci bool unformatted = false; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci r = __superblock_all_zeroes(cmd->bm, &unformatted); 5238c2ecf20Sopenharmony_ci if (r) 5248c2ecf20Sopenharmony_ci return r; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (unformatted) 5278c2ecf20Sopenharmony_ci return format_device ? __format_metadata(cmd) : -EPERM; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return __open_metadata(cmd); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int __create_persistent_data_objects(struct dm_cache_metadata *cmd, 5338c2ecf20Sopenharmony_ci bool may_format_device) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci int r; 5368c2ecf20Sopenharmony_ci cmd->bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, 5378c2ecf20Sopenharmony_ci CACHE_MAX_CONCURRENT_LOCKS); 5388c2ecf20Sopenharmony_ci if (IS_ERR(cmd->bm)) { 5398c2ecf20Sopenharmony_ci DMERR("could not create block manager"); 5408c2ecf20Sopenharmony_ci r = PTR_ERR(cmd->bm); 5418c2ecf20Sopenharmony_ci cmd->bm = NULL; 5428c2ecf20Sopenharmony_ci return r; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci r = __open_or_format_metadata(cmd, may_format_device); 5468c2ecf20Sopenharmony_ci if (r) { 5478c2ecf20Sopenharmony_ci dm_block_manager_destroy(cmd->bm); 5488c2ecf20Sopenharmony_ci cmd->bm = NULL; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return r; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic void __destroy_persistent_data_objects(struct dm_cache_metadata *cmd, 5558c2ecf20Sopenharmony_ci bool destroy_bm) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci dm_sm_destroy(cmd->metadata_sm); 5588c2ecf20Sopenharmony_ci dm_tm_destroy(cmd->tm); 5598c2ecf20Sopenharmony_ci if (destroy_bm) 5608c2ecf20Sopenharmony_ci dm_block_manager_destroy(cmd->bm); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_citypedef unsigned long (*flags_mutator)(unsigned long); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void update_flags(struct cache_disk_superblock *disk_super, 5668c2ecf20Sopenharmony_ci flags_mutator mutator) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci uint32_t sb_flags = mutator(le32_to_cpu(disk_super->flags)); 5698c2ecf20Sopenharmony_ci disk_super->flags = cpu_to_le32(sb_flags); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic unsigned long set_clean_shutdown(unsigned long flags) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci set_bit(CLEAN_SHUTDOWN, &flags); 5758c2ecf20Sopenharmony_ci return flags; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic unsigned long clear_clean_shutdown(unsigned long flags) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci clear_bit(CLEAN_SHUTDOWN, &flags); 5818c2ecf20Sopenharmony_ci return flags; 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic void read_superblock_fields(struct dm_cache_metadata *cmd, 5858c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci cmd->version = le32_to_cpu(disk_super->version); 5888c2ecf20Sopenharmony_ci cmd->flags = le32_to_cpu(disk_super->flags); 5898c2ecf20Sopenharmony_ci cmd->root = le64_to_cpu(disk_super->mapping_root); 5908c2ecf20Sopenharmony_ci cmd->hint_root = le64_to_cpu(disk_super->hint_root); 5918c2ecf20Sopenharmony_ci cmd->discard_root = le64_to_cpu(disk_super->discard_root); 5928c2ecf20Sopenharmony_ci cmd->discard_block_size = le64_to_cpu(disk_super->discard_block_size); 5938c2ecf20Sopenharmony_ci cmd->discard_nr_blocks = to_dblock(le64_to_cpu(disk_super->discard_nr_blocks)); 5948c2ecf20Sopenharmony_ci cmd->data_block_size = le32_to_cpu(disk_super->data_block_size); 5958c2ecf20Sopenharmony_ci cmd->cache_blocks = to_cblock(le32_to_cpu(disk_super->cache_blocks)); 5968c2ecf20Sopenharmony_ci strncpy(cmd->policy_name, disk_super->policy_name, sizeof(cmd->policy_name)); 5978c2ecf20Sopenharmony_ci cmd->policy_version[0] = le32_to_cpu(disk_super->policy_version[0]); 5988c2ecf20Sopenharmony_ci cmd->policy_version[1] = le32_to_cpu(disk_super->policy_version[1]); 5998c2ecf20Sopenharmony_ci cmd->policy_version[2] = le32_to_cpu(disk_super->policy_version[2]); 6008c2ecf20Sopenharmony_ci cmd->policy_hint_size = le32_to_cpu(disk_super->policy_hint_size); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci cmd->stats.read_hits = le32_to_cpu(disk_super->read_hits); 6038c2ecf20Sopenharmony_ci cmd->stats.read_misses = le32_to_cpu(disk_super->read_misses); 6048c2ecf20Sopenharmony_ci cmd->stats.write_hits = le32_to_cpu(disk_super->write_hits); 6058c2ecf20Sopenharmony_ci cmd->stats.write_misses = le32_to_cpu(disk_super->write_misses); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) 6088c2ecf20Sopenharmony_ci cmd->dirty_root = le64_to_cpu(disk_super->dirty_root); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci cmd->changed = false; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* 6148c2ecf20Sopenharmony_ci * The mutator updates the superblock flags. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_cistatic int __begin_transaction_flags(struct dm_cache_metadata *cmd, 6178c2ecf20Sopenharmony_ci flags_mutator mutator) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci int r; 6208c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super; 6218c2ecf20Sopenharmony_ci struct dm_block *sblock; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci r = superblock_lock(cmd, &sblock); 6248c2ecf20Sopenharmony_ci if (r) 6258c2ecf20Sopenharmony_ci return r; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci disk_super = dm_block_data(sblock); 6288c2ecf20Sopenharmony_ci update_flags(disk_super, mutator); 6298c2ecf20Sopenharmony_ci read_superblock_fields(cmd, disk_super); 6308c2ecf20Sopenharmony_ci dm_bm_unlock(sblock); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return dm_bm_flush(cmd->bm); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int __begin_transaction(struct dm_cache_metadata *cmd) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci int r; 6388c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super; 6398c2ecf20Sopenharmony_ci struct dm_block *sblock; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* 6428c2ecf20Sopenharmony_ci * We re-read the superblock every time. Shouldn't need to do this 6438c2ecf20Sopenharmony_ci * really. 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_ci r = superblock_read_lock(cmd, &sblock); 6468c2ecf20Sopenharmony_ci if (r) 6478c2ecf20Sopenharmony_ci return r; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci disk_super = dm_block_data(sblock); 6508c2ecf20Sopenharmony_ci read_superblock_fields(cmd, disk_super); 6518c2ecf20Sopenharmony_ci dm_bm_unlock(sblock); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int __commit_transaction(struct dm_cache_metadata *cmd, 6578c2ecf20Sopenharmony_ci flags_mutator mutator) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci int r; 6608c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super; 6618c2ecf20Sopenharmony_ci struct dm_block *sblock; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* 6648c2ecf20Sopenharmony_ci * We need to know if the cache_disk_superblock exceeds a 512-byte sector. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cache_disk_superblock) > 512); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) { 6698c2ecf20Sopenharmony_ci r = dm_bitset_flush(&cmd->dirty_info, cmd->dirty_root, 6708c2ecf20Sopenharmony_ci &cmd->dirty_root); 6718c2ecf20Sopenharmony_ci if (r) 6728c2ecf20Sopenharmony_ci return r; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root, 6768c2ecf20Sopenharmony_ci &cmd->discard_root); 6778c2ecf20Sopenharmony_ci if (r) 6788c2ecf20Sopenharmony_ci return r; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci r = dm_tm_pre_commit(cmd->tm); 6818c2ecf20Sopenharmony_ci if (r < 0) 6828c2ecf20Sopenharmony_ci return r; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci r = __save_sm_root(cmd); 6858c2ecf20Sopenharmony_ci if (r) 6868c2ecf20Sopenharmony_ci return r; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci r = superblock_lock(cmd, &sblock); 6898c2ecf20Sopenharmony_ci if (r) 6908c2ecf20Sopenharmony_ci return r; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci disk_super = dm_block_data(sblock); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci disk_super->flags = cpu_to_le32(cmd->flags); 6958c2ecf20Sopenharmony_ci if (mutator) 6968c2ecf20Sopenharmony_ci update_flags(disk_super, mutator); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci disk_super->mapping_root = cpu_to_le64(cmd->root); 6998c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) 7008c2ecf20Sopenharmony_ci disk_super->dirty_root = cpu_to_le64(cmd->dirty_root); 7018c2ecf20Sopenharmony_ci disk_super->hint_root = cpu_to_le64(cmd->hint_root); 7028c2ecf20Sopenharmony_ci disk_super->discard_root = cpu_to_le64(cmd->discard_root); 7038c2ecf20Sopenharmony_ci disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size); 7048c2ecf20Sopenharmony_ci disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks)); 7058c2ecf20Sopenharmony_ci disk_super->cache_blocks = cpu_to_le32(from_cblock(cmd->cache_blocks)); 7068c2ecf20Sopenharmony_ci strncpy(disk_super->policy_name, cmd->policy_name, sizeof(disk_super->policy_name)); 7078c2ecf20Sopenharmony_ci disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]); 7088c2ecf20Sopenharmony_ci disk_super->policy_version[1] = cpu_to_le32(cmd->policy_version[1]); 7098c2ecf20Sopenharmony_ci disk_super->policy_version[2] = cpu_to_le32(cmd->policy_version[2]); 7108c2ecf20Sopenharmony_ci disk_super->policy_hint_size = cpu_to_le32(cmd->policy_hint_size); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits); 7138c2ecf20Sopenharmony_ci disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); 7148c2ecf20Sopenharmony_ci disk_super->write_hits = cpu_to_le32(cmd->stats.write_hits); 7158c2ecf20Sopenharmony_ci disk_super->write_misses = cpu_to_le32(cmd->stats.write_misses); 7168c2ecf20Sopenharmony_ci __copy_sm_root(cmd, disk_super); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci return dm_tm_commit(cmd->tm, sblock); 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci/* 7248c2ecf20Sopenharmony_ci * The mappings are held in a dm-array that has 64-bit values stored in 7258c2ecf20Sopenharmony_ci * little-endian format. The index is the cblock, the high 48bits of the 7268c2ecf20Sopenharmony_ci * value are the oblock and the low 16 bit the flags. 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_ci#define FLAGS_MASK ((1 << 16) - 1) 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic __le64 pack_value(dm_oblock_t block, unsigned flags) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci uint64_t value = from_oblock(block); 7338c2ecf20Sopenharmony_ci value <<= 16; 7348c2ecf20Sopenharmony_ci value = value | (flags & FLAGS_MASK); 7358c2ecf20Sopenharmony_ci return cpu_to_le64(value); 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci uint64_t value = le64_to_cpu(value_le); 7418c2ecf20Sopenharmony_ci uint64_t b = value >> 16; 7428c2ecf20Sopenharmony_ci *block = to_oblock(b); 7438c2ecf20Sopenharmony_ci *flags = value & FLAGS_MASK; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic struct dm_cache_metadata *metadata_open(struct block_device *bdev, 7498c2ecf20Sopenharmony_ci sector_t data_block_size, 7508c2ecf20Sopenharmony_ci bool may_format_device, 7518c2ecf20Sopenharmony_ci size_t policy_hint_size, 7528c2ecf20Sopenharmony_ci unsigned metadata_version) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci int r; 7558c2ecf20Sopenharmony_ci struct dm_cache_metadata *cmd; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 7588c2ecf20Sopenharmony_ci if (!cmd) { 7598c2ecf20Sopenharmony_ci DMERR("could not allocate metadata struct"); 7608c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci cmd->version = metadata_version; 7648c2ecf20Sopenharmony_ci refcount_set(&cmd->ref_count, 1); 7658c2ecf20Sopenharmony_ci init_rwsem(&cmd->root_lock); 7668c2ecf20Sopenharmony_ci cmd->bdev = bdev; 7678c2ecf20Sopenharmony_ci cmd->data_block_size = data_block_size; 7688c2ecf20Sopenharmony_ci cmd->cache_blocks = 0; 7698c2ecf20Sopenharmony_ci cmd->policy_hint_size = policy_hint_size; 7708c2ecf20Sopenharmony_ci cmd->changed = true; 7718c2ecf20Sopenharmony_ci cmd->fail_io = false; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci r = __create_persistent_data_objects(cmd, may_format_device); 7748c2ecf20Sopenharmony_ci if (r) { 7758c2ecf20Sopenharmony_ci kfree(cmd); 7768c2ecf20Sopenharmony_ci return ERR_PTR(r); 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci r = __begin_transaction_flags(cmd, clear_clean_shutdown); 7808c2ecf20Sopenharmony_ci if (r < 0) { 7818c2ecf20Sopenharmony_ci dm_cache_metadata_close(cmd); 7828c2ecf20Sopenharmony_ci return ERR_PTR(r); 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci return cmd; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci/* 7898c2ecf20Sopenharmony_ci * We keep a little list of ref counted metadata objects to prevent two 7908c2ecf20Sopenharmony_ci * different target instances creating separate bufio instances. This is 7918c2ecf20Sopenharmony_ci * an issue if a table is reloaded before the suspend. 7928c2ecf20Sopenharmony_ci */ 7938c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(table_lock); 7948c2ecf20Sopenharmony_cistatic LIST_HEAD(table); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic struct dm_cache_metadata *lookup(struct block_device *bdev) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct dm_cache_metadata *cmd; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci list_for_each_entry(cmd, &table, list) 8018c2ecf20Sopenharmony_ci if (cmd->bdev == bdev) { 8028c2ecf20Sopenharmony_ci refcount_inc(&cmd->ref_count); 8038c2ecf20Sopenharmony_ci return cmd; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return NULL; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic struct dm_cache_metadata *lookup_or_open(struct block_device *bdev, 8108c2ecf20Sopenharmony_ci sector_t data_block_size, 8118c2ecf20Sopenharmony_ci bool may_format_device, 8128c2ecf20Sopenharmony_ci size_t policy_hint_size, 8138c2ecf20Sopenharmony_ci unsigned metadata_version) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct dm_cache_metadata *cmd, *cmd2; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci mutex_lock(&table_lock); 8188c2ecf20Sopenharmony_ci cmd = lookup(bdev); 8198c2ecf20Sopenharmony_ci mutex_unlock(&table_lock); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (cmd) 8228c2ecf20Sopenharmony_ci return cmd; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci cmd = metadata_open(bdev, data_block_size, may_format_device, 8258c2ecf20Sopenharmony_ci policy_hint_size, metadata_version); 8268c2ecf20Sopenharmony_ci if (!IS_ERR(cmd)) { 8278c2ecf20Sopenharmony_ci mutex_lock(&table_lock); 8288c2ecf20Sopenharmony_ci cmd2 = lookup(bdev); 8298c2ecf20Sopenharmony_ci if (cmd2) { 8308c2ecf20Sopenharmony_ci mutex_unlock(&table_lock); 8318c2ecf20Sopenharmony_ci __destroy_persistent_data_objects(cmd, true); 8328c2ecf20Sopenharmony_ci kfree(cmd); 8338c2ecf20Sopenharmony_ci return cmd2; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci list_add(&cmd->list, &table); 8368c2ecf20Sopenharmony_ci mutex_unlock(&table_lock); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return cmd; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci if (cmd->data_block_size != data_block_size) { 8458c2ecf20Sopenharmony_ci DMERR("data_block_size (%llu) different from that in metadata (%llu)", 8468c2ecf20Sopenharmony_ci (unsigned long long) data_block_size, 8478c2ecf20Sopenharmony_ci (unsigned long long) cmd->data_block_size); 8488c2ecf20Sopenharmony_ci return false; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci return true; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistruct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev, 8558c2ecf20Sopenharmony_ci sector_t data_block_size, 8568c2ecf20Sopenharmony_ci bool may_format_device, 8578c2ecf20Sopenharmony_ci size_t policy_hint_size, 8588c2ecf20Sopenharmony_ci unsigned metadata_version) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, may_format_device, 8618c2ecf20Sopenharmony_ci policy_hint_size, metadata_version); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) { 8648c2ecf20Sopenharmony_ci dm_cache_metadata_close(cmd); 8658c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return cmd; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_civoid dm_cache_metadata_close(struct dm_cache_metadata *cmd) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&cmd->ref_count)) { 8748c2ecf20Sopenharmony_ci mutex_lock(&table_lock); 8758c2ecf20Sopenharmony_ci list_del(&cmd->list); 8768c2ecf20Sopenharmony_ci mutex_unlock(&table_lock); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (!cmd->fail_io) 8798c2ecf20Sopenharmony_ci __destroy_persistent_data_objects(cmd, true); 8808c2ecf20Sopenharmony_ci kfree(cmd); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci/* 8858c2ecf20Sopenharmony_ci * Checks that the given cache block is either unmapped or clean. 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_cistatic int block_clean_combined_dirty(struct dm_cache_metadata *cmd, dm_cblock_t b, 8888c2ecf20Sopenharmony_ci bool *result) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci int r; 8918c2ecf20Sopenharmony_ci __le64 value; 8928c2ecf20Sopenharmony_ci dm_oblock_t ob; 8938c2ecf20Sopenharmony_ci unsigned flags; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value); 8968c2ecf20Sopenharmony_ci if (r) 8978c2ecf20Sopenharmony_ci return r; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci unpack_value(value, &ob, &flags); 9008c2ecf20Sopenharmony_ci *result = !((flags & M_VALID) && (flags & M_DIRTY)); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic int blocks_are_clean_combined_dirty(struct dm_cache_metadata *cmd, 9068c2ecf20Sopenharmony_ci dm_cblock_t begin, dm_cblock_t end, 9078c2ecf20Sopenharmony_ci bool *result) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci int r; 9108c2ecf20Sopenharmony_ci *result = true; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci while (begin != end) { 9138c2ecf20Sopenharmony_ci r = block_clean_combined_dirty(cmd, begin, result); 9148c2ecf20Sopenharmony_ci if (r) { 9158c2ecf20Sopenharmony_ci DMERR("block_clean_combined_dirty failed"); 9168c2ecf20Sopenharmony_ci return r; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (!*result) { 9208c2ecf20Sopenharmony_ci DMERR("cache block %llu is dirty", 9218c2ecf20Sopenharmony_ci (unsigned long long) from_cblock(begin)); 9228c2ecf20Sopenharmony_ci return 0; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci begin = to_cblock(from_cblock(begin) + 1); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic int blocks_are_clean_separate_dirty(struct dm_cache_metadata *cmd, 9328c2ecf20Sopenharmony_ci dm_cblock_t begin, dm_cblock_t end, 9338c2ecf20Sopenharmony_ci bool *result) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci int r; 9368c2ecf20Sopenharmony_ci bool dirty_flag; 9378c2ecf20Sopenharmony_ci *result = true; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (from_cblock(cmd->cache_blocks) == 0) 9408c2ecf20Sopenharmony_ci /* Nothing to do */ 9418c2ecf20Sopenharmony_ci return 0; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci r = dm_bitset_cursor_begin(&cmd->dirty_info, cmd->dirty_root, 9448c2ecf20Sopenharmony_ci from_cblock(cmd->cache_blocks), &cmd->dirty_cursor); 9458c2ecf20Sopenharmony_ci if (r) { 9468c2ecf20Sopenharmony_ci DMERR("%s: dm_bitset_cursor_begin for dirty failed", __func__); 9478c2ecf20Sopenharmony_ci return r; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci r = dm_bitset_cursor_skip(&cmd->dirty_cursor, from_cblock(begin)); 9518c2ecf20Sopenharmony_ci if (r) { 9528c2ecf20Sopenharmony_ci DMERR("%s: dm_bitset_cursor_skip for dirty failed", __func__); 9538c2ecf20Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 9548c2ecf20Sopenharmony_ci return r; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci while (begin != end) { 9588c2ecf20Sopenharmony_ci /* 9598c2ecf20Sopenharmony_ci * We assume that unmapped blocks have their dirty bit 9608c2ecf20Sopenharmony_ci * cleared. 9618c2ecf20Sopenharmony_ci */ 9628c2ecf20Sopenharmony_ci dirty_flag = dm_bitset_cursor_get_value(&cmd->dirty_cursor); 9638c2ecf20Sopenharmony_ci if (dirty_flag) { 9648c2ecf20Sopenharmony_ci DMERR("%s: cache block %llu is dirty", __func__, 9658c2ecf20Sopenharmony_ci (unsigned long long) from_cblock(begin)); 9668c2ecf20Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 9678c2ecf20Sopenharmony_ci *result = false; 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci begin = to_cblock(from_cblock(begin) + 1); 9728c2ecf20Sopenharmony_ci if (begin == end) 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci r = dm_bitset_cursor_next(&cmd->dirty_cursor); 9768c2ecf20Sopenharmony_ci if (r) { 9778c2ecf20Sopenharmony_ci DMERR("%s: dm_bitset_cursor_next for dirty failed", __func__); 9788c2ecf20Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 9798c2ecf20Sopenharmony_ci return r; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci return 0; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd, 9898c2ecf20Sopenharmony_ci dm_cblock_t begin, dm_cblock_t end, 9908c2ecf20Sopenharmony_ci bool *result) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) 9938c2ecf20Sopenharmony_ci return blocks_are_clean_separate_dirty(cmd, begin, end, result); 9948c2ecf20Sopenharmony_ci else 9958c2ecf20Sopenharmony_ci return blocks_are_clean_combined_dirty(cmd, begin, end, result); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic bool cmd_write_lock(struct dm_cache_metadata *cmd) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci down_write(&cmd->root_lock); 10018c2ecf20Sopenharmony_ci if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { 10028c2ecf20Sopenharmony_ci up_write(&cmd->root_lock); 10038c2ecf20Sopenharmony_ci return false; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci return true; 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci#define WRITE_LOCK(cmd) \ 10098c2ecf20Sopenharmony_ci do { \ 10108c2ecf20Sopenharmony_ci if (!cmd_write_lock((cmd))) \ 10118c2ecf20Sopenharmony_ci return -EINVAL; \ 10128c2ecf20Sopenharmony_ci } while(0) 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci#define WRITE_LOCK_VOID(cmd) \ 10158c2ecf20Sopenharmony_ci do { \ 10168c2ecf20Sopenharmony_ci if (!cmd_write_lock((cmd))) \ 10178c2ecf20Sopenharmony_ci return; \ 10188c2ecf20Sopenharmony_ci } while(0) 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci#define WRITE_UNLOCK(cmd) \ 10218c2ecf20Sopenharmony_ci up_write(&(cmd)->root_lock) 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic bool cmd_read_lock(struct dm_cache_metadata *cmd) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci down_read(&cmd->root_lock); 10268c2ecf20Sopenharmony_ci if (cmd->fail_io) { 10278c2ecf20Sopenharmony_ci up_read(&cmd->root_lock); 10288c2ecf20Sopenharmony_ci return false; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci return true; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci#define READ_LOCK(cmd) \ 10348c2ecf20Sopenharmony_ci do { \ 10358c2ecf20Sopenharmony_ci if (!cmd_read_lock((cmd))) \ 10368c2ecf20Sopenharmony_ci return -EINVAL; \ 10378c2ecf20Sopenharmony_ci } while(0) 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci#define READ_LOCK_VOID(cmd) \ 10408c2ecf20Sopenharmony_ci do { \ 10418c2ecf20Sopenharmony_ci if (!cmd_read_lock((cmd))) \ 10428c2ecf20Sopenharmony_ci return; \ 10438c2ecf20Sopenharmony_ci } while(0) 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci#define READ_UNLOCK(cmd) \ 10468c2ecf20Sopenharmony_ci up_read(&(cmd)->root_lock) 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ciint dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci int r; 10518c2ecf20Sopenharmony_ci bool clean; 10528c2ecf20Sopenharmony_ci __le64 null_mapping = pack_value(0, 0); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 10558c2ecf20Sopenharmony_ci __dm_bless_for_disk(&null_mapping); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (from_cblock(new_cache_size) < from_cblock(cmd->cache_blocks)) { 10588c2ecf20Sopenharmony_ci r = blocks_are_unmapped_or_clean(cmd, new_cache_size, cmd->cache_blocks, &clean); 10598c2ecf20Sopenharmony_ci if (r) { 10608c2ecf20Sopenharmony_ci __dm_unbless_for_disk(&null_mapping); 10618c2ecf20Sopenharmony_ci goto out; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (!clean) { 10658c2ecf20Sopenharmony_ci DMERR("unable to shrink cache due to dirty blocks"); 10668c2ecf20Sopenharmony_ci r = -EINVAL; 10678c2ecf20Sopenharmony_ci __dm_unbless_for_disk(&null_mapping); 10688c2ecf20Sopenharmony_ci goto out; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks), 10738c2ecf20Sopenharmony_ci from_cblock(new_cache_size), 10748c2ecf20Sopenharmony_ci &null_mapping, &cmd->root); 10758c2ecf20Sopenharmony_ci if (r) 10768c2ecf20Sopenharmony_ci goto out; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) { 10798c2ecf20Sopenharmony_ci r = dm_bitset_resize(&cmd->dirty_info, cmd->dirty_root, 10808c2ecf20Sopenharmony_ci from_cblock(cmd->cache_blocks), from_cblock(new_cache_size), 10818c2ecf20Sopenharmony_ci false, &cmd->dirty_root); 10828c2ecf20Sopenharmony_ci if (r) 10838c2ecf20Sopenharmony_ci goto out; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci cmd->cache_blocks = new_cache_size; 10878c2ecf20Sopenharmony_ci cmd->changed = true; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ciout: 10908c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci return r; 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ciint dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd, 10968c2ecf20Sopenharmony_ci sector_t discard_block_size, 10978c2ecf20Sopenharmony_ci dm_dblock_t new_nr_entries) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci int r; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 11028c2ecf20Sopenharmony_ci r = dm_bitset_resize(&cmd->discard_info, 11038c2ecf20Sopenharmony_ci cmd->discard_root, 11048c2ecf20Sopenharmony_ci from_dblock(cmd->discard_nr_blocks), 11058c2ecf20Sopenharmony_ci from_dblock(new_nr_entries), 11068c2ecf20Sopenharmony_ci false, &cmd->discard_root); 11078c2ecf20Sopenharmony_ci if (!r) { 11088c2ecf20Sopenharmony_ci cmd->discard_block_size = discard_block_size; 11098c2ecf20Sopenharmony_ci cmd->discard_nr_blocks = new_nr_entries; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci cmd->changed = true; 11138c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci return r; 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistatic int __set_discard(struct dm_cache_metadata *cmd, dm_dblock_t b) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci return dm_bitset_set_bit(&cmd->discard_info, cmd->discard_root, 11218c2ecf20Sopenharmony_ci from_dblock(b), &cmd->discard_root); 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic int __clear_discard(struct dm_cache_metadata *cmd, dm_dblock_t b) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci return dm_bitset_clear_bit(&cmd->discard_info, cmd->discard_root, 11278c2ecf20Sopenharmony_ci from_dblock(b), &cmd->discard_root); 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic int __discard(struct dm_cache_metadata *cmd, 11318c2ecf20Sopenharmony_ci dm_dblock_t dblock, bool discard) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci int r; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci r = (discard ? __set_discard : __clear_discard)(cmd, dblock); 11368c2ecf20Sopenharmony_ci if (r) 11378c2ecf20Sopenharmony_ci return r; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci cmd->changed = true; 11408c2ecf20Sopenharmony_ci return 0; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ciint dm_cache_set_discard(struct dm_cache_metadata *cmd, 11448c2ecf20Sopenharmony_ci dm_dblock_t dblock, bool discard) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci int r; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 11498c2ecf20Sopenharmony_ci r = __discard(cmd, dblock, discard); 11508c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci return r; 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic int __load_discards(struct dm_cache_metadata *cmd, 11568c2ecf20Sopenharmony_ci load_discard_fn fn, void *context) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci int r = 0; 11598c2ecf20Sopenharmony_ci uint32_t b; 11608c2ecf20Sopenharmony_ci struct dm_bitset_cursor c; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (from_dblock(cmd->discard_nr_blocks) == 0) 11638c2ecf20Sopenharmony_ci /* nothing to do */ 11648c2ecf20Sopenharmony_ci return 0; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (cmd->clean_when_opened) { 11678c2ecf20Sopenharmony_ci r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root, &cmd->discard_root); 11688c2ecf20Sopenharmony_ci if (r) 11698c2ecf20Sopenharmony_ci return r; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci r = dm_bitset_cursor_begin(&cmd->discard_info, cmd->discard_root, 11728c2ecf20Sopenharmony_ci from_dblock(cmd->discard_nr_blocks), &c); 11738c2ecf20Sopenharmony_ci if (r) 11748c2ecf20Sopenharmony_ci return r; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci for (b = 0; ; b++) { 11778c2ecf20Sopenharmony_ci r = fn(context, cmd->discard_block_size, to_dblock(b), 11788c2ecf20Sopenharmony_ci dm_bitset_cursor_get_value(&c)); 11798c2ecf20Sopenharmony_ci if (r) 11808c2ecf20Sopenharmony_ci break; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (b >= (from_dblock(cmd->discard_nr_blocks) - 1)) 11838c2ecf20Sopenharmony_ci break; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci r = dm_bitset_cursor_next(&c); 11868c2ecf20Sopenharmony_ci if (r) 11878c2ecf20Sopenharmony_ci break; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci dm_bitset_cursor_end(&c); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci } else { 11938c2ecf20Sopenharmony_ci for (b = 0; b < from_dblock(cmd->discard_nr_blocks); b++) { 11948c2ecf20Sopenharmony_ci r = fn(context, cmd->discard_block_size, to_dblock(b), false); 11958c2ecf20Sopenharmony_ci if (r) 11968c2ecf20Sopenharmony_ci return r; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci return r; 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ciint dm_cache_load_discards(struct dm_cache_metadata *cmd, 12048c2ecf20Sopenharmony_ci load_discard_fn fn, void *context) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci int r; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci READ_LOCK(cmd); 12098c2ecf20Sopenharmony_ci r = __load_discards(cmd, fn, context); 12108c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return r; 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ciint dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci READ_LOCK(cmd); 12188c2ecf20Sopenharmony_ci *result = cmd->cache_blocks; 12198c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci return 0; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci int r; 12278c2ecf20Sopenharmony_ci __le64 value = pack_value(0, 0); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci __dm_bless_for_disk(&value); 12308c2ecf20Sopenharmony_ci r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), 12318c2ecf20Sopenharmony_ci &value, &cmd->root); 12328c2ecf20Sopenharmony_ci if (r) 12338c2ecf20Sopenharmony_ci return r; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci cmd->changed = true; 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ciint dm_cache_remove_mapping(struct dm_cache_metadata *cmd, dm_cblock_t cblock) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci int r; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 12448c2ecf20Sopenharmony_ci r = __remove(cmd, cblock); 12458c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci return r; 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic int __insert(struct dm_cache_metadata *cmd, 12518c2ecf20Sopenharmony_ci dm_cblock_t cblock, dm_oblock_t oblock) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci int r; 12548c2ecf20Sopenharmony_ci __le64 value = pack_value(oblock, M_VALID); 12558c2ecf20Sopenharmony_ci __dm_bless_for_disk(&value); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), 12588c2ecf20Sopenharmony_ci &value, &cmd->root); 12598c2ecf20Sopenharmony_ci if (r) 12608c2ecf20Sopenharmony_ci return r; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci cmd->changed = true; 12638c2ecf20Sopenharmony_ci return 0; 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ciint dm_cache_insert_mapping(struct dm_cache_metadata *cmd, 12678c2ecf20Sopenharmony_ci dm_cblock_t cblock, dm_oblock_t oblock) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci int r; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 12728c2ecf20Sopenharmony_ci r = __insert(cmd, cblock, oblock); 12738c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return r; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistruct thunk { 12798c2ecf20Sopenharmony_ci load_mapping_fn fn; 12808c2ecf20Sopenharmony_ci void *context; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci struct dm_cache_metadata *cmd; 12838c2ecf20Sopenharmony_ci bool respect_dirty_flags; 12848c2ecf20Sopenharmony_ci bool hints_valid; 12858c2ecf20Sopenharmony_ci}; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic bool policy_unchanged(struct dm_cache_metadata *cmd, 12888c2ecf20Sopenharmony_ci struct dm_cache_policy *policy) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci const char *policy_name = dm_cache_policy_get_name(policy); 12918c2ecf20Sopenharmony_ci const unsigned *policy_version = dm_cache_policy_get_version(policy); 12928c2ecf20Sopenharmony_ci size_t policy_hint_size = dm_cache_policy_get_hint_size(policy); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* 12958c2ecf20Sopenharmony_ci * Ensure policy names match. 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci if (strncmp(cmd->policy_name, policy_name, sizeof(cmd->policy_name))) 12988c2ecf20Sopenharmony_ci return false; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* 13018c2ecf20Sopenharmony_ci * Ensure policy major versions match. 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci if (cmd->policy_version[0] != policy_version[0]) 13048c2ecf20Sopenharmony_ci return false; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* 13078c2ecf20Sopenharmony_ci * Ensure policy hint sizes match. 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_ci if (cmd->policy_hint_size != policy_hint_size) 13108c2ecf20Sopenharmony_ci return false; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci return true; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic bool hints_array_initialized(struct dm_cache_metadata *cmd) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci return cmd->hint_root && cmd->policy_hint_size; 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic bool hints_array_available(struct dm_cache_metadata *cmd, 13218c2ecf20Sopenharmony_ci struct dm_cache_policy *policy) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci return cmd->clean_when_opened && policy_unchanged(cmd, policy) && 13248c2ecf20Sopenharmony_ci hints_array_initialized(cmd); 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic int __load_mapping_v1(struct dm_cache_metadata *cmd, 13288c2ecf20Sopenharmony_ci uint64_t cb, bool hints_valid, 13298c2ecf20Sopenharmony_ci struct dm_array_cursor *mapping_cursor, 13308c2ecf20Sopenharmony_ci struct dm_array_cursor *hint_cursor, 13318c2ecf20Sopenharmony_ci load_mapping_fn fn, void *context) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci int r = 0; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci __le64 mapping; 13368c2ecf20Sopenharmony_ci __le32 hint = 0; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci __le64 *mapping_value_le; 13398c2ecf20Sopenharmony_ci __le32 *hint_value_le; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci dm_oblock_t oblock; 13428c2ecf20Sopenharmony_ci unsigned flags; 13438c2ecf20Sopenharmony_ci bool dirty = true; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le); 13468c2ecf20Sopenharmony_ci memcpy(&mapping, mapping_value_le, sizeof(mapping)); 13478c2ecf20Sopenharmony_ci unpack_value(mapping, &oblock, &flags); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (flags & M_VALID) { 13508c2ecf20Sopenharmony_ci if (hints_valid) { 13518c2ecf20Sopenharmony_ci dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le); 13528c2ecf20Sopenharmony_ci memcpy(&hint, hint_value_le, sizeof(hint)); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci if (cmd->clean_when_opened) 13558c2ecf20Sopenharmony_ci dirty = flags & M_DIRTY; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci r = fn(context, oblock, to_cblock(cb), dirty, 13588c2ecf20Sopenharmony_ci le32_to_cpu(hint), hints_valid); 13598c2ecf20Sopenharmony_ci if (r) { 13608c2ecf20Sopenharmony_ci DMERR("policy couldn't load cache block %llu", 13618c2ecf20Sopenharmony_ci (unsigned long long) from_cblock(to_cblock(cb))); 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci return r; 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic int __load_mapping_v2(struct dm_cache_metadata *cmd, 13698c2ecf20Sopenharmony_ci uint64_t cb, bool hints_valid, 13708c2ecf20Sopenharmony_ci struct dm_array_cursor *mapping_cursor, 13718c2ecf20Sopenharmony_ci struct dm_array_cursor *hint_cursor, 13728c2ecf20Sopenharmony_ci struct dm_bitset_cursor *dirty_cursor, 13738c2ecf20Sopenharmony_ci load_mapping_fn fn, void *context) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci int r = 0; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci __le64 mapping; 13788c2ecf20Sopenharmony_ci __le32 hint = 0; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci __le64 *mapping_value_le; 13818c2ecf20Sopenharmony_ci __le32 *hint_value_le; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci dm_oblock_t oblock; 13848c2ecf20Sopenharmony_ci unsigned flags; 13858c2ecf20Sopenharmony_ci bool dirty = true; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le); 13888c2ecf20Sopenharmony_ci memcpy(&mapping, mapping_value_le, sizeof(mapping)); 13898c2ecf20Sopenharmony_ci unpack_value(mapping, &oblock, &flags); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (flags & M_VALID) { 13928c2ecf20Sopenharmony_ci if (hints_valid) { 13938c2ecf20Sopenharmony_ci dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le); 13948c2ecf20Sopenharmony_ci memcpy(&hint, hint_value_le, sizeof(hint)); 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci if (cmd->clean_when_opened) 13978c2ecf20Sopenharmony_ci dirty = dm_bitset_cursor_get_value(dirty_cursor); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci r = fn(context, oblock, to_cblock(cb), dirty, 14008c2ecf20Sopenharmony_ci le32_to_cpu(hint), hints_valid); 14018c2ecf20Sopenharmony_ci if (r) { 14028c2ecf20Sopenharmony_ci DMERR("policy couldn't load cache block %llu", 14038c2ecf20Sopenharmony_ci (unsigned long long) from_cblock(to_cblock(cb))); 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci return r; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic int __load_mappings(struct dm_cache_metadata *cmd, 14118c2ecf20Sopenharmony_ci struct dm_cache_policy *policy, 14128c2ecf20Sopenharmony_ci load_mapping_fn fn, void *context) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci int r; 14158c2ecf20Sopenharmony_ci uint64_t cb; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci bool hints_valid = hints_array_available(cmd, policy); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (from_cblock(cmd->cache_blocks) == 0) 14208c2ecf20Sopenharmony_ci /* Nothing to do */ 14218c2ecf20Sopenharmony_ci return 0; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci r = dm_array_cursor_begin(&cmd->info, cmd->root, &cmd->mapping_cursor); 14248c2ecf20Sopenharmony_ci if (r) 14258c2ecf20Sopenharmony_ci return r; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (hints_valid) { 14288c2ecf20Sopenharmony_ci r = dm_array_cursor_begin(&cmd->hint_info, cmd->hint_root, &cmd->hint_cursor); 14298c2ecf20Sopenharmony_ci if (r) { 14308c2ecf20Sopenharmony_ci dm_array_cursor_end(&cmd->mapping_cursor); 14318c2ecf20Sopenharmony_ci return r; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) { 14368c2ecf20Sopenharmony_ci r = dm_bitset_cursor_begin(&cmd->dirty_info, cmd->dirty_root, 14378c2ecf20Sopenharmony_ci from_cblock(cmd->cache_blocks), 14388c2ecf20Sopenharmony_ci &cmd->dirty_cursor); 14398c2ecf20Sopenharmony_ci if (r) { 14408c2ecf20Sopenharmony_ci dm_array_cursor_end(&cmd->hint_cursor); 14418c2ecf20Sopenharmony_ci dm_array_cursor_end(&cmd->mapping_cursor); 14428c2ecf20Sopenharmony_ci return r; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci for (cb = 0; ; cb++) { 14478c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) 14488c2ecf20Sopenharmony_ci r = __load_mapping_v2(cmd, cb, hints_valid, 14498c2ecf20Sopenharmony_ci &cmd->mapping_cursor, 14508c2ecf20Sopenharmony_ci &cmd->hint_cursor, 14518c2ecf20Sopenharmony_ci &cmd->dirty_cursor, 14528c2ecf20Sopenharmony_ci fn, context); 14538c2ecf20Sopenharmony_ci else 14548c2ecf20Sopenharmony_ci r = __load_mapping_v1(cmd, cb, hints_valid, 14558c2ecf20Sopenharmony_ci &cmd->mapping_cursor, &cmd->hint_cursor, 14568c2ecf20Sopenharmony_ci fn, context); 14578c2ecf20Sopenharmony_ci if (r) 14588c2ecf20Sopenharmony_ci goto out; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* 14618c2ecf20Sopenharmony_ci * We need to break out before we move the cursors. 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci if (cb >= (from_cblock(cmd->cache_blocks) - 1)) 14648c2ecf20Sopenharmony_ci break; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci r = dm_array_cursor_next(&cmd->mapping_cursor); 14678c2ecf20Sopenharmony_ci if (r) { 14688c2ecf20Sopenharmony_ci DMERR("dm_array_cursor_next for mapping failed"); 14698c2ecf20Sopenharmony_ci goto out; 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (hints_valid) { 14738c2ecf20Sopenharmony_ci r = dm_array_cursor_next(&cmd->hint_cursor); 14748c2ecf20Sopenharmony_ci if (r) { 14758c2ecf20Sopenharmony_ci dm_array_cursor_end(&cmd->hint_cursor); 14768c2ecf20Sopenharmony_ci hints_valid = false; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) { 14818c2ecf20Sopenharmony_ci r = dm_bitset_cursor_next(&cmd->dirty_cursor); 14828c2ecf20Sopenharmony_ci if (r) { 14838c2ecf20Sopenharmony_ci DMERR("dm_bitset_cursor_next for dirty failed"); 14848c2ecf20Sopenharmony_ci goto out; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ciout: 14898c2ecf20Sopenharmony_ci dm_array_cursor_end(&cmd->mapping_cursor); 14908c2ecf20Sopenharmony_ci if (hints_valid) 14918c2ecf20Sopenharmony_ci dm_array_cursor_end(&cmd->hint_cursor); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) 14948c2ecf20Sopenharmony_ci dm_bitset_cursor_end(&cmd->dirty_cursor); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci return r; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ciint dm_cache_load_mappings(struct dm_cache_metadata *cmd, 15008c2ecf20Sopenharmony_ci struct dm_cache_policy *policy, 15018c2ecf20Sopenharmony_ci load_mapping_fn fn, void *context) 15028c2ecf20Sopenharmony_ci{ 15038c2ecf20Sopenharmony_ci int r; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci READ_LOCK(cmd); 15068c2ecf20Sopenharmony_ci r = __load_mappings(cmd, policy, fn, context); 15078c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci return r; 15108c2ecf20Sopenharmony_ci} 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic int __dump_mapping(void *context, uint64_t cblock, void *leaf) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci int r = 0; 15158c2ecf20Sopenharmony_ci __le64 value; 15168c2ecf20Sopenharmony_ci dm_oblock_t oblock; 15178c2ecf20Sopenharmony_ci unsigned flags; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci memcpy(&value, leaf, sizeof(value)); 15208c2ecf20Sopenharmony_ci unpack_value(value, &oblock, &flags); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci return r; 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_cistatic int __dump_mappings(struct dm_cache_metadata *cmd) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci return dm_array_walk(&cmd->info, cmd->root, __dump_mapping, NULL); 15288c2ecf20Sopenharmony_ci} 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_civoid dm_cache_dump(struct dm_cache_metadata *cmd) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci READ_LOCK_VOID(cmd); 15338c2ecf20Sopenharmony_ci __dump_mappings(cmd); 15348c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ciint dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd) 15388c2ecf20Sopenharmony_ci{ 15398c2ecf20Sopenharmony_ci int r; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci READ_LOCK(cmd); 15428c2ecf20Sopenharmony_ci r = cmd->changed; 15438c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci return r; 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cistatic int __dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci int r; 15518c2ecf20Sopenharmony_ci unsigned flags; 15528c2ecf20Sopenharmony_ci dm_oblock_t oblock; 15538c2ecf20Sopenharmony_ci __le64 value; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(cblock), &value); 15568c2ecf20Sopenharmony_ci if (r) 15578c2ecf20Sopenharmony_ci return r; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci unpack_value(value, &oblock, &flags); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (((flags & M_DIRTY) && dirty) || (!(flags & M_DIRTY) && !dirty)) 15628c2ecf20Sopenharmony_ci /* nothing to be done */ 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci value = pack_value(oblock, (flags & ~M_DIRTY) | (dirty ? M_DIRTY : 0)); 15668c2ecf20Sopenharmony_ci __dm_bless_for_disk(&value); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci r = dm_array_set_value(&cmd->info, cmd->root, from_cblock(cblock), 15698c2ecf20Sopenharmony_ci &value, &cmd->root); 15708c2ecf20Sopenharmony_ci if (r) 15718c2ecf20Sopenharmony_ci return r; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci cmd->changed = true; 15748c2ecf20Sopenharmony_ci return 0; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci} 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_cistatic int __set_dirty_bits_v1(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci int r; 15818c2ecf20Sopenharmony_ci unsigned i; 15828c2ecf20Sopenharmony_ci for (i = 0; i < nr_bits; i++) { 15838c2ecf20Sopenharmony_ci r = __dirty(cmd, to_cblock(i), test_bit(i, bits)); 15848c2ecf20Sopenharmony_ci if (r) 15858c2ecf20Sopenharmony_ci return r; 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int is_dirty_callback(uint32_t index, bool *value, void *context) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci unsigned long *bits = context; 15948c2ecf20Sopenharmony_ci *value = test_bit(index, bits); 15958c2ecf20Sopenharmony_ci return 0; 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic int __set_dirty_bits_v2(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci int r = 0; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci /* nr_bits is really just a sanity check */ 16038c2ecf20Sopenharmony_ci if (nr_bits != from_cblock(cmd->cache_blocks)) { 16048c2ecf20Sopenharmony_ci DMERR("dirty bitset is wrong size"); 16058c2ecf20Sopenharmony_ci return -EINVAL; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci r = dm_bitset_del(&cmd->dirty_info, cmd->dirty_root); 16098c2ecf20Sopenharmony_ci if (r) 16108c2ecf20Sopenharmony_ci return r; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci cmd->changed = true; 16138c2ecf20Sopenharmony_ci return dm_bitset_new(&cmd->dirty_info, &cmd->dirty_root, nr_bits, is_dirty_callback, bits); 16148c2ecf20Sopenharmony_ci} 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ciint dm_cache_set_dirty_bits(struct dm_cache_metadata *cmd, 16178c2ecf20Sopenharmony_ci unsigned nr_bits, 16188c2ecf20Sopenharmony_ci unsigned long *bits) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci int r; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 16238c2ecf20Sopenharmony_ci if (separate_dirty_bits(cmd)) 16248c2ecf20Sopenharmony_ci r = __set_dirty_bits_v2(cmd, nr_bits, bits); 16258c2ecf20Sopenharmony_ci else 16268c2ecf20Sopenharmony_ci r = __set_dirty_bits_v1(cmd, nr_bits, bits); 16278c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci return r; 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_civoid dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd, 16338c2ecf20Sopenharmony_ci struct dm_cache_statistics *stats) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci READ_LOCK_VOID(cmd); 16368c2ecf20Sopenharmony_ci *stats = cmd->stats; 16378c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 16388c2ecf20Sopenharmony_ci} 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_civoid dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd, 16418c2ecf20Sopenharmony_ci struct dm_cache_statistics *stats) 16428c2ecf20Sopenharmony_ci{ 16438c2ecf20Sopenharmony_ci WRITE_LOCK_VOID(cmd); 16448c2ecf20Sopenharmony_ci cmd->stats = *stats; 16458c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ciint dm_cache_commit(struct dm_cache_metadata *cmd, bool clean_shutdown) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci int r = -EINVAL; 16518c2ecf20Sopenharmony_ci flags_mutator mutator = (clean_shutdown ? set_clean_shutdown : 16528c2ecf20Sopenharmony_ci clear_clean_shutdown); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 16558c2ecf20Sopenharmony_ci if (cmd->fail_io) 16568c2ecf20Sopenharmony_ci goto out; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci r = __commit_transaction(cmd, mutator); 16598c2ecf20Sopenharmony_ci if (r) 16608c2ecf20Sopenharmony_ci goto out; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci r = __begin_transaction(cmd); 16638c2ecf20Sopenharmony_ciout: 16648c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 16658c2ecf20Sopenharmony_ci return r; 16668c2ecf20Sopenharmony_ci} 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ciint dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd, 16698c2ecf20Sopenharmony_ci dm_block_t *result) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci int r = -EINVAL; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci READ_LOCK(cmd); 16748c2ecf20Sopenharmony_ci if (!cmd->fail_io) 16758c2ecf20Sopenharmony_ci r = dm_sm_get_nr_free(cmd->metadata_sm, result); 16768c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci return r; 16798c2ecf20Sopenharmony_ci} 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ciint dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd, 16828c2ecf20Sopenharmony_ci dm_block_t *result) 16838c2ecf20Sopenharmony_ci{ 16848c2ecf20Sopenharmony_ci int r = -EINVAL; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci READ_LOCK(cmd); 16878c2ecf20Sopenharmony_ci if (!cmd->fail_io) 16888c2ecf20Sopenharmony_ci r = dm_sm_get_nr_blocks(cmd->metadata_sm, result); 16898c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci return r; 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_cistatic int get_hint(uint32_t index, void *value_le, void *context) 16978c2ecf20Sopenharmony_ci{ 16988c2ecf20Sopenharmony_ci uint32_t value; 16998c2ecf20Sopenharmony_ci struct dm_cache_policy *policy = context; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci value = policy_get_hint(policy, to_cblock(index)); 17028c2ecf20Sopenharmony_ci *((__le32 *) value_le) = cpu_to_le32(value); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci return 0; 17058c2ecf20Sopenharmony_ci} 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci/* 17088c2ecf20Sopenharmony_ci * It's quicker to always delete the hint array, and recreate with 17098c2ecf20Sopenharmony_ci * dm_array_new(). 17108c2ecf20Sopenharmony_ci */ 17118c2ecf20Sopenharmony_cistatic int write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci int r; 17148c2ecf20Sopenharmony_ci size_t hint_size; 17158c2ecf20Sopenharmony_ci const char *policy_name = dm_cache_policy_get_name(policy); 17168c2ecf20Sopenharmony_ci const unsigned *policy_version = dm_cache_policy_get_version(policy); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (!policy_name[0] || 17198c2ecf20Sopenharmony_ci (strlen(policy_name) > sizeof(cmd->policy_name) - 1)) 17208c2ecf20Sopenharmony_ci return -EINVAL; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci strncpy(cmd->policy_name, policy_name, sizeof(cmd->policy_name)); 17238c2ecf20Sopenharmony_ci memcpy(cmd->policy_version, policy_version, sizeof(cmd->policy_version)); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci hint_size = dm_cache_policy_get_hint_size(policy); 17268c2ecf20Sopenharmony_ci if (!hint_size) 17278c2ecf20Sopenharmony_ci return 0; /* short-circuit hints initialization */ 17288c2ecf20Sopenharmony_ci cmd->policy_hint_size = hint_size; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (cmd->hint_root) { 17318c2ecf20Sopenharmony_ci r = dm_array_del(&cmd->hint_info, cmd->hint_root); 17328c2ecf20Sopenharmony_ci if (r) 17338c2ecf20Sopenharmony_ci return r; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci return dm_array_new(&cmd->hint_info, &cmd->hint_root, 17378c2ecf20Sopenharmony_ci from_cblock(cmd->cache_blocks), 17388c2ecf20Sopenharmony_ci get_hint, policy); 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ciint dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *policy) 17428c2ecf20Sopenharmony_ci{ 17438c2ecf20Sopenharmony_ci int r; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 17468c2ecf20Sopenharmony_ci r = write_hints(cmd, policy); 17478c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci return r; 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ciint dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result) 17538c2ecf20Sopenharmony_ci{ 17548c2ecf20Sopenharmony_ci int r; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci READ_LOCK(cmd); 17578c2ecf20Sopenharmony_ci r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result); 17588c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci return r; 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_civoid dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci WRITE_LOCK_VOID(cmd); 17668c2ecf20Sopenharmony_ci dm_bm_set_read_only(cmd->bm); 17678c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 17688c2ecf20Sopenharmony_ci} 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_civoid dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci WRITE_LOCK_VOID(cmd); 17738c2ecf20Sopenharmony_ci dm_bm_set_read_write(cmd->bm); 17748c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ciint dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci int r; 17808c2ecf20Sopenharmony_ci struct dm_block *sblock; 17818c2ecf20Sopenharmony_ci struct cache_disk_superblock *disk_super; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 17848c2ecf20Sopenharmony_ci set_bit(NEEDS_CHECK, &cmd->flags); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci r = superblock_lock(cmd, &sblock); 17878c2ecf20Sopenharmony_ci if (r) { 17888c2ecf20Sopenharmony_ci DMERR("couldn't read superblock"); 17898c2ecf20Sopenharmony_ci goto out; 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci disk_super = dm_block_data(sblock); 17938c2ecf20Sopenharmony_ci disk_super->flags = cpu_to_le32(cmd->flags); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci dm_bm_unlock(sblock); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ciout: 17988c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 17998c2ecf20Sopenharmony_ci return r; 18008c2ecf20Sopenharmony_ci} 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ciint dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result) 18038c2ecf20Sopenharmony_ci{ 18048c2ecf20Sopenharmony_ci READ_LOCK(cmd); 18058c2ecf20Sopenharmony_ci *result = !!test_bit(NEEDS_CHECK, &cmd->flags); 18068c2ecf20Sopenharmony_ci READ_UNLOCK(cmd); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci return 0; 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ciint dm_cache_metadata_abort(struct dm_cache_metadata *cmd) 18128c2ecf20Sopenharmony_ci{ 18138c2ecf20Sopenharmony_ci int r = -EINVAL; 18148c2ecf20Sopenharmony_ci struct dm_block_manager *old_bm = NULL, *new_bm = NULL; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* fail_io is double-checked with cmd->root_lock held below */ 18178c2ecf20Sopenharmony_ci if (unlikely(cmd->fail_io)) 18188c2ecf20Sopenharmony_ci return r; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci /* 18218c2ecf20Sopenharmony_ci * Replacement block manager (new_bm) is created and old_bm destroyed outside of 18228c2ecf20Sopenharmony_ci * cmd root_lock to avoid ABBA deadlock that would result (due to life-cycle of 18238c2ecf20Sopenharmony_ci * shrinker associated with the block manager's bufio client vs cmd root_lock). 18248c2ecf20Sopenharmony_ci * - must take shrinker_rwsem without holding cmd->root_lock 18258c2ecf20Sopenharmony_ci */ 18268c2ecf20Sopenharmony_ci new_bm = dm_block_manager_create(cmd->bdev, DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT, 18278c2ecf20Sopenharmony_ci CACHE_MAX_CONCURRENT_LOCKS); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci WRITE_LOCK(cmd); 18308c2ecf20Sopenharmony_ci if (cmd->fail_io) { 18318c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 18328c2ecf20Sopenharmony_ci goto out; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci __destroy_persistent_data_objects(cmd, false); 18368c2ecf20Sopenharmony_ci old_bm = cmd->bm; 18378c2ecf20Sopenharmony_ci if (IS_ERR(new_bm)) { 18388c2ecf20Sopenharmony_ci DMERR("could not create block manager during abort"); 18398c2ecf20Sopenharmony_ci cmd->bm = NULL; 18408c2ecf20Sopenharmony_ci r = PTR_ERR(new_bm); 18418c2ecf20Sopenharmony_ci goto out_unlock; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci cmd->bm = new_bm; 18458c2ecf20Sopenharmony_ci r = __open_or_format_metadata(cmd, false); 18468c2ecf20Sopenharmony_ci if (r) { 18478c2ecf20Sopenharmony_ci cmd->bm = NULL; 18488c2ecf20Sopenharmony_ci goto out_unlock; 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci new_bm = NULL; 18518c2ecf20Sopenharmony_ciout_unlock: 18528c2ecf20Sopenharmony_ci if (r) 18538c2ecf20Sopenharmony_ci cmd->fail_io = true; 18548c2ecf20Sopenharmony_ci WRITE_UNLOCK(cmd); 18558c2ecf20Sopenharmony_ci dm_block_manager_destroy(old_bm); 18568c2ecf20Sopenharmony_ciout: 18578c2ecf20Sopenharmony_ci if (new_bm && !IS_ERR(new_bm)) 18588c2ecf20Sopenharmony_ci dm_block_manager_destroy(new_bm); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci return r; 18618c2ecf20Sopenharmony_ci} 1862