X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmd%2Fdm-log.c;fp=drivers%2Fmd%2Fdm-log.c;h=d73779a42417f25a1fac190d4bc4907aa939a782;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=5a110fcc7007655fd34b18d596868fb8cc7e6c62;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 5a110fcc7..d73779a42 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -12,8 +12,6 @@ #include "dm-log.h" #include "dm-io.h" -#define DM_MSG_PREFIX "mirror log" - static LIST_HEAD(_log_types); static DEFINE_SPINLOCK(_lock); @@ -32,8 +30,7 @@ int dm_unregister_dirty_log_type(struct dirty_log_type *type) spin_lock(&_lock); if (type->use_count) - DMWARN("Unregister failed: log type '%s' still in use", - type->name); + DMWARN("Attempt to unregister a log type that is still in use"); else list_del(&type->list); @@ -139,7 +136,7 @@ struct log_c { unsigned bitset_uint32_count; uint32_t *clean_bits; uint32_t *sync_bits; - uint32_t *recovering_bits; + uint32_t *recovering_bits; /* FIXME: this seems excessive */ int sync_search; @@ -150,17 +147,16 @@ struct log_c { FORCESYNC, /* Force a sync to happen */ } sync; - int failure_response; - /* * Disk log fields */ - int log_dev_failed; struct dm_dev *log_dev; struct log_header header; struct io_region header_location; struct log_header *disk_header; + + struct io_region bits_location; }; /* @@ -244,40 +240,58 @@ static inline int write_header(struct log_c *log) log->disk_header, &ebits); } +/*---------------------------------------------------------------- + * Bits IO + *--------------------------------------------------------------*/ +static int read_bits(struct log_c *log) +{ + int r; + unsigned long ebits; + + r = dm_io_sync_vm(1, &log->bits_location, READ, + log->clean_bits, &ebits); + if (r) + return r; + + return 0; +} + +static int write_bits(struct log_c *log) +{ + unsigned long ebits; + return dm_io_sync_vm(1, &log->bits_location, WRITE, + log->clean_bits, &ebits); +} + /*---------------------------------------------------------------- * core log constructor/destructor * - * argv contains 1 - 3 arguments: - * [[no]sync] [block_on_error] + * argv contains region_size followed optionally by [no]sync *--------------------------------------------------------------*/ #define BYTE_SHIFT 3 -static int create_log_context(struct dirty_log *log, struct dm_target *ti, - unsigned int argc, char **argv, - struct dm_dev *dev) +static int core_ctr(struct dirty_log *log, struct dm_target *ti, + unsigned int argc, char **argv) { - int i; enum sync sync = DEFAULTSYNC; - int failure_response = DMLOG_IOERR_IGNORE; + struct log_c *lc; uint32_t region_size; unsigned int region_count; - size_t bitset_size, buf_size; + size_t bitset_size; - if (argc < 1 || argc > 3) { + if (argc < 1 || argc > 2) { DMWARN("wrong number of arguments to mirror log"); return -EINVAL; } - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "sync")) + if (argc > 1) { + if (!strcmp(argv[1], "sync")) sync = FORCESYNC; - else if (!strcmp(argv[i], "nosync")) + else if (!strcmp(argv[1], "nosync")) sync = NOSYNC; - else if (!strcmp(argv[i], "block_on_error")) - failure_response = DMLOG_IOERR_BLOCK; else { DMWARN("unrecognised sync argument to mirror log: %s", - argv[i]); + argv[1]); return -EINVAL; } } @@ -300,60 +314,27 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, lc->region_size = region_size; lc->region_count = region_count; lc->sync = sync; - lc->failure_response = failure_response; /* * Work out how many "unsigned long"s we need to hold the bitset. */ bitset_size = dm_round_up(region_count, - sizeof(*lc->clean_bits) << BYTE_SHIFT); + sizeof(unsigned long) << BYTE_SHIFT); bitset_size >>= BYTE_SHIFT; - lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits); - - /* - * Disk log? - */ - if (!dev) { - lc->clean_bits = vmalloc(bitset_size); - if (!lc->clean_bits) { - DMWARN("couldn't allocate clean bitset"); - kfree(lc); - return -ENOMEM; - } - lc->disk_header = NULL; - } else { - lc->log_dev = dev; - lc->log_dev_failed = 0; - lc->header_location.bdev = lc->log_dev->bdev; - lc->header_location.sector = 0; - - /* - * Buffer holds both header and bitset. - */ - buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + - bitset_size, ti->limits.hardsect_size); - lc->header_location.count = buf_size >> SECTOR_SHIFT; - - lc->disk_header = vmalloc(buf_size); - if (!lc->disk_header) { - DMWARN("couldn't allocate disk log buffer"); - kfree(lc); - return -ENOMEM; - } - - lc->clean_bits = (void *)lc->disk_header + - (LOG_OFFSET << SECTOR_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"); - if (!dev) - vfree(lc->clean_bits); - vfree(lc->disk_header); + vfree(lc->clean_bits); kfree(lc); return -ENOMEM; } @@ -362,55 +343,41 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti, lc->recovering_bits = vmalloc(bitset_size); if (!lc->recovering_bits) { - DMWARN("couldn't allocate recovering bitset"); + DMWARN("couldn't allocate sync bitset"); vfree(lc->sync_bits); - if (!dev) - vfree(lc->clean_bits); - vfree(lc->disk_header); + vfree(lc->clean_bits); kfree(lc); return -ENOMEM; } memset(lc->recovering_bits, 0, bitset_size); lc->sync_search = 0; log->context = lc; - return 0; } -static int core_ctr(struct dirty_log *log, struct dm_target *ti, - unsigned int argc, char **argv) -{ - return create_log_context(log, ti, argc, argv, NULL); -} - -static void destroy_log_context(struct log_c *lc) -{ - vfree(lc->sync_bits); - vfree(lc->recovering_bits); - kfree(lc); -} - static void core_dtr(struct dirty_log *log) { struct log_c *lc = (struct log_c *) log->context; - vfree(lc->clean_bits); - destroy_log_context(lc); + vfree(lc->sync_bits); + vfree(lc->recovering_bits); + kfree(lc); } /*---------------------------------------------------------------- * disk log constructor/destructor * - * argv contains 2 - 4 arguments: - * [[no]sync] [block_on_error] + * argv contains log_device region_size followed optionally by [no]sync *--------------------------------------------------------------*/ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, unsigned int argc, char **argv) { int r; + size_t size; + struct log_c *lc; struct dm_dev *dev; - if (argc < 2 || argc > 4) { + if (argc < 2 || argc > 3) { DMWARN("wrong number of arguments to disk mirror log"); return -EINVAL; } @@ -420,22 +387,49 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, if (r) return r; - r = create_log_context(log, ti, argc - 1, argv + 1, dev); + r = core_ctr(log, ti, argc - 1, argv + 1); if (r) { dm_put_device(ti, dev); return r; } + lc = (struct log_c *) log->context; + lc->log_dev = dev; + + /* setup the disk header fields */ + lc->header_location.bdev = lc->log_dev->bdev; + lc->header_location.sector = 0; + lc->header_location.count = 1; + + /* + * We can't read less than this amount, even though we'll + * not be using most of this space. + */ + lc->disk_header = vmalloc(1 << SECTOR_SHIFT); + if (!lc->disk_header) + goto bad; + + /* setup the disk bitset fields */ + lc->bits_location.bdev = lc->log_dev->bdev; + lc->bits_location.sector = LOG_OFFSET; + + size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t), + 1 << SECTOR_SHIFT); + lc->bits_location.count = size >> SECTOR_SHIFT; return 0; + + bad: + dm_put_device(ti, lc->log_dev); + core_dtr(log); + return -ENOMEM; } static void disk_dtr(struct dirty_log *log) { struct log_c *lc = (struct log_c *) log->context; - dm_put_device(lc->ti, lc->log_dev); vfree(lc->disk_header); - destroy_log_context(lc); + core_dtr(log); } static int count_bits32(uint32_t *addr, unsigned size) @@ -448,21 +442,6 @@ static int count_bits32(uint32_t *addr, unsigned size) return count; } -static void fail_log_device(struct log_c *lc) -{ - if (lc->log_dev_failed) - return; - - lc->log_dev_failed = 1; - if (lc->failure_response == DMLOG_IOERR_BLOCK) - dm_table_event(lc->ti->table); -} - -static void restore_log_device(struct log_c *lc) -{ - lc->log_dev_failed = 0; -} - static int disk_resume(struct dirty_log *log) { int r; @@ -470,18 +449,17 @@ static int disk_resume(struct dirty_log *log) struct log_c *lc = (struct log_c *) log->context; size_t size = lc->bitset_uint32_count * sizeof(uint32_t); - /* - * Read the disk header, but only if we know it is good. - * Assume the worst in the event of failure. - */ - if (!lc->log_dev_failed && read_header(lc)) { - DMWARN("Failed to read header on mirror log device, %s", - lc->log_dev->name); - fail_log_device(lc); - lc->header.nr_regions = 0; - } + /* read the disk header */ + r = read_header(lc); + if (r) + return r; + + /* read the bits */ + r = read_bits(lc); + if (r) + return r; - /* set or clear any new bits -- device has grown */ + /* set or clear any new bits */ if (lc->sync == NOSYNC) for (i = lc->header.nr_regions; i < lc->region_count; i++) /* FIXME: amazingly inefficient */ @@ -491,28 +469,20 @@ static int disk_resume(struct dirty_log *log) /* FIXME: amazingly inefficient */ log_clear_bit(lc, lc->clean_bits, i); - /* clear any old bits -- device has shrunk */ - for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++) - log_clear_bit(lc, lc->clean_bits, i); - /* copy clean across to sync */ memcpy(lc->sync_bits, lc->clean_bits, size); lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count); - lc->sync_search = 0; + + /* write the bits */ + r = write_bits(lc); + if (r) + return r; /* set the correct number of regions in the header */ lc->header.nr_regions = lc->region_count; /* write the new header */ - r = write_header(lc); - if (r) { - DMWARN("Failed to write header on mirror log device, %s", - lc->log_dev->name); - fail_log_device(lc); - } else - restore_log_device(lc); - - return r; + return write_header(lc); } static uint32_t core_get_region_size(struct dirty_log *log) @@ -521,13 +491,6 @@ static uint32_t core_get_region_size(struct dirty_log *log) return lc->region_size; } -static int core_resume(struct dirty_log *log) -{ - struct log_c *lc = (struct log_c *) log->context; - lc->sync_search = 0; - return 0; -} - static int core_is_clean(struct dirty_log *log, region_t region) { struct log_c *lc = (struct log_c *) log->context; @@ -546,11 +509,6 @@ static int core_flush(struct dirty_log *log) return 0; } -static int disk_presuspend(struct dirty_log *log) -{ - return 0; -} - static int disk_flush(struct dirty_log *log) { int r; @@ -560,13 +518,10 @@ static int disk_flush(struct dirty_log *log) if (!lc->touched) return 0; - r = write_header(lc); - if (r) - fail_log_device(lc); - else { + r = write_bits(lc); + if (!r) lc->touched = 0; - restore_log_device(lc); - } + return r; } @@ -605,19 +560,16 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region) return 1; } -static void core_set_region_sync(struct dirty_log *log, region_t region, - int in_sync) +static void core_complete_resync_work(struct dirty_log *log, region_t region, + int success) { struct log_c *lc = (struct log_c *) log->context; log_clear_bit(lc, lc->recovering_bits, region); - if (in_sync) { + if (success) { log_set_bit(lc, lc->sync_bits, region); lc->sync_count++; - } else if (log_test_bit(lc->sync_bits, region)) { - lc->sync_count--; - log_clear_bit(lc, lc->sync_bits, region); - } + } } static region_t core_get_sync_count(struct dirty_log *log) @@ -635,22 +587,16 @@ static int core_status(struct dirty_log *log, status_type_t status, char *result, unsigned int maxlen) { int sz = 0; - int params; struct log_c *lc = log->context; switch(status) { case STATUSTYPE_INFO: - DMEMIT("1 core"); break; case STATUSTYPE_TABLE: - params = (lc->sync == DEFAULTSYNC) ? 1 : 2; - params += (lc->failure_response == DMLOG_IOERR_BLOCK) ? 1 : 0; - - DMEMIT("%s %d %u ", log->type->name, params, lc->region_size); + DMEMIT("%s %u %u ", log->type->name, + lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size); DMEMIT_SYNC; - if (lc->failure_response == DMLOG_IOERR_BLOCK) - DMEMIT("block_on_error "); } return sz; @@ -660,44 +606,29 @@ static int disk_status(struct dirty_log *log, status_type_t status, char *result, unsigned int maxlen) { int sz = 0; - int params; + char buffer[16]; struct log_c *lc = log->context; switch(status) { case STATUSTYPE_INFO: - DMEMIT("3 disk %s %c", lc->log_dev->name, - lc->log_dev_failed ? 'D' : 'A'); break; case STATUSTYPE_TABLE: - params = (lc->sync == DEFAULTSYNC) ? 2 : 3; - params += (lc->failure_response == DMLOG_IOERR_BLOCK) ? 1 : 0; - - DMEMIT("%s %d %s %u ", log->type->name, - params, - lc->log_dev->name, + format_dev_t(buffer, lc->log_dev->bdev->bd_dev); + DMEMIT("%s %u %s %u ", log->type->name, + lc->sync == DEFAULTSYNC ? 2 : 3, buffer, lc->region_size); DMEMIT_SYNC; - if (lc->failure_response == DMLOG_IOERR_BLOCK) - DMEMIT("block_on_error "); } return sz; } -static int core_get_failure_response(struct dirty_log *log) -{ - struct log_c *lc = log->context; - - return lc->failure_response; -} - static struct dirty_log_type _core_type = { .name = "core", .module = THIS_MODULE, .ctr = core_ctr, .dtr = core_dtr, - .resume = core_resume, .get_region_size = core_get_region_size, .is_clean = core_is_clean, .in_sync = core_in_sync, @@ -705,10 +636,9 @@ static struct dirty_log_type _core_type = { .mark_region = core_mark_region, .clear_region = core_clear_region, .get_resync_work = core_get_resync_work, - .set_region_sync = core_set_region_sync, + .complete_resync_work = core_complete_resync_work, .get_sync_count = core_get_sync_count, .status = core_status, - .get_failure_response = core_get_failure_response, }; static struct dirty_log_type _disk_type = { @@ -716,8 +646,7 @@ static struct dirty_log_type _disk_type = { .module = THIS_MODULE, .ctr = disk_ctr, .dtr = disk_dtr, - .presuspend = disk_presuspend, - .postsuspend = disk_flush, + .suspend = disk_flush, .resume = disk_resume, .get_region_size = core_get_region_size, .is_clean = core_is_clean, @@ -726,10 +655,9 @@ static struct dirty_log_type _disk_type = { .mark_region = core_mark_region, .clear_region = core_clear_region, .get_resync_work = core_get_resync_work, - .set_region_sync = core_set_region_sync, + .complete_resync_work = core_complete_resync_work, .get_sync_count = core_get_sync_count, .status = disk_status, - .get_failure_response = core_get_failure_response, }; int __init dm_dirty_log_init(void)