|
[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 |