[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC Patch v2 02/16] block-remus: introduce colo mode
In colo mode, SVM is running, so we can't use mode_backup for colo. Introduce a new mode: mode_cole, to do it. write: cache all write requests in ramdisk.local read: first, try to read it from ramdisk. If SVM doesn't modify this sector, read it from disk file. flush: drop all cached write requests, flush the request from master into disk file when doing checkpoint. The PVM uses mode_primary. Signed-off-by: Ye Wei <wei.ye1987@xxxxxxxxx> Signed-off-by: Jiang Yunhong <yunhong.jiang@xxxxxxxxx> Signed-off-by: Wen Congyang <wency@xxxxxxxxxxxxxx> --- tools/blktap2/drivers/block-remus.c | 139 ++++++++++++++++++++++++++++++++++- 1 files changed, 137 insertions(+), 2 deletions(-) diff --git a/tools/blktap2/drivers/block-remus.c b/tools/blktap2/drivers/block-remus.c index 079588d..bced0e9 100644 --- a/tools/blktap2/drivers/block-remus.c +++ b/tools/blktap2/drivers/block-remus.c @@ -57,6 +57,7 @@ #include <sys/sysctl.h> #include <unistd.h> #include <sys/stat.h> +#include <stdbool.h> /* timeout for reads and writes in ms */ #define HEARTBEAT_MS 1000 @@ -71,7 +72,8 @@ enum tdremus_mode { mode_invalid = 0, mode_unprotected, mode_primary, - mode_backup + mode_backup, + mode_colo }; struct tdremus_req { @@ -121,6 +123,14 @@ struct ramdisk { * */ struct hashtable* inprogress; + + /* local holds the requests from backup vm. + * If we flush the requests hold in h, we will drop all requests in + * local. + * If we switch to unprotected mode, all requests in local should be + * flushed to disk. + */ + struct hashtable* local; }; /* the ramdisk intercepts the original callback for reads and writes. @@ -1195,6 +1205,126 @@ static int backup_start(td_driver_t *driver) return 0; } +static int ramdisk_read_colo(struct ramdisk* ramdisk, uint64_t sector, + int nb_sectors, char* buf) +{ + int i; + char* v; + uint64_t key; + + for (i = 0; i < nb_sectors; i++) { + key = sector + i; + /* check whether it is queued in a previous flush request */ + if (!(v = hashtable_search(ramdisk->local, &key))) + return -1; + memcpy(buf + i * ramdisk->sector_size, v, ramdisk->sector_size); + } + + return 0; +} + +static void colo_queue_read(td_driver_t *driver, td_request_t treq) +{ + struct tdremus_state *s = (struct tdremus_state *)driver->data; + int i; + if(!remus_image) + remus_image = treq.image; + + /* check if this read is queued in any currently ongoing flush */ + if (ramdisk_read_colo(&s->ramdisk, treq.sec, treq.secs, treq.buf)) { + /* TODO: Add to pending read hash */ + td_forward_request(treq); + } else { + /* complete the request */ + td_complete_request(treq, 0); + } +} + +static inline int ramdisk_write_colo(struct ramdisk* ramdisk, uint64_t sector, + int nb_sectors, char* buf) +{ + int i, rc; + + for (i = 0; i < nb_sectors; i++) { + rc = ramdisk_write_hash(ramdisk->local, sector + i, + buf + i * ramdisk->sector_size, + ramdisk->sector_size); + if (rc) + return rc; + } + + return 0; +} + +static void colo_queue_write(td_driver_t *driver, td_request_t treq) +{ + struct tdremus_state *s = (struct tdremus_state *)driver->data; + + if (ramdisk_write_colo(&s->ramdisk, treq.sec, treq.secs, treq.buf) < 0) + td_complete_request(treq, -EBUSY); + else + td_complete_request(treq, 0); +} + +/* flush_local: + * true: we have switched to unprotected mode, so all queued requests in h + * should be dropped. + * false: all queued requests in local should be dropped, and all queued + * requests in h should be flushed. + * + */ +static int ramdisk_start_flush_colo(td_driver_t *driver, bool flush_local) +{ + struct tdremus_state *s = (struct tdremus_state *)driver->data; + + if (flush_local) { + if (s->ramdisk.h) { + hashtable_destroy(s->ramdisk.h, 1); + s->ramdisk.h = NULL; + } + if (s->ramdisk.local) { + s->ramdisk.h = s->ramdisk.local; + s->ramdisk.local = NULL; + } + } else if (s->ramdisk.local){ + hashtable_destroy(s->ramdisk.local, 1); + s->ramdisk.local = create_hashtable(RAMDISK_HASHSIZE, + uint64_hash, + rd_hash_equal); + } + + return ramdisk_start_flush(driver); +} + +/* This function will be called when we switch to unprotected mode. In this + * case, we should flush queued request in prev and local. + */ +static int colo_flush(td_driver_t *driver) +{ + struct tdremus_state *s = (struct tdremus_state *)driver->data; + + ramdisk_start_flush_colo(driver, 1); + + /* all queued requests should be flushed are in prev now, so we can + * use server_flush to do flush. + */ + s->queue_flush = server_flush; + return 0; +} + +static int colo_start(td_driver_t *driver) +{ + struct tdremus_state *s = (struct tdremus_state *)driver->data; + + /* colo mode is switched from backup mode */ + s->ramdisk.local = create_hashtable(RAMDISK_HASHSIZE, uint64_hash, + rd_hash_equal); + tapdisk_remus.td_queue_read = colo_queue_read; + tapdisk_remus.td_queue_write = colo_queue_write; + s->queue_flush = colo_flush; + return 0; +} + static int server_do_wreq(td_driver_t *driver) { struct tdremus_state *s = (struct tdremus_state *)driver->data; @@ -1255,7 +1385,10 @@ static int server_do_creq(td_driver_t *driver) // RPRINTF("committing buffer\n"); - ramdisk_start_flush(driver); + if (s->mode == mode_colo) + ramdisk_start_flush_colo(driver, 0); + else + ramdisk_start_flush(driver); /* XXX this message should not be sent until flush completes! */ if (write(s->stream_fd.fd, TDREMUS_DONE, strlen(TDREMUS_DONE)) != 4) @@ -1470,6 +1603,8 @@ static int switch_mode(td_driver_t *driver, enum tdremus_mode mode) rc = primary_start(driver); else if (mode == mode_backup) rc = backup_start(driver); + else if (mode == mode_colo) + rc = colo_start(driver); else { RPRINTF("unknown mode requested: %d\n", mode); rc = -1; -- 1.7.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |