diff --git a/savevm.c b/savevm.c
index e44eccd..1c2a7fb 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1601,29 +1601,68 @@ bool qemu_savevm_state_blocked(Monitor *mon)
     return false;
 }
 
-int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
-                            int shared)
+/*
+ * section: header to write
+ * inc: if true, forces to pass SECTION_PART instead of SECTION_START
+ * pause: if true, breaks the loop when live handler returned 0
+ */
+static int qemu_savevm_state_live(Monitor *mon, QEMUFile *f, int section,
+                                  bool inc, bool pause)
 {
     SaveStateEntry *se;
+    int skip = 0, ret;
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
-        if(se->set_params == NULL) {
+        int len, stage;
+
+        if (se->save_live_state == NULL) {
             continue;
-	}
-	se->set_params(blk_enable, shared, se->opaque);
+        }
+
+        /* Section type */
+        qemu_put_byte(f, section);
+        qemu_put_be32(f, se->section_id);
+
+        if (section == QEMU_VM_SECTION_START) {
+            /* ID string */
+            len = strlen(se->idstr);
+            qemu_put_byte(f, len);
+            qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+
+            qemu_put_be32(f, se->instance_id);
+            qemu_put_be32(f, se->version_id);
+
+            stage = inc ? QEMU_VM_SECTION_PART : QEMU_VM_SECTION_START;
+        } else {
+            assert(inc);
+            stage = section;
+        }
+
+        ret = se->save_live_state(mon, f, stage, se->opaque);
+        if (!ret) {
+            skip++;
+            if (pause) {
+                break;
+            }
+        }
     }
-    
-    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
-    qemu_put_be32(f, QEMU_VM_FILE_VERSION);
+
+    return skip;
+}
+
+static void qemu_savevm_state_full(QEMUFile *f)
+{
+    SaveStateEntry *se;
 
     QTAILQ_FOREACH(se, &savevm_handlers, entry) {
         int len;
 
-        if (se->save_live_state == NULL)
+        if (se->save_state == NULL && se->vmsd == NULL) {
             continue;
+        }
 
         /* Section type */
-        qemu_put_byte(f, QEMU_VM_SECTION_START);
+        qemu_put_byte(f, QEMU_VM_SECTION_FULL);
         qemu_put_be32(f, se->section_id);
 
         /* ID string */
@@ -1634,9 +1673,29 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
         qemu_put_be32(f, se->instance_id);
         qemu_put_be32(f, se->version_id);
 
-        se->save_live_state(mon, f, QEMU_VM_SECTION_START, se->opaque);
+        vmstate_save(f, se);
+    }
+
+    qemu_put_byte(f, QEMU_VM_EOF);
+}
+
+int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
+                            int shared)
+{
+    SaveStateEntry *se;
+
+    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
+        if (se->set_params == NULL) {
+            continue;
+        }
+        se->set_params(blk_enable, shared, se->opaque);
     }
 
+    qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
+    qemu_put_be32(f, QEMU_VM_FILE_VERSION);
+
+    qemu_savevm_state_live(mon, f, QEMU_VM_SECTION_START, 0, 0);
+
     if (qemu_file_has_error(f)) {
         qemu_savevm_state_cancel(mon, f);
         return -EIO;
@@ -1647,29 +1706,16 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
 
 int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
 {
-    SaveStateEntry *se;
     int ret = 1;
 
-    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
-        if (se->save_live_state == NULL)
-            continue;
-
-        /* Section type */
-        qemu_put_byte(f, QEMU_VM_SECTION_PART);
-        qemu_put_be32(f, se->section_id);
-
-        ret = se->save_live_state(mon, f, QEMU_VM_SECTION_PART, se->opaque);
-        if (!ret) {
-            /* Do not proceed to the next vmstate before this one reported
-               completion of the current stage. This serializes the migration
-               and reduces the probability that a faster changing state is
-               synchronized over and over again. */
-            break;
-        }
-    }
-
-    if (ret)
+    /* Do not proceed to the next vmstate before this one reported
+       completion of the current stage. This serializes the migration
+       and reduces the probability that a faster changing state is
+       synchronized over and over again. */
+    ret = qemu_savevm_state_live(mon, f, QEMU_VM_SECTION_PART, 1, 1);
+    if (!ret) {
         return 1;
+    }
 
     if (qemu_file_has_error(f)) {
         qemu_savevm_state_cancel(mon, f);
@@ -1681,46 +1727,41 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
 
 int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
 {
-    SaveStateEntry *se;
-
     cpu_synchronize_all_states();
 
-    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
-        if (se->save_live_state == NULL)
-            continue;
-
-        /* Section type */
-        qemu_put_byte(f, QEMU_VM_SECTION_END);
-        qemu_put_be32(f, se->section_id);
+    qemu_savevm_state_live(mon, f, QEMU_VM_SECTION_END, 1, 0);
+    qemu_savevm_state_full(f);
 
-        se->save_live_state(mon, f, QEMU_VM_SECTION_END, se->opaque);
+    if (qemu_file_has_error(f)) {
+        return -EIO;
     }
 
-    QTAILQ_FOREACH(se, &savevm_handlers, entry) {
-        int len;
+    return 0;
+}
 
-	if (se->save_state == NULL && se->vmsd == NULL)
-	    continue;
+int qemu_savevm_trans_begin(Monitor *mon, QEMUFile *f, int init)
+{
+    int ret;
 
-        /* Section type */
-        qemu_put_byte(f, QEMU_VM_SECTION_FULL);
-        qemu_put_be32(f, se->section_id);
+    ret = qemu_savevm_state_live(mon, f, QEMU_VM_SECTION_START, !init, 0);
 
-        /* ID string */
-        len = strlen(se->idstr);
-        qemu_put_byte(f, len);
-        qemu_put_buffer(f, (uint8_t *)se->idstr, len);
+    if (qemu_file_has_error(f)) {
+        return -EIO;
+    }
 
-        qemu_put_be32(f, se->instance_id);
-        qemu_put_be32(f, se->version_id);
+    return ret;
+}
 
-        vmstate_save(f, se);
-    }
+int qemu_savevm_trans_complete(Monitor *mon, QEMUFile *f)
+{
+    cpu_synchronize_all_states();
 
-    qemu_put_byte(f, QEMU_VM_EOF);
+    qemu_savevm_state_live(mon, f, QEMU_VM_SECTION_PART, 1, 0);
+    qemu_savevm_state_full(f);
 
-    if (qemu_file_has_error(f))
+    if (qemu_file_has_error(f)) {
         return -EIO;
+    }
 
     return 0;
 }
diff --git a/sysemu.h b/sysemu.h
index c86b4e8..6579714 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -81,6 +81,8 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
 int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f);
 int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f);
 void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f);
+int qemu_savevm_trans_begin(Monitor *mon, QEMUFile *f, int init);
+int qemu_savevm_trans_complete(Monitor *mon, QEMUFile *f);
 int qemu_loadvm_state(QEMUFile *f, int skip_header);
 
 /* SLIRP */
