1827 lines · 42.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2012 Red Hat, Inc. * * This file is released under the GPL. */ #include "dm-cache-metadata.h" #include "persistent-data/dm-array.h"#include "persistent-data/dm-bitset.h"#include "persistent-data/dm-space-map.h"#include "persistent-data/dm-space-map-disk.h"#include "persistent-data/dm-transaction-manager.h" #include <linux/device-mapper.h>#include <linux/refcount.h> /*----------------------------------------------------------------*/ #define DM_MSG_PREFIX   "cache metadata" #define CACHE_SUPERBLOCK_MAGIC 06142003#define CACHE_SUPERBLOCK_LOCATION 0 /* * defines a range of metadata versions that this module can handle. */#define MIN_CACHE_VERSION 1#define MAX_CACHE_VERSION 2 /* *  3 for btree insert + *  2 for btree lookup used within space map */#define CACHE_MAX_CONCURRENT_LOCKS 5#define SPACE_MAP_ROOT_SIZE 128 enum superblock_flag_bits {	/* for spotting crashes that would invalidate the dirty bitset */	CLEAN_SHUTDOWN,	/* metadata must be checked using the tools */	NEEDS_CHECK,}; /* * Each mapping from cache block -> origin block carries a set of flags. */enum mapping_bits {	/*	 * A valid mapping.  Because we're using an array we clear this	 * flag for an non existant mapping.	 */	M_VALID = 1, 	/*	 * The data on the cache is different from that on the origin.	 * This flag is only used by metadata format 1.	 */	M_DIRTY = 2}; struct cache_disk_superblock {	__le32 csum;	__le32 flags;	__le64 blocknr; 	__u8 uuid[16];	__le64 magic;	__le32 version; 	__u8 policy_name[CACHE_POLICY_NAME_SIZE];	__le32 policy_hint_size; 	__u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];	__le64 mapping_root;	__le64 hint_root; 	__le64 discard_root;	__le64 discard_block_size;	__le64 discard_nr_blocks; 	__le32 data_block_size;	__le32 metadata_block_size;	__le32 cache_blocks; 	__le32 compat_flags;	__le32 compat_ro_flags;	__le32 incompat_flags; 	__le32 read_hits;	__le32 read_misses;	__le32 write_hits;	__le32 write_misses; 	__le32 policy_version[CACHE_POLICY_VERSION_SIZE]; 	/*	 * Metadata format 2 fields.	 */	__le64 dirty_root;} __packed; struct dm_cache_metadata {	refcount_t ref_count;	struct list_head list; 	unsigned int version;	struct block_device *bdev;	struct dm_block_manager *bm;	struct dm_space_map *metadata_sm;	struct dm_transaction_manager *tm; 	struct dm_array_info info;	struct dm_array_info hint_info;	struct dm_disk_bitset discard_info; 	struct rw_semaphore root_lock;	unsigned long flags;	dm_block_t root;	dm_block_t hint_root;	dm_block_t discard_root; 	sector_t discard_block_size;	dm_dblock_t discard_nr_blocks; 	sector_t data_block_size;	dm_cblock_t cache_blocks;	bool changed:1;	bool clean_when_opened:1; 	char policy_name[CACHE_POLICY_NAME_SIZE];	unsigned int policy_version[CACHE_POLICY_VERSION_SIZE];	size_t policy_hint_size;	struct dm_cache_statistics stats; 	/*	 * Reading the space map root can fail, so we read it into this	 * buffer before the superblock is locked and updated.	 */	__u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE]; 	/*	 * Set if a transaction has to be aborted but the attempt to roll	 * back to the previous (good) transaction failed.  The only	 * metadata operation permissible in this state is the closing of	 * the device.	 */	bool fail_io:1; 	/*	 * Metadata format 2 fields.	 */	dm_block_t dirty_root;	struct dm_disk_bitset dirty_info; 	/*	 * These structures are used when loading metadata.  They're too	 * big to put on the stack.	 */	struct dm_array_cursor mapping_cursor;	struct dm_array_cursor hint_cursor;	struct dm_bitset_cursor dirty_cursor;}; /* *----------------------------------------------------------------- * superblock validator *----------------------------------------------------------------- */#define SUPERBLOCK_CSUM_XOR 9031977 static void sb_prepare_for_write(const struct dm_block_validator *v,				 struct dm_block *b,				 size_t sb_block_size){	struct cache_disk_superblock *disk_super = dm_block_data(b); 	disk_super->blocknr = cpu_to_le64(dm_block_location(b));	disk_super->csum = cpu_to_le32(dm_bm_checksum(&disk_super->flags,						      sb_block_size - sizeof(__le32),						      SUPERBLOCK_CSUM_XOR));} static int check_metadata_version(struct cache_disk_superblock *disk_super){	uint32_t metadata_version = le32_to_cpu(disk_super->version); 	if (metadata_version < MIN_CACHE_VERSION || metadata_version > MAX_CACHE_VERSION) {		DMERR("Cache metadata version %u found, but only versions between %u and %u supported.",		      metadata_version, MIN_CACHE_VERSION, MAX_CACHE_VERSION);		return -EINVAL;	} 	return 0;} static int sb_check(const struct dm_block_validator *v,		    struct dm_block *b,		    size_t sb_block_size){	struct cache_disk_superblock *disk_super = dm_block_data(b);	__le32 csum_le; 	if (dm_block_location(b) != le64_to_cpu(disk_super->blocknr)) {		DMERR("%s failed: blocknr %llu: wanted %llu",		      __func__, le64_to_cpu(disk_super->blocknr),		      (unsigned long long)dm_block_location(b));		return -ENOTBLK;	} 	if (le64_to_cpu(disk_super->magic) != CACHE_SUPERBLOCK_MAGIC) {		DMERR("%s failed: magic %llu: wanted %llu",		      __func__, le64_to_cpu(disk_super->magic),		      (unsigned long long)CACHE_SUPERBLOCK_MAGIC);		return -EILSEQ;	} 	csum_le = cpu_to_le32(dm_bm_checksum(&disk_super->flags,					     sb_block_size - sizeof(__le32),					     SUPERBLOCK_CSUM_XOR));	if (csum_le != disk_super->csum) {		DMERR("%s failed: csum %u: wanted %u",		      __func__, le32_to_cpu(csum_le), le32_to_cpu(disk_super->csum));		return -EILSEQ;	} 	return check_metadata_version(disk_super);} static const struct dm_block_validator sb_validator = {	.name = "superblock",	.prepare_for_write = sb_prepare_for_write,	.check = sb_check}; /*----------------------------------------------------------------*/ static int superblock_read_lock(struct dm_cache_metadata *cmd,				struct dm_block **sblock){	return dm_bm_read_lock(cmd->bm, CACHE_SUPERBLOCK_LOCATION,			       &sb_validator, sblock);} static int superblock_lock_zero(struct dm_cache_metadata *cmd,				struct dm_block **sblock){	return dm_bm_write_lock_zero(cmd->bm, CACHE_SUPERBLOCK_LOCATION,				     &sb_validator, sblock);} static int superblock_lock(struct dm_cache_metadata *cmd,			   struct dm_block **sblock){	return dm_bm_write_lock(cmd->bm, CACHE_SUPERBLOCK_LOCATION,				&sb_validator, sblock);} /*----------------------------------------------------------------*/ static int __superblock_all_zeroes(struct dm_block_manager *bm, bool *result){	int r;	unsigned int i;	struct dm_block *b;	__le64 *data_le, zero = cpu_to_le64(0);	unsigned int sb_block_size = dm_bm_block_size(bm) / sizeof(__le64); 	/*	 * We can't use a validator here - it may be all zeroes.	 */	r = dm_bm_read_lock(bm, CACHE_SUPERBLOCK_LOCATION, NULL, &b);	if (r)		return r; 	data_le = dm_block_data(b);	*result = true;	for (i = 0; i < sb_block_size; i++) {		if (data_le[i] != zero) {			*result = false;			break;		}	} 	dm_bm_unlock(b); 	return 0;} static void __setup_mapping_info(struct dm_cache_metadata *cmd){	struct dm_btree_value_type vt; 	vt.context = NULL;	vt.size = sizeof(__le64);	vt.inc = NULL;	vt.dec = NULL;	vt.equal = NULL;	dm_array_info_init(&cmd->info, cmd->tm, &vt); 	if (cmd->policy_hint_size) {		vt.size = sizeof(__le32);		dm_array_info_init(&cmd->hint_info, cmd->tm, &vt);	}} static int __save_sm_root(struct dm_cache_metadata *cmd){	int r;	size_t metadata_len; 	r = dm_sm_root_size(cmd->metadata_sm, &metadata_len);	if (r < 0)		return r; 	return dm_sm_copy_root(cmd->metadata_sm, &cmd->metadata_space_map_root,			       metadata_len);} static void __copy_sm_root(struct dm_cache_metadata *cmd,			   struct cache_disk_superblock *disk_super){	memcpy(&disk_super->metadata_space_map_root,	       &cmd->metadata_space_map_root,	       sizeof(cmd->metadata_space_map_root));} static bool separate_dirty_bits(struct dm_cache_metadata *cmd){	return cmd->version >= 2;} static int __write_initial_superblock(struct dm_cache_metadata *cmd){	int r;	struct dm_block *sblock;	struct cache_disk_superblock *disk_super;	sector_t bdev_size = bdev_nr_sectors(cmd->bdev); 	/* FIXME: see if we can lose the max sectors limit */	if (bdev_size > DM_CACHE_METADATA_MAX_SECTORS)		bdev_size = DM_CACHE_METADATA_MAX_SECTORS; 	r = dm_tm_pre_commit(cmd->tm);	if (r < 0)		return r; 	/*	 * dm_sm_copy_root() can fail.  So we need to do it before we start	 * updating the superblock.	 */	r = __save_sm_root(cmd);	if (r)		return r; 	r = superblock_lock_zero(cmd, &sblock);	if (r)		return r; 	disk_super = dm_block_data(sblock);	disk_super->flags = 0;	memset(disk_super->uuid, 0, sizeof(disk_super->uuid));	disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC);	disk_super->version = cpu_to_le32(cmd->version);	memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name));	memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version));	disk_super->policy_hint_size = cpu_to_le32(0); 	__copy_sm_root(cmd, disk_super); 	disk_super->mapping_root = cpu_to_le64(cmd->root);	disk_super->hint_root = cpu_to_le64(cmd->hint_root);	disk_super->discard_root = cpu_to_le64(cmd->discard_root);	disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size);	disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks));	disk_super->metadata_block_size = cpu_to_le32(DM_CACHE_METADATA_BLOCK_SIZE);	disk_super->data_block_size = cpu_to_le32(cmd->data_block_size);	disk_super->cache_blocks = cpu_to_le32(0); 	disk_super->read_hits = cpu_to_le32(0);	disk_super->read_misses = cpu_to_le32(0);	disk_super->write_hits = cpu_to_le32(0);	disk_super->write_misses = cpu_to_le32(0); 	if (separate_dirty_bits(cmd))		disk_super->dirty_root = cpu_to_le64(cmd->dirty_root); 	return dm_tm_commit(cmd->tm, sblock);} static int __format_metadata(struct dm_cache_metadata *cmd){	int r; 	r = dm_tm_create_with_sm(cmd->bm, CACHE_SUPERBLOCK_LOCATION,				 &cmd->tm, &cmd->metadata_sm);	if (r < 0) {		DMERR("tm_create_with_sm failed");		return r;	} 	__setup_mapping_info(cmd); 	r = dm_array_empty(&cmd->info, &cmd->root);	if (r < 0)		goto bad; 	if (separate_dirty_bits(cmd)) {		dm_disk_bitset_init(cmd->tm, &cmd->dirty_info);		r = dm_bitset_empty(&cmd->dirty_info, &cmd->dirty_root);		if (r < 0)			goto bad;	} 	dm_disk_bitset_init(cmd->tm, &cmd->discard_info);	r = dm_bitset_empty(&cmd->discard_info, &cmd->discard_root);	if (r < 0)		goto bad; 	cmd->discard_block_size = 0;	cmd->discard_nr_blocks = 0; 	r = __write_initial_superblock(cmd);	if (r)		goto bad; 	cmd->clean_when_opened = true;	return 0; bad:	dm_tm_destroy(cmd->tm);	dm_sm_destroy(cmd->metadata_sm); 	return r;} static int __check_incompat_features(struct cache_disk_superblock *disk_super,				     struct dm_cache_metadata *cmd){	uint32_t incompat_flags, features; 	incompat_flags = le32_to_cpu(disk_super->incompat_flags);	features = incompat_flags & ~DM_CACHE_FEATURE_INCOMPAT_SUPP;	if (features) {		DMERR("could not access metadata due to unsupported optional features (%lx).",		      (unsigned long)features);		return -EINVAL;	} 	/*	 * Check for read-only metadata to skip the following RDWR checks.	 */	if (bdev_read_only(cmd->bdev))		return 0; 	features = le32_to_cpu(disk_super->compat_ro_flags) & ~DM_CACHE_FEATURE_COMPAT_RO_SUPP;	if (features) {		DMERR("could not access metadata RDWR due to unsupported optional features (%lx).",		      (unsigned long)features);		return -EINVAL;	} 	return 0;} static int __open_metadata(struct dm_cache_metadata *cmd){	int r;	struct dm_block *sblock;	struct cache_disk_superblock *disk_super;	unsigned long sb_flags; 	r = superblock_read_lock(cmd, &sblock);	if (r < 0) {		DMERR("couldn't read lock superblock");		return r;	} 	disk_super = dm_block_data(sblock); 	/* Verify the data block size hasn't changed */	if (le32_to_cpu(disk_super->data_block_size) != cmd->data_block_size) {		DMERR("changing the data block size (from %u to %llu) is not supported",		      le32_to_cpu(disk_super->data_block_size),		      (unsigned long long)cmd->data_block_size);		r = -EINVAL;		goto bad;	} 	r = __check_incompat_features(disk_super, cmd);	if (r < 0)		goto bad; 	r = dm_tm_open_with_sm(cmd->bm, CACHE_SUPERBLOCK_LOCATION,			       disk_super->metadata_space_map_root,			       sizeof(disk_super->metadata_space_map_root),			       &cmd->tm, &cmd->metadata_sm);	if (r < 0) {		DMERR("tm_open_with_sm failed");

Lines 1–500 of 1827.