[Qemu-devel] [PULL 26/57] MIG_CMD_PACKAGED: Send a packaged chunk of migration stream

2015-11-10 Thread Juan Quintela
From: "Dr. David Alan Gilbert" 

MIG_CMD_PACKAGED is a migration command that wraps a chunk of migration
stream inside a package whose length can be determined purely by reading
its header.  The destination guarantees that the whole MIG_CMD_PACKAGED
is read off the stream prior to parsing the contents.

This is used by postcopy to load device state (from the package)
while leaving the main stream free to receive memory pages.

Signed-off-by: Dr. David Alan Gilbert 
Reviewed-by: Amit Shah 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
---
 include/sysemu/sysemu.h |   4 ++
 migration/savevm.c  | 104 +---
 trace-events|   4 ++
 3 files changed, 107 insertions(+), 5 deletions(-)

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 6225e00..c27b926 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -99,9 +99,12 @@ enum qemu_vm_cmd {
 MIG_CMD_POSTCOPY_RAM_DISCARD,  /* A list of pages to discard that
   were previously sent during
   precopy but are dirty. */
+MIG_CMD_PACKAGED,  /* Send a wrapped stream within this stream */
 MIG_CMD_MAX
 };

+#define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24)
+
 bool qemu_savevm_state_blocked(Error **errp);
 void qemu_savevm_state_begin(QEMUFile *f,
  const MigrationParams *params);
@@ -114,6 +117,7 @@ void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd 
command,
   uint16_t len, uint8_t *data);
 void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);
 void qemu_savevm_send_open_return_path(QEMUFile *f);
+int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb);
 void qemu_savevm_send_postcopy_advise(QEMUFile *f);
 void qemu_savevm_send_postcopy_listen(QEMUFile *f);
 void qemu_savevm_send_postcopy_run(QEMUFile *f);
diff --git a/migration/savevm.c b/migration/savevm.c
index 1ce022a..f499dfa 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -74,6 +74,7 @@ static struct mig_cmd_args {
 [MIG_CMD_POSTCOPY_RUN] = { .len =  0, .name = "POSTCOPY_RUN" },
 [MIG_CMD_POSTCOPY_RAM_DISCARD] = {
.len = -1, .name = "POSTCOPY_RAM_DISCARD" },
+[MIG_CMD_PACKAGED] = { .len =  4, .name = "PACKAGED" },
 [MIG_CMD_MAX]  = { .len = -1, .name = "MAX" },
 };

@@ -749,6 +750,48 @@ void qemu_savevm_send_open_return_path(QEMUFile *f)
 qemu_savevm_command_send(f, MIG_CMD_OPEN_RETURN_PATH, 0, NULL);
 }

