Commit 96ab8043 authored by Alasdair G. Kergon's avatar Alasdair G. Kergon Committed by Linus Torvalds

[PATCH] device-mapper: mirror log sync optional

From: Heinz Mauelshagen <mauelshagen@redhat.com>

Make mirror log synchronization optional.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 841faa00
...@@ -140,6 +140,13 @@ struct log_c { ...@@ -140,6 +140,13 @@ struct log_c {
int sync_search; 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 * Disk log fields
*/ */
...@@ -205,7 +212,8 @@ static int read_header(struct log_c *log) ...@@ -205,7 +212,8 @@ static int read_header(struct log_c *log)
header_from_disk(&log->header, log->disk_header); header_from_disk(&log->header, log->disk_header);
if (log->header.magic != MIRROR_MAGIC) { /* New log required? */
if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) {
log->header.magic = MIRROR_MAGIC; log->header.magic = MIRROR_MAGIC;
log->header.version = MIRROR_DISK_VERSION; log->header.version = MIRROR_DISK_VERSION;
log->header.nr_regions = 0; log->header.nr_regions = 0;
...@@ -273,21 +281,37 @@ static int write_bits(struct log_c *log) ...@@ -273,21 +281,37 @@ static int write_bits(struct log_c *log)
} }
/*---------------------------------------------------------------- /*----------------------------------------------------------------
* constructor/destructor * core log constructor/destructor
*
* argv contains region_size followed optionally by [no]sync
*--------------------------------------------------------------*/ *--------------------------------------------------------------*/
#define BYTE_SHIFT 3 #define BYTE_SHIFT 3
static int core_ctr(struct dirty_log *log, struct dm_target *ti, static int core_ctr(struct dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv) unsigned int argc, char **argv)
{ {
enum sync sync = DEFAULTSYNC;
struct log_c *lc; struct log_c *lc;
sector_t region_size; sector_t region_size;
unsigned int region_count; unsigned int region_count;
size_t bitset_size; size_t bitset_size;
if (argc != 1) { if (argc < 1 || argc > 2) {
DMWARN("wrong number of arguments to log_c"); 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; return -EINVAL;
} }
}
if (sscanf(argv[0], SECTOR_FORMAT, &region_size) != 1) { if (sscanf(argv[0], SECTOR_FORMAT, &region_size) != 1) {
DMWARN("invalid region size string"); DMWARN("invalid region size string");
...@@ -306,6 +330,7 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, ...@@ -306,6 +330,7 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti,
lc->touched = 0; lc->touched = 0;
lc->region_size = region_size; lc->region_size = region_size;
lc->region_count = region_count; lc->region_count = region_count;
lc->sync = sync;
/* /*
* Work out how many words we need to hold the bitset. * Work out how many words we need to hold the bitset.
...@@ -330,8 +355,8 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti, ...@@ -330,8 +355,8 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti,
kfree(lc); kfree(lc);
return -ENOMEM; return -ENOMEM;
} }
memset(lc->sync_bits, 0, bitset_size); memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size);
lc->sync_count = 0; lc->sync_count = (sync == NOSYNC) ? region_count : 0;
lc->recovering_bits = vmalloc(bitset_size); lc->recovering_bits = vmalloc(bitset_size);
if (!lc->recovering_bits) { if (!lc->recovering_bits) {
...@@ -356,6 +381,11 @@ static void core_dtr(struct dirty_log *log) ...@@ -356,6 +381,11 @@ static void core_dtr(struct dirty_log *log)
kfree(lc); kfree(lc);
} }
/*----------------------------------------------------------------
* disk log constructor/destructor
*
* argv contains log_device region_size followed optionally by [no]sync
*--------------------------------------------------------------*/
static int disk_ctr(struct dirty_log *log, struct dm_target *ti, static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv) unsigned int argc, char **argv)
{ {
...@@ -364,8 +394,8 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti, ...@@ -364,8 +394,8 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
struct log_c *lc; struct log_c *lc;
struct dm_dev *dev; struct dm_dev *dev;
if (argc != 2) { if (argc < 2 || argc > 3) {
DMWARN("wrong number of arguments to log_d"); DMWARN("wrong number of arguments to disk mirror log");
return -EINVAL; return -EINVAL;
} }
...@@ -452,7 +482,12 @@ static int disk_resume(struct dirty_log *log) ...@@ -452,7 +482,12 @@ static int disk_resume(struct dirty_log *log)
if (r) if (r)
return r; return r;
/* zero any new bits if the mirror 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 */
log_set_bit(lc, lc->clean_bits, i);
else
for (i = lc->header.nr_regions; i < lc->region_count; i++) for (i = lc->header.nr_regions; i < lc->region_count; i++)
/* FIXME: amazingly inefficient */ /* FIXME: amazingly inefficient */
log_clear_bit(lc, lc->clean_bits, i); log_clear_bit(lc, lc->clean_bits, i);
...@@ -566,6 +601,51 @@ static region_t core_get_sync_count(struct dirty_log *log) ...@@ -566,6 +601,51 @@ static region_t core_get_sync_count(struct dirty_log *log)
return lc->sync_count; return lc->sync_count;
} }
#define DMEMIT_SYNC \
if (lc->sync != DEFAULTSYNC) \
DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
static int core_status(struct dirty_log *log, status_type_t status,
char *result, unsigned int maxlen)
{
int sz = 0;
struct log_c *lc = log->context;
switch(status) {
case STATUSTYPE_INFO:
break;
case STATUSTYPE_TABLE:
DMEMIT("%s %u " SECTOR_FORMAT " ", log->type->name,
lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size);
DMEMIT_SYNC;
}
return sz;
}
static int disk_status(struct dirty_log *log, status_type_t status,
char *result, unsigned int maxlen)
{
int sz = 0;
char buffer[16];
struct log_c *lc = log->context;
switch(status) {
case STATUSTYPE_INFO:
break;
case STATUSTYPE_TABLE:
format_dev_t(buffer, lc->log_dev->bdev->bd_dev);
DMEMIT("%s %u %s " SECTOR_FORMAT " ", log->type->name,
lc->sync == DEFAULTSYNC ? 2 : 3, buffer,
lc->region_size);
DMEMIT_SYNC;
}
return sz;
}
static struct dirty_log_type _core_type = { static struct dirty_log_type _core_type = {
.name = "core", .name = "core",
.module = THIS_MODULE, .module = THIS_MODULE,
...@@ -579,7 +659,8 @@ static struct dirty_log_type _core_type = { ...@@ -579,7 +659,8 @@ static struct dirty_log_type _core_type = {
.clear_region = core_clear_region, .clear_region = core_clear_region,
.get_resync_work = core_get_resync_work, .get_resync_work = core_get_resync_work,
.complete_resync_work = core_complete_resync_work, .complete_resync_work = core_complete_resync_work,
.get_sync_count = core_get_sync_count .get_sync_count = core_get_sync_count,
.status = core_status,
}; };
static struct dirty_log_type _disk_type = { static struct dirty_log_type _disk_type = {
...@@ -597,7 +678,8 @@ static struct dirty_log_type _disk_type = { ...@@ -597,7 +678,8 @@ static struct dirty_log_type _disk_type = {
.clear_region = core_clear_region, .clear_region = core_clear_region,
.get_resync_work = core_get_resync_work, .get_resync_work = core_get_resync_work,
.complete_resync_work = core_complete_resync_work, .complete_resync_work = core_complete_resync_work,
.get_sync_count = core_get_sync_count .get_sync_count = core_get_sync_count,
.status = disk_status,
}; };
int __init dm_dirty_log_init(void) int __init dm_dirty_log_init(void)
......
...@@ -101,6 +101,12 @@ struct dirty_log_type { ...@@ -101,6 +101,12 @@ struct dirty_log_type {
* Returns the number of regions that are in sync. * Returns the number of regions that are in sync.
*/ */
region_t (*get_sync_count)(struct dirty_log *log); region_t (*get_sync_count)(struct dirty_log *log);
/*
* Support function for mirror status requests.
*/
int (*status)(struct dirty_log *log, status_type_t status_type,
char *result, unsigned int maxlen);
}; };
int dm_register_dirty_log_type(struct dirty_log_type *type); int dm_register_dirty_log_type(struct dirty_log_type *type);
......
...@@ -1009,8 +1009,8 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti, ...@@ -1009,8 +1009,8 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
* log_type #log_params <log_params> * log_type #log_params <log_params>
* #mirrors [mirror_path offset]{2,} * #mirrors [mirror_path offset]{2,}
* *
* For now, #log_params = 1, log_type = "core" * log_type is "core" or "disk"
* * #log_params is between 1 and 3
*/ */
#define DM_IO_PAGES 64 #define DM_IO_PAGES 64
static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
...@@ -1182,13 +1182,14 @@ static int mirror_status(struct dm_target *ti, status_type_t type, ...@@ -1182,13 +1182,14 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
char *result, unsigned int maxlen) char *result, unsigned int maxlen)
{ {
char buffer[32]; char buffer[32];
unsigned int m, sz = 0; unsigned int m, sz;
struct mirror_set *ms = (struct mirror_set *) ti->private; struct mirror_set *ms = (struct mirror_set *) ti->private;
sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
switch (type) { switch (type) {
case STATUSTYPE_INFO: case STATUSTYPE_INFO:
DMEMIT("%d ", ms->nr_mirrors); DMEMIT("%d ", ms->nr_mirrors);
for (m = 0; m < ms->nr_mirrors; m++) { for (m = 0; m < ms->nr_mirrors; m++) {
format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);
DMEMIT("%s ", buffer); DMEMIT("%s ", buffer);
...@@ -1200,10 +1201,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type, ...@@ -1200,10 +1201,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
break; break;
case STATUSTYPE_TABLE: case STATUSTYPE_TABLE:
DMEMIT("%s 1 " SECTOR_FORMAT " %d ", DMEMIT("%d ", ms->nr_mirrors);
ms->rh.log->type->name, ms->rh.region_size,
ms->nr_mirrors);
for (m = 0; m < ms->nr_mirrors; m++) { for (m = 0; m < ms->nr_mirrors; m++) {
format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev); format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);
DMEMIT("%s " SECTOR_FORMAT " ", DMEMIT("%s " SECTOR_FORMAT " ",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment