From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:58081) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SFljc-0008MO-91 for qemu-devel@nongnu.org; Thu, 05 Apr 2012 08:24:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SFljC-00042c-Ee for qemu-devel@nongnu.org; Thu, 05 Apr 2012 08:24:13 -0400 Received: from mail-qc0-f173.google.com ([209.85.216.173]:56022) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SFljB-00041W-R2 for qemu-devel@nongnu.org; Thu, 05 Apr 2012 08:23:50 -0400 Received: by qcsc20 with SMTP id c20so794348qcs.4 for ; Thu, 05 Apr 2012 05:23:40 -0700 (PDT) From: Ori Mamluk MIME-Version: 1.0 Date: Thu, 5 Apr 2012 15:17:52 +0300 Message-ID: <9a75ff0ba418292c14268031ae7c000f@mail.gmail.com> Content-Type: multipart/alternative; boundary=20cf302ef8ce16288104bced88b4 Subject: [Qemu-devel] [RFC PATCH v3 3/9] repagent: moved the module into block subdir, use REPAGENT instead of REPLICATION in configure List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Kevin Wolf , Roni Luxenberg , Stefan Hajnoczi , dlaor@redhat.com, Anthony Liguori , Oded Kedem , Yair Kuszpet , Paolo Bonzini --20cf302ef8ce16288104bced88b4 Content-Type: text/plain; charset=ISO-8859-1 Sent as repagent patch v2 --- Makefile | 4 +- Makefile.objs | 10 +- block.c | 8 +- block/repagent/qemu-repagent.txt | 104 ++++++++++++ block/repagent/repagent.c | 327 ++++++++++++++++++++++++++++++++++++++ block/repagent/repagent.h | 46 ++++++ block/repagent/repagent_client.c | 162 +++++++++++++++++++ block/repagent/repagent_client.h | 36 ++++ block/repagent/repcmd.h | 59 +++++++ block/repagent/repcmd_listener.c | 173 ++++++++++++++++++++ block/repagent/repcmd_listener.h | 34 ++++ block/repagent/rephub_cmds.h | 151 ++++++++++++++++++ block/repagent/rephub_defs.h | 40 +++++ configure | 14 +- replication/qemu-repagent.txt | 104 ------------ replication/repagent.c | 327 -------------------------------------- replication/repagent.h | 46 ------ replication/repagent_client.c | 160 ------------------- replication/repagent_client.h | 36 ---- replication/repcmd.h | 59 ------- replication/repcmd_listener.c | 173 -------------------- replication/repcmd_listener.h | 34 ---- replication/rephub_cmds.h | 151 ------------------ replication/rephub_defs.h | 40 ----- vl.c | 6 +- 25 files changed, 1153 insertions(+), 1151 deletions(-) create mode 100644 block/repagent/qemu-repagent.txt create mode 100644 block/repagent/repagent.c create mode 100644 block/repagent/repagent.h create mode 100644 block/repagent/repagent_client.c create mode 100644 block/repagent/repagent_client.h create mode 100644 block/repagent/repcmd.h create mode 100644 block/repagent/repcmd_listener.c create mode 100644 block/repagent/repcmd_listener.h create mode 100644 block/repagent/rephub_cmds.h create mode 100644 block/repagent/rephub_defs.h delete mode 100644 replication/qemu-repagent.txt delete mode 100644 replication/repagent.c delete mode 100644 replication/repagent.h delete mode 100644 replication/repagent_client.c delete mode 100644 replication/repagent_client.h delete mode 100644 replication/repcmd.h delete mode 100644 replication/repcmd_listener.c delete mode 100644 replication/repcmd_listener.h delete mode 100644 replication/rephub_cmds.h delete mode 100644 replication/rephub_defs.h diff --git a/Makefile b/Makefile index b6379fb..f7966f8 100644 --- a/Makefile +++ b/Makefile @@ -224,7 +224,7 @@ clean: rm -f $(GENERATED_SOURCES) rm -rf $(qapi-dir) $(MAKE) -C tests/tcg clean - rm -f replication/*.{o,d} + rm -f block/repagent/*.{o,d} for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ rm -f $$d/qemu-options.def; \ @@ -391,4 +391,4 @@ tar: rm -rf /tmp/$(FILE) # Include automatically generated dependency files --include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d replication/*.d) +-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d block/repagent/*.d) diff --git a/Makefile.objs b/Makefile.objs index 01413a2..86fad8a 100755 --- a/Makefile.objs +++ b/Makefile.objs @@ -30,10 +30,10 @@ block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y) block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o -# Replication agent -replication-nested-y = repagent_client.o repagent.o repcmd_listener.o -replication-obj-y = $(addprefix replication/, $(replication-nested-y)) -block-obj-y += $(replication-obj-y) +# Replication agent block driver - repagent +repagent-nested-y = repagent_client.o repagent.o repcmd_listener.o +repagent-obj-y = $(addprefix block/repagent/, $(repagent-nested-y)) +block-obj-y += $(repagent-obj-y) block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o @@ -80,7 +80,7 @@ fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y)) # single QEMU executable should support all CPUs and machines. common-obj-y = $(block-obj-y) blockdev.o -common-obj-y += $(replication-obj-$(CONFIG_REPLICATION)) +common-obj-y += $(repagent-obj-$(CONFIG_REPAGENT)) common-obj-y += $(net-obj-y) common-obj-y += $(qobject-obj-y) common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX)) diff --git a/block.c b/block.c index 4809416..78756d8 100644 --- a/block.c +++ b/block.c @@ -32,8 +32,8 @@ #include "qmp-commands.h" #include "qemu-timer.h" -#ifdef CONFIG_REPLICATION -#include "replication/repagent.h" +#ifdef CONFIG_REPAGENT +#include "block/repagent/repagent.h" #endif #ifdef CONFIG_BSD @@ -753,7 +753,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, goto unlink_and_fail; } -#ifdef CONFIG_REPLICATION +#ifdef CONFIG_REPAGENT repagent_register_drive(filename, bs); #endif /* Open the image */ @@ -1850,7 +1850,7 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs, } -#ifdef CONFIG_REPLICATION +#ifdef CONFIG_REPAGENT if (bs->device_name[0] != '\0') { /* We split the IO only at the highest stack driver layer. Currently we know that by checking device_name - only diff --git a/block/repagent/qemu-repagent.txt b/block/repagent/qemu-repagent.txt new file mode 100644 index 0000000..e3b0c1e --- /dev/null +++ b/block/repagent/qemu-repagent.txt @@ -0,0 +1,104 @@ + repagent - replication agent - a Qemu module for enabling continuous async replication of VM volumes + +Introduction + This document describes a feature in Qemu - a replication agent (AKA Repagent). + The Repagent is a new module that exposes an API to an external replication system (AKA Rephub). + This API allows a Rephub to communicate with a Qemu VM and continuously replicate its volumes. + The imlementation of a Rephub is outside of the scope of this document. There may be several various Rephub + implenetations using the same repagent in Qemu. + +Main feature of Repagent + Repagent does the following: + * Report volumes - report a list of all volumes in a VM to the Rephub. + * Report writes to a volume - send all writes made to a protected volume to the Rephub. + The reporting of an IO is asyncronuous - i.e. the IO is not delayed by the Repagent to get any acknowledgement from the Rephub. + It is only copied to the Rephub. + * Read a protected volume - allows the Rephub to read a protected volume, to enable the protected hub to syncronize the content of a protected volume. + +Description of the Repagent module + +Build and run options + New configure option: --enable-replication + New command line option: + -repagent [hub IP/name] + Enable replication support for disks + hub is the ip or name of the machine running the replication hub. + +Module APIs + The Repagent module interfaces two main components: + 1. The Rephub - An external API based on socket messages + 2. The generic block layer- block.c + + Rephub message API + The external replication API is a message based API. + We won't go into the structure of the messages here - just the sematics. + + Messages list + (The updated list and comments are in Rephub_cmds.h) + + Messages from the Repagent to the Rephub: + * Protected write + The Repagent sends each write to a protected volume to the hub with the IO status. + In case the status is bad the write content is not sent + * Report VM volumes + The agent reports all the volumes of the VM to the hub. + * Read Volume Response + A response to a Read Volume Request + Sends the data read from a protected volume to the hub + * Agent shutdown + Notifies the hub that the agent is about to shutdown. + This allows a graceful shutdown. Any disconnection of an agent without + sending this command will result in a full sync of the VM volumes. + + Messages from the Rephub to the Repagent: + * Start protect + The hub instructs the agent to start protecting a volume. When a volume is protected + all its writes are sent to to the hub. + With this command the hub also assigns a volume ID to the given volume name. + * Read volume request + The hub issues a read IO to a protected volume. + This command is used during sync - when the hub needs to read unsyncronized + sections of a protected volume. + This command is a request, the read data is returned by the read volume response message (see above). + block.c API + The API to the generic block storage layer contains 3 functionalities: + 1. Handle writes to protected volumes + In bdrv_co_do_writev, each write is reported to the Repagent module. + 2. Handle each new volume that registers + In bdrv_open - each new bottom-level block driver that registers is reported. + 2. Read from a volume + Repagent calls bdrv_aio_readv to handle read requests coming from the hub. + + +General description of a Rephub - a replication system the repagent connects to + This section describes in high level a sample Rephub - a replication system that uses the repagent API + to replicate disks. + It describes a simple Rephub that comntinuously maintains a mirror of the volumes of a VM. + + Say we have a VM we want to protect - call it PVM, say it has 2 volumes - V1, V2. + Our Rephub is called SingleRephub - a Rephub protecting a single VM. + + Preparations + 1. The user chooses a host to rub SingleRephub - a different host than PVM, call it Host2 + 2. The user creates two volumes on Host2 - same sizes of V1 and V2, call them V1R (V1 recovery) and V2R. + 3. The user runs SingleRephub process on Host2, and gives V1R and V2R as command line arguments. + From now on SingleRephub waits for the protected VM repagent to connect. + 4. The user runs the protected VM PVM - and uses the switch -repagent . + + Runtime + 1. The repagent module connects to SingleRephub on startup. + 2. repagent reports V1 and V2 to SingleRephub. + 3. SingleRephub starts to perform an initial synchronization of the protected volumes- + it reads each protected volume (V1 and V2) - using read volume requests - and copies the data into the + recovery volume V1R and V2R. + 4. SingleRephub enters 'protection' mode - each write to the protected volume is sent by the repagent to the Rephub, + and the Rephub performs the write on the matching recovery volume. + + * Note that during stage 3 writes to the protected volumes are not ignored - they're kept in a bitmap, + and will be read again when stage 3 ends, in an interative convergin process. + + This flow continuously maintains an updated recovery volume. + If the protected system is damaged, the user can create a new VM on Host2 with the replicated volumes attached to it. + The new VM is a replica of the protected system. + + diff --git a/block/repagent/repagent.c b/block/repagent/repagent.c new file mode 100644 index 0000000..c291915 --- /dev/null +++ b/block/repagent/repagent.c @@ -0,0 +1,327 @@ +#include +#include +#include +#include +#include + +#include "block.h" +#include "rephub_defs.h" +#include "block_int.h" +#include "repagent_client.h" +#include "repagent.h" +#include "rephub_cmds.h" + +#define ZERO_MEM_OBJ(pObj) memset(pObj, 0, sizeof(*pObj)) +#define REPAGENT_MAX_NUM_VOLUMES (64) +#define REPAGENT_VOLUME_ID_NONE (0) + +typedef struct RepagentVolume { + uint64_t vol_id; + const char *vol_path; + BlockDriverState *driver_ptr; +} RepagentVolume; + +struct RepAgentState { + int is_init; + int num_volumes; + RepagentVolume *volumes[REPAGENT_MAX_NUM_VOLUMES]; +}; + +typedef struct RepagentReadVolIo { + QEMUIOVector qiov; + RepCmdReadVolReq rep_cmd; + uint8_t *buf; + struct timeval start_time; +} RepagentReadVolIo; + +static int repagent_get_volume_by_name(const char *name); +static void repagent_report_volumes_to_hub(void); +static void repagent_vol_read_done(void *opaque, int ret); +static struct timeval tsub(struct timeval t1, struct timeval t2); + +RepAgentState g_rep_agent = { 0 }; + +void repagent_init(const char *hubname, int port) +{ + /* It is the responsibility of the thread to free this struct */ + rephub_params *pParams = (rephub_params *)g_malloc(sizeof(rephub_params)); + if (hubname == NULL) { + hubname = "127.0.0.1"; + } + if (port == 0) { + port = 9010; + } + + printf("repagent_init %s\n", hubname); + + pParams->port = port; + pParams->name = g_strdup(hubname); + + pthread_t thread_id = 0; + + /* Create the repagent client listener thread */ + pthread_create(&thread_id, 0, repagent_listen, (void *) pParams); + pthread_detach(thread_id); +} + +void repagent_register_drive(const char *drive_path, + BlockDriverState *driver_ptr) +{ + int i; + for (i = 0; i < g_rep_agent.num_volumes ; i++) { + RepagentVolume *vol = g_rep_agent.volumes[i]; + if (vol != NULL) { + assert( + strcmp(drive_path, vol->vol_path) != 0 + && driver_ptr != vol->driver_ptr); + } + } + + assert(g_rep_agent.num_volumes < REPAGENT_MAX_NUM_VOLUMES); + + printf("zerto repagent: Registering drive. Num drives %d, path %s\n", + g_rep_agent.num_volumes, drive_path); + g_rep_agent.volumes[i] = + (RepagentVolume *)g_malloc(sizeof(RepagentVolume)); + g_rep_agent.volumes[i]->driver_ptr = driver_ptr; + /* orim todo strcpy? */ + g_rep_agent.volumes[i]->vol_path = drive_path; + + /* Orim todo thread-safety? */ + g_rep_agent.num_volumes++; + + repagent_report_volumes_to_hub(); +} + +/* orim todo destruction? */ + +static RepagentVolume *repagent_get_protected_volume_by_driver( + BlockDriverState *bs) +{ + /* orim todo optimize search */ + int i = 0; + for (i = 0; i < g_rep_agent.num_volumes ; i++) { + RepagentVolume *p_vol = g_rep_agent.volumes[i]; + if (p_vol != NULL && p_vol->driver_ptr == (void *) bs) { + return p_vol; + } + } + return NULL; +} + +void repagent_handle_protected_write(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov, int ret_status) +{ + printf("zerto Protected write offset %lld, size %d, IO return status %d", + (long long int) sector_num, nb_sectors, ret_status); + if (bs->filename != NULL) { + printf(", filename %s", bs->filename); + } + + printf("\n"); + + RepagentVolume *p_vol = repagent_get_protected_volume_by_driver(bs); + if (p_vol == NULL || p_vol->vol_id == REPAGENT_VOLUME_ID_NONE) { + /* Unprotected */ + printf("Got a write to an unprotected volume.\n"); + return; + } + + /* Report IO to rephub */ + + int data_size = qiov->size; + if (ret_status < 0) { + /* On failed ios we don't send the data to the hub */ + data_size = 0; + } + uint8_t *pdata = NULL; + RepCmdProtectedWrite *p_cmd = (RepCmdProtectedWrite *) repcmd_new( + REPHUB_CMD_PROTECTED_WRITE, data_size, (uint8_t **) &pdata); + + if (ret_status >= 0) { + qemu_iovec_to_buffer(qiov, pdata); + } + + p_cmd->volume_id = p_vol->vol_id; + p_cmd->offset_sectors = sector_num; + p_cmd->size_sectors = nb_sectors; + p_cmd->ret_status = ret_status; + + if (repagent_client_send((RepCmd *) p_cmd) != 0) { + printf("Error sending command\n"); + } +} + +static void repagent_report_volumes_to_hub(void) +{ + /* Report IO to rephub */ + int i; + RepCmdDataReportVmVolumes *p_cmd_data = NULL; + RepCmdReportVmVolumes *p_cmd = (RepCmdReportVmVolumes *) repcmd_new( + REPHUB_CMD_REPORT_VM_VOLUMES, + g_rep_agent.num_volumes * sizeof(RepVmVolumeInfo), + (uint8_t **) &p_cmd_data); + p_cmd->num_volumes = g_rep_agent.num_volumes; + printf("reporting %u volumes\n", g_rep_agent.num_volumes); + for (i = 0; i < g_rep_agent.num_volumes ; i++) { + assert(g_rep_agent.volumes[i] != NULL); + printf("reporting volume %s size %u\n", + g_rep_agent.volumes[i]->vol_path, + (uint32_t) sizeof(p_cmd_data->volumes[i].name)); + strncpy((char *) p_cmd_data->volumes[i].name, + g_rep_agent.volumes[i]->vol_path, + sizeof(p_cmd_data->volumes[i].name)); + p_cmd_data->volumes[i].volume_id = g_rep_agent.volumes[i]->vol_id; + } + if (repagent_client_send((RepCmd *) p_cmd) != 0) { + printf("Error sending command\n"); + } +} + +int repaget_start_protect(RepCmdStartProtect *pcmd, + RepCmdDataStartProtect *pcmd_data) +{ + printf("Start protect vol %s, ID %llu\n", pcmd_data->volume_name, + (unsigned long long) pcmd->volume_id); + int vol_index = repagent_get_volume_by_name(pcmd_data->volume_name); + if (g_rep_agent.num_volumes > 0 + && strcmp(pcmd_data->volume_name, "stam") == 0) { + /* Choose the first one for rephub */ + vol_index = 0; + } + if (vol_index < 0) { + printf("The volume doesn't exist\n"); + return TRUE; + } + /* orim todo protect */ + g_rep_agent.volumes[vol_index]->vol_id = pcmd->volume_id; + + return TRUE; +} + +static int repagent_get_volume_by_name(const char *name) +{ + int i = 0; + for (i = 0; i < g_rep_agent.num_volumes ; i++) { + if (g_rep_agent.volumes[i] != NULL + && strcmp(name, g_rep_agent.volumes[i]->vol_path) == 0) { + return i; + } + } + return -1; +} + +static int repagent_get_volume_by_id(uint64_t vol_id) +{ + int i = 0; + for (i = 0; i < g_rep_agent.num_volumes ; i++) { + if (g_rep_agent.volumes[i] != NULL + && g_rep_agent.volumes[i]->vol_id == vol_id) { + return i; + } + } + return -1; +} + +int repaget_read_vol(RepCmdReadVolReq *pcmd, uint8_t *pdata) +{ + int index = repagent_get_volume_by_id(pcmd->volume_id); + int size_bytes = pcmd->size_sectors * 512; + if (index < 0) { + printf("Vol read - Could not find vol id %llx\n", + (unsigned long long int) pcmd->volume_id); + RepCmdReadVolRes *p_res_cmd = (RepCmdReadVolRes *) repcmd_new( + REPHUB_CMD_READ_VOL_RES, 0, NULL); + p_res_cmd->req_id = pcmd->req_id; + p_res_cmd->volume_id = pcmd->volume_id; + p_res_cmd->is_status_success = FALSE; + repagent_client_send((RepCmd *) p_res_cmd); + return TRUE; + } + + printf("Vol read - driver %p, volId %llu, offset %llu, size %u\n", + g_rep_agent.volumes[index]->driver_ptr, + (unsigned long long int) pcmd->volume_id, + (unsigned long long int) pcmd->offset_sectors, pcmd->size_sectors); + + { + RepagentReadVolIo *read_xact = calloc(1, sizeof(RepagentReadVolIo)); + +/* BlockDriverAIOCB *acb; */ + + ZERO_MEM_OBJ(read_xact); + + qemu_iovec_init(&read_xact->qiov, 1); + + /*read_xact->buf = + qemu_blockalign(g_rep_agent.volumes[index]->driver_ptr, size_bytes); */ + read_xact->buf = (uint8_t *) g_malloc(size_bytes); + read_xact->rep_cmd = *pcmd; + qemu_iovec_add(&read_xact->qiov, read_xact->buf, size_bytes); + + gettimeofday(&read_xact->start_time, NULL); + /* orim TODO - use the returned acb to cancel the request on shutdown */ + /*acb = */bdrv_aio_readv(g_rep_agent.volumes[index]->driver_ptr, + read_xact->rep_cmd.offset_sectors, &read_xact->qiov, + read_xact->rep_cmd.size_sectors, repagent_vol_read_done, + read_xact); + } + + return TRUE; +} + +static void repagent_vol_read_done(void *opaque, int ret) +{ + struct timeval t2; + RepagentReadVolIo *read_xact = (RepagentReadVolIo *) opaque; + uint8_t *pdata = NULL; + RepCmdReadVolRes *pcmd = (RepCmdReadVolRes *) repcmd_new( + REPHUB_CMD_READ_VOL_RES, read_xact->rep_cmd.size_sectors * 512, + &pdata); + pcmd->req_id = read_xact->rep_cmd.req_id; + pcmd->volume_id = read_xact->rep_cmd.volume_id; + pcmd->is_status_success = FALSE; + + printf("Protected vol read - volId %llu, offset %llu, size %u\n", + (unsigned long long int) read_xact->rep_cmd.volume_id, + (unsigned long long int) read_xact->rep_cmd.offset_sectors, + read_xact->rep_cmd.size_sectors); + gettimeofday(&t2, NULL); + + if (ret >= 0) { + /* Read response - send the data to the hub */ + t2 = tsub(t2, read_xact->start_time); + printf("Read prot vol done. Took %u seconds, %u us.", + (uint32_t) t2.tv_sec, (uint32_t) t2.tv_usec); + + pcmd->is_status_success = TRUE; + /* orim todo optimize - don't copy, use the qiov buffer */ + qemu_iovec_to_buffer(&read_xact->qiov, pdata); + } else { + printf("readv failed: %s\n", strerror(-ret)); + } + + repagent_client_send((RepCmd *) pcmd); + + /*qemu_vfree(read_xact->buf); */ + g_free(read_xact->buf); + + g_free(read_xact); +} + +static struct timeval tsub(struct timeval t1, struct timeval t2) +{ + t1.tv_usec -= t2.tv_usec; + if (t1.tv_usec < 0) { + t1.tv_usec += 1000000; + t1.tv_sec--; + } + t1.tv_sec -= t2.tv_sec; + return t1; +} + +void repagent_client_connected(void) +{ + /* orim todo thread protection */ + repagent_report_volumes_to_hub(); +} diff --git a/block/repagent/repagent.h b/block/repagent/repagent.h new file mode 100644 index 0000000..98ccbf2 --- /dev/null +++ b/block/repagent/repagent.h @@ -0,0 +1,46 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef REPAGENT_H +#define REPAGENT_H +#include + +#include "qemu-common.h" + +typedef struct RepAgentState RepAgentState; +typedef struct RepCmdStartProtect RepCmdStartProtect; +typedef struct RepCmdDataStartProtect RepCmdDataStartProtect; +struct RepCmdReadVolReq; + +void repagent_init(const char *hubname, int port); +void repagent_handle_protected_write(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int ret_status); +void repagent_register_drive(const char *drive_path, + BlockDriverState *driver_ptr); +int repaget_start_protect(RepCmdStartProtect *pcmd, + RepCmdDataStartProtect *pcmd_data); +int repaget_read_vol(struct RepCmdReadVolReq *pcmd, uint8_t *pdata); +void repagent_client_connected(void); + + +#endif /* REPAGENT_H */ diff --git a/block/repagent/repagent_client.c b/block/repagent/repagent_client.c new file mode 100644 index 0000000..9ed8485 --- /dev/null +++ b/block/repagent/repagent_client.c @@ -0,0 +1,162 @@ +#include "repcmd.h" +#include "rephub_cmds.h" +#include "repcmd_listener.h" +#include "repagent_client.h" +#include "repagent.h" +#include "main-loop.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZERO_MEM_OBJ(pObj) memset(pObj, 0, sizeof(*pObj)) + +static void repagent_process_cmd(RepCmd *pCmd, uint8_t *pData, void *clientPtr); + +typedef struct repagent_client_state { + int is_connected; + int is_terminate_receive; + int hsock; +} repagent_client_state; + +static repagent_client_state g_client_state = { 0 }; + +static void repagent_client_read(void *opaque) +{ + printf("repagent_client_read\n"); + int bytes_read = repcmd_listener_socket_read_next_buf(g_client_state.hsock); + if (bytes_read <= 0) { + printf("repagent_client_read failed (%d), errno=%d\n", + bytes_read, errno); + g_client_state.is_connected = 0; + } +} + +void *repagent_listen(void *pParam) +{ + rephub_params *pServerParams = (rephub_params *) pParam; + int host_port = pServerParams->port; + const char *host_name = pServerParams->name; + + printf("Creating repagent listener thread...\n"); + g_free(pServerParams); + + struct sockaddr_in my_addr; + + int err; + int retries = 0; + + g_client_state.hsock = socket(AF_INET, SOCK_STREAM, 0); + if (g_client_state.hsock == -1) { + printf("Error initializing socket %d\n", errno); + return (void *) -1; + } + + int param = 1; + + if ((setsockopt(g_client_state.hsock, SOL_SOCKET, SO_REUSEADDR, + (char *) ¶m, sizeof(int)) == -1) + || (setsockopt(g_client_state.hsock, SOL_SOCKET, SO_KEEPALIVE, + (char *) ¶m, sizeof(int)) == -1)) { + printf("Error setting options %d\n", errno); + return (void *) -1; + } + + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(host_port); + memset(&(my_addr.sin_zero), 0, 8); + + my_addr.sin_addr.s_addr = inet_addr(host_name); + + /* Reconnect loop */ + while (!g_client_state.is_terminate_receive) { + + if (connect(g_client_state.hsock, (struct sockaddr *) &my_addr, + sizeof(my_addr)) == -1) { + err = errno; + if (err != EINPROGRESS) { + retries++; + fprintf( + stderr, + "Error connecting socket %d. Host %s, port %u. Retry count %d\n", + errno, host_name, host_port, retries); + usleep(5 * 1000 * 1000); + continue; + } + } + retries = 0; + + printf("After connect\n"); + g_client_state.is_connected = 1; + repagent_client_connected(); + repcmd_listener_init(repagent_process_cmd, NULL); + static int c; + /* repcmd_listener_socket_thread_listener(g_client_state.hsock); */ + qemu_set_fd_handler(g_client_state.hsock, repagent_client_read, NULL, + NULL); + while (g_client_state.is_connected) { + printf("Connected (%d)...\n", c++); + usleep(1 * 1000 * 1000); + } + /* Unregister */ + qemu_set_fd_handler(g_client_state.hsock, NULL, NULL, NULL); + + printf("Disconnected\n"); + g_client_state.is_connected = 0; + close(g_client_state.hsock); + + } + return 0; +} + +void repagent_process_cmd(RepCmd *pcmd, uint8_t *pdata, void *clientPtr) +{ + int is_free_data = 1; + printf("Repagent got cmd %d\n", pcmd->hdr.cmdid); + switch (pcmd->hdr.cmdid) { + case REPHUB_CMD_START_PROTECT: { + is_free_data = repaget_start_protect((RepCmdStartProtect *) pcmd, + (RepCmdDataStartProtect *) pdata); + } + break; + case REPHUB_CMD_READ_VOL_REQ: { + is_free_data = repaget_read_vol((RepCmdReadVolReq *) pcmd, pdata); + } + break; + default: + assert(0); + break; + + } + + if (is_free_data) { + g_free(pdata); + } +} + +int repagent_client_send(RepCmd *p_cmd) +{ + int bytecount = 0; + printf("Send cmd %u, data size %u\n", p_cmd->hdr.cmdid, + p_cmd->hdr.data_size_bytes); + if (!g_client_state.is_connected) { + printf("Not connected to hub\n"); + return -1; + } + + bytecount = send(g_client_state.hsock, p_cmd, + sizeof(RepCmd) + p_cmd->hdr.data_size_bytes, 0); + if (bytecount < sizeof(RepCmd) + p_cmd->hdr.data_size_bytes) { + printf("Bad send %d, errno %d\n", bytecount, errno); + return bytecount; + } + + /* Success */ + return 0; +} diff --git a/block/repagent/repagent_client.h b/block/repagent/repagent_client.h new file mode 100644 index 0000000..62a5377 --- /dev/null +++ b/block/repagent/repagent_client.h @@ -0,0 +1,36 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef REPAGENT_CLIENT_H +#define REPAGENT_CLIENT_H +#include "repcmd.h" + +typedef struct rephub_params { + char *name; + int port; +} rephub_params; + +void *repagent_listen(void *pParam); +int repagent_client_send(RepCmd *p_cmd); + +#endif /* REPAGENT_CLIENT_H */ diff --git a/block/repagent/repcmd.h b/block/repagent/repcmd.h new file mode 100644 index 0000000..8c6cf1b --- /dev/null +++ b/block/repagent/repcmd.h @@ -0,0 +1,59 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef REPCMD_H +#define REPCMD_H + +#include + +#define REPCMD_MAGIC1 (0x1122) +#define REPCMD_MAGIC2 (0x3344) +#define REPCMD_NUM_U32_PARAMS (11) + +enum RepCmds { + REPCMD_FIRST_INVALID = 0, + REPCMD_FIRST_HUBCMD = 1, + REPHUB_CMD_PROTECTED_WRITE = 2, + REPHUB_CMD_REPORT_VM_VOLUMES = 3, + REPHUB_CMD_START_PROTECT = 4, + REPHUB_CMD_READ_VOL_REQ = 5, + REPHUB_CMD_READ_VOL_RES = 6, + REPHUB_CMD_AGENT_SHUTDOWN = 7, +}; + +typedef struct RepCmdHdr { + uint16_t magic1; + uint16_t cmdid; + uint32_t data_size_bytes; +} RepCmdHdr; + +typedef struct RepCmd { + RepCmdHdr hdr; + unsigned int parameters[REPCMD_NUM_U32_PARAMS]; + unsigned int magic2; + uint8_t data[0]; +} RepCmd; + +RepCmd *repcmd_new(int cmd_id, int data_size, uint8_t **p_out_pdata); + +#endif /* REPCMD_H */ diff --git a/block/repagent/repcmd_listener.c b/block/repagent/repcmd_listener.c new file mode 100644 index 0000000..54d3f60 --- /dev/null +++ b/block/repagent/repcmd_listener.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Use the CONFIG_REPAGENT flag to determine whether + * we're under qemu build or a hub When under + * qemu use g_malloc */ +#ifdef CONFIG_REPAGENT +#include +#define REPCMD_MALLOC g_malloc +#else +#define REPCMD_MALLOC malloc +#endif + +#include "repcmd.h" +#include "repcmd_listener.h" + +#define ZERO_MEM_OBJ(pObj) memset((void *)pObj, 0, sizeof(*pObj)) + + +typedef struct RepCmdRxCmdState { + RepCmd curCmd; + uint8_t *pReadBuf; + int bytesToGet; + int bytesGotten; + int isGotHeader; + uint8_t *pdata; +} RepCmdRxCmdState; + +typedef struct RepCmdListenerState { + int is_terminate_receive; + pfn_received_cmd_cb receive_cb; + void *opaque; + int hsock; + RepCmdRxCmdState cur_cmd; +} RepCmdListenerState; + +static RepCmdListenerState g_listenerState = { 0 }; + +static int repcmd_listener_process_rx(int bytecount); + +void repcmd_listener_init(pfn_received_cmd_cb callback, void *opaque) +{ + ZERO_MEM_OBJ(&g_listenerState); + g_listenerState.receive_cb = callback; + g_listenerState.opaque = opaque; + + g_listenerState.cur_cmd.bytesToGet = sizeof(RepCmd); + g_listenerState.cur_cmd.pReadBuf = + (uint8_t *) &g_listenerState.cur_cmd.curCmd; +} + +int repcmd_listener_socket_read_next_buf(int hsock) +{ + RepCmdRxCmdState *cmd_state = &g_listenerState.cur_cmd; + int bytecount = recv(hsock, cmd_state->pReadBuf + cmd_state->bytesGotten, + cmd_state->bytesToGet - cmd_state->bytesGotten, 0); + return repcmd_listener_process_rx(bytecount); +} + +/* Returns 0 for initiated termination or socket error value on error */ +int repcmd_listener_socket_thread_listener(int hsock) +{ + int ret = 0; + /* receive loop */ + while (!g_listenerState.is_terminate_receive) { + ret = repcmd_listener_socket_read_next_buf(hsock); + if (ret <= 0) { + return ret; + } + } + return 0; +} + +static int repcmd_listener_process_rx(int bytecount) +{ + RepCmdRxCmdState *cmd_state = &g_listenerState.cur_cmd; + if (bytecount == -1) { + fprintf(stderr, "Error receiving data %d\n", errno); + return errno; + } + + if (bytecount == 0) { + printf("Disconnected\n"); + return 0; + } + cmd_state->bytesGotten += bytecount; +/* printf("Recieved bytes %d, got %d/%d\n", + bytecount, cmd_state->bytesGotten, cmd_state->bytesToGet); */ + /* print content */ + if (0) { + int i; + for (i = 0; i < bytecount ; i += 4) { + /*printf("%d/%d", i, bytecount/4); */ + printf( + "%#x ", + *(int *) (&cmd_state->pReadBuf[cmd_state->bytesGotten + - bytecount + i])); + + } + printf("\n"); + } + assert(cmd_state->bytesGotten <= cmd_state->bytesToGet); + if (cmd_state->bytesGotten == cmd_state->bytesToGet) { + int isGotData = 0; + cmd_state->bytesGotten = 0; + if (!cmd_state->isGotHeader) { + /* We just got the header */ + cmd_state->isGotHeader = 1; + + assert(cmd_state->curCmd.hdr.magic1 == REPCMD_MAGIC1); + assert(cmd_state->curCmd.magic2 == REPCMD_MAGIC2); + if (cmd_state->curCmd.hdr.data_size_bytes > 0) { + cmd_state->pdata = (uint8_t *)REPCMD_MALLOC( + cmd_state->curCmd.hdr.data_size_bytes); +/* printf("malloc %p\n", cmd_state->pdata); */ + cmd_state->pReadBuf = cmd_state->pdata; + } else { + /* no data */ + isGotData = 1; + cmd_state->pdata = NULL; + } + cmd_state->bytesToGet = cmd_state->curCmd.hdr.data_size_bytes; + } else { + isGotData = 1; + } + + if (isGotData) { + /* Got command and data */ + (*g_listenerState.receive_cb)(&cmd_state->curCmd, cmd_state->pdata, + g_listenerState.opaque); + + /* It's the callee responsibility to free cmd_state->pdata */ + cmd_state->pdata = NULL; + ZERO_MEM_OBJ(&cmd_state->curCmd); + cmd_state->pReadBuf = (uint8_t *) &cmd_state->curCmd; + cmd_state->bytesGotten = 0; + cmd_state->bytesToGet = sizeof(RepCmd); + cmd_state->isGotHeader = 0; + } + } + return bytecount; +} + +RepCmd *repcmd_new(int cmd_id, int data_size, uint8_t **p_out_pdata) +{ + RepCmd *p_cmd = (RepCmd *)REPCMD_MALLOC(sizeof(RepCmd) + data_size); + assert(p_cmd != NULL); + + /* Zero the CMD (not the data) */ + ZERO_MEM_OBJ(p_cmd); + + p_cmd->hdr.cmdid = cmd_id; + p_cmd->hdr.magic1 = REPCMD_MAGIC1; + p_cmd->magic2 = REPCMD_MAGIC2; + p_cmd->hdr.data_size_bytes = data_size; + + if (p_out_pdata != NULL) { + *p_out_pdata = p_cmd->data; + } + + return p_cmd; +} + diff --git a/block/repagent/repcmd_listener.h b/block/repagent/repcmd_listener.h new file mode 100644 index 0000000..19b9ea9 --- /dev/null +++ b/block/repagent/repcmd_listener.h @@ -0,0 +1,34 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef REPCMD_LISTENER_H +#define REPCMD_LISTENER_H +#include +typedef void (*pfn_received_cmd_cb)(RepCmd *pcmd, + uint8_t *pdata, void *opaque); + +void repcmd_listener_init(pfn_received_cmd_cb callback, void *opaque); +int repcmd_listener_socket_read_next_buf(int hsock); +int repcmd_listener_socket_thread_listener(int hsock); + +#endif /* REPCMD_LISTENER_H */ diff --git a/block/repagent/rephub_cmds.h b/block/repagent/rephub_cmds.h new file mode 100644 index 0000000..3bd4eb4 --- /dev/null +++ b/block/repagent/rephub_cmds.h @@ -0,0 +1,151 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef REPHUB_CMDS_H +#define REPHUB_CMDS_H + +#include +#include "repcmd.h" +#include "rephub_defs.h" + +/********************************************************* + * RepCmd Report a protected IO + * + * REPHUB_CMD_PROTECTED_WRITE + * Direction: agent->hub + * + * Any write of a protected volume is send with this + * message to the hub, with its status. + * When case the status is bad no data is sent + *********************************************************/ +typedef struct RepCmdProtectedWrite { + RepCmdHdr hdr; + uint64_t volume_id; + uint64_t offset_sectors; + /* The size field duplicates the RepCmd size, + * but it is needed for reporting failed IOs' sizes */ + uint32_t size_sectors; + int ret_status; +} RepCmdProtectedWrite; + +/********************************************************* + * RepCmd Report VM volumes + * + * REPHUB_CMD_REPORT_VM_VOLUMES + * Direction: agent->hub + * + * The agent reports all the volumes of the VM + * to the hub. + *********************************************************/ +typedef struct RepVmVolumeInfo { + char name[REPHUB_MAX_VOL_NAME_LEN]; + uint64_t volume_id; + uint32_t size_mb; + uint32_t padding; +} RepVmVolumeInfo; + +typedef struct RepCmdReportVmVolumes { + RepCmdHdr hdr; + int num_volumes; +} RepCmdReportVmVolumes; + +typedef struct RepCmdDataReportVmVolumes { + RepVmVolumeInfo volumes[0]; +} RepCmdDataReportVmVolumes; + + +/********************************************************* + * RepCmd Start protect + * + * REPHUB_CMD_START_PROTECT + * Direction: hub->agent + * + * The hub instructs the agent to start protecting + * a volume. When a volume is protected all its writes + * are sent to to the hub. + * With this command the hub also assigns a volume ID to + * the given volume name. + *********************************************************/ +typedef struct RepCmdStartProtect { + RepCmdHdr hdr; + uint64_t volume_id; +} RepCmdStartProtect; + +typedef struct RepCmdDataStartProtect { + char volume_name[REPHUB_MAX_VOL_NAME_LEN]; +} RepCmdDataStartProtect; + + +/********************************************************* + * RepCmd Read Volume Request + * + * REPHUB_CMD_READ_VOL_REQ + * Direction: hub->agent + * + * The hub issues a read IO to a protected volume. + * This command is used during sync - when the hub needs + * to read unsyncronized sections of a protected volume. + * This command is a request, the read data is returned + * by the response command REPHUB_CMD_READ_VOL_RES + *********************************************************/ +typedef struct RepCmdReadVolReq { + RepCmdHdr hdr; + int req_id; + int size_sectors; + uint64_t volume_id; + uint64_t offset_sectors; +} RepCmdReadVolReq; + +/********************************************************* + * RepCmd Read Volume Response + * + * REPHUB_CMD_READ_VOL_RES + * Direction: agent->hub + * + * A response to REPHUB_CMD_READ_VOL_REQ. + * Sends the data read from a protected volume + *********************************************************/ +typedef struct RepCmdReadVolRes { + RepCmdHdr hdr; + int req_id; + int is_status_success; + uint64_t volume_id; +} RepCmdReadVolRes; + +/********************************************************* + * RepCmd Agent shutdown + * + * REPHUB_CMD_AGENT_SHUTDOWN + * Direction: agent->hub + * + * Notifies the hub that the agent is about to shutdown. + * This allows a graceful shutdown. Any disconnection + * of an agent without sending this command will result + * in a full sync of the VM volumes. + *********************************************************/ +typedef struct RepCmdAgentShutdown { + RepCmdHdr hdr; +} RepCmdAgentShutdown; + + +#endif /* REPHUB_CMDS_H */ diff --git a/block/repagent/rephub_defs.h b/block/repagent/rephub_defs.h new file mode 100644 index 0000000..e34e0ce --- /dev/null +++ b/block/repagent/rephub_defs.h @@ -0,0 +1,40 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef REP_HUB_DEFS_H +#define REP_HUB_DEFS_H + +#include + +#define REPHUB_MAX_VOL_NAME_LEN (1024) +#define REPHUB_MAX_NUM_VOLUMES (512) + +#ifndef TRUE + #define TRUE (1) +#endif + +#ifndef FALSE + #define FALSE (0) +#endif + +#endif /* REP_HUB_DEFS_H */ diff --git a/configure b/configure index 83b74c2..3d17ae5 100755 --- a/configure +++ b/configure @@ -189,7 +189,7 @@ spice="" rbd="" smartcard="" smartcard_nss="" -replication="" +repagent="" usb_redir="" opengl="" zlib="yes" @@ -807,9 +807,9 @@ for opt do ;; --enable-smartcard-nss) smartcard_nss="yes" ;; - --disable-replication) replication="no" + --disable-repagent) repagent="no" ;; - --enable-replication) replication="yes" + --enable-repagent) repagent="yes" ;; --disable-usb-redir) usb_redir="no" ;; @@ -1109,7 +1109,7 @@ echo " --disable-usb-redir disable usb network redirection support" echo " --enable-usb-redir enable usb network redirection support" echo " --disable-guest-agent disable building of the QEMU Guest Agent" echo " --enable-guest-agent enable building of the QEMU Guest Agent" -echo " --enable-replication enable replication support" +echo " --enable-repagent enable replication support" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -3220,8 +3220,8 @@ if test "$smartcard_nss" = "yes" ; then echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak fi -if test "$replication" = "yes" ; then - echo "CONFIG_REPLICATION=y" >> $config_host_mak +if test "$repagent" = "yes" ; then + echo "CONFIG_REPAGENT=y" >> $config_host_mak fi if test "$usb_redir" = "yes" ; then @@ -3904,4 +3904,4 @@ if test "$docs" = "yes" ; then mkdir -p QMP fi -echo "Replication $replication" +echo "Repagent $repagent" diff --git a/replication/qemu-repagent.txt b/replication/qemu-repagent.txt deleted file mode 100644 index e3b0c1e..0000000 --- a/replication/qemu-repagent.txt +++ /dev/null @@ -1,104 +0,0 @@ - repagent - replication agent - a Qemu module for enabling continuous async replication of VM volumes - -Introduction - This document describes a feature in Qemu - a replication agent (AKA Repagent). - The Repagent is a new module that exposes an API to an external replication system (AKA Rephub). - This API allows a Rephub to communicate with a Qemu VM and continuously replicate its volumes. - The imlementation of a Rephub is outside of the scope of this document. There may be several various Rephub - implenetations using the same repagent in Qemu. - -Main feature of Repagent - Repagent does the following: - * Report volumes - report a list of all volumes in a VM to the Rephub. - * Report writes to a volume - send all writes made to a protected volume to the Rephub. - The reporting of an IO is asyncronuous - i.e. the IO is not delayed by the Repagent to get any acknowledgement from the Rephub. - It is only copied to the Rephub. - * Read a protected volume - allows the Rephub to read a protected volume, to enable the protected hub to syncronize the content of a protected volume. - -Description of the Repagent module - -Build and run options - New configure option: --enable-replication - New command line option: - -repagent [hub IP/name] - Enable replication support for disks - hub is the ip or name of the machine running the replication hub. - -Module APIs - The Repagent module interfaces two main components: - 1. The Rephub - An external API based on socket messages - 2. The generic block layer- block.c - - Rephub message API - The external replication API is a message based API. - We won't go into the structure of the messages here - just the sematics. - - Messages list - (The updated list and comments are in Rephub_cmds.h) - - Messages from the Repagent to the Rephub: - * Protected write - The Repagent sends each write to a protected volume to the hub with the IO status. - In case the status is bad the write content is not sent - * Report VM volumes - The agent reports all the volumes of the VM to the hub. - * Read Volume Response - A response to a Read Volume Request - Sends the data read from a protected volume to the hub - * Agent shutdown - Notifies the hub that the agent is about to shutdown. - This allows a graceful shutdown. Any disconnection of an agent without - sending this command will result in a full sync of the VM volumes. - - Messages from the Rephub to the Repagent: - * Start protect - The hub instructs the agent to start protecting a volume. When a volume is protected - all its writes are sent to to the hub. - With this command the hub also assigns a volume ID to the given volume name. - * Read volume request - The hub issues a read IO to a protected volume. - This command is used during sync - when the hub needs to read unsyncronized - sections of a protected volume. - This command is a request, the read data is returned by the read volume response message (see above). - block.c API - The API to the generic block storage layer contains 3 functionalities: - 1. Handle writes to protected volumes - In bdrv_co_do_writev, each write is reported to the Repagent module. - 2. Handle each new volume that registers - In bdrv_open - each new bottom-level block driver that registers is reported. - 2. Read from a volume - Repagent calls bdrv_aio_readv to handle read requests coming from the hub. - - -General description of a Rephub - a replication system the repagent connects to - This section describes in high level a sample Rephub - a replication system that uses the repagent API - to replicate disks. - It describes a simple Rephub that comntinuously maintains a mirror of the volumes of a VM. - - Say we have a VM we want to protect - call it PVM, say it has 2 volumes - V1, V2. - Our Rephub is called SingleRephub - a Rephub protecting a single VM. - - Preparations - 1. The user chooses a host to rub SingleRephub - a different host than PVM, call it Host2 - 2. The user creates two volumes on Host2 - same sizes of V1 and V2, call them V1R (V1 recovery) and V2R. - 3. The user runs SingleRephub process on Host2, and gives V1R and V2R as command line arguments. - From now on SingleRephub waits for the protected VM repagent to connect. - 4. The user runs the protected VM PVM - and uses the switch -repagent . - - Runtime - 1. The repagent module connects to SingleRephub on startup. - 2. repagent reports V1 and V2 to SingleRephub. - 3. SingleRephub starts to perform an initial synchronization of the protected volumes- - it reads each protected volume (V1 and V2) - using read volume requests - and copies the data into the - recovery volume V1R and V2R. - 4. SingleRephub enters 'protection' mode - each write to the protected volume is sent by the repagent to the Rephub, - and the Rephub performs the write on the matching recovery volume. - - * Note that during stage 3 writes to the protected volumes are not ignored - they're kept in a bitmap, - and will be read again when stage 3 ends, in an interative convergin process. - - This flow continuously maintains an updated recovery volume. - If the protected system is damaged, the user can create a new VM on Host2 with the replicated volumes attached to it. - The new VM is a replica of the protected system. - - diff --git a/replication/repagent.c b/replication/repagent.c deleted file mode 100644 index c291915..0000000 --- a/replication/repagent.c +++ /dev/null @@ -1,327 +0,0 @@ -#include -#include -#include -#include -#include - -#include "block.h" -#include "rephub_defs.h" -#include "block_int.h" -#include "repagent_client.h" -#include "repagent.h" -#include "rephub_cmds.h" - -#define ZERO_MEM_OBJ(pObj) memset(pObj, 0, sizeof(*pObj)) -#define REPAGENT_MAX_NUM_VOLUMES (64) -#define REPAGENT_VOLUME_ID_NONE (0) - -typedef struct RepagentVolume { - uint64_t vol_id; - const char *vol_path; - BlockDriverState *driver_ptr; -} RepagentVolume; - -struct RepAgentState { - int is_init; - int num_volumes; - RepagentVolume *volumes[REPAGENT_MAX_NUM_VOLUMES]; -}; - -typedef struct RepagentReadVolIo { - QEMUIOVector qiov; - RepCmdReadVolReq rep_cmd; - uint8_t *buf; - struct timeval start_time; -} RepagentReadVolIo; - -static int repagent_get_volume_by_name(const char *name); -static void repagent_report_volumes_to_hub(void); -static void repagent_vol_read_done(void *opaque, int ret); -static struct timeval tsub(struct timeval t1, struct timeval t2); - -RepAgentState g_rep_agent = { 0 }; - -void repagent_init(const char *hubname, int port) -{ - /* It is the responsibility of the thread to free this struct */ - rephub_params *pParams = (rephub_params *)g_malloc(sizeof(rephub_params)); - if (hubname == NULL) { - hubname = "127.0.0.1"; - } - if (port == 0) { - port = 9010; - } - - printf("repagent_init %s\n", hubname); - - pParams->port = port; - pParams->name = g_strdup(hubname); - - pthread_t thread_id = 0; - - /* Create the repagent client listener thread */ - pthread_create(&thread_id, 0, repagent_listen, (void *) pParams); - pthread_detach(thread_id); -} - -void repagent_register_drive(const char *drive_path, - BlockDriverState *driver_ptr) -{ - int i; - for (i = 0; i < g_rep_agent.num_volumes ; i++) { - RepagentVolume *vol = g_rep_agent.volumes[i]; - if (vol != NULL) { - assert( - strcmp(drive_path, vol->vol_path) != 0 - && driver_ptr != vol->driver_ptr); - } - } - - assert(g_rep_agent.num_volumes < REPAGENT_MAX_NUM_VOLUMES); - - printf("zerto repagent: Registering drive. Num drives %d, path %s\n", - g_rep_agent.num_volumes, drive_path); - g_rep_agent.volumes[i] = - (RepagentVolume *)g_malloc(sizeof(RepagentVolume)); - g_rep_agent.volumes[i]->driver_ptr = driver_ptr; - /* orim todo strcpy? */ - g_rep_agent.volumes[i]->vol_path = drive_path; - - /* Orim todo thread-safety? */ - g_rep_agent.num_volumes++; - - repagent_report_volumes_to_hub(); -} - -/* orim todo destruction? */ - -static RepagentVolume *repagent_get_protected_volume_by_driver( - BlockDriverState *bs) -{ - /* orim todo optimize search */ - int i = 0; - for (i = 0; i < g_rep_agent.num_volumes ; i++) { - RepagentVolume *p_vol = g_rep_agent.volumes[i]; - if (p_vol != NULL && p_vol->driver_ptr == (void *) bs) { - return p_vol; - } - } - return NULL; -} - -void repagent_handle_protected_write(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, QEMUIOVector *qiov, int ret_status) -{ - printf("zerto Protected write offset %lld, size %d, IO return status %d", - (long long int) sector_num, nb_sectors, ret_status); - if (bs->filename != NULL) { - printf(", filename %s", bs->filename); - } - - printf("\n"); - - RepagentVolume *p_vol = repagent_get_protected_volume_by_driver(bs); - if (p_vol == NULL || p_vol->vol_id == REPAGENT_VOLUME_ID_NONE) { - /* Unprotected */ - printf("Got a write to an unprotected volume.\n"); - return; - } - - /* Report IO to rephub */ - - int data_size = qiov->size; - if (ret_status < 0) { - /* On failed ios we don't send the data to the hub */ - data_size = 0; - } - uint8_t *pdata = NULL; - RepCmdProtectedWrite *p_cmd = (RepCmdProtectedWrite *) repcmd_new( - REPHUB_CMD_PROTECTED_WRITE, data_size, (uint8_t **) &pdata); - - if (ret_status >= 0) { - qemu_iovec_to_buffer(qiov, pdata); - } - - p_cmd->volume_id = p_vol->vol_id; - p_cmd->offset_sectors = sector_num; - p_cmd->size_sectors = nb_sectors; - p_cmd->ret_status = ret_status; - - if (repagent_client_send((RepCmd *) p_cmd) != 0) { - printf("Error sending command\n"); - } -} - -static void repagent_report_volumes_to_hub(void) -{ - /* Report IO to rephub */ - int i; - RepCmdDataReportVmVolumes *p_cmd_data = NULL; - RepCmdReportVmVolumes *p_cmd = (RepCmdReportVmVolumes *) repcmd_new( - REPHUB_CMD_REPORT_VM_VOLUMES, - g_rep_agent.num_volumes * sizeof(RepVmVolumeInfo), - (uint8_t **) &p_cmd_data); - p_cmd->num_volumes = g_rep_agent.num_volumes; - printf("reporting %u volumes\n", g_rep_agent.num_volumes); - for (i = 0; i < g_rep_agent.num_volumes ; i++) { - assert(g_rep_agent.volumes[i] != NULL); - printf("reporting volume %s size %u\n", - g_rep_agent.volumes[i]->vol_path, - (uint32_t) sizeof(p_cmd_data->volumes[i].name)); - strncpy((char *) p_cmd_data->volumes[i].name, - g_rep_agent.volumes[i]->vol_path, - sizeof(p_cmd_data->volumes[i].name)); - p_cmd_data->volumes[i].volume_id = g_rep_agent.volumes[i]->vol_id; - } - if (repagent_client_send((RepCmd *) p_cmd) != 0) { - printf("Error sending command\n"); - } -} - -int repaget_start_protect(RepCmdStartProtect *pcmd, - RepCmdDataStartProtect *pcmd_data) -{ - printf("Start protect vol %s, ID %llu\n", pcmd_data->volume_name, - (unsigned long long) pcmd->volume_id); - int vol_index = repagent_get_volume_by_name(pcmd_data->volume_name); - if (g_rep_agent.num_volumes > 0 - && strcmp(pcmd_data->volume_name, "stam") == 0) { - /* Choose the first one for rephub */ - vol_index = 0; - } - if (vol_index < 0) { - printf("The volume doesn't exist\n"); - return TRUE; - } - /* orim todo protect */ - g_rep_agent.volumes[vol_index]->vol_id = pcmd->volume_id; - - return TRUE; -} - -static int repagent_get_volume_by_name(const char *name) -{ - int i = 0; - for (i = 0; i < g_rep_agent.num_volumes ; i++) { - if (g_rep_agent.volumes[i] != NULL - && strcmp(name, g_rep_agent.volumes[i]->vol_path) == 0) { - return i; - } - } - return -1; -} - -static int repagent_get_volume_by_id(uint64_t vol_id) -{ - int i = 0; - for (i = 0; i < g_rep_agent.num_volumes ; i++) { - if (g_rep_agent.volumes[i] != NULL - && g_rep_agent.volumes[i]->vol_id == vol_id) { - return i; - } - } - return -1; -} - -int repaget_read_vol(RepCmdReadVolReq *pcmd, uint8_t *pdata) -{ - int index = repagent_get_volume_by_id(pcmd->volume_id); - int size_bytes = pcmd->size_sectors * 512; - if (index < 0) { - printf("Vol read - Could not find vol id %llx\n", - (unsigned long long int) pcmd->volume_id); - RepCmdReadVolRes *p_res_cmd = (RepCmdReadVolRes *) repcmd_new( - REPHUB_CMD_READ_VOL_RES, 0, NULL); - p_res_cmd->req_id = pcmd->req_id; - p_res_cmd->volume_id = pcmd->volume_id; - p_res_cmd->is_status_success = FALSE; - repagent_client_send((RepCmd *) p_res_cmd); - return TRUE; - } - - printf("Vol read - driver %p, volId %llu, offset %llu, size %u\n", - g_rep_agent.volumes[index]->driver_ptr, - (unsigned long long int) pcmd->volume_id, - (unsigned long long int) pcmd->offset_sectors, pcmd->size_sectors); - - { - RepagentReadVolIo *read_xact = calloc(1, sizeof(RepagentReadVolIo)); - -/* BlockDriverAIOCB *acb; */ - - ZERO_MEM_OBJ(read_xact); - - qemu_iovec_init(&read_xact->qiov, 1); - - /*read_xact->buf = - qemu_blockalign(g_rep_agent.volumes[index]->driver_ptr, size_bytes); */ - read_xact->buf = (uint8_t *) g_malloc(size_bytes); - read_xact->rep_cmd = *pcmd; - qemu_iovec_add(&read_xact->qiov, read_xact->buf, size_bytes); - - gettimeofday(&read_xact->start_time, NULL); - /* orim TODO - use the returned acb to cancel the request on shutdown */ - /*acb = */bdrv_aio_readv(g_rep_agent.volumes[index]->driver_ptr, - read_xact->rep_cmd.offset_sectors, &read_xact->qiov, - read_xact->rep_cmd.size_sectors, repagent_vol_read_done, - read_xact); - } - - return TRUE; -} - -static void repagent_vol_read_done(void *opaque, int ret) -{ - struct timeval t2; - RepagentReadVolIo *read_xact = (RepagentReadVolIo *) opaque; - uint8_t *pdata = NULL; - RepCmdReadVolRes *pcmd = (RepCmdReadVolRes *) repcmd_new( - REPHUB_CMD_READ_VOL_RES, read_xact->rep_cmd.size_sectors * 512, - &pdata); - pcmd->req_id = read_xact->rep_cmd.req_id; - pcmd->volume_id = read_xact->rep_cmd.volume_id; - pcmd->is_status_success = FALSE; - - printf("Protected vol read - volId %llu, offset %llu, size %u\n", - (unsigned long long int) read_xact->rep_cmd.volume_id, - (unsigned long long int) read_xact->rep_cmd.offset_sectors, - read_xact->rep_cmd.size_sectors); - gettimeofday(&t2, NULL); - - if (ret >= 0) { - /* Read response - send the data to the hub */ - t2 = tsub(t2, read_xact->start_time); - printf("Read prot vol done. Took %u seconds, %u us.", - (uint32_t) t2.tv_sec, (uint32_t) t2.tv_usec); - - pcmd->is_status_success = TRUE; - /* orim todo optimize - don't copy, use the qiov buffer */ - qemu_iovec_to_buffer(&read_xact->qiov, pdata); - } else { - printf("readv failed: %s\n", strerror(-ret)); - } - - repagent_client_send((RepCmd *) pcmd); - - /*qemu_vfree(read_xact->buf); */ - g_free(read_xact->buf); - - g_free(read_xact); -} - -static struct timeval tsub(struct timeval t1, struct timeval t2) -{ - t1.tv_usec -= t2.tv_usec; - if (t1.tv_usec < 0) { - t1.tv_usec += 1000000; - t1.tv_sec--; - } - t1.tv_sec -= t2.tv_sec; - return t1; -} - -void repagent_client_connected(void) -{ - /* orim todo thread protection */ - repagent_report_volumes_to_hub(); -} diff --git a/replication/repagent.h b/replication/repagent.h deleted file mode 100644 index 98ccbf2..0000000 --- a/replication/repagent.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef REPAGENT_H -#define REPAGENT_H -#include - -#include "qemu-common.h" - -typedef struct RepAgentState RepAgentState; -typedef struct RepCmdStartProtect RepCmdStartProtect; -typedef struct RepCmdDataStartProtect RepCmdDataStartProtect; -struct RepCmdReadVolReq; - -void repagent_init(const char *hubname, int port); -void repagent_handle_protected_write(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int ret_status); -void repagent_register_drive(const char *drive_path, - BlockDriverState *driver_ptr); -int repaget_start_protect(RepCmdStartProtect *pcmd, - RepCmdDataStartProtect *pcmd_data); -int repaget_read_vol(struct RepCmdReadVolReq *pcmd, uint8_t *pdata); -void repagent_client_connected(void); - - -#endif /* REPAGENT_H */ diff --git a/replication/repagent_client.c b/replication/repagent_client.c deleted file mode 100644 index eaa0a28..0000000 --- a/replication/repagent_client.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "repcmd.h" -#include "rephub_cmds.h" -#include "repcmd_listener.h" -#include "repagent_client.h" -#include "repagent.h" -#include "main-loop.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ZERO_MEM_OBJ(pObj) memset(pObj, 0, sizeof(*pObj)) - -static void repagent_process_cmd(RepCmd *pCmd, uint8_t *pData, void *clientPtr); - -typedef struct repagent_client_state { - int is_connected; - int is_terminate_receive; - int hsock; -} repagent_client_state; - -static repagent_client_state g_client_state = { 0 }; - -static void repagent_client_read(void *opaque) -{ - printf("repagent_client_read\n"); - int bytes_read = repcmd_listener_socket_read_next_buf(g_client_state.hsock); - if (bytes_read <= 0) { - g_client_state.is_connected = 0; - } -} - -void *repagent_listen(void *pParam) -{ - rephub_params *pServerParams = (rephub_params *) pParam; - int host_port = pServerParams->port; - const char *host_name = pServerParams->name; - - printf("Creating repagent listener thread...\n"); - g_free(pServerParams); - - struct sockaddr_in my_addr; - - int err; - int retries = 0; - - g_client_state.hsock = socket(AF_INET, SOCK_STREAM, 0); - if (g_client_state.hsock == -1) { - printf("Error initializing socket %d\n", errno); - return (void *) -1; - } - - int param = 1; - - if ((setsockopt(g_client_state.hsock, SOL_SOCKET, SO_REUSEADDR, - (char *) ¶m, sizeof(int)) == -1) - || (setsockopt(g_client_state.hsock, SOL_SOCKET, SO_KEEPALIVE, - (char *) ¶m, sizeof(int)) == -1)) { - printf("Error setting options %d\n", errno); - return (void *) -1; - } - - my_addr.sin_family = AF_INET; - my_addr.sin_port = htons(host_port); - memset(&(my_addr.sin_zero), 0, 8); - - my_addr.sin_addr.s_addr = inet_addr(host_name); - - /* Reconnect loop */ - while (!g_client_state.is_terminate_receive) { - - if (connect(g_client_state.hsock, (struct sockaddr *) &my_addr, - sizeof(my_addr)) == -1) { - err = errno; - if (err != EINPROGRESS) { - retries++; - fprintf( - stderr, - "Error connecting socket %d. Host %s, port %u. Retry count %d\n", - errno, host_name, host_port, retries); - usleep(5 * 1000 * 1000); - continue; - } - } - retries = 0; - - - repagent_client_connected(); - repcmd_listener_init(repagent_process_cmd, NULL); - g_client_state.is_connected = 1; - static int c; - /* repcmd_listener_socket_thread_listener(g_client_state.hsock); */ - qemu_set_fd_handler(g_client_state.hsock, repagent_client_read, NULL, - NULL); - while (g_client_state.is_connected) { - printf("Connected (%d)...\n", c++); - usleep(1 * 1000 * 1000); - } - /* Unregister */ - qemu_set_fd_handler(g_client_state.hsock, NULL, NULL, NULL); - - printf("Disconnected\n"); - g_client_state.is_connected = 0; - close(g_client_state.hsock); - - } - return 0; -} - -void repagent_process_cmd(RepCmd *pcmd, uint8_t *pdata, void *clientPtr) -{ - int is_free_data = 1; - printf("Repagent got cmd %d\n", pcmd->hdr.cmdid); - switch (pcmd->hdr.cmdid) { - case REPHUB_CMD_START_PROTECT: { - is_free_data = repaget_start_protect((RepCmdStartProtect *) pcmd, - (RepCmdDataStartProtect *) pdata); - } - break; - case REPHUB_CMD_READ_VOL_REQ: { - is_free_data = repaget_read_vol((RepCmdReadVolReq *) pcmd, pdata); - } - break; - default: - assert(0); - break; - - } - - if (is_free_data) { - g_free(pdata); - } -} - -int repagent_client_send(RepCmd *p_cmd) -{ - int bytecount = 0; - printf("Send cmd %u, data size %u\n", p_cmd->hdr.cmdid, - p_cmd->hdr.data_size_bytes); - if (!g_client_state.is_connected) { - printf("Not connected to hub\n"); - return -1; - } - - bytecount = send(g_client_state.hsock, p_cmd, - sizeof(RepCmd) + p_cmd->hdr.data_size_bytes, 0); - if (bytecount < sizeof(RepCmd) + p_cmd->hdr.data_size_bytes) { - printf("Bad send %d, errno %d\n", bytecount, errno); - return bytecount; - } - - /* Success */ - return 0; -} diff --git a/replication/repagent_client.h b/replication/repagent_client.h deleted file mode 100644 index 62a5377..0000000 --- a/replication/repagent_client.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef REPAGENT_CLIENT_H -#define REPAGENT_CLIENT_H -#include "repcmd.h" - -typedef struct rephub_params { - char *name; - int port; -} rephub_params; - -void *repagent_listen(void *pParam); -int repagent_client_send(RepCmd *p_cmd); - -#endif /* REPAGENT_CLIENT_H */ diff --git a/replication/repcmd.h b/replication/repcmd.h deleted file mode 100644 index 8c6cf1b..0000000 --- a/replication/repcmd.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef REPCMD_H -#define REPCMD_H - -#include - -#define REPCMD_MAGIC1 (0x1122) -#define REPCMD_MAGIC2 (0x3344) -#define REPCMD_NUM_U32_PARAMS (11) - -enum RepCmds { - REPCMD_FIRST_INVALID = 0, - REPCMD_FIRST_HUBCMD = 1, - REPHUB_CMD_PROTECTED_WRITE = 2, - REPHUB_CMD_REPORT_VM_VOLUMES = 3, - REPHUB_CMD_START_PROTECT = 4, - REPHUB_CMD_READ_VOL_REQ = 5, - REPHUB_CMD_READ_VOL_RES = 6, - REPHUB_CMD_AGENT_SHUTDOWN = 7, -}; - -typedef struct RepCmdHdr { - uint16_t magic1; - uint16_t cmdid; - uint32_t data_size_bytes; -} RepCmdHdr; - -typedef struct RepCmd { - RepCmdHdr hdr; - unsigned int parameters[REPCMD_NUM_U32_PARAMS]; - unsigned int magic2; - uint8_t data[0]; -} RepCmd; - -RepCmd *repcmd_new(int cmd_id, int data_size, uint8_t **p_out_pdata); - -#endif /* REPCMD_H */ diff --git a/replication/repcmd_listener.c b/replication/repcmd_listener.c deleted file mode 100644 index c1ce97f..0000000 --- a/replication/repcmd_listener.c +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Use the CONFIG_REPLICATION flag to determine whether - * we're under qemu build or a hub When under - * qemu use g_malloc */ -#ifdef CONFIG_REPLICATION -#include -#define REPCMD_MALLOC g_malloc -#else -#define REPCMD_MALLOC malloc -#endif - -#include "repcmd.h" -#include "repcmd_listener.h" - -#define ZERO_MEM_OBJ(pObj) memset((void *)pObj, 0, sizeof(*pObj)) - - -typedef struct RepCmdRxCmdState { - RepCmd curCmd; - uint8_t *pReadBuf; - int bytesToGet; - int bytesGotten; - int isGotHeader; - uint8_t *pdata; -} RepCmdRxCmdState; - -typedef struct RepCmdListenerState { - int is_terminate_receive; - pfn_received_cmd_cb receive_cb; - void *opaque; - int hsock; - RepCmdRxCmdState cur_cmd; -} RepCmdListenerState; - -static RepCmdListenerState g_listenerState = { 0 }; - -static int repcmd_listener_process_rx(int bytecount); - -void repcmd_listener_init(pfn_received_cmd_cb callback, void *opaque) -{ - ZERO_MEM_OBJ(&g_listenerState); - g_listenerState.receive_cb = callback; - g_listenerState.opaque = opaque; - - g_listenerState.cur_cmd.bytesToGet = sizeof(RepCmd); - g_listenerState.cur_cmd.pReadBuf = - (uint8_t *) &g_listenerState.cur_cmd.curCmd; -} - -int repcmd_listener_socket_read_next_buf(int hsock) -{ - RepCmdRxCmdState *cmd_state = &g_listenerState.cur_cmd; - int bytecount = recv(hsock, cmd_state->pReadBuf + cmd_state->bytesGotten, - cmd_state->bytesToGet - cmd_state->bytesGotten, 0); - return repcmd_listener_process_rx(bytecount); -} - -/* Returns 0 for initiated termination or socket error value on error */ -int repcmd_listener_socket_thread_listener(int hsock) -{ - int ret = 0; - /* receive loop */ - while (!g_listenerState.is_terminate_receive) { - ret = repcmd_listener_socket_read_next_buf(hsock); - if (ret <= 0) { - return ret; - } - } - return 0; -} - -static int repcmd_listener_process_rx(int bytecount) -{ - RepCmdRxCmdState *cmd_state = &g_listenerState.cur_cmd; - if (bytecount == -1) { - fprintf(stderr, "Error receiving data %d\n", errno); - return errno; - } - - if (bytecount == 0) { - printf("Disconnected\n"); - return 0; - } - cmd_state->bytesGotten += bytecount; -/* printf("Recieved bytes %d, got %d/%d\n", - bytecount, cmd_state->bytesGotten, cmd_state->bytesToGet); */ - /* print content */ - if (0) { - int i; - for (i = 0; i < bytecount ; i += 4) { - /*printf("%d/%d", i, bytecount/4); */ - printf( - "%#x ", - *(int *) (&cmd_state->pReadBuf[cmd_state->bytesGotten - - bytecount + i])); - - } - printf("\n"); - } - assert(cmd_state->bytesGotten <= cmd_state->bytesToGet); - if (cmd_state->bytesGotten == cmd_state->bytesToGet) { - int isGotData = 0; - cmd_state->bytesGotten = 0; - if (!cmd_state->isGotHeader) { - /* We just got the header */ - cmd_state->isGotHeader = 1; - - assert(cmd_state->curCmd.hdr.magic1 == REPCMD_MAGIC1); - assert(cmd_state->curCmd.magic2 == REPCMD_MAGIC2); - if (cmd_state->curCmd.hdr.data_size_bytes > 0) { - cmd_state->pdata = (uint8_t *)REPCMD_MALLOC( - cmd_state->curCmd.hdr.data_size_bytes); -/* printf("malloc %p\n", cmd_state->pdata); */ - cmd_state->pReadBuf = cmd_state->pdata; - } else { - /* no data */ - isGotData = 1; - cmd_state->pdata = NULL; - } - cmd_state->bytesToGet = cmd_state->curCmd.hdr.data_size_bytes; - } else { - isGotData = 1; - } - - if (isGotData) { - /* Got command and data */ - (*g_listenerState.receive_cb)(&cmd_state->curCmd, cmd_state->pdata, - g_listenerState.opaque); - - /* It's the callee responsibility to free cmd_state->pdata */ - cmd_state->pdata = NULL; - ZERO_MEM_OBJ(&cmd_state->curCmd); - cmd_state->pReadBuf = (uint8_t *) &cmd_state->curCmd; - cmd_state->bytesGotten = 0; - cmd_state->bytesToGet = sizeof(RepCmd); - cmd_state->isGotHeader = 0; - } - } - return bytecount; -} - -RepCmd *repcmd_new(int cmd_id, int data_size, uint8_t **p_out_pdata) -{ - RepCmd *p_cmd = (RepCmd *)REPCMD_MALLOC(sizeof(RepCmd) + data_size); - assert(p_cmd != NULL); - - /* Zero the CMD (not the data) */ - ZERO_MEM_OBJ(p_cmd); - - p_cmd->hdr.cmdid = cmd_id; - p_cmd->hdr.magic1 = REPCMD_MAGIC1; - p_cmd->magic2 = REPCMD_MAGIC2; - p_cmd->hdr.data_size_bytes = data_size; - - if (p_out_pdata != NULL) { - *p_out_pdata = p_cmd->data; - } - - return p_cmd; -} - diff --git a/replication/repcmd_listener.h b/replication/repcmd_listener.h deleted file mode 100644 index 19b9ea9..0000000 --- a/replication/repcmd_listener.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef REPCMD_LISTENER_H -#define REPCMD_LISTENER_H -#include -typedef void (*pfn_received_cmd_cb)(RepCmd *pcmd, - uint8_t *pdata, void *opaque); - -void repcmd_listener_init(pfn_received_cmd_cb callback, void *opaque); -int repcmd_listener_socket_read_next_buf(int hsock); -int repcmd_listener_socket_thread_listener(int hsock); - -#endif /* REPCMD_LISTENER_H */ diff --git a/replication/rephub_cmds.h b/replication/rephub_cmds.h deleted file mode 100644 index 3bd4eb4..0000000 --- a/replication/rephub_cmds.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef REPHUB_CMDS_H -#define REPHUB_CMDS_H - -#include -#include "repcmd.h" -#include "rephub_defs.h" - -/********************************************************* - * RepCmd Report a protected IO - * - * REPHUB_CMD_PROTECTED_WRITE - * Direction: agent->hub - * - * Any write of a protected volume is send with this - * message to the hub, with its status. - * When case the status is bad no data is sent - *********************************************************/ -typedef struct RepCmdProtectedWrite { - RepCmdHdr hdr; - uint64_t volume_id; - uint64_t offset_sectors; - /* The size field duplicates the RepCmd size, - * but it is needed for reporting failed IOs' sizes */ - uint32_t size_sectors; - int ret_status; -} RepCmdProtectedWrite; - -/********************************************************* - * RepCmd Report VM volumes - * - * REPHUB_CMD_REPORT_VM_VOLUMES - * Direction: agent->hub - * - * The agent reports all the volumes of the VM - * to the hub. - *********************************************************/ -typedef struct RepVmVolumeInfo { - char name[REPHUB_MAX_VOL_NAME_LEN]; - uint64_t volume_id; - uint32_t size_mb; - uint32_t padding; -} RepVmVolumeInfo; - -typedef struct RepCmdReportVmVolumes { - RepCmdHdr hdr; - int num_volumes; -} RepCmdReportVmVolumes; - -typedef struct RepCmdDataReportVmVolumes { - RepVmVolumeInfo volumes[0]; -} RepCmdDataReportVmVolumes; - - -/********************************************************* - * RepCmd Start protect - * - * REPHUB_CMD_START_PROTECT - * Direction: hub->agent - * - * The hub instructs the agent to start protecting - * a volume. When a volume is protected all its writes - * are sent to to the hub. - * With this command the hub also assigns a volume ID to - * the given volume name. - *********************************************************/ -typedef struct RepCmdStartProtect { - RepCmdHdr hdr; - uint64_t volume_id; -} RepCmdStartProtect; - -typedef struct RepCmdDataStartProtect { - char volume_name[REPHUB_MAX_VOL_NAME_LEN]; -} RepCmdDataStartProtect; - - -/********************************************************* - * RepCmd Read Volume Request - * - * REPHUB_CMD_READ_VOL_REQ - * Direction: hub->agent - * - * The hub issues a read IO to a protected volume. - * This command is used during sync - when the hub needs - * to read unsyncronized sections of a protected volume. - * This command is a request, the read data is returned - * by the response command REPHUB_CMD_READ_VOL_RES - *********************************************************/ -typedef struct RepCmdReadVolReq { - RepCmdHdr hdr; - int req_id; - int size_sectors; - uint64_t volume_id; - uint64_t offset_sectors; -} RepCmdReadVolReq; - -/********************************************************* - * RepCmd Read Volume Response - * - * REPHUB_CMD_READ_VOL_RES - * Direction: agent->hub - * - * A response to REPHUB_CMD_READ_VOL_REQ. - * Sends the data read from a protected volume - *********************************************************/ -typedef struct RepCmdReadVolRes { - RepCmdHdr hdr; - int req_id; - int is_status_success; - uint64_t volume_id; -} RepCmdReadVolRes; - -/********************************************************* - * RepCmd Agent shutdown - * - * REPHUB_CMD_AGENT_SHUTDOWN - * Direction: agent->hub - * - * Notifies the hub that the agent is about to shutdown. - * This allows a graceful shutdown. Any disconnection - * of an agent without sending this command will result - * in a full sync of the VM volumes. - *********************************************************/ -typedef struct RepCmdAgentShutdown { - RepCmdHdr hdr; -} RepCmdAgentShutdown; - - -#endif /* REPHUB_CMDS_H */ diff --git a/replication/rephub_defs.h b/replication/rephub_defs.h deleted file mode 100644 index e34e0ce..0000000 --- a/replication/rephub_defs.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef REP_HUB_DEFS_H -#define REP_HUB_DEFS_H - -#include - -#define REPHUB_MAX_VOL_NAME_LEN (1024) -#define REPHUB_MAX_NUM_VOLUMES (512) - -#ifndef TRUE - #define TRUE (1) -#endif - -#ifndef FALSE - #define FALSE (0) -#endif - -#endif /* REP_HUB_DEFS_H */ diff --git a/vl.c b/vl.c index 7f8f14c..17cf6ce 100644 --- a/vl.c +++ b/vl.c @@ -167,7 +167,7 @@ int main(int argc, char **argv) #include "ui/qemu-spice.h" -#include "replication/repagent.h" +#include "block/repagent/repagent.h" //#define DEBUG_NET //#define DEBUG_SLIRP @@ -2413,10 +2413,10 @@ int main(int argc, char **argv, char **envp) HD_OPTS); break; case QEMU_OPTION_repagent: -#ifdef CONFIG_REPLICATION +#ifdef CONFIG_REPAGENT repagent_init(optarg, 0); #else - fprintf(stderr, "Replication support is disabled. " + fprintf(stderr, "Repagent support is disabled. " "Don't use -repagent option.\n"); exit(1); #endif -- 1.7.6.5 --20cf302ef8ce16288104bced88b4 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable

Sent as repagent patch v2

=

---

Makefile=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 |=A0=A0=A0 4 += -

Makefile.objs=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 |=A0=A0 10 +-

block.c=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 |= =A0=A0=A0 8 +-

block/repagent/qemu-repagent.txt = |=A0 104 ++++++++++++

block/repagent/repagent.c=A0=A0=A0=A0=A0=A0=A0 |=A0 327 ++++++++++++++++++= ++++++++++++++++++++

block/repagent/repagent.h= =A0=A0=A0=A0=A0=A0=A0 |=A0=A0 46 ++++++

block/re= pagent/repagent_client.c |=A0 162 +++++++++++++++++++

block/repagent/repagent_client.h |=A0=A0 36 ++++

block/repagent/repcmd.h=A0=A0=A0=A0=A0=A0=A0=A0=A0= |=A0=A0 59 +++++++

block/repagent/repcmd_listen= er.c |=A0 173 ++++++++++++++++++++

block/repagent/repcmd_listener.h |=A0=A0 34 ++++

block/repagent/rephub_cmds.h=A0=A0=A0=A0 |=A0 151 = ++++++++++++++++++

block/repagent/rephub_defs.h= =A0=A0=A0=A0 |=A0=A0 40 +++++

configure=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 |=A0=A0 14 +-

replic= ation/qemu-repagent.txt=A0=A0=A0 |=A0 104 ------------

replication/repagent.c=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 |=A0 327 ------= --------------------------------

replication/repagent.h=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 |=A0=A0 46 ------

replication/repagent_clien= t.c=A0=A0=A0 |=A0 160 -------------------

replic= ation/repagent_client.h=A0=A0=A0 |=A0=A0 36 ----

replication/repcmd.h=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 |=A0=A0 59 -------

replication/repcmd_lis= tener.c=A0=A0=A0 |=A0 173 --------------------

r= eplication/repcmd_listener.h=A0=A0=A0 |=A0=A0 34 ----

replication/rephub_cmds.h=A0=A0=A0=A0=A0=A0=A0 |=A0= 151 ------------------

replication/rephub_defs.= h=A0=A0=A0=A0=A0=A0=A0 |=A0=A0 40 -----

vl.c=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 |=A0=A0=A0 6 +-

25 files changed, 1153 insertions(+), 1151 deletion= s(-)

create mode 100644 block/repagent/qemu-repa= gent.txt

create mode 100644 block/repagent/repag= ent.c

create mode 100644 block/repagent/repagent.h

create mode 100644 block/repagent/repagent_client.c

create mode 100644 block/repagent/repagent_client.= h

create mode 100644 block/repagent/repcmd.h

create mode 100644 block/repagent/repcmd_listener.c

<= p class=3D"MsoNormal"> create mode 100644 block/repagent/repcmd_listener.h<= /p>

create mode 100644 block/repagent/rephub_cmds.h

=

create mode 100644 block/repagent/rephub_defs.h

=

delete mode 100644 replication/qemu-repagent.txt

delete mode 100644 replication/repagent.c

delet= e mode 100644 replication/repagent.h

delete mode= 100644 replication/repagent_client.c

delete mod= e 100644 replication/repagent_client.h

delete mode 100644 replication/repcmd.h

delete mode 100644 replication/repcmd_listener.c

delete mode 100644 replication/repcmd_listener.h

delete mode 100644 replication/rephub_cmds.h

de= lete mode 100644 replication/rephub_defs.h

=A0

diff --git a/Makefile b/Makefile

index b6379fb..f7966f8 100644

--- a/Makefile

<= p class=3D"MsoNormal">+++ b/Makefile

@@ -224,7 +2= 24,7 @@ clean:

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 rm -f $(GENERATED_SOURCES)

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 rm -rf $= (qapi-dir)

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 $(MAKE) -C tests/tcg clean

-=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 rm -f replication/*.{o,d}

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 rm -f block/repagent/*.{o,d}

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 for d in= $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \

=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if test -d $$d; then $(MAKE) -C $$d= $@ || exit 1; fi; \

=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 rm -f $$d/qemu-options.def; \

@@ -391,4 +391,4 @@ tar:

= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 rm -rf /tmp/$(FILE)

=A0# Include automatically gener= ated dependency files

--include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/= *.d qga/*.d replication/*.d)

+-include $(wildcard= *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d block/re= pagent/*.d)

diff --git a/Makefile.objs b/Makefile.objs

index 01413a2..86fad8a 100755

--= - a/Makefile.objs

+++ b/Makefile.objs

@@ -30,10 +30,10 @@ block-obj-y +=3D $(coroutine-obj-y) $(qobject-obj-y) $(= version-obj-y)

block-obj-$(CONFIG_POSIX) +=3D po= six-aio-compat.o

block-obj-$(CONFIG_LINUX_AIO) += =3D linux-aio.o

-# Replication agent

=

-replication-nested-y =3D repagent_client.o=A0 repag= ent.o=A0 repcmd_listener.o

-replication-obj-y =3D= $(addprefix replication/, $(replication-nested-y))

-block-obj-y +=3D $(replication-obj-y)

+# Replication agent block driver - repagent

+repagent-nested-y =3D repagent_client.o=A0 repagent.o=A0 repcmd= _listener.o

+repagent-obj-y =3D $(addprefix block/repagent/, $(r= epagent-nested-y))

+block-obj-y +=3D $(repagent-o= bj-y)

=A0block-nested= -y +=3D raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o=

block-nested-y +=3D qcow2.o qcow2-refcount.o qcow2-= cluster.o qcow2-snapshot.o qcow2-cache.o

@@ -80,7= +80,7 @@ fsdev-obj-$(CONFIG_VIRTFS) +=3D $(addprefix fsdev/, $(fsdev-neste= d-y))

# single QEMU executable should support all CPUs an= d machines.

=A0common= -obj-y =3D $(block-obj-y) blockdev.o

-common-obj-= y +=3D $(replication-obj-$(CONFIG_REPLICATION))

+common-obj-y +=3D $(repagent-obj-$(CONFIG_REPAGENT)= )

common-obj-y +=3D $(net-obj-y)

common-obj-y +=3D $(qobject-obj-y)

c= ommon-obj-$(CONFIG_LINUX) +=3D $(fsdev-obj-$(CONFIG_LINUX))

diff --git a/block.c b/block.c

index 4809416..78756d8 100644

--- a/block.c<= /p>

+++ b/block.c

@@ -32,8 = +32,8 @@

#include "qmp-commands.h"

#include "qemu-timer.h"

-#ifdef CONFIG_REPLICATION

-#include "replication/repagent.h"

+#ifdef CONFIG_REPAGENT

+#= include "block/repagent/repagent.h"

#e= ndif

=A0#ifdef CONFIG= _BSD

@@ -753,7 +753,7 @@ int bdrv_open(BlockDriverState *= bs, const char *filename, int flags,

=A0=A0=A0=A0= =A0=A0=A0=A0 goto unlink_and_fail;

=A0=A0=A0=A0 }=

-#ifdef CONFIG_REPLICATION

+#ifdef CONFIG_REPAGENT

=A0=A0=A0=A0 repagent_re= gister_drive(filename,=A0 bs);

#endif

=A0=A0=A0 =A0/* Open the image */

@@ -1850,7 +185= 0,7 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,

<= p class=3D"MsoNormal">=A0=A0=A0=A0 }

=A0

-#ifdef CONFIG_REPLICATION

+#ifdef CONFIG_REPAGENT

=A0=A0=A0=A0 if (bs->= device_name[0] !=3D '\0') {

=A0=A0=A0=A0= =A0=A0=A0=A0 /* We split the IO only at the highest stack driver layer.

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Currently we know = that by checking device_name - only

diff --git a/= block/repagent/qemu-repagent.txt b/block/repagent/qemu-repagent.txt

new file mode 100644

index 0000000..e3b0c1e

---= /dev/null

+++ b/block/repagent/qemu-repagent.txt=

@@ -0,0 +1,104 @@

+=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 repagent - replication agent - a Qemu mod= ule for enabling continuous async replication of VM volumes

+

+Introduction

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This document describ= es a feature in Qemu - a replication agent (AKA Repagent).

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The Repagent is a new modul= e that exposes an API to an external replication system (AKA Rephub).

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This API allow= s a Rephub to communicate with a Qemu VM and continuously replicate its vol= umes.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The i= mlementation of a Rephub is outside of the scope of this document. There ma= y be several various Rephub

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 implenetations= using the same repagent in Qemu.

+

+Main feature of Repagent

+=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Repagent does the following:

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Report volum= es - report a list of all volumes in a VM to the Rephub.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Report writes to a volume -= send all writes made to a protected volume to the Rephub.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The reporting of an IO is asyncronuous - = i.e. the IO is not delayed by the Repagent to get any acknowledgement from = the Rephub.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 It is only copied to the R= ephub.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Read a prote= cted volume - allows the Rephub to read a protected volume, to enable the p= rotected hub to syncronize the content of a protected volume.

+

+Description of the Repagent module

+

+Build and run options

+=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 New configure option: --enable-replication

<= p class=3D"MsoNormal">+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 New command lin= e option:

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 -repagent [hub= IP/name]

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Enable replication support for d= isks

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 hub is the ip or name of the machine running the replication hub.

+

+Module APIs

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The Repagent module interfaces two ma= in components:

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 1. The Rephub - An external API based on socket messages

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 2. The generic block laye= r- block.c

+

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 Rephub message API

+=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Th= e external replication API is a message based API.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 We won't go into the structure of the messages here - just= the sematics.

+

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Messages li= st

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 (The updated list and comments are in Rephub_cmds.h)

+

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 Messages from the Repagent to the Rephub:

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Protec= ted write

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The Repagent sends each write to a protec= ted volume to the hub with the IO status.

+=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 In case the status is bad the write content is not= sent

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 * Report VM volumes

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 The agent reports all the volumes of the VM to the hub.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 * Read Volume Response

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 A response to a Read Volume Request

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Sends the data read from a protected volu= me to the hub

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 * Agent shutdown

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Notifies the hub that the agent is about to = shutdown.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This = allows a graceful shutdown. Any disconnection of an agent without

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sending this command= will result in a full sync of the VM volumes.

+<= /p>

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 Messages from the Rephub to the Repagent:

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 * Start protect

+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 The hub instructs the agent to start protecting a volume. When a vol= ume is protected

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 all its writes are s= ent to to the hub.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 With this command the hub also assigns a volume ID to the given volume = name.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 * Read volume request

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 The hub issues a read IO to a protected volume.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This command is used= during sync - when the hub needs to read unsyncronized

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sections of a protected volume.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This command is a re= quest, the read data is returned by the read volume response message (see a= bove).

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 bloc= k.c API

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The API to the generic block storage laye= r contains 3 functionalities:

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 1. Handl= e writes to protected volumes

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 In bdrv_co_do_= writev, each write is reported to the Repagent module.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 2. Handle each new volume that registers

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 In bdrv_open -= each new bottom-level block driver that registers is reported.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 2. Read from a volume

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Repagent calls= bdrv_aio_readv to handle read requests coming from the hub.

+

+

+Genera= l description of a Rephub=A0 - a replication system the repagent connects t= o

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This section d= escribes in high level a sample Rephub - a replication system that uses the= repagent API

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 to replicate disks.

+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 It describes a simple Rephub that comntinuously maintains a mi= rror of the volumes of a VM.

+

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 Say we have a VM we want to protect - call it PVM, say it h= as 2 volumes - V1, V2.

+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 Our Rephub is called SingleRephub - a Rephub protecting a sing= le VM.

+

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 Preparations

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 1. The user chooses a host to rub SingleRephub - a diffe= rent host than PVM, call it Host2

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 2. The user creates two volumes on Ho= st2 - same sizes of V1 and V2, call them V1R (V1 recovery) and V2R.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 3. The user runs S= ingleRephub process on Host2, and gives V1R and V2R as command line argumen= ts.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 From now on SingleRephub waits for the pr= otected VM repagent to connect.

+=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 4. The user runs the protected VM PVM - and uses the = switch -repagent <Host2 IP>.

+

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 Runtime

+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 1. The repagent module connects to SingleRephub on startup.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 2. repagent r= eports V1 and V2 to SingleRephub.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 3. SingleRephu= b starts to perform an initial synchronization of the protected volumes-

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 it reads each protected volume (V1 and= V2) - using read volume requests - and copies the data into the

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 recovery volume V1R and V2R.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 4. SingleRephub enters= 'protection' mode - each write to the protected volume is sent by = the repagent to the Rephub,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 and the Rephub performs the write on the = matching recovery volume.

+

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Note that during stage 3 write= s to the protected volumes are not ignored - they're kept in a bitmap,<= /p>

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 and will be read again when stage 3 ends,= in an interative convergin process.

+

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This flow continuousl= y maintains an updated recovery volume.

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 If the protect= ed system is damaged, the user can create a new VM on Host2 with the replic= ated volumes attached to it.

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 The new VM is a replica of the protected system.

+

+

diff --git a/block/repagent/repagent.c b/block/repagent/repagent.c

<= p class=3D"MsoNormal">new file mode 100644

index = 0000000..c291915

--- /dev/null

+++ b/block/= repagent/repagent.c

@@ -0,0 +1,327 @@

+#include <string.h>

+#inclu= de <stdlib.h>

+#include <stdio.h>

= +#include <pthread.h>

+#include <stdint.= h>

+

+#include "= ;block.h"

+#include "rephub_defs.h"

+#include "block_int.h"

+#inc= lude "repagent_client.h"

+#include &quo= t;repagent.h"

+#include "rephub_cmds.h"

+

+#define ZERO_MEM_OBJ(pObj) memset(pO= bj, 0, sizeof(*pObj))

+#define REPAGENT_MAX_NUM_V= OLUMES (64)

+#define REPAGENT_VOLUME_ID_NONE (0)

+

+typedef struct RepagentVolume {

=

+=A0=A0=A0 uint64_t vol_id;

+=A0=A0=A0 const char *vol_path;

+=A0=A0=A0 BlockDriverState *driver_ptr;

+} RepagentVolume;

+

+struct RepAgentState {

+=A0=A0=A0= int is_init;

+=A0=A0=A0 int num_volumes;

+=A0=A0=A0 RepagentVo= lume *volumes[REPAGENT_MAX_NUM_VOLUMES];

+};

<= p class=3D"MsoNormal">+

+typedef struct RepagentR= eadVolIo {

+=A0=A0=A0 QEMUIOVector qiov;

+=A0=A0=A0 RepCmdRe= adVolReq rep_cmd;

+=A0=A0=A0 uint8_t *buf;

+=A0=A0=A0 struct timeval start_time;

+} RepagentReadVolIo;

+

+static int repagent_get= _volume_by_name(const char *name);

+static void r= epagent_report_volumes_to_hub(void);

+static void= repagent_vol_read_done(void *opaque, int ret);

+static struct timeval tsub(struct timeval t1, struc= t timeval t2);

+

+RepAg= entState g_rep_agent =3D { 0 };

+

+void repagent_init(const char *hubname, int port)

+{

+=A0=A0=A0 /* It is the responsibility of th= e thread to free this struct */

+=A0=A0=A0 rephub= _params *pParams =3D (rephub_params *)g_malloc(sizeof(rephub_params));

+=A0=A0=A0 if (hubname =3D=3D NULL) {

+=A0=A0=A0=A0=A0=A0=A0 hubname =3D "127.0.0.1";

+=A0=A0=A0 }

+=A0=A0=A0 if (= port =3D=3D 0) {

+=A0=A0=A0=A0=A0=A0=A0 port =3D = 9010;

+=A0=A0=A0 }

+

+=A0=A0=A0 printf("repagent_init %s\n", hubname);<= /p>

+

+=A0=A0=A0 pParams-&g= t;port =3D port;

+=A0=A0=A0 pParams->name =3D g_strdup(hubname);

+

+=A0=A0=A0 pthread_t thread_id =3D 0;

+

+=A0=A0=A0 /* Create the rep= agent client listener thread */

+=A0=A0=A0 pthread_create(&thread_id, 0, repagen= t_listen, (void *) pParams);

+=A0=A0=A0 pthread_d= etach(thread_id);

+}

+<= /p>

+void repagent_register_drive(const char *drive_path,

+=A0=A0=A0=A0=A0=A0=A0 BlockDriverState *driver_ptr)

+{

+=A0=A0=A0 int i;

+=A0=A0=A0 for (i =3D 0; i < g_rep_agent.num_volumes ; i++) {

+=A0=A0=A0=A0=A0=A0=A0 RepagentVolume *vol =3D g_rep= _agent.volumes[i];

+=A0=A0=A0=A0=A0=A0=A0 if (vol= !=3D NULL) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 = assert(

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 strcmp(drive_path, vol->vol_path) !=3D 0

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 && driver_ptr !=3D vol->driver_ptr);

+=A0=A0=A0=A0=A0=A0=A0 }

+=A0=A0=A0 }

+

+=A0=A0=A0 assert(g_rep_ag= ent.num_volumes < REPAGENT_MAX_NUM_VOLUMES);

+

+=A0=A0=A0 printf("= zerto repagent: Registering drive. Num drives %d, path %s\n",

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep_agent.num_volume= s, drive_path);

+=A0=A0=A0 g_rep_agent.volumes[i] =3D

+=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 (RepagentVolume *)g_malloc(sizeof(RepagentVolume))= ;

+=A0=A0=A0 g_rep_agent.volumes[i]->driver_pt= r =3D driver_ptr;

+=A0=A0=A0 /* orim todo strcpy? */

+=A0=A0=A0 g_r= ep_agent.volumes[i]->vol_path =3D drive_path;

= +

+=A0=A0=A0 /* Orim todo thread-safety? */

+=A0=A0=A0 g_rep_agent.num_volumes++;

+

+=A0=A0=A0 repagent_repo= rt_volumes_to_hub();

+}

+

+/* orim todo destruction? */

+

+static RepagentVolume *repagent_get_protected_volum= e_by_driver(

+=A0=A0=A0=A0=A0=A0=A0 BlockDriverSt= ate *bs)

+{

+=A0=A0=A0 = /* orim todo optimize search */

+=A0=A0=A0 int i =3D 0;

+= =A0=A0=A0 for (i =3D 0; i < g_rep_agent.num_volumes ; i++) {

+=A0=A0=A0=A0=A0=A0=A0 RepagentVolume *p_vol =3D g_rep_agent= .volumes[i];

+=A0=A0=A0=A0=A0=A0=A0 if (p_vol !=3D NULL && p_vol->driver_ptr = =3D=3D (void *) bs) {

+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 return p_vol;

+=A0=A0=A0=A0=A0=A0=A0 }<= /p>

+=A0=A0=A0 }

+=A0=A0=A0= return NULL;

+}

+

+void repagent_handle_protected_write(BlockDriverState *bs, int64_t se= ctor_num,

+=A0=A0=A0=A0=A0=A0=A0 int nb_sectors, = QEMUIOVector *qiov, int ret_status)

+{

+=A0=A0=A0 printf("= ;zerto Protected write offset %lld, size %d, IO return status %d",

=

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (long long int) s= ector_num, nb_sectors, ret_status);

+=A0=A0=A0 if (bs->filename !=3D NULL) {

+=A0=A0=A0=A0=A0=A0=A0 printf(", filename %s", = bs->filename);

+=A0=A0=A0 }

+

+=A0=A0=A0 printf("\n");

+

+=A0=A0=A0 RepagentVolume *p_vol =3D repagent_get_protected_= volume_by_driver(bs);

+=A0=A0=A0 if (p_vol =3D=3D= NULL || p_vol->vol_id =3D=3D REPAGENT_VOLUME_ID_NONE) {

+=A0=A0=A0=A0=A0=A0=A0 /* Unprotected */

+=A0=A0=A0=A0=A0=A0=A0 printf("Got a write to an unprot= ected volume.\n");

+=A0=A0=A0=A0=A0=A0=A0 re= turn;

+=A0=A0=A0 }

+

+=A0=A0=A0 /* Report IO to rephub */

+

+=A0=A0=A0 int data_size =3D qi= ov->size;

+=A0=A0=A0 if (ret_status < 0) {<= /p>

+=A0=A0=A0=A0=A0=A0=A0 /* On failed ios we don't send the data to the h= ub */

+=A0=A0=A0=A0=A0=A0=A0 data_size =3D 0;

=

+=A0=A0=A0 }

+=A0=A0=A0 ui= nt8_t *pdata =3D NULL;

+=A0=A0=A0 RepCmdProtectedWrite *p_cmd =3D (RepCmdProtectedWrite *) repcmd_= new(

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 REPHUB_CM= D_PROTECTED_WRITE, data_size, (uint8_t **) &pdata);

+

+=A0=A0=A0 if (ret_status >=3D 0) {

+=A0=A0=A0= =A0=A0=A0=A0 qemu_iovec_to_buffer(qiov, pdata);

+= =A0=A0=A0 }

+

+=A0=A0= =A0 p_cmd->volume_id =3D p_vol->vol_id;

+=A0=A0=A0 p_cmd->offset_sectors =3D sector_num;<= /p>

+=A0=A0=A0 p_cmd->size_sectors =3D nb_sectors;=

+=A0=A0=A0 p_cmd->ret_status =3D ret_status;<= /p>

+

+=A0=A0=A0 if (repagent_client_send((RepCmd *) p_cmd= ) !=3D 0) {

+=A0=A0=A0=A0=A0=A0=A0 printf("E= rror sending command\n");

+=A0=A0=A0 }

+}

+

+static void repagent_report_volumes_to_hub(voi= d)

+{

+=A0=A0=A0 /* Rep= ort IO to rephub */

+=A0=A0=A0 int i;

+=A0=A0=A0 RepCmdDataReportVmVolumes *p_cmd_data =3D NULL;

+=A0=A0=A0 RepCmdReportVmVolumes *p_cmd =3D (RepCmdR= eportVmVolumes *) repcmd_new(

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 REPHUB_CMD_REPORT_VM_VOLUMES,

+= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep_agent.num_volumes * sizeof(RepVmVol= umeInfo),

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint8_t **) &= ;p_cmd_data);

+=A0=A0=A0 p_cmd->num_volumes = =3D g_rep_agent.num_volumes;

+=A0=A0=A0 printf(&q= uot;reporting %u volumes\n", g_rep_agent.num_volumes);

+=A0=A0=A0 for (i =3D 0; i < g_rep_agent.num_volu= mes ; i++) {

+=A0=A0=A0=A0=A0=A0=A0 assert(g_rep_= agent.volumes[i] !=3D NULL);

+=A0=A0=A0=A0=A0=A0= =A0 printf("reporting volume %s size %u\n",

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep= _agent.volumes[i]->vol_path,

+=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint32_t) sizeof(p_cmd_data->volumes[i].= name));

+=A0=A0=A0=A0=A0=A0=A0 strncpy((char *) p= _cmd_data->volumes[i].name,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep= _agent.volumes[i]->vol_path,

+=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeof(p_cmd_data->volumes[i].name));

=

+=A0=A0=A0=A0=A0=A0=A0 p_cmd_data->volumes[i].vol= ume_id =3D g_rep_agent.volumes[i]->vol_id;

+=A0=A0=A0 }

+=A0=A0=A0 if= (repagent_client_send((RepCmd *) p_cmd) !=3D 0) {

+=A0=A0=A0=A0=A0=A0=A0 printf("Error sending command\n");

+=A0=A0=A0 }

+}

+

+int repaget_start= _protect(RepCmdStartProtect *pcmd,

+=A0=A0=A0=A0= =A0=A0=A0 RepCmdDataStartProtect *pcmd_data)

+{

+=A0=A0=A0 printf("Start protect vol %s, ID %llu\n", pcmd_data-&g= t;volume_name,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= (unsigned long long) pcmd->volume_id);

+=A0= =A0=A0 int vol_index =3D repagent_get_volume_by_name(pcmd_data->volume_n= ame);

+=A0=A0=A0 if (g_rep_agent.num_volumes > 0

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 && strcmp(pc= md_data->volume_name, "stam") =3D=3D 0) {

+=A0=A0=A0=A0=A0=A0=A0 /* Choose the first one for rephub */

+=A0=A0=A0=A0=A0=A0=A0 vol_index =3D 0;

+=A0=A0=A0 }

+=A0=A0=A0 if (vol_in= dex < 0) {

+=A0=A0=A0=A0=A0=A0=A0 printf("= ;The volume doesn't exist\n");

+=A0=A0=A0=A0=A0=A0=A0 return TRUE;

+=A0=A0=A0 }<= /p>

+=A0=A0=A0 /* orim todo protect */

+=A0=A0=A0 g_rep_agent.volumes[vol_index]->vol_id =3D pcmd-&= gt;volume_id;

+

+=A0=A0=A0 return TRUE;

+}

+

+static int rep= agent_get_volume_by_name(const char *name)

+{

=

+=A0=A0=A0 int i =3D 0;

+=A0=A0=A0 for (i =3D 0; = i < g_rep_agent.num_volumes ; i++) {

+=A0=A0= =A0=A0=A0=A0=A0 if (g_rep_agent.volumes[i] !=3D NULL

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 && strcmp(name, = g_rep_agent.volumes[i]->vol_path) =3D=3D 0) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return i;

+=A0=A0=A0=A0=A0=A0=A0 }

+=A0= =A0=A0 }

+=A0=A0=A0 return -1;

+}

+

+static int repagent_get_volume_by_id(uint64_t vol_id)

+{

+=A0=A0=A0 int i =3D 0;

+=A0=A0=A0 for (i =3D 0; i < g_rep_agent.num_volumes ; i++) {<= /p>

+=A0=A0=A0=A0=A0=A0=A0 if (g_rep_agent.volumes[i] !=3D NULL

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 && g_rep_= agent.volumes[i]->vol_id =3D=3D vol_id) {

+=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return i;

+=A0=A0= =A0=A0=A0=A0=A0 }

+=A0=A0=A0 }

+=A0=A0=A0 re= turn -1;

+}

+

+int repaget_read_vol(RepCmdReadVolReq *pcmd, uint8_t *pda= ta)

+{

+=A0=A0=A0 int index =3D repagent_get_volume_b= y_id(pcmd->volume_id);

+=A0=A0 =A0int size_byt= es =3D pcmd->size_sectors * 512;

+=A0=A0=A0 if= (index < 0) {

+=A0=A0=A0=A0=A0=A0=A0 printf("Vol read - Could not find vol id %llx\n= ",

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 (unsigned long long int) pcmd->volume_id);

+=A0=A0=A0=A0=A0=A0=A0 RepCmdReadVolRes *p_res_cmd =3D (RepCmdReadVolRe= s *) repcmd_new(

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 REPHU= B_CMD_READ_VOL_RES, 0, NULL);

+=A0=A0=A0=A0=A0=A0= =A0 p_res_cmd->req_id =3D pcmd->req_id;

+= =A0=A0=A0=A0=A0=A0=A0 p_res_cmd->volume_id =3D pcmd->volume_id;

+=A0=A0=A0=A0=A0=A0=A0 p_res_cmd->is_status_succe= ss =3D FALSE;

+=A0=A0=A0=A0=A0=A0=A0 repagent_cli= ent_send((RepCmd *) p_res_cmd);

+=A0=A0=A0=A0=A0= =A0=A0 return TRUE;

+=A0=A0=A0 }

+

+=A0=A0=A0 printf("= Vol read - driver %p, volId %llu, offset %llu, size %u\n",

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep_agent.volumes[index= ]->driver_ptr,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned long long int) pcmd->volume= _id,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned= long long int) pcmd->offset_sectors, pcmd->size_sectors);

+

+=A0=A0=A0 {

+=A0=A0=A0=A0=A0=A0=A0 RepagentReadVolIo *read_xact = =3D calloc(1, sizeof(RepagentReadVolIo));

+

+/*=A0=A0=A0=A0=A0=A0=A0 BlockDriverAIOCB *acb; */

=

+

+=A0=A0=A0=A0=A0=A0=A0 ZERO_MEM_OBJ(read_xact);

+=

+=A0=A0=A0=A0=A0=A0=A0 qemu_iovec_init(&read= _xact->qiov, 1);

+

+= =A0=A0=A0=A0=A0=A0=A0 /*read_xact->buf =3D

+=A0=A0=A0=A0=A0=A0=A0 qemu_blockalign(g_rep_agent.v= olumes[index]->driver_ptr, size_bytes); */

+= =A0=A0=A0=A0=A0=A0=A0 read_xact->buf =3D (uint8_t *) g_malloc(size_bytes= );

+=A0=A0=A0=A0=A0=A0=A0 read_xact->rep_cmd = =3D *pcmd;

+=A0=A0=A0=A0=A0=A0=A0 qemu_iovec_add(&read_xact= ->qiov, read_xact->buf, size_bytes);

+

<= p class=3D"MsoNormal">+=A0=A0=A0=A0=A0=A0=A0 gettimeofday(&read_xact-&g= t;start_time, NULL);

+=A0=A0=A0=A0=A0=A0=A0 /* orim TODO - use the returned acb to cancel the re= quest on shutdown */

+=A0=A0=A0=A0=A0=A0=A0 /*acb= =3D */bdrv_aio_readv(g_rep_agent.volumes[index]->driver_ptr,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 read_xact-&g= t;rep_cmd.offset_sectors, &read_xact->qiov,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 read_= xact->rep_cmd.size_sectors, repagent_vol_read_done,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 read_xact);

+=A0=A0=A0 }

+

+=A0=A0=A0 return TRUE;

+}

+

+static void repagent_vol_read_done(void *o= paque, int ret)

+{

+=A0= =A0=A0 struct timeval t2;

+=A0=A0=A0 RepagentReadVolIo *read_xact =3D (Repagen= tReadVolIo *) opaque;

+=A0=A0=A0 uint8_t *pdata = =3D NULL;

+=A0=A0=A0 RepCmdReadVolRes *pcmd =3D (= RepCmdReadVolRes *) repcmd_new(

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 REPHUB_CMD_READ_V= OL_RES, read_xact->rep_cmd.size_sectors * 512,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 &pdata);

= +=A0=A0=A0 pcmd->req_id =3D read_xact->rep_cmd.req_id;

+=A0=A0=A0 pcmd->volume_id =3D read_xact->rep_= cmd.volume_id;

+=A0=A0=A0 pcmd->is_status_succ= ess =3D FALSE;

+

+=A0= =A0=A0 printf("Protected vol read - volId %llu, offset %llu, size %u\n= ",

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned long lo= ng int) read_xact->rep_cmd.volume_id,

+=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned long long int) read_xact->rep_cmd.= offset_sectors,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 read_xact->rep_cmd.size_sectors);

+=A0=A0=A0 gettimeofday(&t2, NULL);

+

+=A0=A0=A0 if (ret >=3D 0) {<= /p>

+=A0=A0=A0=A0=A0=A0=A0 /* Read response - send th= e data to the hub */

+=A0=A0=A0=A0=A0=A0=A0 t2 =3D tsub(t2, read_xact->start_time);

+=A0=A0=A0=A0=A0=A0=A0 printf("Read prot vol done. To= ok %u seconds, %u us.",

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint32_t) t2.tv_sec, (uint32_t) t2.tv_usec);

+

+=A0=A0=A0=A0=A0=A0=A0 p= cmd->is_status_success =3D TRUE;

+=A0=A0=A0=A0= =A0=A0=A0 /* orim todo optimize - don't copy, use the qiov buffer */

+=A0=A0=A0=A0=A0=A0=A0 qemu_iovec_to_buffer(&re= ad_xact->qiov, pdata);

+=A0=A0=A0 } else {

+=A0= =A0=A0=A0=A0=A0=A0 printf("readv failed: %s\n", strerror(-ret));<= /p>

+=A0=A0=A0 }

+

+=A0=A0=A0 repagent_client_send((RepCmd *) pcmd);

+

+=A0=A0=A0 /*qemu_vfree(= read_xact->buf); */

+=A0=A0=A0 g_free(read_xac= t->buf);

+

+=A0=A0= =A0 g_free(read_xact);

+}

+

+static struct timeval tsub(struct timeval t1, struct timeval t2)

<= p class=3D"MsoNormal">+{

+=A0=A0=A0 t1.tv_usec -= =3D t2.tv_usec;

+=A0=A0=A0 if (t1.tv_usec < 0) {

+=A0=A0=A0=A0=A0=A0=A0 t1.tv_usec +=3D 1000000;

+=A0=A0=A0=A0=A0=A0=A0 t1.tv_sec--;

+=A0= =A0=A0 }

+=A0=A0=A0 t1.tv_sec -=3D t2.tv_sec;

+=A0=A0=A0 return t1;

+}

+

+void repagent_client_= connected(void)

+{

+=A0= =A0=A0 /* orim todo thread protection */

+=A0=A0=A0 repagent_report_volumes_to_hub();

+}

diff --git a/block/repagent= /repagent.h b/block/repagent/repagent.h

new file = mode 100644

index 0000000..98ccbf2

---= /dev/null

+++ b/block/repagent/repagent.h

@@ -0,0 +1,46 @@

+/*

+ * QEMU System Emulator

+ *

+ * Copyright (c) 2003-2008 Fabrice Bellard

+ *

+ * Permission is hereby granted, free of ch= arge, to any person obtaining a copy

+ * of this software and associated documentation fi= les (the "Software"), to deal

+ * in th= e Software without restriction, including without limitation the rights

+ * to use, copy, modify, merge, publish, distribute= , sublicense, and/or sell

+ * copies of the Softw= are, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following conditions:

+ *

+ * The above copyright notice an= d this permission notice shall be included in

+ *= all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PR= OVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES = OF MERCHANTABILITY,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGE= MENT. IN NO EVENT SHALL

+ * THE AUTHORS OR COPYRI= GHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM,

+ * OUT OF OR IN CONNECTION WITH THE SOFTW= ARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTW= ARE.

+ */

+#ifndef REPAGENT_H

+#define REPAGENT_H

+#in= clude <stdint.h>

+

+#include "qemu-common.h"

+

+typedef struct RepAgent= State RepAgentState;

+typedef struct RepCmdStartP= rotect RepCmdStartProtect;

+typedef struct RepCmd= DataStartProtect RepCmdDataStartProtect;

+struct RepCmdReadVolReq;

= +

+void repagent_init(const char *hubname, int po= rt);

+void repagent_handle_protected_write(BlockD= riverState *bs,

+=A0=A0=A0=A0=A0=A0=A0 int64_t sector_num, int nb_se= ctors, QEMUIOVector *qiov, int ret_status);

+void= repagent_register_drive(const char *drive_path,

= +=A0=A0=A0=A0=A0=A0=A0 BlockDriverState *driver_ptr);

+int repaget_start_protect(RepCmdStartProtect *pcmd,=

+=A0=A0=A0=A0=A0=A0=A0 RepCmdDataStartProtect *p= cmd_data);

+int repaget_read_vol(struct RepCmdRea= dVolReq *pcmd, uint8_t *pdata);

+void repagent_client_connected(void);

+

+

+#en= dif /* REPAGENT_H */

diff --git a/block/repagent/= repagent_client.c b/block/repagent/repagent_client.c

new file mode 100644

index= 0000000..9ed8485

--- /dev/null

+++ b/block/repagent/repagent_client.c

@= @ -0,0 +1,162 @@

+#include "repcmd.h"

+#include "rephub_cmds.h"

+#includ= e "repcmd_listener.h"

+#include "r= epagent_client.h"

+#include "repagent.h"

+#include "main-loop.h"

+

+#include <string.h>

+#= include <stdlib.h>

+#include <errno.h>

= +#include <stdio.h>

+#include <resolv.h&= gt;

+#include <sys/socket.h>

+#include <arpa/inet.h>

+#include <netin= et/in.h>

+#include <unistd.h>

+

+#define ZERO_MEM_OBJ(pObj) mem= set(pObj, 0, sizeof(*pObj))

+

+static void repagent_pr= ocess_cmd(RepCmd *pCmd, uint8_t *pData, void *clientPtr);

+

+typedef struct repagent_client_state = {

+=A0=A0=A0 int is_connected;

+=A0=A0=A0 int is_terminate_receive;

+=A0=A0= =A0 int hsock;

+} repagent_client_state;

+

+static repagent_client_state g_client_state =3D { 0 };

+

+static void repagent_client_read(void *= opaque)

+{

+=A0=A0=A0 p= rintf("repagent_client_read\n");

+=A0=A0=A0 int bytes_read =3D repcmd_listener_socket= _read_next_buf(g_client_state.hsock);

+=A0=A0=A0 = if (bytes_read <=3D 0) {

+=A0=A0=A0=A0=A0=A0= =A0 printf("repagent_client_read failed (%d), errno=3D%d\n",

+=A0=A0=A0=A0=A0=A0=A0 bytes_read, errno);

+=A0=A0=A0=A0=A0=A0=A0 g_client_state.is_connected =3D 0;<= /p>

+=A0=A0=A0 }

+}

+

+void *repagent_listen(void *pParam)

+{

+=A0=A0=A0 rephub_params *pServerParams =3D (rephub_params= *) pParam;

+=A0=A0=A0 int host_port =3D pServerP= arams->port;

+=A0=A0=A0 const char *host_name =3D pServerParams-&= gt;name;

+

+=A0=A0=A0 p= rintf("Creating repagent listener thread...\n");

+=A0=A0=A0 g_free(pServerParams);

+

+=A0=A0=A0 struct sockad= dr_in my_addr;

+

+=A0= =A0=A0 int err;

+=A0=A0=A0 int retries =3D 0;

=

+

+=A0=A0=A0 g_client_state.hsock =3D socket(AF_INET, SOCK_STREAM, 0);

+=A0=A0=A0 if (g_client_state.hsock =3D=3D -1) {

+=A0=A0=A0=A0=A0=A0=A0 printf("Error initializing = socket %d\n", errno);

+=A0=A0=A0=A0=A0=A0=A0 return (void *) -1;

+=A0= =A0=A0 }

+

+=A0=A0=A0 i= nt param =3D 1;

+

+=A0= =A0=A0 if ((setsockopt(g_client_state.hsock, SOL_SOCKET, SO_REUSEADDR,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (char *) &par= am, sizeof(int)) =3D=3D -1)

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 || (setsockopt(g_client_state.hsock, SOL_SOCKET, SO_KEEPALI= VE,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 (char *) &param, sizeof(int)) =3D=3D -1)) {

+=A0=A0=A0=A0=A0=A0=A0 printf("Error setting op= tions %d\n", errno);

+=A0=A0=A0=A0=A0=A0=A0 = return (void *) -1;

+=A0=A0=A0 }

+

+=A0=A0=A0 my_addr.sin_family =3D AF_= INET;

+=A0=A0=A0 my_addr.sin_port =3D htons(host_port);

+=A0=A0=A0 memset(&(my_addr.sin_zero), 0, 8);

+

+=A0=A0=A0 my_addr.sin= _addr.s_addr =3D inet_addr(host_name);

+

+=A0=A0=A0 /* Reconnect = loop */

+=A0=A0=A0 while (!g_client_state.is_term= inate_receive) {

+

+=A0= =A0=A0=A0=A0=A0=A0 if (connect(g_client_state.hsock, (struct sockaddr *) &a= mp;my_addr,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeo= f(my_addr)) =3D=3D -1) {

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 err =3D errno;

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 if (err !=3D EINPROGRESS) {

+=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 retries++;

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 fprin= tf(

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 stderr,

+=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "Error conne= cting socket %d. Host %s, port %u. Retry count %d\n",

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 errno, host_name, host_port, retries);

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 usleep(5 * 1000 * 1= 000);

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 continue;

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 }

+=A0=A0=A0= =A0=A0=A0=A0 }

+=A0=A0=A0=A0=A0=A0=A0 retries =3D= 0;

+

+=A0=A0=A0=A0=A0= =A0=A0 printf("After connect\n");

+=A0= =A0=A0=A0=A0=A0=A0 g_client_state.is_connected =3D 1;

+=A0=A0=A0=A0=A0=A0=A0 repagent_client_connected();<= /p>

+=A0=A0=A0=A0=A0=A0=A0 repcmd_listener_init(repag= ent_process_cmd, NULL);

+=A0=A0=A0=A0=A0=A0=A0 st= atic int c;

+=A0=A0=A0=A0=A0=A0=A0 /* repcmd_list= ener_socket_thread_listener(g_client_state.hsock); */

+=A0=A0=A0=A0=A0=A0=A0 qemu_set_fd_handler(g_client_= state.hsock, repagent_client_read, NULL,

+=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 NULL);

+= =A0=A0=A0=A0=A0=A0=A0 while (g_client_state.is_connected) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 printf("Conn= ected (%d)...\n", c++);

+=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 usleep(1 * 1000 * 1000);

+=A0=A0= =A0=A0=A0=A0=A0 }

+=A0=A0=A0=A0=A0=A0=A0 /* Unreg= ister */

+=A0=A0=A0=A0=A0=A0=A0 qemu_set_fd_handler(g_client_= state.hsock, NULL, NULL, NULL);

+

+=A0=A0=A0=A0=A0 =A0=A0printf("Disconnected\n");

+=A0=A0=A0=A0=A0=A0=A0 g_client_state.is_connected =3D= 0;

+=A0=A0=A0=A0=A0=A0=A0 close(g_client_state.hsock);<= /p>

+

+=A0=A0=A0 }

+=A0=A0=A0 return 0;

+}

+

+void repagent_process_cmd(RepCmd *pcmd, uint8_t *pdata, void *clientPtr)

+{

+=A0=A0=A0 int is_fre= e_data =3D 1;

+=A0=A0=A0 printf("Repagent go= t cmd %d\n", pcmd->hdr.cmdid);

+=A0=A0=A0 switch (pcmd->hdr.cmdid) {

+=A0=A0=A0 case REPHUB_CMD_START_PROTECT: {

+=A0=A0=A0=A0=A0=A0=A0 is_free_data =3D repaget_start_protect((Re= pCmdStartProtect *) pcmd,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (RepCmdDataStartProtect *) p= data);

+=A0=A0 =A0}

+= =A0=A0=A0=A0=A0=A0=A0 break;

+=A0=A0=A0 case REPH= UB_CMD_READ_VOL_REQ: {

+=A0=A0=A0=A0=A0=A0=A0 is_= free_data =3D repaget_read_vol((RepCmdReadVolReq *) pcmd, pdata);

+=A0=A0=A0 }

+=A0=A0=A0=A0= =A0=A0=A0 break;

+=A0=A0=A0 default:

+=A0=A0=A0=A0=A0=A0=A0 assert(0);

= +=A0=A0=A0=A0=A0=A0=A0 break;

+

+=A0=A0=A0 }

+

+=A0=A0= =A0 if (is_free_data) {

+=A0=A0=A0=A0=A0=A0=A0 g_= free(pdata);

+=A0=A0=A0 }

+}

+

+int repagent_client_send(RepCmd *p_cmd)

+{

+=A0=A0=A0 int bytecount =3D 0;

+=A0=A0=A0 printf("Send cmd %u, data size %u\n", p_cmd->hd= r.cmdid,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 p_cmd->hdr.data_size_bytes);

+=A0=A0=A0 if (!g_client_state.is_connected) {

+=A0=A0=A0=A0=A0=A0=A0 printf("Not connected to hub\n&= quot;);

+=A0=A0=A0=A0=A0=A0=A0 return -1;

+=A0=A0=A0 }

+

+=A0=A0=A0 bytecount =3D send(g_client_state.hsock, p_cmd,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeof(RepCmd) = + p_cmd->hdr.data_size_bytes, 0);

+=A0=A0=A0 if (bytecount < sizeof(RepCmd) + p_cmd= ->hdr.data_size_bytes) {

+=A0 =A0=A0=A0=A0=A0= =A0printf("Bad send %d, errno %d\n", bytecount, errno);

+=A0=A0=A0=A0=A0=A0=A0 return bytecount;

+=A0=A0=A0 }

+

+=A0=A0=A0 /* Success */

+=A0=A0= =A0 return 0;

+}

diff -= -git a/block/repagent/repagent_client.h b/block/repagent/repagent_client.h<= /p>

new file mode 100644

index= 0000000..62a5377

--- /dev/null

+++ b/block/repagent/repagent_client.h

@= @ -0,0 +1,36 @@

+/*

+ * QEMU System Emulat= or

+ *

+ * Copyright (c= ) 2003-2008 Fabrice Bellard

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining a= copy

+ * of this software and associated documen= tation files (the "Software"), to deal

+ * in the Software without restriction, including without limitation the r= ights

+ * to use, copy, modify, merge, publish, d= istribute, sublicense, and/or sell

+ * copies of = the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following con= ditions:

+ *

+ * The ab= ove copyright notice and this permission notice shall be included in

+ * all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS = IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY= ,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINF= RINGEMENT. IN NO EVENT SHALL

+ * THE AUTHORS OR C= OPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TOR= T OR OTHERWISE, ARISING FROM,

+ * OUT OF OR IN CO= NNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTWARE.

+ */

= +#ifndef REPAGENT_CLIENT_H

+#define REPAGENT_CLIE= NT_H

+#include "repcmd.h"

+

+typedef struct rephub_params {

+=A0=A0=A0 char *name;

+=A0=A0=A0 int = port;

+} rephub_params;

+

+void *repagent_listen(void *pParam);

+int repage= nt_client_send(RepCmd *p_cmd);

+

+#endif /* REPAGENT_CLIENT_H */

diff --= git a/block/repagent/repcmd.h b/block/repagent/repcmd.h

new file mode 100644

index= 0000000..8c6cf1b

--- /dev/null

+++ b/block/repagent/repcmd.h

@@ -0,0 +1= ,59 @@

+/*

+ * QEMU System Emulat= or

+ *

+ * Copyright (c= ) 2003-2008 Fabrice Bellard

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining a= copy

+ * of this software and associated documen= tation files (the "Software"), to deal

+ * in the Software without restriction, including without limitation the r= ights

+ * to use, copy, modify, merge, publish, d= istribute, sublicense, and/or sell

+ * copies of = the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following con= ditions:

+ *

+ * The ab= ove copyright notice and this permission notice shall be included in

+ * all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS = IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY= ,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINF= RINGEMENT. IN NO EVENT SHALL

+ * THE AUTHORS OR C= OPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TOR= T OR OTHERWISE, ARISING FROM,

+ * OUT OF OR IN CO= NNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTWARE.

+ */

= +#ifndef REPCMD_H

+#define REPCMD_H

+

+#include <stdint.h>

+

+#define REPCMD_MAGIC1 (0x1122)

+#define REPCMD_MAGIC2 (0x3344)

+#defi= ne REPCMD_NUM_U32_PARAMS (11)

+

+enum RepCmds {

+=A0=A0=A0 REPCMD_FIRST_INVALID= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 0,

+=A0=A0=A0 REPCMD_FIRST_HUBCMD=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 1,

+=A0=A0= =A0 REPHUB_CMD_PROTECTED_WRITE=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 2= ,

+=A0=A0=A0 REPHUB_CMD_REPORT_VM_VOLUMES=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 =3D 3,

+ =A0=A0=A0REPHUB_CM= D_START_PROTECT=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 4,

+=A0=A0=A0 REPHUB_CMD_READ_VOL_REQ=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 5,

+=A0=A0=A0 REPHUB_CMD_READ_VOL_RES=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 6,

+=A0=A0=A0 = REPHUB_CMD_AGENT_SHUTDOWN=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 7,<= /p>

+};

+

+typedef struct RepCmdHdr {

+=A0=A0=A0 uint16_t m= agic1;

+ =A0=A0=A0uint16_t cmdid;

+=A0=A0=A0 uint32_t data_size_bytes;

+= } RepCmdHdr;

+

+typedef struct RepCmd {

+=A0=A0=A0 RepCmdHdr hdr;

+=A0=A0=A0 unsigned= int parameters[REPCMD_NUM_U32_PARAMS];

+=A0=A0= =A0 unsigned int magic2;

+=A0=A0=A0 uint8_t data[0];

+} RepCmd;

+

+RepCmd = *repcmd_new(int cmd_id, int data_size, uint8_t **p_out_pdata);

+

+#endif /* REPCMD_H */

diff --git a/block/repagent/repcmd_listener.c b/block/repagent/repcmd_lis= tener.c

new file mode 100644

index 0000000..54d3f60

--- /dev/null

+++ b/block/repagent/repcmd_listener.c

@@ -0,0 +1,173 @@

+#include <fcntl.h><= /p>

+#include <string.h>

+#include <stdlib.h= >

+#include <errno.h>

+#include <stdio.h>

+#include <n= etinet/in.h>

+#include <resolv.h>

+#include <sys/socket.h>

+#include <arp= a/inet.h>

+#include <unistd.h>

+#include <pthread.h>

+#include <assert.= h>

+

+/* Use the CON= FIG_REPAGENT flag to determine whether

+ * we'= ;re under qemu build or a hub When under

+ * qemu use g_malloc */

+= #ifdef CONFIG_REPAGENT

+#include <glib.h>

+#define REPCMD_MALLOC g_malloc

+#else

+#define REPCMD_MALLOC malloc

+#endif

+

+#include "repcmd.h"

+#include "= repcmd_listener.h"

+

+#define ZERO_MEM_OBJ(pO= bj) memset((void *)pObj, 0, sizeof(*pObj))

+

<= p class=3D"MsoNormal">+

+typedef struct RepCmdRxC= mdState {

+=A0=A0=A0 RepCmd curCmd;

= +=A0=A0=A0 uint8_t *pReadBuf;

+=A0=A0=A0 int byte= sToGet;

+=A0=A0=A0 int bytesGotten;

+=A0=A0=A0 int isGotHeader;

+=A0=A0=A0 uint8_t *pdata;

+} RepCmdRxCmdState;

+

+typedef struct RepCmdListenerState {

+=A0=A0=A0= int is_terminate_receive;

+=A0=A0=A0 pfn_received_cmd_cb=A0 receive_cb;

+=A0=A0=A0 void *opaque;

+=A0= =A0=A0 int hsock;

+=A0=A0=A0 RepCmdRxCmdState cur= _cmd;

+} RepCmdListenerState;

+

+static RepCmdListenerState g_listenerState =3D { 0 };

+

+static int repcmd_listener_process_rx= (int bytecount);

+

+void repcmd_listener_in= it(pfn_received_cmd_cb callback, void *opaque)

+{=

+=A0=A0=A0 ZERO_MEM_OBJ(&g_listenerState);

+=A0=A0=A0 g_listenerState.receive_cb =3D callback;

+=A0=A0=A0 g_listenerState.opaque =3D opaque;

= +

+=A0=A0=A0 g_listenerState.cur_cmd.bytesToGet = =3D sizeof(RepCmd);

+=A0=A0=A0 g_listenerState.cur_cmd.pReadBuf =3D

+= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint8_t *) &g_listenerState.cur_cmd.= curCmd;

+}

+

+int repcmd_listener_socket_read_next_buf(int hsock)

+{

+=A0=A0=A0 RepCmdRxCmdS= tate *cmd_state =3D &g_listenerState.cur_cmd;

+=A0=A0=A0 int bytecount =3D recv(hsock, cmd_state->pReadBuf + cmd_stat= e->bytesGotten,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->byt= esToGet - cmd_state->bytesGotten, 0);

+=A0=A0= =A0 return repcmd_listener_process_rx(bytecount);

+}

+

+/* Returns 0 for initiated termination or socket er= ror value on error */

+int repcmd_listener_socket= _thread_listener(int hsock)

+{

+=A0=A0=A0 int ret =3D 0;

+=A0=A0=A0 /* receive l= oop */

+=A0=A0=A0 while (!g_listenerState.is_term= inate_receive) {

+=A0=A0=A0=A0=A0=A0=A0 ret =3D r= epcmd_listener_socket_read_next_buf(hsock);

+=A0=A0=A0=A0=A0=A0=A0 if (ret <=3D 0) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return ret;

+=A0=A0=A0=A0=A0=A0=A0 }

+=A0=A0= =A0 }

+=A0=A0=A0 return 0;

+}

+

+static int repcmd= _listener_process_rx(int bytecount)