+/* We have a buffer of data to send; we don't want that all to be loaded
+ * by the command itself, so the command contains just the length of the
+ * extra buffer that we then send straight after it.
+ * TODO: Must be a better way to organise that
+ *
+ * Returns:
+ *0 on success
+ *-ve on error
+ */
+int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
+{
+size_t cur_iov;
+size_t len = qsb_get_length(qsb);
+uint32_t tmp;
+
+if (len > MAX_VM_CMD_PACKAGED_SIZE) {
+error_report("%s: Unreasonably large packaged state: %zu",
+ __func__, len);
+return -1;
+}
+
+tmp = cpu_to_be32(len);
+
+trace_qemu_savevm_send_packaged();
+qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *));
+
+/* all the data follows (concatinating the iov's) */
+for (cur_iov = 0; cur_iov < qsb->n_iov; cur_iov++) {
+/* The iov entries are partially filled */
+size_t towrite = MIN(qsb->iov[cur_iov].iov_len, len);
+len -= towrite;
+
+if (!towrite) {
+break;
+}
+
+qemu_put_buffer(f, qsb->iov[cur_iov].iov_base, towrite);
+}
+
+return 0;
+}
+
 /* Send prior to any postcopy transfer */
 void qemu_savevm_send_postcopy_advise(QEMUFile *f)
 {
@@ -1300,12 +1343,60 @@ static int 
loadvm_postcopy_handle_run(MigrationIncomingState *mis)
 }

 /**
- * loadvm_process_command: Process an incoming 'QEMU_VM_COMMAND'
+ * Immediately following this command is a blob of data containing an embedded
+ * chunk of migration stream; read it and load it.
  *
- * Returns: 0 on just a normal return
- *  LOADVM_QUIT All good, but exit the loop
- *  <0 error (in which case it will issue an error message).
- * @f: The stream to read the command data from.
+ * @mis: Incoming state
+ * @length: Length of packaged data to read
+ *
+ * Returns: Negative values on error
+ *
+ */
+static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
+{
+int ret;
+uint8_t *buffer;
+uint32_t length;
+QEMUSizedBuffer *qsb;
+
+length = qemu_get_be32(mis->from_src_file);
+trace_loadvm_handle_cmd_packaged(length);
+
+if (length > MAX_VM_CMD_PACKAGED_SIZE) {
+error_report("Unreasonably large packaged 

[Qemu-devel] [PULL 26/57] MIG_CMD_PACKAGED: Send a packaged chunk of migration stream

2015-11-09 Thread Juan Quintela
From: "Dr. David Alan Gilbert" 

MIG_CMD_PACKAGED is a migration command that wraps a chunk of migration
stream inside a package whose length can be determined purely by reading
its header.  The destination guarantees that the whole MIG_CMD_PACKAGED
is read off the stream prior to parsing the contents.

This is used by postcopy to load device state (from the package)
while leaving the main stream free to receive memory pages.

Signed-off-by: Dr. David Alan Gilbert 
Reviewed-by: Amit Shah 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
---
 include/sysemu/sysemu.h |   4 ++
 migration/savevm.c  | 104 +---
 trace-events|   4 ++
 3 files changed, 107 insertions(+), 5 deletions(-)

diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 6225e00..c27b926 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -99,9 +99,12 @@ enum qemu_vm_cmd {
 MIG_CMD_POSTCOPY_RAM_DISCARD,  /* A list of pages to discard that
   were previously sent during
   precopy but are dirty. */
+MIG_CMD_PACKAGED,  /* Send a wrapped stream within this stream */
 MIG_CMD_MAX
 };

+#define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24)
+
 bool qemu_savevm_state_blocked(Error **errp);
 void qemu_savevm_state_begin(QEMUFile *f,
  const MigrationParams *params);
@@ -114,6 +117,7 @@ void qemu_savevm_command_send(QEMUFile *f, enum qemu_vm_cmd 
command,
   uint16_t len, uint8_t *data);
 void qemu_savevm_send_ping(QEMUFile *f, uint32_t value);
 void qemu_savevm_send_open_return_path(QEMUFile *f);
+int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb);
 void qemu_savevm_send_postcopy_advise(QEMUFile *f);
 void qemu_savevm_send_postcopy_listen(QEMUFile *f);
 void qemu_savevm_send_postcopy_run(QEMUFile *f);
diff --git a/migration/savevm.c b/migration/savevm.c
index a7a958c..01fdc72 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -74,6 +74,7 @@ static struct mig_cmd_args {
 [MIG_CMD_POSTCOPY_RUN] = { .len =  0, .name = "POSTCOPY_RUN" },
 [MIG_CMD_POSTCOPY_RAM_DISCARD] = {
.len = -1, .name = "POSTCOPY_RAM_DISCARD" },
+[MIG_CMD_PACKAGED] = { .len =  4, .name = "PACKAGED" },
 [MIG_CMD_MAX]  = { .len = -1, .name = "MAX" },
 };

@@ -749,6 +750,48 @@ void qemu_savevm_send_open_return_path(QEMUFile *f)
 qemu_savevm_command_send(f, MIG_CMD_OPEN_RETURN_PATH, 0, NULL);
 }

+/* We have a buffer of data to send; we don't want that all to be loaded
+ * by the command itself, so the command contains just the length of the
+ * extra buffer that we then send straight after it.
+ * TODO: Must be a better way to organise that
+ *
+ * Returns:
+ *0 on success
+ *-ve on error
+ */
+int qemu_savevm_send_packaged(QEMUFile *f, const QEMUSizedBuffer *qsb)
+{
+size_t cur_iov;
+size_t len = qsb_get_length(qsb);
+uint32_t tmp;
+
+if (len > MAX_VM_CMD_PACKAGED_SIZE) {
+error_report("%s: Unreasonably large packaged state: %zu",
+ __func__, len);
+return -1;
+}
+
+tmp = cpu_to_be32(len);
+
+trace_qemu_savevm_send_packaged();
+qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *));
+
+/* all the data follows (concatinating the iov's) */
+for (cur_iov = 0; cur_iov < qsb->n_iov; cur_iov++) {
+/* The iov entries are partially filled */
+size_t towrite = MIN(qsb->iov[cur_iov].iov_len, len);
+len -= towrite;
+
+if (!towrite) {
+break;
+}
+
+qemu_put_buffer(f, qsb->iov[cur_iov].iov_base, towrite);
+}
+
+return 0;
+}
+
 /* Send prior to any postcopy transfer */
 void qemu_savevm_send_postcopy_advise(QEMUFile *f)
 {
@@ -1300,12 +1343,60 @@ static int 
loadvm_postcopy_handle_run(MigrationIncomingState *mis)
 }

 /**
- * loadvm_process_command: Process an incoming 'QEMU_VM_COMMAND'
+ * Immediately following this command is a blob of data containing an embedded
+ * chunk of migration stream; read it and load it.
  *
- * Returns: 0 on just a normal return
- *  LOADVM_QUIT All good, but exit the loop
- *  <0 error (in which case it will issue an error message).
- * @f: The stream to read the command data from.
+ * @mis: Incoming state
+ * @length: Length of packaged data to read
+ *
+ * Returns: Negative values on error
+ *
+ */
+static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
+{
+int ret;
+uint8_t *buffer;
+uint32_t length;
+QEMUSizedBuffer *qsb;
+
+length = qemu_get_be32(mis->from_src_file);
+trace_loadvm_handle_cmd_packaged(length);
+
+if (length > MAX_VM_CMD_PACKAGED_SIZE) {
+error_report("Unreasonably large packaged