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, ®ion_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 + -
显示快捷键?