+{

+=A0=A0=A0 RepCmdRxCmdState *cmd_state =3D &g_listenerS= tate.cur_cmd;

+=A0=A0=A0 if (bytecount =3D=3D -1) {

+=A0=A0=A0=A0=A0=A0=A0 fprintf(stderr, "Error receiving da= ta %d\n", errno);

+=A0=A0=A0=A0=A0=A0=A0 ret= urn errno;

+=A0=A0=A0 }

+

+=A0=A0=A0 if (bytecount= =3D=3D 0) {

+=A0=A0=A0=A0=A0=A0=A0 printf("= Disconnected\n");

+=A0=A0=A0=A0=A0=A0=A0 ret= urn 0;

+=A0=A0=A0 }

+=A0=A0=A0 cmd_state->bytesGotten +=3D bytecount;

+/*=A0=A0=A0=A0 printf("Recieved bytes %d, got %d/%d\n",

<= p class=3D"MsoNormal">+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 bytecount, cmd_sta= te->bytesGotten, cmd_state->bytesToGet); */

+=A0=A0=A0 /* print content */

+=A0=A0=A0 if (0) {

+=A0=A0=A0=A0=A0=A0=A0 i= nt i;

+=A0=A0=A0=A0=A0=A0=A0 for (i =3D 0; i <= bytecount ; i +=3D 4) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /*printf("%d/%d", i, bytecount= /4); */

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 printf= (

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 "%#x ",

+=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 *(int *) (&cmd_state->pRe= adBuf[cmd_state->bytesGotten

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 - bytecount + i]));

+

+=A0=A0=A0=A0=A0=A0=A0 }

+=A0=A0=A0=A0=A0=A0=A0 printf("\n");

+=A0=A0=A0 }

+=A0=A0=A0 assert(cmd_state->bytesGotten <=3D = cmd_state->bytesToGet);

+=A0=A0=A0 if (cmd_sta= te->bytesGotten =3D=3D cmd_state->bytesToGet) {

+=A0=A0=A0=A0=A0=A0=A0 int isGotData =3D 0;

+=A0=A0=A0=A0=A0=A0=A0 cmd_state->bytesGotten =3D= 0;

+=A0=A0=A0=A0=A0=A0=A0 if (!cmd_state->isG= otHeader) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /*= We just got the header */

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 cmd_state->isGotHeader =3D 1;

+

+=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 assert(cmd_state->curCmd.hdr.magic1 =3D=3D REPCMD_MAGIC1);<= /p>

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 assert(cmd_sta= te->curCmd.magic2 =3D=3D REPCMD_MAGIC2);

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (cmd_state->curCmd.hdr.data_size_b= ytes > 0) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 cmd_state->pdata =3D (uint8_t *)REPCMD_MALLOC(

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 cmd_state->curCmd.hdr.data_size_bytes);

+/*=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 printf("malloc %p\n", cmd_state->pdata); */

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state-= >pReadBuf =3D cmd_state->pdata;

+=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 } else {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* no= data */

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 isGotData =3D 1;

+=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 =A0=A0cmd_state->pdata =3D NULL;

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 }

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->bytesToGet =3D cmd_state-&= gt;curCmd.hdr.data_size_bytes;

+=A0=A0=A0=A0=A0= =A0=A0 } else {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 isGotData =3D 1;

+=A0=A0=A0=A0=A0=A0=A0 }

=

+

+=A0=A0=A0=A0=A0=A0=A0 if (isGotData) {

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* Got command and da= ta */

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (*g_list= enerState.receive_cb)(&cmd_state->curCmd, cmd_state->pdata,

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 g_listenerState.opaque);

+

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* It's the callee respon= sibility to free cmd_state->pdata */

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->pdata =3D NULL;

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ZERO_MEM_OBJ(&cmd_st= ate->curCmd);

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 cmd_state->pReadBuf =3D (uint8_t *) &cmd_state->curCmd;

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->byt= esGotten =3D 0;

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 cmd_state->bytesToGet =3D sizeof(RepCmd);

= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->isGotHeader =3D 0;

+=A0=A0=A0=A0=A0=A0=A0 }

+=A0=A0=A0 }

+=A0 =A0=A0return bytecount;

+}

+

+RepCmd *repcmd_new(int= cmd_id, int data_size, uint8_t **p_out_pdata)

+{

+=A0=A0=A0 RepCmd *p_cm= d =3D (RepCmd *)REPCMD_MALLOC(sizeof(RepCmd) + data_size);

+=A0=A0=A0 assert(p_cmd !=3D NULL);

+

+=A0=A0=A0 /* Zero the CMD (not the data) */

+=A0= =A0=A0 ZERO_MEM_OBJ(p_cmd);

+

+=A0=A0=A0 p_cmd->hdr.cmdid =3D cmd_id;

+=A0=A0=A0 p_cmd->hdr.magic1 =3D REPCMD_MAGIC1;

+=A0=A0=A0 p_cmd->magic2 =3D REPCMD_MAGIC2;

+=A0=A0=A0 p_cmd->hdr.data_size_bytes =3D data_size= ;

+

+=A0=A0=A0 if (p_ou= t_pdata !=3D NULL) {

+=A0=A0=A0=A0=A0=A0=A0 *p_out_pdata =3D p_cmd->data;

+=A0=A0=A0 }

+

+= =A0=A0=A0 return p_cmd;

+}

+

diff --git a/block/repagent/repcmd_listener= .h b/block/repagent/repcmd_listener.h

new file mode 100644

index= 0000000..19b9ea9

--- /dev/null

+++ b/block/repagent/repcmd_listener.h

@= @ -0,0 +1,34 @@

+/*

+ * QEMU System Emulat= or

+ *

+ * Copyright (c= ) 2003-2008 Fabrice Bellard

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining a= copy

+ * of this software and associated documen= tation files (the "Software"), to deal

+ * in the Software without restriction, including without limitation the r= ights

+ * to use, copy, modify, merge, publish, d= istribute, sublicense, and/or sell

+ * copies of = the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following con= ditions:

+ *

+ * The ab= ove copyright notice and this permission notice shall be included in

+ * all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS = IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY= ,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINF= RINGEMENT. IN NO EVENT SHALL

+ * THE AUTHORS OR C= OPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TOR= T OR OTHERWISE, ARISING FROM,

+ * OUT OF OR IN CO= NNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTWARE.

+ */

= +#ifndef REPCMD_LISTENER_H

+#define REPCMD_LISTEN= ER_H

+#include <stdint.h>

+typedef void (*pfn_received_cmd_cb)(RepCmd *pcmd,

+=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0=A0=A0uint8_t *pdata, void *opaq= ue);

+

+void repcmd_lis= tener_init(pfn_received_cmd_cb callback, void *opaque);

+int repcmd_listener_socket_read_next_buf(int hsock)= ;

+int repcmd_listener_socket_thread_listener(int= hsock);

+

+#endif /* R= EPCMD_LISTENER_H */

diff --git a/block/repagent/rephub_cmds.h b/block/re= pagent/rephub_cmds.h

new file mode 100644

index 0000000..3bd4eb4

--- /de= v/null

+++ b/block/repagent/rephub_cmds.h

@@ -0,0 +1,151 @@

+/*

+ * QEMU System Emulator

+ *

+ * Copyright (c) 2003-2008 Fabrice Bellard

+ *

+ * Permission is hereby granted, free of charge, = to any person obtaining a copy

+ * of this softwa= re and associated documentation files (the "Software"), to deal

+ * in the Software without restriction, including w= ithout limitation the rights

+ * to use, copy, mo= dify, merge, publish, distribute, sublicense, and/or sell

+ * copies of the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following c= onditions:

+ *

+ * The = above copyright notice and this permission notice shall be included in

+ * all copies or substantial portions of the Softwa= re.

+ *

+ * THE SOFTWAR= E IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRAN= TIES OF MERCHANTABILITY,

+ * FITNESS FOR A PARTIC= ULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRA= CT, TORT OR OTHERWISE, ARISING FROM,

+ * OUT OF O= R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTWARE.

+ */

=

+#ifndef REPHUB_CMDS_H

+#d= efine REPHUB_CMDS_H

+

+= #include <stdint.h>

+#include "repcmd.h"

+#include "rephub_defs.h"

+

+/*****************************************************= ****

+ * RepCmd Report a protected IO

+ *

+ * REPHUB_CMD_PROTECTED_WRITE

+ * Direction: agent->hub

+= *

+ * Any write of a protected volume is send with thi= s

+ * message to the hub, with its status.

+ * When case the status is bad no data is sent

+ *********************************************************/

+typedef struct RepCmdProtectedWrite {

+=A0=A0=A0 RepCmdHdr hdr;

+=A0=A0=A0 uint64_t v= olume_id;

+=A0=A0=A0 uint64_t offset_sectors;

+=A0=A0=A0 /*= The size field duplicates the RepCmd size,

+=A0= =A0=A0=A0 * but it is needed for reporting failed IOs' sizes */

+=A0=A0=A0 uint32_t size_sectors;

+=A0=A0=A0 int ret_status;

+} RepCmdProtectedWrite;

+

+/*********************************************************

+ * RepCmd Report VM volumes

+ *

+ * REPHUB_CMD_REPORT_VM_VOLUMES

+ * Di= rection: agent->hub

+ *

+ * The agent reports all the volumes of the VM

+ * to the hub.

+ ********= *************************************************/

+typedef struct RepVmVolumeInfo {

+=A0=A0=A0 ch= ar name[REPHUB_MAX_VOL_NAME_LEN];

+=A0=A0=A0 uint64_t volume_id;

+=A0=A0=A0 uint32_t size_mb;

+=A0=A0=A0 uint= 32_t padding;

+} RepVmVolumeInfo;

+

+typedef struct RepCmdReportVmVolumes {

+=A0=A0= =A0 RepCmdHdr hdr;

+=A0=A0=A0 int num_volumes;

+} RepCmdReportVmVolumes;

+

+typedef struct RepCmdDataReportVmVolumes {

+=A0= =A0=A0 RepVmVolumeInfo volumes[0];

+} RepCmdDataR= eportVmVolumes;

+

+

=

+/*********************************************************

+ * RepCmd Start protect

+ *

+ * REPHUB_CMD_START_PROTECT

+ *= Direction: hub->agent

+ *

+ * The hub instructs = the agent to start protecting

+ * a volume. When = a volume is protected all its writes

+ * are sent= to to the hub.

+ * With this command the hub also assigns a volume = ID to

+ * the given volume name.

+ *********************************************************/

<= p class=3D"MsoNormal"> +typedef struct RepCmdStartProtect {

+=A0=A0=A0 R= epCmdHdr hdr;

+=A0=A0=A0 uint64_t volume_id;

<= p class=3D"MsoNormal">+} RepCmdStartProtect;

+

+typedef struct RepCmdDataStartProtect {

+=A0=A0= =A0 char volume_name[REPHUB_MAX_VOL_NAME_LEN];

+}= RepCmdDataStartProtect;

+

+

+/*********************************************************

+ * RepCmd Read Volume Request

+ *

=

+ * REPHUB_CMD_READ_VOL_REQ

+ * Direction: hub->agent

+ *

+ * The hub issues a r= ead IO to a protected volume.

+ * This command is= used during sync - when the hub needs

+ * to rea= d unsyncronized sections of a protected volume.

+ * This command is a request, the read data is retu= rned

+ * by the response command REPHUB_CMD_READ_= VOL_RES

+ ***************************************= ******************/

+typedef struct RepCmdReadVolReq {

+=A0=A0=A0 RepCmdHdr hdr;

+=A0=A0=A0 int= req_id;

+=A0=A0=A0 int size_sectors;

+=A0=A0=A0 uint64_t volume_id;

+=A0=A0=A0 uint64_t offset_sectors;

+} RepCmdReadVolReq;

+

+/*********************************************************

+ * RepCmd Read Volume Response

+ *

+ * REPHUB_CMD_READ_VOL_RES

+ * Di= rection: agent->hub

+ *

+ * A response to REPHUB_CMD_READ_VOL_REQ.

+ * Sends the data read from a protected volume

<= p class=3D"MsoNormal">+ ***************************************************= ******/

+typedef struct RepCmdReadVolRes {

+=A0=A0=A0 RepCmdHdr hdr;

+=A0=A0=A0 int req_id;<= /p>

+ =A0=A0=A0int is_status_success;

+=A0=A0=A0 uint64_t volume_id;

+} RepC= mdReadVolRes;

+

+/*********************************************= ************

+ * RepCmd Agent shutdown

+ *

+ * REPHUB_CMD_AGENT_SHUTDOWN=

+ * Direction: agent->hub

+ *

+ * Notifies the hub that the agent is abo= ut to shutdown.

+ * This allows a graceful shutdo= wn. Any disconnection

+ * of an agent without sending this command will re= sult

+ * in a full sync of the VM volumes.

+ *****************************************************= ****/

+typedef struct RepCmdAgentShutdown {

+=A0=A0=A0 RepCmdHdr hdr;

+} RepCmdAg= entShutdown;

+

+

+#endif /* REPHUB_CMDS_H */

diff --git a/block/re= pagent/rephub_defs.h b/block/repagent/rephub_defs.h

new file mode 100644

index 0000000..e34e0ce

--- /dev/null

+++ b/block/repagent/rephub_defs.h<= /p>

@@ -0,0 +1,40 @@

+/*

+ * QEMU System Emulator

= + *

+ * Copyright (c) 2003-2008 Fabrice Bellard

+ *

+ * Permission is hereby gr= anted, free of charge, to any person obtaining a copy

+ * of this software and associated documentation files (the "Software= "), to deal

+ * in the Software without rest= riction, including without limitation the rights

+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll

+ * copies of the Software, and to permit pers= ons to whom the Software is

+ * furnished to do s= o, subject to the following conditions:

+ *

+ * The above copyrigh= t notice and this permission notice shall be included in

+ * all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS"= ;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * I= MPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGE= MENT. IN NO EVENT SHALL

+ * THE AUTHORS OR COPYRI= GHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM,

+ * OUT OF OR IN CONNECTION WITH THE SOFTW= ARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTW= ARE.

+ */

+#ifndef REP_HUB_DEFS= _H

+#define REP_HUB_DEFS_H

+

+#include <stdint.h>

+

+#define REPHUB_MAX_VOL_NAME_LEN (1024)

+#define REPHUB_MAX_NUM_VOLUMES (512)

+

+#ifndef TRUE

+=A0=A0=A0 #define TRUE (1)

+#endif

+

+#ifndef FALSE

+=A0=A0=A0 #define FALSE= (0)

+#endif

+

+#endif /* REP_HUB_DEFS_H */

diff --git a/configu= re b/configure

index 83b74c2..3d17ae5 100755

<= p class=3D"MsoNormal">--- a/configure

+++ b/confi= gure

@@ -189,7 +189,7 @@ spice=3D""

rbd=3D""

smartcard=3D&= quot;"

smartcard_nss=3D""

-replication=3D""

+repagent=3D"&qu= ot;

usb_redir=3D""

opengl=3D""

zlib=3D"yes&q= uot;

@@ -807,9 +807,9 @@ for opt do

=A0=A0 ;;

=A0=A0 --enable-smartcard-nss) smartcard_nss=3D"yes&= quot;

=A0=A0 ;;

-=A0 --= disable-replication) replication=3D"no"

+=A0 --disable-repagent) repagent=3D"no"

=A0=A0 ;;

-=A0 --enable-= replication) replication=3D"yes"

+=A0 -= -enable-repagent) repagent=3D"yes"

=A0=A0 ;;

=A0=A0 --disable= -usb-redir) usb_redir=3D"no"

=A0=A0 ;;<= /p>

@@ -1109,7 +1109,7 @@ echo "=A0 --disable-us= b-redir=A0=A0=A0=A0=A0 disable usb network redirection support"

echo "=A0 --enable-usb-redir=A0=A0=A0=A0=A0=A0= enable usb network redirection support"

ec= ho "=A0 --disable-guest-agent=A0=A0=A0 disable building of the QEMU Gu= est Agent"

echo "=A0 --enable-guest-agent=A0=A0=A0=A0 enable building of the QEM= U Guest Agent"

-echo "=A0 --enable-repl= ication=A0=A0=A0=A0 enable replication support"

+echo "=A0 --enable-repagent=A0=A0=A0=A0=A0=A0=A0 enable replicati= on support"

echo ""

echo &= quot;NOTE: The object files are built at the place where configure is launc= hed"

exit 1

@@ -3= 220,8 +3220,8 @@ if test "$smartcard_nss" =3D "yes" ; t= hen

=A0=A0 echo "libcacard_cflags=3D$libcacard_cfla= gs" >> $config_host_mak

fi

-if test "$replication&quo= t; =3D "yes" ; then

-=A0 echo "CONFIG_REPLICATION=3Dy" >>= ; $config_host_mak

+if test "$repagent"= =3D "yes" ; then

+=A0 echo "CONFI= G_REPAGENT=3Dy" >> $config_host_mak

fi

=A0if test "$usb_redir" =3D "yes" ; then

@@ -3904,4 +3904,4 @@ if test "$docs" =3D "= ;yes" ; then

=A0=A0 mkdir -p QMP

fi

-echo "Replication= =A0=A0=A0=A0=A0 =A0=A0=A0=A0 $replication"

+= echo "Repagent=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0=A0 $repagent"

diff --git a/replication/qemu-repagent.txt b/replica= tion/qemu-repagent.txt

deleted file mode 100644

index e3b0c1e..0000000

-= -- a/replication/qemu-repagent.txt

+++ /dev/null

@@ -1,104 +0= ,0 @@

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 re= pagent - replication agent - a Qemu module for enabling continuous async re= plication of VM volumes

-

-Introduction

-=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This document describes a feature in Qemu= - a replication agent (AKA Repagent).

-=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The Repagent is a new module that exposes an= API to an external replication system (AKA Rephub).

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This API al= lows a Rephub to communicate with a Qemu VM and continuously replicate its = volumes.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= The imlementation of a Rephub is outside of the scope of this document. Th= ere may be several various Rephub

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 implenetati= ons using the same repagent in Qemu.

-

-Main feature of Repagent

-=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Repagent does the following:

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Report vo= lumes - report a list of all volumes in a VM to the Rephub.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Report writes to a vo= lume - send all writes made to a protected volume to the Rephub.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The reporting of an IO is asyncronuous= - i.e. the IO is not delayed by the Repagent to get any acknowledgement fr= om the Rephub.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 It is only copied to= the Rephub.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Read a pr= otected volume - allows the Rephub to read a protected volume, to enable th= e protected hub to syncronize the content of a protected volume.

-

-Description of the Repagent module

-

-Build and run options

-=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 New configure option: --enable-replication

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 New comma= nd line option:

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 -repagent [= hub IP/name]

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Enable replication support= for disks

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 hub is the ip or name of the machine running the replication hub.=

-

-Module APIs

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The Repagent module interfaces two= main components:

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 1. The Rephub - An external API based on socket messages

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 2. The generic b= lock layer- block.c

-

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 Rephub message API

-=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 The external replication API is a message based API.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 We won't go into the structure of the messages he= re - just the sematics.

-

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Messages= list

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 (The updated list and comments are in Rephub_cmds.h)

=

-

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 Messages from the Repagent to the Rephub:

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * = Protected write

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The Repagent sends each write to a pro= tected volume to the hub with the IO status.

-=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 In case the status is bad the write content = is not sent

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 * Report VM volumes

-=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 The agent reports all the volumes of the VM to the hub.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 * Read Volume Response

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 A response to a Read Volume Request

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Sends the data read from a protected v= olume to the hub

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Agent shutdown

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Notifies the hub that the agent is abo= ut to shutdown.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 This allows a graceful shutdown. Any disconnection of an agent without<= /p>

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sending this comm= and will result in a full sync of the VM volumes.

-

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 Messages from the Rephub to the Repagent:

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 * Start protect

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 The hub instructs the agent to start protecting a volume. When= a volume is protected

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 all its writes ar= e sent to to the hub.

-=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 With this command the hub also assigns a volume ID to the given v= olume name.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 * Read volume request

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 The hub issues a read IO to a protected volume.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This command is u= sed during sync - when the hub needs to read unsyncronized

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sections of a protected volum= e.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This command is a= request, the read data is returned by the read volume response message (se= e above).

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 block.c API

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 The API to the generic block storage l= ayer contains 3 functionalities:

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 1.= Handle writes to protected volumes

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 In bdrv_co_= do_writev, each write is reported to the Repagent module.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 2. Handle each new volume that registers

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 In bdrv_ope= n - each new bottom-level block driver that registers is reported.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 2. Read from a volume

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Repagent ca= lls bdrv_aio_readv to handle read requests coming from the hub.

-

-

-Gen= eral description of a Rephub=A0 - a replication system the repagent connect= s to

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This sectio= n describes in high level a sample Rephub - a replication system that uses = the repagent API

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 to replicate disks.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 It describes a simple Rephub that = comntinuously maintains a mirror of the volumes of a VM.

-

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 Say we have a VM we want to protect - call it PVM, say it has 2 volumes= - V1, V2.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 Our Rephub = is called SingleRephub - a Rephub protecting a single VM.

-

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 Preparations

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 1. The user chooses a host to rub SingleRephub - a different host= than PVM, call it Host2

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 2. The user= creates two volumes on Host2 - same sizes of V1 and V2, call them V1R (V1 = recovery) and V2R.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 3. The user runs SingleRephub process on Host2, and gives V1R = and V2R as command line arguments.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 From now on SingleRephub waits for the= protected VM repagent to connect.

-=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 4. The user runs the protected VM PVM - and use= s the switch -repagent <Host2 IP>.

-

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 Runtime

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 1. The repagent module connects to SingleRephub on start= up.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 2. r= epagent reports V1 and V2 to SingleRephub.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 3. SingleRe= phub starts to perform an initial synchronization of the protected volumes-=

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 it reads each protected volume (= V1 and V2) - using read volume requests - and copies the data into the

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 recovery volume V1R and V2R.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 4. SingleRephub e= nters 'protection' mode - each write to the protected volume is sen= t by the repagent to the Rephub,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 and the Rephub performs the write on t= he matching recovery volume.

-

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 * Note that during stage 3= writes to the protected volumes are not ignored - they're kept in a bi= tmap,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 and will be read again when stage 3 en= ds, in an interative convergin process.

-

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 This flow conti= nuously maintains an updated recovery volume.

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 If the prot= ected system is damaged, the user can create a new VM on Host2 with the rep= licated volumes attached to it.

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 The new VM is a replica of the protected system.

-

-

diff --git a/replication/repagent.c b/replication/repagent.c

deleted file mode 100644

index c2= 91915..0000000

--- a/replication/repagent.c

+++ /dev/null

@@ -1,327 +0,0 @@

-#include <string.h>

-#include = <stdlib.h>

-#include <stdio.h>

= -#include <pthread.h>

-#include <stdint.= h>

-

-#include "= ;block.h"

-#include "rephub_defs.h"

-#include "block_int.h"

-#inc= lude "repagent_client.h"

-#include &quo= t;repagent.h"

-#include "rephub_cmds.h"

-

-#define ZERO_MEM_OBJ(pObj) memset(pO= bj, 0, sizeof(*pObj))

-#define REPAGENT_MAX_NUM_V= OLUMES (64)

-#define REPAGENT_VOLUME_ID_NONE (0)

-

-typedef struct RepagentVolume {

=

-=A0=A0=A0 uint64_t vol_id;

-=A0=A0=A0 const char *vol_path;

-=A0=A0=A0 BlockDriverState *driver_ptr;

-} RepagentVolume;

-

-struct RepAgentState {

-=A0=A0=A0= int is_init;

-=A0=A0=A0 int num_volumes;

-=A0=A0=A0 RepagentVo= lume *volumes[REPAGENT_MAX_NUM_VOLUMES];

-};

<= p class=3D"MsoNormal">-

-typedef struct RepagentR= eadVolIo {

-=A0=A0=A0 QEMUIOVector qiov;

-=A0=A0=A0 RepCmdRe= adVolReq rep_cmd;

-=A0=A0=A0 uint8_t *buf;

-=A0=A0=A0 struct timeval start_time;

-} RepagentReadVolIo;

-

-static int repagent_get= _volume_by_name(const char *name);

-static void r= epagent_report_volumes_to_hub(void);

-static void= repagent_vol_read_done(void *opaque, int ret);

-static struct timeval tsub(struct timeval t1, struc= t timeval t2);

-

-RepAg= entState g_rep_agent =3D { 0 };

-

-void repagent_init(const char *hubname, int port)

-{

-=A0=A0=A0 /* It is the responsibility of th= e thread to free this struct */

-=A0=A0=A0 rephub= _params *pParams =3D (rephub_params *)g_malloc(sizeof(rephub_params));

-=A0=A0=A0 if (hubname =3D=3D NULL) {

-=A0=A0=A0=A0=A0=A0=A0 hubname =3D "127.0.0.1";

-=A0=A0=A0 }

-=A0=A0=A0 if (= port =3D=3D 0) {

-=A0=A0=A0=A0=A0=A0=A0 port =3D = 9010;

-=A0=A0=A0 }

-

-=A0=A0=A0 printf("repagent_init %s\n", hubname);<= /p>

-

-=A0=A0=A0 pParams-&g= t;port =3D port;

-=A0=A0=A0 pParams->name =3D g_strdup(hubname);

-

-=A0=A0=A0 pthread_t thread_id =3D 0;

-

-=A0=A0=A0 /* Create the rep= agent client listener thread */

-=A0=A0=A0 pthread_create(&thread_id, 0, repagen= t_listen, (void *) pParams);

-=A0=A0=A0 pthread_d= etach(thread_id);

-}

-<= /p>

-void repagent_register_drive(const char *drive_path,

-=A0=A0=A0=A0=A0=A0=A0 BlockDriverState *driver_ptr)

-{

-=A0=A0=A0 int i;

-=A0=A0=A0 for (i =3D 0; i < g_rep_agent.num_volumes ; i++) {

-=A0=A0=A0=A0=A0=A0=A0 RepagentVolume *vol =3D g_rep= _agent.volumes[i];

-=A0=A0=A0=A0=A0=A0=A0 if (vol= !=3D NULL) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 = assert(

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 strcmp(drive_path, vol->vol_path) !=3D 0

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 && driver_ptr !=3D vol->driver_ptr);

-=A0=A0=A0=A0=A0=A0=A0 }

-=A0=A0=A0 }

-

-=A0=A0=A0 assert(g_rep_ag= ent.num_volumes < REPAGENT_MAX_NUM_VOLUMES);

