dm-log.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 712 行 · 第 1/2 页

C
712
字号
/* * Copyright (C) 2003 Sistina Software * * This file is released under the LGPL. */#include <linux/init.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/vmalloc.h>#include "dm-log.h"#include "dm-io.h"static LIST_HEAD(_log_types);static spinlock_t _lock = SPIN_LOCK_UNLOCKED;int dm_register_dirty_log_type(struct dirty_log_type *type){	if (!try_module_get(type->module))		return -EINVAL;	spin_lock(&_lock);	type->use_count = 0;	list_add(&type->list, &_log_types);	spin_unlock(&_lock);	return 0;}int dm_unregister_dirty_log_type(struct dirty_log_type *type){	spin_lock(&_lock);	if (type->use_count)		DMWARN("Attempt to unregister a log type that is still in use");	else {		list_del(&type->list);		module_put(type->module);	}	spin_unlock(&_lock);	return 0;}static struct dirty_log_type *get_type(const char *type_name){	struct dirty_log_type *type;	spin_lock(&_lock);	list_for_each_entry (type, &_log_types, list)		if (!strcmp(type_name, type->name)) {			type->use_count++;			spin_unlock(&_lock);			return type;		}	spin_unlock(&_lock);	return NULL;}static void put_type(struct dirty_log_type *type){	spin_lock(&_lock);	type->use_count--;	spin_unlock(&_lock);}struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti,				      unsigned int argc, char **argv){	struct dirty_log_type *type;	struct dirty_log *log;	log = kmalloc(sizeof(*log), GFP_KERNEL);	if (!log)		return NULL;	type = get_type(type_name);	if (!type) {		kfree(log);		return NULL;	}	log->type = type;	if (type->ctr(log, ti, argc, argv)) {		kfree(log);		put_type(type);		return NULL;	}	return log;}void dm_destroy_dirty_log(struct dirty_log *log){	log->type->dtr(log);	put_type(log->type);	kfree(log);}/*----------------------------------------------------------------- * Persistent and core logs share a lot of their implementation. * FIXME: need a reload method to be called from a resume *---------------------------------------------------------------*//* * Magic for persistent mirrors: "MiRr" */#define MIRROR_MAGIC 0x4D695272/* * The on-disk version of the metadata. */#define MIRROR_DISK_VERSION 1#define LOG_OFFSET 2struct log_header {	uint32_t magic;	/*	 * Simple, incrementing version. no backward	 * compatibility.	 */	uint32_t version;	sector_t nr_regions;};struct log_c {	struct dm_target *ti;	int touched;	sector_t region_size;	unsigned int region_count;	region_t sync_count;	unsigned bitset_uint32_count;	uint32_t *clean_bits;	uint32_t *sync_bits;	uint32_t *recovering_bits;	/* FIXME: this seems excessive */	int sync_search;	/* Resync flag */	enum sync {		DEFAULTSYNC,	/* Synchronize if necessary */		NOSYNC,		/* Devices known to be already in sync */		FORCESYNC,	/* Force a sync to happen */	} sync;	/*	 * Disk log fields	 */	struct dm_dev *log_dev;	struct log_header header;	struct io_region header_location;	struct log_header *disk_header;	struct io_region bits_location;	uint32_t *disk_bits;};/* * The touched member needs to be updated every time we access * one of the bitsets. */static  inline int log_test_bit(uint32_t *bs, unsigned bit){	return test_bit(bit, (unsigned long *) bs) ? 1 : 0;}static inline void log_set_bit(struct log_c *l,			       uint32_t *bs, unsigned bit){	set_bit(bit, (unsigned long *) bs);	l->touched = 1;}static inline void log_clear_bit(struct log_c *l,				 uint32_t *bs, unsigned bit){	clear_bit(bit, (unsigned long *) bs);	l->touched = 1;}/*---------------------------------------------------------------- * Header IO *--------------------------------------------------------------*/static void header_to_disk(struct log_header *core, struct log_header *disk){	disk->magic = cpu_to_le32(core->magic);	disk->version = cpu_to_le32(core->version);	disk->nr_regions = cpu_to_le64(core->nr_regions);}static void header_from_disk(struct log_header *core, struct log_header *disk){	core->magic = le32_to_cpu(disk->magic);	core->version = le32_to_cpu(disk->version);	core->nr_regions = le64_to_cpu(disk->nr_regions);}static int read_header(struct log_c *log){	int r;	unsigned long ebits;	r = dm_io_sync_vm(1, &log->header_location, READ,			  log->disk_header, &ebits);	if (r)		return r;	header_from_disk(&log->header, log->disk_header);	/* New log required? */	if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) {		log->header.magic = MIRROR_MAGIC;		log->header.version = MIRROR_DISK_VERSION;		log->header.nr_regions = 0;	}	if (log->header.version != MIRROR_DISK_VERSION) {		DMWARN("incompatible disk log version");		return -EINVAL;	}	return 0;}static inline int write_header(struct log_c *log){	unsigned long ebits;	header_to_disk(&log->header, log->disk_header);	return dm_io_sync_vm(1, &log->header_location, WRITE,			     log->disk_header, &ebits);}/*---------------------------------------------------------------- * Bits IO *--------------------------------------------------------------*/static inline void bits_to_core(uint32_t *core, uint32_t *disk, unsigned count){	unsigned i;	for (i = 0; i < count; i++)		core[i] = le32_to_cpu(disk[i]);}static inline void bits_to_disk(uint32_t *core, uint32_t *disk, unsigned count){	unsigned i;	/* copy across the clean/dirty bitset */	for (i = 0; i < count; i++)		disk[i] = cpu_to_le32(core[i]);}static int read_bits(struct log_c *log){	int r;	unsigned long ebits;	r = dm_io_sync_vm(1, &log->bits_location, READ,			  log->disk_bits, &ebits);	if (r)		return r;	bits_to_core(log->clean_bits, log->disk_bits,		     log->bitset_uint32_count);	return 0;}static int write_bits(struct log_c *log){	unsigned long ebits;	bits_to_disk(log->clean_bits, log->disk_bits,		     log->bitset_uint32_count);	return dm_io_sync_vm(1, &log->bits_location, WRITE,			     log->disk_bits, &ebits);}/*---------------------------------------------------------------- * core log constructor/destructor * * argv contains region_size followed optionally by [no]sync *--------------------------------------------------------------*/#define BYTE_SHIFT 3static int core_ctr(struct dirty_log *log, struct dm_target *ti,		    unsigned int argc, char **argv){	enum sync sync = DEFAULTSYNC;	struct log_c *lc;	sector_t region_size;	unsigned int region_count;	size_t bitset_size;	if (argc < 1 || argc > 2) {		DMWARN("wrong number of arguments to mirror log");		return -EINVAL;	}	if (argc > 1) {		if (!strcmp(argv[1], "sync"))			sync = FORCESYNC;		else if (!strcmp(argv[1], "nosync"))			sync = NOSYNC;		else {			DMWARN("unrecognised sync argument to mirror log: %s",			       argv[1]);			return -EINVAL;		}	}	if (sscanf(argv[0], SECTOR_FORMAT, &region_size) != 1) {		DMWARN("invalid region size string");		return -EINVAL;	}	region_count = dm_div_up(ti->len, region_size);	lc = kmalloc(sizeof(*lc), GFP_KERNEL);	if (!lc) {		DMWARN("couldn't allocate core log");		return -ENOMEM;	}	lc->ti = ti;	lc->touched = 0;	lc->region_size = region_size;	lc->region_count = region_count;	lc->sync = sync;	/*	 * Work out how many words we need to hold the bitset.	 */	bitset_size = dm_round_up(region_count,				  sizeof(*lc->clean_bits) << BYTE_SHIFT);	bitset_size >>= BYTE_SHIFT;	lc->bitset_uint32_count = bitset_size / 4;	lc->clean_bits = vmalloc(bitset_size);	if (!lc->clean_bits) {		DMWARN("couldn't allocate clean bitset");		kfree(lc);		return -ENOMEM;	}	memset(lc->clean_bits, -1, bitset_size);	lc->sync_bits = vmalloc(bitset_size);	if (!lc->sync_bits) {		DMWARN("couldn't allocate sync bitset");		vfree(lc->clean_bits);		kfree(lc);		return -ENOMEM;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?