-

-=A0=A0=A0 printf("= zerto repagent: Registering drive. Num drives %d, path %s\n",

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep_agent.num_volume= s, drive_path);

-=A0=A0=A0 g_rep_agent.volumes[i] =3D

-=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 (RepagentVolume *)g_malloc(sizeof(RepagentVolume))= ;

-=A0=A0=A0 g_rep_agent.volumes[i]->driver_pt= r =3D driver_ptr;

-=A0=A0=A0 /* orim todo strcpy? */

-=A0=A0=A0 g_r= ep_agent.volumes[i]->vol_path =3D drive_path;

= -

-=A0=A0=A0 /* Orim todo thread-safety? */

-=A0=A0=A0 g_rep_agent.num_volumes++;

-

-=A0=A0=A0 repagent_repo= rt_volumes_to_hub();

-}

-

-/* orim todo destruction? */

-

-static RepagentVolume *repagent_get_protected_volum= e_by_driver(

-=A0=A0=A0=A0=A0=A0=A0 BlockDriverSt= ate *bs)

-{

-=A0=A0=A0 = /* orim todo optimize search */

-=A0=A0=A0 int i =3D 0;

-= =A0=A0=A0 for (i =3D 0; i < g_rep_agent.num_volumes ; i++) {

-=A0=A0=A0=A0=A0=A0=A0 RepagentVolume *p_vol =3D g_rep_agent= .volumes[i];

-=A0=A0=A0=A0=A0=A0=A0 if (p_vol !=3D NULL && p_vol->driver_ptr = =3D=3D (void *) bs) {

-=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 return p_vol;

-=A0=A0=A0=A0=A0=A0=A0 }<= /p>

-=A0=A0=A0 }

-=A0=A0=A0= return NULL;

-}

-

-void repagent_handle_protected_write(BlockDriverState *bs, int64_t se= ctor_num,

-=A0=A0=A0=A0=A0=A0=A0 int nb_sectors, = QEMUIOVector *qiov, int ret_status)

-{

-=A0=A0=A0 printf("= ;zerto Protected write offset %lld, size %d, IO return status %d",

=

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (long long int) s= ector_num, nb_sectors, ret_status);

-=A0=A0=A0 if (bs->filename !=3D NULL) {

-=A0=A0=A0=A0=A0=A0=A0 printf(", filename %s", = bs->filename);

-=A0=A0=A0 }

-

-=A0=A0=A0 printf("\n");

-

-=A0=A0=A0 RepagentVolume *p_vol =3D repagent_get_protected_= volume_by_driver(bs);

-=A0=A0=A0 if (p_vol =3D=3D= NULL || p_vol->vol_id =3D=3D REPAGENT_VOLUME_ID_NONE) {

-=A0=A0=A0=A0=A0=A0=A0 /* Unprotected */

-=A0=A0=A0=A0=A0=A0=A0 printf("Got a write to an unprot= ected volume.\n");

-=A0=A0=A0=A0=A0=A0=A0 re= turn;

-=A0=A0=A0 }

-

-=A0=A0=A0 /* Report IO to rephub */

-

-=A0=A0=A0 int data_size =3D qi= ov->size;

-=A0=A0=A0 if (ret_status < 0) {<= /p>

-=A0=A0=A0=A0=A0=A0=A0 /* On failed ios we don't send the data to the h= ub */

-=A0=A0=A0=A0=A0=A0=A0 data_size =3D 0;

=

-=A0=A0=A0 }

-=A0=A0=A0 ui= nt8_t *pdata =3D NULL;

-=A0=A0=A0 RepCmdProtectedWrite *p_cmd =3D (RepCmdProtectedWrite *) repcmd_= new(

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 REPHUB_CM= D_PROTECTED_WRITE, data_size, (uint8_t **) &pdata);

-

-=A0=A0=A0 if (ret_status >=3D 0) {

-=A0=A0=A0= =A0=A0=A0=A0 qemu_iovec_to_buffer(qiov, pdata);

-= =A0=A0=A0 }

-

-=A0=A0= =A0 p_cmd->volume_id =3D p_vol->vol_id;

-=A0=A0=A0 p_cmd->offset_sectors =3D sector_num;<= /p>

-=A0=A0=A0 p_cmd->size_sectors =3D nb_sectors;=

-=A0=A0=A0 p_cmd->ret_status =3D ret_status;<= /p>

-

-=A0 =A0=A0if (repagent_client_send((RepCmd *) p_cmd= ) !=3D 0) {

-=A0=A0=A0=A0=A0=A0=A0 printf("E= rror sending command\n");

-=A0=A0=A0 }

-}

-

-static void repagent_report_volumes_to_hub(voi= d)

-{

-=A0=A0=A0 /* Rep= ort IO to rephub */

-=A0=A0=A0 int i;

-=A0=A0=A0 RepCmdDataReportVmVolumes *p_cmd_data =3D NULL;

-=A0=A0=A0 RepCmdReportVmVolumes *p_cmd =3D (RepCmdR= eportVmVolumes *) repcmd_new(

-=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 REPHUB_CMD_REPORT_VM_VOLUMES,

-= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep_agent.num_volumes * sizeof(RepVmVol= umeInfo),

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint8_t **) &= ;p_cmd_data);

-=A0=A0=A0 p_cmd->num_volumes = =3D g_rep_agent.num_volumes;

-=A0=A0=A0 printf(&q= uot;reporting %u volumes\n", g_rep_agent.num_volumes);

-=A0=A0=A0 for (i =3D 0; i < g_rep_agent.num_volu= mes ; i++) {

-=A0=A0=A0=A0=A0=A0=A0 assert(g_rep_= agent.volumes[i] !=3D NULL);

-=A0=A0=A0=A0=A0=A0= =A0 printf("reporting volume %s size %u\n",

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep= _agent.volumes[i]->vol_path,

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint32_t) sizeof(p_cmd_data->volumes[i].= name));

-=A0=A0=A0=A0=A0=A0=A0 strncpy((char *) p= _cmd_data->volumes[i].name,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep= _agent.volumes[i]->vol_path,

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeof(p_cmd_data->volumes[i].name));

=

- =A0=A0=A0=A0=A0=A0=A0p_cmd_data->volumes[i].vol= ume_id =3D g_rep_agent.volumes[i]->vol_id;

-=A0=A0=A0 }

-=A0=A0=A0 if= (repagent_client_send((RepCmd *) p_cmd) !=3D 0) {

-=A0=A0=A0=A0=A0=A0=A0 printf("Error sending command\n");

-=A0=A0=A0 }

-}

-

-int repaget_start= _protect(RepCmdStartProtect *pcmd,

-=A0=A0=A0=A0= =A0=A0=A0 RepCmdDataStartProtect *pcmd_data)

-{

-=A0=A0=A0 printf("Start protect vol %s, ID %llu\n", pcmd_data-&g= t;volume_name,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= (unsigned long long) pcmd->volume_id);

-=A0= =A0=A0 int vol_index =3D repagent_get_volume_by_name(pcmd_data->volume_n= ame);

-=A0=A0=A0 if (g_rep_agent.num_volumes > 0

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 && strcmp(pc= md_data->volume_name, "stam") =3D=3D 0) {

-=A0=A0=A0=A0=A0=A0=A0 /* Choose the first one for rephub */

-=A0=A0=A0=A0=A0=A0=A0 vol_index =3D 0;

-=A0=A0=A0 }

-=A0=A0=A0 if (vol_in= dex < 0) {

-=A0=A0=A0=A0=A0=A0=A0 printf("= ;The volume doesn't exist\n");

-=A0=A0=A0=A0=A0=A0=A0 return TRUE;

-=A0=A0=A0 }<= /p>

-=A0=A0=A0 /* orim todo protect */

-=A0=A0=A0 g_rep_agent.volumes[vol_index]->vol_id =3D pcmd-&= gt;volume_id;

-

-=A0=A0=A0 return TRUE;

-}

-

-static int rep= agent_get_volume_by_name(const char *name)

-{

=

-=A0=A0=A0 int i =3D 0;

-=A0=A0=A0 for (i =3D 0; = i < g_rep_agent.num_volumes ; i++) {

-=A0=A0= =A0=A0=A0=A0=A0 if (g_rep_agent.volumes[i] !=3D NULL

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 && strcmp(name, = g_rep_agent.volumes[i]->vol_path) =3D=3D 0) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return i;

-=A0=A0=A0=A0=A0=A0=A0 }

-=A0= =A0=A0 }

-=A0=A0=A0 return -1;

-}

-

-static int repagent_get_volume_by_id(uint64_t vol_id)

-{

-=A0=A0=A0 int i =3D 0;

- =A0=A0=A0for (i =3D 0; i < g_rep_agent.num_volumes ; i++) {<= /p>

-=A0=A0=A0=A0=A0=A0=A0 if (g_rep_agent.volumes[i] !=3D NULL

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 && g_rep_= agent.volumes[i]->vol_id =3D=3D vol_id) {

-=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return i;

-=A0=A0= =A0=A0=A0=A0=A0 }

-=A0=A0=A0 }

-=A0=A0=A0 re= turn -1;

-}

-

-int repaget_read_vol(RepCmdReadVolReq *pcmd, uint8_t *pda= ta)

-{

-=A0=A0=A0 int index =3D repagent_get_volume_b= y_id(pcmd->volume_id);

-=A0=A0=A0 int size_byt= es =3D pcmd->size_sectors * 512;

-=A0=A0=A0 if= (index < 0) {

-=A0=A0=A0=A0=A0=A0=A0 printf("Vol read - Could not find vol id %llx\n= ",

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 (unsigned long long int) pcmd->volume_id);

-=A0=A0=A0=A0=A0=A0=A0 RepCmdReadVolRes *p_res_cmd =3D (RepCmdReadVolRe= s *) repcmd_new(

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 REPHU= B_CMD_READ_VOL_RES, 0, NULL);

-=A0=A0=A0=A0=A0=A0= =A0 p_res_cmd->req_id =3D pcmd->req_id;

-= =A0=A0=A0=A0=A0=A0=A0 p_res_cmd->volume_id =3D pcmd->volume_id;

-=A0=A0=A0=A0=A0=A0=A0 p_res_cmd->is_status_succe= ss =3D FALSE;

-=A0=A0=A0=A0=A0=A0=A0 repagent_cli= ent_send((RepCmd *) p_res_cmd);

-=A0=A0=A0=A0=A0= =A0=A0 return TRUE;

-=A0=A0=A0 }

-

-=A0=A0=A0 printf("= Vol read - driver %p, volId %llu, offset %llu, size %u\n",

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 g_rep_agent.volumes[index= ]->driver_ptr,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned long long int) pcmd->volume= _id,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned= long long int) pcmd->offset_sectors, pcmd->size_sectors);

-

-=A0=A0=A0 {

-=A0=A0=A0=A0=A0=A0=A0 RepagentReadVolIo *read_xact = =3D calloc(1, sizeof(RepagentReadVolIo));

-

-/*=A0=A0=A0=A0=A0=A0=A0 BlockDriverAIOCB *acb; */

=

-

-=A0=A0=A0=A0=A0=A0=A0 ZERO_MEM_OBJ(read_xact);

-=

-=A0=A0=A0=A0=A0=A0=A0 qemu_iovec_init(&read= _xact->qiov, 1);

-

-= =A0=A0=A0=A0=A0=A0=A0 /*read_xact->buf =3D

-=A0=A0=A0=A0=A0=A0=A0 qemu_blockalign(g_rep_agent.v= olumes[index]->driver_ptr, size_bytes); */

-= =A0=A0=A0=A0=A0=A0=A0 read_xact->buf =3D (uint8_t *) g_malloc(size_bytes= );

-=A0=A0=A0=A0=A0=A0=A0 read_xact->rep_cmd = =3D *pcmd;

-=A0=A0=A0=A0=A0=A0=A0 qemu_iovec_add(&read_xact= ->qiov, read_xact->buf, size_bytes);

-

<= p class=3D"MsoNormal">-=A0=A0=A0=A0=A0=A0=A0 gettimeofday(&read_xact-&g= t;start_time, NULL);

-=A0=A0=A0=A0=A0=A0=A0 /* orim TODO - use the returned acb to cancel the re= quest on shutdown */

-=A0=A0=A0=A0=A0=A0=A0 /*acb= =3D */bdrv_aio_readv(g_rep_agent.volumes[index]->driver_ptr,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 read_xact-&g= t;rep_cmd.offset_sectors, &read_xact->qiov,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 read_= xact->rep_cmd.size_sectors, repagent_vol_read_done,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =A0=A0=A0=A0=A0read_xact);

-=A0=A0=A0 }

-

-=A0=A0=A0 return TRUE;

-}

-

-static void repagent_vol_read_done(void *o= paque, int ret)

-{

-=A0= =A0=A0 struct timeval t2;

-=A0=A0=A0 RepagentReadVolIo *read_xact =3D (Repagen= tReadVolIo *) opaque;

-=A0=A0=A0 uint8_t *pdata = =3D NULL;

-=A0=A0=A0 RepCmdReadVolRes *pcmd =3D (= RepCmdReadVolRes *) repcmd_new(

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 REPHUB_CMD_READ_V= OL_RES, read_xact->rep_cmd.size_sectors * 512,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 &pdata);

= -=A0=A0=A0 pcmd->req_id =3D read_xact->rep_cmd.req_id;

-=A0=A0=A0 pcmd->volume_id =3D read_xact->rep_= cmd.volume_id;

-=A0=A0=A0 pcmd->is_status_succ= ess =3D FALSE;

-

-=A0= =A0=A0 printf("Protected vol read - volId %llu, offset %llu, size %u\n= ",

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned long lo= ng int) read_xact->rep_cmd.volume_id,

-=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (unsigned long long int) read_xact->rep_cmd.= offset_sectors,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 read_xact->rep_cmd.size_sectors);

-=A0=A0=A0 gettimeofday(&t2, NULL);

-

-=A0=A0=A0 if (ret >=3D 0) {<= /p>

-=A0=A0=A0=A0=A0=A0=A0 /* Read response - send th= e data to the hub */

-=A0=A0=A0=A0=A0=A0=A0 t2 =3D tsub(t2, read_xact->start_time);

-=A0=A0=A0=A0=A0=A0=A0 printf("Read prot vol done. To= ok %u seconds, %u us.",

-=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint32_t) t2.tv_sec, (uint32_t) t2.tv_usec);

-

-=A0=A0=A0=A0=A0=A0=A0 p= cmd->is_status_success =3D TRUE;

-=A0=A0=A0=A0= =A0=A0=A0 /* orim todo optimize - don't copy, use the qiov buffer */

-=A0=A0=A0=A0=A0=A0=A0 qemu_iovec_to_buffer(&re= ad_xact->qiov, pdata);

-=A0=A0=A0 } else {

-=A0= =A0=A0=A0=A0=A0=A0 printf("readv failed: %s\n", strerror(-ret));<= /p>

-=A0=A0=A0 }

-

-=A0=A0=A0 repagent_client_send((RepCmd *) pcmd);

-

-=A0=A0=A0 /*qemu_vfree(= read_xact->buf); */

-=A0=A0=A0 g_free(read_xac= t->buf);

-

-=A0=A0= =A0 g_free(read_xact);

-}

-

-static struct timeval tsub(struct timeval t1, struct timeval t2)

<= p class=3D"MsoNormal">-{

-=A0=A0=A0 t1.tv_usec -= =3D t2.tv_usec;

-=A0=A0=A0 if (t1.tv_usec < 0) {

-=A0=A0=A0=A0=A0=A0=A0 t1.tv_usec +=3D 1000000;

-=A0=A0=A0=A0=A0=A0=A0 t1.tv_sec--;

-=A0= =A0=A0 }

-=A0=A0=A0 t1.tv_sec -=3D t2.tv_sec;

-=A0=A0=A0 return t1;

-}

-

-void repagent_client_= connected(void)

-{

-=A0= =A0=A0 /* orim todo thread protection */

-=A0=A0=A0 repagent_report_volumes_to_hub();

-}

diff --git a/replication/re= pagent.h b/replication/repagent.h

deleted file mo= de 100644

index 98ccbf2..0000000

---= a/replication/repagent.h

+++ /dev/null

@@ -1,46 +0,0 @@

-/*

- * QEMU System Emulator

- *

- * Copyright (c) 2003-2008 Fabrice Bellard

- *

- * Permission is hereby granted, free of ch= arge, to any person obtaining a copy

- * of this software and associated documentation fi= les (the "Software"), to deal

- * in th= e Software without restriction, including without limitation the rights

- * to use, copy, modify, merge, publish, distribute= , sublicense, and/or sell

- * copies of the Softw= are, and to permit persons to whom the Software is

- * furnished to do so, subject to the following conditions:

- *

- * The above copyright notice an= d this permission notice shall be included in

- *= all copies or substantial portions of the Software.

- *

- * THE SOFTWARE IS PR= OVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES = OF MERCHANTABILITY,

- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGE= MENT. IN NO EVENT SHALL

- * THE AUTHORS OR COPYRI= GHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM,

- * OUT OF OR IN CONNECTION WITH THE SOFTW= ARE OR THE USE OR OTHER DEALINGS IN

- * THE SOFTW= ARE.

- */

-#ifndef REPAGENT_H

-#define REPAGENT_H

-#in= clude <stdint.h>

-

-#include "qemu-common.h"

-

-typedef struct RepAgent= State RepAgentState;

-typedef struct RepCmdStartP= rotect RepCmdStartProtect;

-typedef struct RepCmd= DataStartProtect RepCmdDataStartProtect;

-struct RepCmdReadVolReq;

= -

-void repagent_init(const char *hubname, int po= rt);

-void repagent_handle_protected_write(BlockD= riverState *bs,

-=A0=A0=A0=A0=A0=A0=A0 int64_t sector_num, int nb_se= ctors, QEMUIOVector *qiov, int ret_status);

-void= repagent_register_drive(const char *drive_path,

= -=A0=A0=A0=A0=A0=A0=A0 BlockDriverState *driver_ptr);

-int repaget_start_protect(RepCmdStartProtect *pcmd,=

-=A0=A0=A0=A0=A0=A0=A0 RepCmdDataStartProtect *p= cmd_data);

-int repaget_read_vol(struct RepCmdRea= dVolReq *pcmd, uint8_t *pdata);

-void repagent_client_connected(void);

-

-

-#en= dif /* REPAGENT_H */

diff --git a/replication/rep= agent_client.c b/replication/repagent_client.c

deleted file mode 100644

i= ndex eaa0a28..0000000

--- a/replication/repagent_= client.c

+++ /dev/null

= @@ -1,160 +0,0 @@

-#include "repcmd.h"

-#include "rephub_cmds.h"

-#includ= e "repcmd_listener.h"

-#include "r= epagent_client.h"

-#include "repagent.h"

-#include "main-loop.h"

-

-#include <string.h>

-#= include <stdlib.h>

-#include <errno.h>

= -#include <stdio.h>

-#include <resolv.h&= gt;

-#include <sys/socket.h>

-#include <arpa/inet.h>

-#include <netin= et/in.h>

-#include <unistd.h>

-

-#define ZERO_MEM_OBJ(pObj) mem= set(pObj, 0, sizeof(*pObj))

-

-static void repagent_pr= ocess_cmd(RepCmd *pCmd, uint8_t *pData, void *clientPtr);

-

-typedef struct repagent_client_state = {

-=A0=A0=A0 int is_connected;

-=A0=A0=A0 int is_terminate_receive;

-=A0=A0= =A0 int hsock;

-} repagent_client_state;

-

-static repagent_client_state g_client_state =3D { 0 };

-

-static void repagent_client_read(void *= opaque)

-{

-=A0=A0=A0 p= rintf("repagent_client_read\n");

-=A0=A0=A0 int bytes_read =3D repcmd_listener_socket= _read_next_buf(g_client_state.hsock);

-=A0=A0=A0 = if (bytes_read <=3D 0) {

-=A0=A0=A0=A0=A0=A0= =A0 g_client_state.is_connected =3D 0;

-=A0=A0=A0 }

-}

-

-void *repagent_listen(void *pP= aram)

-{

-=A0=A0=A0 rep= hub_params *pServerParams =3D (rephub_params *) pParam;

-=A0=A0=A0 int host_port =3D pServerParams->port;=

-=A0=A0=A0 const char *host_name =3D pServerPara= ms->name;

-

-=A0=A0= =A0 printf("Creating repagent listener thread...\n");

-=A0=A0=A0 g_free(pServerParams);

-

-=A0=A0=A0 struct sockaddr_in my_addr;<= /p>

-

-=A0=A0=A0 int err;

-=A0=A0=A0 int retries =3D 0;

-

-=A0=A0=A0 g_client_stat= e.hsock =3D socket(AF_INET, SOCK_STREAM, 0);

-=A0= =A0=A0 if (g_client_state.hsock =3D=3D -1) {

-=A0= =A0=A0=A0=A0=A0=A0 printf("Error initializing socket %d\n", errno= );

-=A0=A0=A0=A0=A0=A0=A0 return (void *) -1;

-=A0=A0=A0 }

-

- =A0=A0=A0int param =3D 1;

-

-=A0=A0=A0 if ((setsockopt(g_client_state.hsock, SOL_SOCKET= , SO_REUSEADDR,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (char *) &par= am, sizeof(int)) =3D=3D -1)

-=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 || (setsockopt(g_client_state.hsock, SOL_SOCKET, SO_KEEPALI= VE,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 (char *) &param, sizeof(int)) =3D=3D -1)) {

-=A0=A0=A0=A0=A0=A0=A0 printf("Error setting op= tions %d\n", errno);

-=A0=A0=A0=A0=A0=A0=A0 = return (void *) -1;

-=A0=A0=A0 }

-

-=A0=A0=A0 my_addr.sin_family =3D AF_= INET;

-=A0=A0=A0 my_addr.sin_port =3D htons(host_port);

-=A0=A0=A0 memset(&(my_addr.sin_zero), 0, 8);

-

-=A0=A0=A0 my_addr.sin= _addr.s_addr =3D inet_addr(host_name);

-

-=A0=A0=A0 /* Reconnect = loop */

-=A0=A0=A0 while (!g_client_state.is_term= inate_receive) {

-

-=A0= =A0=A0=A0=A0=A0=A0 if (connect(g_client_state.hsock, (struct sockaddr *) &a= mp;my_addr,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeo= f(my_addr)) =3D=3D -1) {

-=A0=A0=A0 =A0=A0=A0=A0= =A0=A0=A0=A0err =3D errno;

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 if (err !=3D EINPROGRESS) {

-=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 retries++;

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 fprin= tf(

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 stderr,

-=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "Error conne= cting socket %d. Host %s, port %u. Retry count %d\n",

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 = =A0=A0=A0=A0=A0=A0=A0errno, host_name, host_port, retries);

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 usleep(5 * 1000 *= 1000);

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 continue;

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 }

-=A0=A0=A0= =A0=A0=A0=A0 }

-=A0=A0=A0=A0=A0=A0=A0 retries =3D= 0;

-

-

-=A0=A0=A0=A0=A0=A0=A0 repagent_client_connected();

-=A0=A0=A0=A0=A0=A0=A0 repcmd_listener_init(repagent_process_cmd, NULL);

-=A0=A0=A0=A0=A0=A0=A0 g_client_state.is_connected = =3D 1;

-=A0=A0=A0=A0=A0=A0=A0 static int c;

-=A0=A0=A0=A0=A0=A0=A0 /* repcmd_listener_socket_threa= d_listener(g_client_state.hsock); */

-=A0=A0=A0=A0=A0=A0=A0 qemu_set_fd_handler(g_client_= state.hsock, repagent_client_read, NULL,

-=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 NULL);

-= =A0=A0=A0=A0=A0=A0=A0 while (g_client_state.is_connected) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 printf("Conn= ected (%d)...\n", c++);

-=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 usleep(1 * 1000 * 1000);

-=A0=A0= =A0=A0=A0=A0=A0 }

-=A0=A0=A0=A0=A0=A0=A0 /* Unreg= ister */

-=A0=A0=A0=A0=A0=A0=A0 qemu_set_fd_handler(g_client_= state.hsock, NULL, NULL, NULL);

-

-=A0=A0=A0=A0=A0=A0=A0 printf("Disconnected\n");

-=A0=A0=A0=A0=A0=A0=A0 g_client_state.is_connected =3D= 0;

-=A0=A0=A0=A0=A0=A0=A0 close(g_client_state.hsock);<= /p>

-

-=A0=A0=A0 }

-=A0=A0=A0 return 0;

-}

-

-void repagent_process_cmd(RepCmd *pcmd, uint8_t *pdata, void *clientPtr)

-{

-=A0=A0=A0 int is_fre= e_data =3D 1;

-=A0=A0=A0 printf("Repagent go= t cmd %d\n", pcmd->hdr.cmdid);

-=A0=A0=A0 switch (pcmd->hdr.cmdid) {

-=A0=A0=A0 case REPHUB_CMD_START_PROTECT: {

-=A0=A0=A0=A0=A0=A0=A0 is_free_data =3D repaget_start_protect((Re= pCmdStartProtect *) pcmd,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (RepCmdDataStartProtect *) p= data);

-=A0=A0=A0 }

-= =A0=A0=A0=A0=A0=A0=A0 break;

-=A0=A0=A0 case REPH= UB_CMD_READ_VOL_REQ: {

-=A0=A0=A0=A0=A0=A0=A0 is_= free_data =3D repaget_read_vol((RepCmdReadVolReq *) pcmd, pdata);

-=A0=A0=A0 }

-=A0=A0=A0=A0= =A0=A0=A0 break;

-=A0=A0=A0 default:

-=A0=A0=A0=A0=A0=A0=A0 assert(0);

= -=A0=A0=A0=A0=A0=A0=A0 break;

-

-=A0=A0=A0 }

-

-=A0=A0= =A0 if (is_free_data) {

-=A0=A0=A0=A0=A0=A0=A0 g_= free(pdata);

-=A0=A0=A0 }

-}

-

-int repagent_client_send(RepCmd *p_cmd)

-{

-=A0=A0=A0 int bytecount =3D 0;

-=A0=A0=A0 printf("Send cmd %u, data size %u\n", p_cmd->hd= r.cmdid,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 p_cmd->hdr.data_size_bytes);

-=A0=A0=A0 if (!g_client_state.is_connected) {

-=A0=A0=A0=A0=A0=A0=A0 printf("Not connected to hub\n&= quot;);

-=A0=A0=A0=A0=A0=A0=A0 return -1;

-=A0=A0=A0 }

-

-=A0=A0=A0 bytecount =3D send(g_client_state.hsock, p_cmd,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 sizeof(RepCmd) = + p_cmd->hdr.data_size_bytes, 0);

-=A0=A0=A0 if (bytecount < sizeof(RepCmd) + p_cmd= ->hdr.data_size_bytes) {

-=A0=A0=A0=A0=A0=A0= =A0 printf("Bad send %d, errno %d\n", bytecount, errno);

-=A0=A0=A0=A0=A0=A0=A0 return bytecount;

-=A0=A0=A0 }

-

-=A0=A0=A0 /* Success */

-=A0=A0= =A0 return 0;

-}

diff -= -git a/replication/repagent_client.h b/replication/repagent_client.h

deleted file mode 100644

i= ndex 62a5377..0000000

--- a/replication/repagent_= client.h

+++ /dev/null

= @@ -1,36 +0,0 @@

-/*

- * QEMU System Emulat= or

- *

- * Copyright (c= ) 2003-2008 Fabrice Bellard

- *

- * Permission is hereby granted, free of charge, to any person obtaining a= copy

- * of this software and associated documen= tation files (the "Software"), to deal

- * in the Software without restriction, including without limitation the r= ights

- * to use, copy, modify, merge, publish, d= istribute, sublicense, and/or sell

- * copies of = the Software, and to permit persons to whom the Software is

- * furnished to do so, subject to the following con= ditions:

- *

- * The ab= ove copyright notice and this permission notice shall be included in

- * all copies or substantial portions of the Software.

- *

- * THE SOFTWARE IS PROVIDED "AS = IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY= ,

- * FITNESS FOR A PARTICULAR PURPOSE AND NONINF= RINGEMENT. IN NO EVENT SHALL

- * THE AUTHORS OR C= OPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TOR= T OR OTHERWISE, ARISING FROM,

- * OUT OF OR IN CO= NNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

- * THE SOFTWARE.

- */

= -#ifndef REPAGENT_CLIENT_H

-#define REPAGENT_CLIE= NT_H

-#include "repcmd.h"

-

-typedef struct rephub_params {

-=A0=A0=A0 char *name;

-=A0=A0=A0 int = port;

-} rephub_params;

-

-void *repagent_listen(void *pParam);

-int repage= nt_client_send(RepCmd *p_cmd);

-

-#endif /* REPAGENT_CLIENT_H */

diff --= git a/replication/repcmd.h b/replication/repcmd.h

deleted file mode 100644

i= ndex 8c6cf1b..0000000

--- a/replication/repcmd.h<= /p>

+++ /dev/null

@@ -1,59 = +0,0 @@

-/*

- * QEMU System Emulat= or

- *

- * Copyright (c= ) 2003-2008 Fabrice Bellard

- *

- * Permission is hereby granted, free of charge, to any person obtaining a= copy

- * of this software and associated documen= tation files (the "Software"), to deal

- * in the Software without restriction, including without limitation the r= ights

- * to use, copy, modify, merge, publish, d= istribute, sublicense, and/or sell

- * copies of = the Software, and to permit persons to whom the Software is

- * furnished to do so, subject to the following con= ditions:

- *

- * The ab= ove copyright notice and this permission notice shall be included in

- * all copies or substantial portions of the Software.

- *

- * THE SOFTWARE IS PROVIDED "AS = IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY= ,

- * FITNESS FOR A PARTICULAR PURPOSE AND NONINF= RINGEMENT. IN NO EVENT SHALL

- * THE AUTHORS OR C= OPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TOR= T OR OTHERWISE, ARISING FROM,

- * OUT OF OR IN CO= NNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

- * THE SOFTWARE.

- */

= -#ifndef REPCMD_H

-#define REPCMD_H

-

-#include <stdint.h>

-

-#define REPCMD_MAGIC1 (0x1122)

-#define REPCMD_MAGIC2 (0x3344)

-#defi= ne REPCMD_NUM_U32_PARAMS (11)

-

-enum RepCmds {

-=A0=A0=A0 REPCMD_FIRST_INVALID= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 0,

-=A0=A0=A0 REPCMD_FIRST_HUBCMD=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 1,

-=A0=A0= =A0 REPHUB_CMD_PROTECTED_WRITE=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 2= ,

-=A0=A0=A0 REPHUB_CMD_REPORT_VM_VOLUMES=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 =3D 3,

-=A0=A0=A0 REPHUB_CM= D_START_PROTECT=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 4,

-=A0=A0=A0 REPHUB_CMD_READ_VOL_REQ=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 5,

-=A0=A0=A0 REPHUB_CMD_READ_VOL_RES=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 6,

-=A0=A0=A0 = REPHUB_CMD_AGENT_SHUTDOWN=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D 7,<= /p>

-};

-

-typedef struct RepCmdHdr {

-=A0=A0=A0 uint16_t m= agic1;

-=A0=A0=A0 uint16_t cmdid;

-=A0=A0=A0 uint32_t data_size_bytes;

-= } RepCmdHdr;

-

-typedef struct RepCmd {

-=A0=A0=A0 RepCmdHdr hdr;

-=A0=A0=A0 unsigned= int parameters[REPCMD_NUM_U32_PARAMS];

-=A0=A0= =A0 unsigned int magic2;

-=A0=A0=A0 uint8_t data[0];

-} RepCmd;

-

-RepCmd = *repcmd_new(int cmd_id, int data_size, uint8_t **p_out_pdata);

-

-#endif /* REPCMD_H */

diff --git a/replication/repcmd_listener.c b/replication/repcmd_listener.= c

deleted file mode 100644

index c1ce97f..0000000

--- a/replication/repcmd_l= istener.c

+++ /dev/null

@@ -1,173 +0,0 @@

-#include <fcntl.h>

<= p class=3D"MsoNormal"> -#include <string.h>

-#include <stdlib.h= >

-#include <errno.h>

-#include <stdio.h>

-#include <n= etinet/in.h>

-#include <resolv.h>

-#include <sys/socket.h>

-#include <arp= a/inet.h>

-#include <unistd.h>

-#include <pthread.h>

-#include <assert.= h>

-

-/* Use the CON= FIG_REPLICATION flag to determine whether

- * we&= #39;re under qemu build or a hub When under

- * qemu use g_malloc */

-= #ifdef CONFIG_REPLICATION

-#include <glib.h>= ;

-#define REPCMD_MALLOC g_malloc

-#else

-#define REPCMD_MALLOC malloc

-#endif

-

-#include "repcmd.h"

-#include "= repcmd_listener.h"

-

-#define ZERO_MEM_OBJ(pO= bj) memset((void *)pObj, 0, sizeof(*pObj))

-

<= p class=3D"MsoNormal">-

-typedef struct RepCmdRxC= mdState {

-=A0=A0=A0 RepCmd curCmd;

= -=A0=A0=A0 uint8_t *pReadBuf;

-=A0=A0=A0 int byte= sToGet;

-=A0=A0=A0 int bytesGotten;

-=A0=A0=A0 int isGotHeader;

-=A0=A0=A0 uint8_t *pdata;

-} RepCmdRxCmdState;

-

-typedef struct RepCmdListenerState {

-=A0=A0=A0= int is_terminate_receive;

-=A0=A0=A0 pfn_received_cmd_cb=A0 receive_cb;

-=A0=A0=A0 void *opaque;

-=A0= =A0=A0 int hsock;

-=A0=A0=A0 RepCmdRxCmdState cur= _cmd;

-} RepCmdListenerState;

-

-static RepCmdListenerState g_listenerState =3D { 0 };

-

-static int repcmd_listener_process_rx= (int bytecount);

-

-void repcmd_listener_in= it(pfn_received_cmd_cb callback, void *opaque)

-{=

-=A0=A0=A0 ZERO_MEM_OBJ(&g_listenerState);

-=A0=A0=A0 g_listenerState.receive_cb =3D callback;

-=A0=A0=A0 g_listenerState.opaque =3D opaque;

= -

-=A0=A0=A0 g_listenerState.cur_cmd.bytesToGet = =3D sizeof(RepCmd);

-=A0=A0=A0 g_listenerState.cur_cmd.pReadBuf =3D

-= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (uint8_t *) &g_listenerState.cur_cmd.= curCmd;

-}

-

-int repcmd_listener_socket_read_next_buf(int hsock)

-{

-=A0=A0=A0 RepCmdRxCmdS= tate *cmd_state =3D &g_listenerState.cur_cmd;

-=A0=A0=A0 int bytecount =3D recv(hsock, cmd_state->pReadBuf + cmd_stat= e->bytesGotten,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->byt= esToGet - cmd_state->bytesGotten, 0);

-=A0=A0= =A0 return repcmd_listener_process_rx(bytecount);

-}

-

-/* Returns 0 for initiated termination or socket er= ror value on error */

-int repcmd_listener_socket= _thread_listener(int hsock)

-{

-=A0=A0=A0 int ret =3D 0;

-=A0=A0=A0 /* receive l= oop */

-=A0=A0=A0 while (!g_listenerState.is_term= inate_receive) {

-=A0=A0=A0=A0=A0=A0=A0 ret =3D r= epcmd_listener_socket_read_next_buf(hsock);

-=A0=A0=A0=A0=A0=A0=A0 if (ret <=3D 0) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return ret;

-=A0=A0=A0=A0=A0=A0=A0 }

-=A0=A0= =A0 }

-=A0=A0=A0 return 0;

-}

-

-static int repcmd= _listener_process_rx(int bytecount)

-{

-=A0=A0=A0 RepCmdRxCmdState *cmd_state =3D &g_listenerS= tate.cur_cmd;

-=A0=A0=A0 if (bytecount =3D=3D -1) {

-=A0=A0=A0=A0=A0=A0=A0 fprintf(stderr, "Error receiving da= ta %d\n", errno);

-=A0=A0=A0=A0=A0=A0=A0 ret= urn errno;

-=A0=A0=A0 }

-

-=A0=A0=A0 if (bytecount= =3D=3D 0) {

-=A0=A0=A0=A0=A0=A0=A0 printf("= Disconnected\n");

-=A0=A0=A0=A0=A0=A0=A0 ret= urn 0;

-=A0=A0=A0 }

-=A0=A0=A0 cmd_state->bytesGotten +=3D bytecount;

-/*=A0=A0=A0=A0 printf("Recieved bytes %d, got %d/%d\n",

<= p class=3D"MsoNormal">-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 bytecount, cmd_sta= te->bytesGotten, cmd_state->bytesToGet); */

-=A0=A0=A0 /* print content */

-=A0=A0=A0 if (0) {

-=A0=A0=A0=A0=A0=A0=A0 i= nt i;

-=A0=A0=A0=A0=A0=A0=A0 for (i =3D 0; i <= bytecount ; i +=3D 4) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /*printf("%d/%d", i, bytecount= /4); */

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 printf= (

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 "%#x ",

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 *(int *) (&cmd_state->pRe= adBuf[cmd_state->bytesGotten

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 - bytecount + i]));

-

-=A0=A0=A0=A0=A0=A0=A0 }

-=A0=A0=A0=A0=A0=A0=A0 printf("\n");

-=A0=A0=A0 }

-=A0=A0=A0 assert(cmd_state->bytesGotten <=3D = cmd_state->bytesToGet);

-=A0=A0=A0 if (cmd_sta= te->bytesGotten =3D=3D cmd_state->bytesToGet) {

-=A0=A0=A0=A0=A0=A0=A0 int isGotData =3D 0;

-=A0=A0=A0=A0=A0=A0=A0 cmd_state->bytesGotten =3D= 0;

-=A0=A0=A0=A0=A0=A0=A0 if (!cmd_state->isG= otHeader) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /*= We just got the header */

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 cmd_state->isGotHeader =3D 1;

-

-=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 assert(cmd_state->curCmd.hdr.magic1 =3D=3D REPCMD_MAGIC1);<= /p>

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 assert(cmd_sta= te->curCmd.magic2 =3D=3D REPCMD_MAGIC2);

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if (cmd_state->curCmd.hdr.data_size_b= ytes > 0) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 cmd_state->pdata =3D (uint8_t *)REPCMD_MALLOC(

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0 cmd_state->curCmd.hdr.data_size_bytes);

-/*=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0 printf("malloc %p\n", cmd_state->pdata); */

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state-= >pReadBuf =3D cmd_state->pdata;

-=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 } else {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* no= data */

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 isGotData =3D 1;

-=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 cmd_state->pdata =3D NULL;

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 }

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->bytesToGet =3D cmd_state-&= gt;curCmd.hdr.data_size_bytes;

-=A0=A0=A0=A0=A0= =A0=A0 } else {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 isGotData =3D 1;

-=A0=A0=A0=A0=A0=A0=A0 }

=

-

-=A0=A0=A0=A0=A0=A0=A0 if (isGotData) {

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* Got command and da= ta */

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 (*g_list= enerState.receive_cb)(&cmd_state->curCmd, cmd_state->pdata,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0 g_listenerState.opaque);

-

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 /* It's the callee respon= sibility to free cmd_state->pdata */

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->pdata =3D NULL;

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ZERO_MEM_OBJ(&cmd_st= ate->curCmd);

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 cmd_state->pReadBuf =3D (uint8_t *) &cmd_state->curCmd;

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->byt= esGotten =3D 0;

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 cmd_state->bytesToGet =3D sizeof(RepCmd);

= -=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 cmd_state->isGotHeader =3D 0;

-=A0=A0=A0=A0=A0=A0=A0 }

-=A0=A0=A0 }

-=A0=A0=A0 return bytecount;

-}

-

-RepCmd *repcmd_new(int= cmd_id, int data_size, uint8_t **p_out_pdata)

-{

-=A0=A0=A0 RepCmd *p_cm= d =3D (RepCmd *)REPCMD_MALLOC(sizeof(RepCmd) + data_size);

-=A0=A0=A0 assert(p_cmd !=3D NULL);

-

-=A0=A0=A0 /* Zero the CMD (not the data) */

-=A0= =A0=A0 ZERO_MEM_OBJ(p_cmd);

-

-=A0=A0=A0 p_cmd->hdr.cmdid =3D cmd_id;

-=A0=A0=A0 p_cmd->hdr.magic1 =3D REPCMD_MAGIC1;

-=A0=A0=A0 p_cmd->magic2 =3D REPCMD_MAGIC2;

-=A0=A0=A0 p_cmd->hdr.data_size_bytes =3D data_size= ;

-

-=A0=A0=A0 if (p_ou= t_pdata !=3D NULL) {

-=A0=A0=A0=A0=A0=A0=A0 *p_out_pdata =3D p_cmd->data;

-=A0=A0=A0 }

-

-= =A0=A0=A0 return p_cmd;

-}

-

diff --git a/replication/repcmd_listener.h = b/replication/repcmd_listener.h

deleted file mode 100644

i= ndex 19b9ea9..0000000

--- a/replication/repcmd_li= stener.h

+++ /dev/null

= @@ -1,34 +0,0 @@

-/*

- * QEMU System Emulat= or

- *

- * Copyright (c= ) 2003-2008 Fabrice Bellard

- *

- * Permission is hereby granted, free of charge, to any person obtaining a= copy

- * of this software and associated documen= tation files (the "Software"), to deal

- * in the Software without restriction, including without limitation the r= ights

- * to use, copy, modify, merge, publish, d= istribute, sublicense, and/or sell

- * copies of = the Software, and to permit persons to whom the Software is

- * furnished to do so, subject to the following con= ditions:

- *

- * The ab= ove copyright notice and this permission notice shall be included in

- * all copies or substantial portions of the Software.

- *

- * THE SOFTWARE IS PROVIDED "AS = IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY= ,

- * FITNESS FOR A PARTICULAR PURPOSE AND NONINF= RINGEMENT. IN NO EVENT SHALL

- * THE AUTHORS OR C= OPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TOR= T OR OTHERWISE, ARISING FROM,

- * OUT OF OR IN CO= NNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

- * THE SOFTWARE.

- */

= -#ifndef REPCMD_LISTENER_H

-#define REPCMD_LISTEN= ER_H

-#include <stdint.h>

-typedef void (*pfn_received_cmd_cb)(RepCmd *pcmd,

-=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 uint8_t *pdata, void *opaq= ue);

-

-void repcmd_lis= tener_init(pfn_received_cmd_cb callback, void *opaque);

-int repcmd_listener_socket_read_next_buf(int hsock)= ;

-int repcmd_listener_socket_thread_listener(int= hsock);

-

-#endif /* R= EPCMD_LISTENER_H */

diff --git a/replication/rephub_cmds.h b/replication= /rephub_cmds.h

deleted file mode 100644

index 3bd4eb4..0000000

--- a/rep= lication/rephub_cmds.h

+++ /dev/null

@@ -1,151 +0= ,0 @@

-/*

- * QEMU Syst= em Emulator

- *

- * Cop= yright (c) 2003-2008 Fabrice Bellard

- *

- * Permission is here= by granted, free of charge, to any person obtaining a copy

- * of this software and associated documentation files (the &quo= t;Software"), to deal

- * in the Software without restriction, including w= ithout limitation the rights

- * to use, copy, mo= dify, merge, publish, distribute, sublicense, and/or sell

- * copies of the Software, and to permit persons to whom the Software is

- * furnished to do so, subject to the following c= onditions:

- *

- * The = above copyright notice and this permission notice shall be included in

- * all copies or substantial portions of the Softwa= re.

- *

- * THE SOFTWAR= E IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRAN= TIES OF MERCHANTABILITY,

- * FITNESS FOR A PARTIC= ULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER

- * LIABILITY, WHETHER IN AN ACTION OF CONTRA= CT, TORT OR OTHERWISE, ARISING FROM,

- * OUT OF O= R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

- * THE SOFTWARE.

- */

=

-#ifndef REPHUB_CMDS_H

-#d= efine REPHUB_CMDS_H

-

-= #include <stdint.h>

-#include "repcmd.h"

-#include "rephub_defs.h"

-

-/*****************************************************= ****

- * RepCmd Report a protected IO

- *

- * REPHUB_CMD_PROTECTED_WRITE

- * Direction: agent->hub

-= *

- * Any write of a protected volume is send with thi= s

- * message to the hub, with its status.

- * When case the status is bad no data is sent

- *********************************************************/

-typedef struct RepCmdProtectedWrite {

-=A0=A0=A0 RepCmdHdr hdr;

-=A0=A0=A0 uint64_t v= olume_id;

-=A0=A0=A0 uint64_t offset_sectors;

-=A0=A0=A0 /*= The size field duplicates the RepCmd size,

-=A0= =A0=A0=A0 * but it is needed for reporting failed IOs' sizes */

-=A0=A0=A0 uint32_t size_sectors;

-=A0=A0=A0 int ret_status;

-} RepCmdProtectedWrite;

-

-/*********************************************************

- * RepCmd Report VM volumes

- *

- * REPHUB_CMD_REPORT_VM_VOLUMES

- * Di= rection: agent->hub

- *

- * The agent reports all the volumes of the VM

- * to the hub.

- ********= *************************************************/

-typedef struct RepVmVolumeInfo {

-=A0=A0=A0 ch= ar name[REPHUB_MAX_VOL_NAME_LEN];

-=A0=A0=A0 uint64_t volume_id;

-=A0=A0=A0 uint32_t size_mb;

- =A0=A0=A0uint= 32_t padding;

-} RepVmVolumeInfo;

-

-typedef struct RepCmdReportVmVolumes {

-=A0=A0= =A0 RepCmdHdr hdr;

-=A0=A0=A0 int num_volumes;

-} RepCmdReportVmVolumes;

-

-typedef struct RepCmdDataReportVmVolumes {

-=A0= =A0=A0 RepVmVolumeInfo volumes[0];

-} RepCmdDataR= eportVmVolumes;

-

-

=

-/*********************************************************

- * RepCmd Start protect

- *

- * REPHUB_CMD_START_PROTECT

- *= Direction: hub->agent

- *

- * The hub instructs = the agent to start protecting

- * a volume. When = a volume is protected all its writes

- * are sent= to to the hub.

- * With this command the hub also assigns a volume = ID to

- * the given volume name.

- *********************************************************/

<= p class=3D"MsoNormal"> -typedef struct RepCmdStartProtect {

-=A0=A0=A0 R= epCmdHdr hdr;

-=A0=A0=A0 uint64_t volume_id;

<= p class=3D"MsoNormal">-} RepCmdStartProtect;

-

-typedef struct RepCmdDataStartProtect {

-=A0=A0= =A0 char volume_name[REPHUB_MAX_VOL_NAME_LEN];

-}= RepCmdDataStartProtect;

-

-

-/*********************************************************

- * RepCmd Read Volume Request

- *

=

- * REPHUB_CMD_READ_VOL_REQ

- * Direction: hub->agent

- *

- * The hub issues a r= ead IO to a protected volume.

- * This command is= used during sync - when the hub needs

- * to rea= d unsyncronized sections of a protected volume.

- * This command is a request, the read data is retu= rned

- * by the response command REPHUB_CMD_READ_= VOL_RES

- ***************************************= ******************/

-typedef struct RepCmdReadVolReq {

-=A0=A0=A0 RepCmdHdr hdr;

-=A0=A0=A0 int= req_id;

-=A0=A0=A0 int size_sectors;

-=A0=A0=A0 uint64_t volume_id;

-=A0=A0=A0 uint64_t offset_sectors;

-} RepCmdReadVolReq;

-

-/*********************************************************

- * RepCmd Read Volume Response

- *

- * REPHUB_CMD_READ_VOL_RES

- * Di= rection: agent->hub

- *

- * A response to REPHUB_CMD_READ_VOL_REQ.

- * Sends the data read from a protected volume

<= p class=3D"MsoNormal">- ***************************************************= ******/

-typedef struct RepCmdReadVolRes {

-=A0=A0=A0 RepCmdHdr hdr;

-=A0=A0=A0 int req_id;<= /p>

-=A0=A0=A0 int is_status_success;

-=A0=A0 =A0uint64_t volume_id;

-} RepC= mdReadVolRes;

-

-/*********************************************= ************

- * RepCmd Agent shutdown

- *

- * REPHUB_CMD_AGENT_SHUTDOWN=

- * Direction: agent->hub

- *

- * Notifies the hub that the agent is abo= ut to shutdown.

- * This allows a graceful shutdo= wn. Any disconnection

- * of an agent without sending this command will re= sult

- * in a full sync of the VM volumes.

- *****************************************************= ****/

-typedef struct RepCmdAgentShutdown {

-=A0=A0=A0 RepCmdHdr hdr;

-} RepCmdAg= entShutdown;

-

-

-#endif /* REPHUB_CMDS_H */

diff --git a/replicat= ion/rephub_defs.h b/replication/rephub_defs.h

del= eted file mode 100644

index e34e0ce..0000000

<= p class=3D"MsoNormal"> --- a/replication/rephub_defs.h

+++ /dev/null

=

@@ -1,40 +0,0 @@

-/*

- * QEMU System Emulator

- *=

- * Copyright (c) 2003-2008 Fabrice Bellard

- *

- * Permission is hereby granted, free of charge, = to any person obtaining a copy

- * of this softwa= re and associated documentation files (the "Software"), to deal

- * in the Software without restriction, including w= ithout limitation the rights

- * to use, copy, mo= dify, merge, publish, distribute, sublicense, and/or sell

- * copies of the Software, and to permit persons to whom the Software is

- * furnished to do so, subject to the following c= onditions:

- *

- * The = above copyright notice and this permission notice shall be included in

- * all copies or substantial portions of the Softwa= re.

- *

- * THE SOFTWAR= E IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRAN= TIES OF MERCHANTABILITY,

- * FITNESS FOR A PARTIC= ULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OT= HER

- * LIABILITY, WHETHER IN AN ACTION OF CONTRA= CT, TORT OR OTHERWISE, ARISING FROM,

- * OUT OF O= R IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

- * THE SOFTWARE.

- */

=

-#ifndef REP_HUB_DEFS_H

-#= define REP_HUB_DEFS_H

-

-#include <stdint.h>

-

-#define REPHUB_MAX_VOL_= NAME_LEN (1024)

-#define REPHUB_MAX_NUM_VOLUMES (= 512)

-

-#ifndef TRUE

-=A0=A0=A0 #define TRUE (1)

-#endif

-

-#ifndef FALSE

-=A0=A0=A0 #define FALSE (0)

-#endif

=

-

-#endif /* REP_HUB_DEFS_H */

diff --git a/vl.c b/vl.c

index 7f8f14c..1= 7cf6ce 100644

--- a/vl.c

+++ b/vl.c

@@ -167,7 +167,7 @@ int main(int argc, char **argv)<= /p>

=A0#include "ui/= qemu-spice.h"

-#= include "replication/repagent.h"

+#include "block/repagent/repagent.h"

<= p class=3D"MsoNormal"> //#define DEBUG_NET

//#de= fine DEBUG_SLIRP

@@ -= 2413,10 +2413,10 @@ int main(int argc, char **argv, char **envp)

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0 HD_OPTS);

=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 break;

= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 case QEMU_OPTION_repagent:

-#ifdef CONFIG_REPLICATION

+#ifdef CONFIG_REPAGENT

= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 repagent_init(optarg, 0);<= /p>

#else

-=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 fprintf(stderr, "Replication support is= disabled. "

+=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 fprin= tf(stderr, "Repagent support is disabled. "

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "Don= 't use -repagent option.\n");

=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 exit(1);

#endif

--

1.7.6.5

--20cf302ef8ce16288104bced88b4--