[qemu/f19] backport migration cleanup (bz #962954)

Alon Levy alon at fedoraproject.org
Thu May 23 02:21:48 UTC 2013


commit 408bdb5e745ce72aa7c91ba9980787359cfbb844
Author: Alon Levy <alevy at redhat.com>
Date:   Wed May 22 21:48:57 2013 -0400

    backport migration cleanup (bz #962954)

 0200-ui-vnc-tls.c-fix-gnutls-warning.patch         |   45 +++
 ...change-initial-value-of-expected_downtime.patch |   31 +++
 ...alculate-end-time-after-we-have-sent-the-.patch |   37 +++
 ...on-t-account-sleep-time-for-calculating-b.patch |   54 ++++
 0204-migration-calculate-expected_downtime.patch   |   63 +++++
 0205-migration-simplify-while-loop.patch           |   50 ++++
 ...-migration-always-use-vm_stop_force_state.patch |   52 ++++
 ...ove-more-error-handling-to-migrate_fd_cle.patch |   69 +++++
 ...ush-qemu_savevm_state_cancel-out-of-qemu_.patch |   72 +++++
 ...tion-remove-useless-calls-to-blk_mig_clea.patch |  106 ++++++++
 ...ass-errno-from-qemu_fflush-via-f-last_err.patch |   87 ++++++
 ...se-qemu_file_set_error-to-pass-error-code.patch |  145 ++++++++++
 ...emporarily-expose-qemu_file_set_error-and.patch |   71 +++++
 ...lush-all-data-to-fd-when-buffered_flush-i.patch |   32 +++
 0214-migration-use-qemu_file_set_error.patch       |   82 ++++++
 0215-migration-simplify-error-handling.patch       |  142 ++++++++++
 ...ation-do-not-nest-flushing-of-device-data.patch |  154 +++++++++++
 ...igration-add-migrate_set_state-tracepoint.patch |   83 ++++++
 ...repare-to-access-s-state-outside-critical.patch |  128 +++++++++
 ...leanup-migration-including-thread-in-the-.patch |  131 +++++++++
 ...tion-remove-variables-that-are-never-read.patch |   72 +++++
 ...tion-small-preparatory-changes-for-lockin.patch |   91 +++++++
 ...tion-document-usage-of-state-across-threa.patch |   78 ++++++
 0223-block-migration-add-lock.patch                |  281 ++++++++++++++++++++
 ...-migration-reorder-SaveVMHandlers-members.patch |   42 +++
 ...un-pending-iterate-callbacks-out-of-big-l.patch |  268 +++++++++++++++++++
 ...ation-run-setup-callbacks-out-of-big-lock.patch |  119 +++++++++
 0227-migration-yay-buffering-is-gone.patch         |  178 +++++++++++++
 0228-Rename-buffered_-to-migration_.patch          |  116 ++++++++
 ...ake-qemu_fflush-and-qemu_file_set_error-p.patch |   60 +++++
 0230-migration-eliminate-last_round.patch          |   69 +++++
 0231-migration-detect-error-before-sleeping.patch  |   41 +++
 ...-remove-useless-qemu_file_get_error-check.patch |   35 +++
 ...ion-use-qemu_file_rate_limit-consistently.patch |   38 +++
 ...tion-merge-qemu_popen_cmd-with-qemu_popen.patch |  105 ++++++++
 ...qemu-file-fsync-a-writable-stdio-QEMUFile.patch |   47 ++++
 ...heck-exit-status-when-closing-a-pipe-QEMU.patch |   68 +++++
 0237-qemu-file-add-writable-socket-QEMUFile.patch  |  113 ++++++++
 ...-qemu-file-simplify-and-export-qemu_ftell.patch |   75 ++++++
 ...se-QEMUFile-for-migration-channel-lifetim.patch |  278 +++++++++++++++++++
 ...se-QEMUFile-for-writing-outgoing-migratio.patch |  254 ++++++++++++++++++
 ...ation-use-qemu_ftell-to-compute-bandwidth.patch |   47 ++++
 ...ration-small-changes-around-rate-limiting.patch |   80 ++++++
 ...-migration-move-rate-limiting-to-QEMUFile.patch |  272 +++++++++++++++++++
 ...ove-contents-of-migration_close-to-migrat.patch |   54 ++++
 0245-migration-eliminate-s-migration_file.patch    |  198 ++++++++++++++
 0246-migration-inline-migrate_fd_close.patch       |   50 ++++
 qemu.spec                                          |  103 +++++++-
 48 files changed, 4865 insertions(+), 1 deletions(-)
---
diff --git a/0200-ui-vnc-tls.c-fix-gnutls-warning.patch b/0200-ui-vnc-tls.c-fix-gnutls-warning.patch
new file mode 100644
index 0000000..54c034e
--- /dev/null
+++ b/0200-ui-vnc-tls.c-fix-gnutls-warning.patch
@@ -0,0 +1,45 @@
+From ad2bca6903af3d02737b893679396343cd598a3e Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Wed, 22 May 2013 19:22:26 -0400
+Subject: [PATCH 200/246] ui/vnc-tls.c: fix gnutls warning
+
+---
+ ui/vnc-tls.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c
+index 5629263..2d01982 100644
+--- a/ui/vnc-tls.c
++++ b/ui/vnc-tls.c
+@@ -99,9 +99,13 @@ static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
+ }
+ 
+ 
+-static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
++static gnutls_anon_server_credentials_t vnc_tls_initialize_anon_cred(void)
+ {
++#if GNUTLS_VERSION_MAJOR < 3
+     gnutls_anon_server_credentials anon_cred;
++#else
++    gnutls_anon_server_credentials_t anon_cred;
++#endif
+     int ret;
+ 
+     if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
+@@ -382,7 +386,12 @@ int vnc_tls_client_setup(struct VncState *vs,
+             }
+ 
+         } else {
+-            gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
++#if GNUTLS_VERSION_MAJOR < 2
++            gnutls_anon_server_credentials
++#else
++            gnutls_anon_server_credentials_t
++#endif
++               anon_cred = vnc_tls_initialize_anon_cred();
+             if (!anon_cred) {
+                 gnutls_deinit(vs->tls.session);
+                 vs->tls.session = NULL;
+-- 
+1.8.2.1
+
diff --git a/0201-migration-change-initial-value-of-expected_downtime.patch b/0201-migration-change-initial-value-of-expected_downtime.patch
new file mode 100644
index 0000000..d1873df
--- /dev/null
+++ b/0201-migration-change-initial-value-of-expected_downtime.patch
@@ -0,0 +1,31 @@
+From c30be405e8d7344268900de953df863667950217 Mon Sep 17 00:00:00 2001
+From: Juan Quintela <quintela at redhat.com>
+Date: Fri, 1 Feb 2013 11:12:26 +0100
+Subject: [PATCH 201/246] migration: change initial value of expected_downtime
+
+0 is a very bad initial value, what we are trying to get is
+max_downtime, so that is a much better estimation.
+
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+---
+ migration.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/migration.c b/migration.c
+index 98c7696..3584a24 100644
+--- a/migration.c
++++ b/migration.c
+@@ -774,6 +774,8 @@ void migrate_fd_connect(MigrationState *s)
+     s->buffer = NULL;
+     s->buffer_size = 0;
+     s->buffer_capacity = 0;
++    /* This is a best 1st approximation. ns to ms */
++    s->expected_downtime = max_downtime/1000000;
+ 
+     s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
+     s->complete = false;
+-- 
+1.8.2.1
+
diff --git a/0202-migration-calculate-end-time-after-we-have-sent-the-.patch b/0202-migration-calculate-end-time-after-we-have-sent-the-.patch
new file mode 100644
index 0000000..9975359
--- /dev/null
+++ b/0202-migration-calculate-end-time-after-we-have-sent-the-.patch
@@ -0,0 +1,37 @@
+From 306e49f278d465051e83253022252b1c69737eb1 Mon Sep 17 00:00:00 2001
+From: Juan Quintela <quintela at redhat.com>
+Date: Fri, 1 Feb 2013 12:39:08 +0100
+Subject: [PATCH 202/246] migration: calculate end time after we have sent the
+ data
+
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+---
+ migration.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/migration.c b/migration.c
+index 3584a24..0026f08 100644
+--- a/migration.c
++++ b/migration.c
+@@ -673,7 +673,7 @@ static void *buffered_file_thread(void *opaque)
+     qemu_mutex_unlock_iothread();
+ 
+     while (true) {
+-        int64_t current_time = qemu_get_clock_ms(rt_clock);
++        int64_t current_time;
+         uint64_t pending_size;
+ 
+         qemu_mutex_lock_iothread();
+@@ -727,6 +727,7 @@ static void *buffered_file_thread(void *opaque)
+             }
+         }
+         qemu_mutex_unlock_iothread();
++        current_time = qemu_get_clock_ms(rt_clock);
+         if (current_time >= initial_time + BUFFER_DELAY) {
+             uint64_t transferred_bytes = s->bytes_xfer;
+             uint64_t time_spent = current_time - initial_time;
+-- 
+1.8.2.1
+
diff --git a/0203-migration-don-t-account-sleep-time-for-calculating-b.patch b/0203-migration-don-t-account-sleep-time-for-calculating-b.patch
new file mode 100644
index 0000000..e5d20d0
--- /dev/null
+++ b/0203-migration-don-t-account-sleep-time-for-calculating-b.patch
@@ -0,0 +1,54 @@
+From abda6f8a1cd72a04737ebd9e814a8eb427783a21 Mon Sep 17 00:00:00 2001
+From: Juan Quintela <quintela at redhat.com>
+Date: Fri, 1 Feb 2013 12:41:38 +0100
+Subject: [PATCH 203/246] migration: don't account sleep time for calculating
+ bandwidth
+
+While we are sleeping we are not sending, so we should not use that
+time to estimate our bandwidth.
+
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+---
+ migration.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/migration.c b/migration.c
+index 0026f08..ebfbbde 100644
+--- a/migration.c
++++ b/migration.c
+@@ -658,6 +658,7 @@ static void *buffered_file_thread(void *opaque)
+ {
+     MigrationState *s = opaque;
+     int64_t initial_time = qemu_get_clock_ms(rt_clock);
++    int64_t sleep_time = 0;
+     int64_t max_size = 0;
+     bool last_round = false;
+     int ret;
+@@ -730,7 +731,7 @@ static void *buffered_file_thread(void *opaque)
+         current_time = qemu_get_clock_ms(rt_clock);
+         if (current_time >= initial_time + BUFFER_DELAY) {
+             uint64_t transferred_bytes = s->bytes_xfer;
+-            uint64_t time_spent = current_time - initial_time;
++            uint64_t time_spent = current_time - initial_time - sleep_time;
+             double bandwidth = transferred_bytes / time_spent;
+             max_size = bandwidth * migrate_max_downtime() / 1000000;
+ 
+@@ -739,11 +740,13 @@ static void *buffered_file_thread(void *opaque)
+                     transferred_bytes, time_spent, bandwidth, max_size);
+ 
+             s->bytes_xfer = 0;
++            sleep_time = 0;
+             initial_time = current_time;
+         }
+         if (!last_round && (s->bytes_xfer >= s->xfer_limit)) {
+             /* usleep expects microseconds */
+             g_usleep((initial_time + BUFFER_DELAY - current_time)*1000);
++            sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+         ret = buffered_flush(s);
+         if (ret < 0) {
+-- 
+1.8.2.1
+
diff --git a/0204-migration-calculate-expected_downtime.patch b/0204-migration-calculate-expected_downtime.patch
new file mode 100644
index 0000000..a365a37
--- /dev/null
+++ b/0204-migration-calculate-expected_downtime.patch
@@ -0,0 +1,63 @@
+From 5b6a7544893648bc29dee219a634bfa7d2ca857a Mon Sep 17 00:00:00 2001
+From: Juan Quintela <quintela at redhat.com>
+Date: Fri, 1 Feb 2013 13:22:37 +0100
+Subject: [PATCH 204/246] migration: calculate expected_downtime
+
+We removed the calculation in commit e4ed1541ac9413eac494a03532e34beaf8a7d1c5
+
+Now we add it back.  We need to create dirty_bytes_rate because we
+can't include cpu-all.h from migration.c, and there is no other way to
+include TARGET_PAGE_SIZE.
+
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+---
+ arch_init.c                   | 1 +
+ include/migration/migration.h | 1 +
+ migration.c                   | 5 +++++
+ 3 files changed, 7 insertions(+)
+
+diff --git a/arch_init.c b/arch_init.c
+index 8da868b..8daeafa 100644
+--- a/arch_init.c
++++ b/arch_init.c
+@@ -414,6 +414,7 @@ static void migration_bitmap_sync(void)
+     if (end_time > start_time + 1000) {
+         s->dirty_pages_rate = num_dirty_pages_period * 1000
+             / (end_time - start_time);
++        s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
+         start_time = end_time;
+         num_dirty_pages_period = 0;
+     }
+diff --git a/include/migration/migration.h b/include/migration/migration.h
+index a8c9639..d121409 100644
+--- a/include/migration/migration.h
++++ b/include/migration/migration.h
+@@ -51,6 +51,7 @@ struct MigrationState
+     int64_t downtime;
+     int64_t expected_downtime;
+     int64_t dirty_pages_rate;
++    int64_t dirty_bytes_rate;
+     bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+     int64_t xbzrle_cache_size;
+     bool complete;
+diff --git a/migration.c b/migration.c
+index ebfbbde..59e479d 100644
+--- a/migration.c
++++ b/migration.c
+@@ -738,6 +738,11 @@ static void *buffered_file_thread(void *opaque)
+             DPRINTF("transferred %" PRIu64 " time_spent %" PRIu64
+                     " bandwidth %g max_size %" PRId64 "\n",
+                     transferred_bytes, time_spent, bandwidth, max_size);
++            /* if we haven't sent anything, we don't want to recalculate
++               10000 is a small enough number for our purposes */
++            if (s->dirty_bytes_rate && transferred_bytes > 10000) {
++                s->expected_downtime = s->dirty_bytes_rate / bandwidth;
++            }
+ 
+             s->bytes_xfer = 0;
+             sleep_time = 0;
+-- 
+1.8.2.1
+
diff --git a/0205-migration-simplify-while-loop.patch b/0205-migration-simplify-while-loop.patch
new file mode 100644
index 0000000..a1a895c
--- /dev/null
+++ b/0205-migration-simplify-while-loop.patch
@@ -0,0 +1,50 @@
+From 9c9566a75a88ff2db9d747ab24cbb7a3d71c4d8b Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:07 +0100
+Subject: [PATCH 205/246] migration: simplify while loop
+
+Unify the goto around the loop, with the exit condition at the end of it.
+Both can be expressed as "while (ret >= 0)".
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 59e479d..71c0eec 100644
+--- a/migration.c
++++ b/migration.c
+@@ -666,14 +666,9 @@ static void *buffered_file_thread(void *opaque)
+     qemu_mutex_lock_iothread();
+     DPRINTF("beginning savevm\n");
+     ret = qemu_savevm_state_begin(s->file, &s->params);
+-    if (ret < 0) {
+-        DPRINTF("failed, %d\n", ret);
+-        qemu_mutex_unlock_iothread();
+-        goto out;
+-    }
+     qemu_mutex_unlock_iothread();
+ 
+-    while (true) {
++    while (ret >= 0) {
+         int64_t current_time;
+         uint64_t pending_size;
+ 
+@@ -754,12 +749,8 @@ static void *buffered_file_thread(void *opaque)
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+         ret = buffered_flush(s);
+-        if (ret < 0) {
+-            break;
+-        }
+     }
+ 
+-out:
+     if (ret < 0) {
+         migrate_fd_error(s);
+     }
+-- 
+1.8.2.1
+
diff --git a/0206-migration-always-use-vm_stop_force_state.patch b/0206-migration-always-use-vm_stop_force_state.patch
new file mode 100644
index 0000000..048951e
--- /dev/null
+++ b/0206-migration-always-use-vm_stop_force_state.patch
@@ -0,0 +1,52 @@
+From 9a914ea26d69de42b55e70c6d330eeec0cb7ccfe Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:08 +0100
+Subject: [PATCH 206/246] migration: always use vm_stop_force_state
+
+vm_stop_force_state does:
+
+    if (runstate_is_running()) {
+        vm_stop(state);
+    } else {
+        runstate_set(state);
+    }
+
+migration.c does:
+
+    if (runstate_is_running()) {
+        vm_stop(state);
+    } else {
+        vm_stop_force_state(state);
+    }
+
+The code run is the same even if we always use vm_stop_force_state in
+migration.c.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 71c0eec..d601641 100644
+--- a/migration.c
++++ b/migration.c
+@@ -699,11 +699,7 @@ static void *buffered_file_thread(void *opaque)
+                 DPRINTF("done iterating\n");
+                 start_time = qemu_get_clock_ms(rt_clock);
+                 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+-                if (old_vm_running) {
+-                    vm_stop(RUN_STATE_FINISH_MIGRATE);
+-                } else {
+-                    vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+-                }
++                vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+                 ret = qemu_savevm_state_complete(s->file);
+                 if (ret < 0) {
+                     qemu_mutex_unlock_iothread();
+-- 
+1.8.2.1
+
diff --git a/0207-migration-move-more-error-handling-to-migrate_fd_cle.patch b/0207-migration-move-more-error-handling-to-migrate_fd_cle.patch
new file mode 100644
index 0000000..fc4c0f2
--- /dev/null
+++ b/0207-migration-move-more-error-handling-to-migrate_fd_cle.patch
@@ -0,0 +1,69 @@
+From fa25441af918e5e19c181cd5aac537a6bb8799ed Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:09 +0100
+Subject: [PATCH 207/246] migration: move more error handling to
+ migrate_fd_cleanup
+
+The next patch will add more cases where qemu_savevm_state_cancel
+needs to be called; prepare for that already, the function can be
+called twice with no ill effect.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 16 ++++++++++------
+ 1 file changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index d601641..739e38c 100644
+--- a/migration.c
++++ b/migration.c
+@@ -260,7 +260,7 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+ 
+ /* shared migration helpers */
+ 
+-static int migrate_fd_cleanup(MigrationState *s)
++static void migrate_fd_cleanup(MigrationState *s)
+ {
+     int ret = 0;
+ 
+@@ -271,7 +271,13 @@ static int migrate_fd_cleanup(MigrationState *s)
+     }
+ 
+     assert(s->fd == -1);
+-    return ret;
++    if (ret < 0 && s->state == MIG_STATE_ACTIVE) {
++        s->state = MIG_STATE_ERROR;
++    }
++
++    if (s->state != MIG_STATE_ACTIVE) {
++        qemu_savevm_state_cancel();
++    }
+ }
+ 
+ void migrate_fd_error(MigrationState *s)
+@@ -285,9 +291,8 @@ void migrate_fd_error(MigrationState *s)
+ static void migrate_fd_completed(MigrationState *s)
+ {
+     DPRINTF("setting completed state\n");
+-    if (migrate_fd_cleanup(s) < 0) {
+-        s->state = MIG_STATE_ERROR;
+-    } else {
++    migrate_fd_cleanup(s);
++    if (s->state == MIG_STATE_ACTIVE) {
+         s->state = MIG_STATE_COMPLETED;
+         runstate_set(RUN_STATE_POSTMIGRATE);
+     }
+@@ -322,7 +327,6 @@ static void migrate_fd_cancel(MigrationState *s)
+ 
+     s->state = MIG_STATE_CANCELLED;
+     notifier_list_notify(&migration_state_notifiers, s);
+-    qemu_savevm_state_cancel();
+ 
+     migrate_fd_cleanup(s);
+ }
+-- 
+1.8.2.1
+
diff --git a/0208-migration-push-qemu_savevm_state_cancel-out-of-qemu_.patch b/0208-migration-push-qemu_savevm_state_cancel-out-of-qemu_.patch
new file mode 100644
index 0000000..f6e6063
--- /dev/null
+++ b/0208-migration-push-qemu_savevm_state_cancel-out-of-qemu_.patch
@@ -0,0 +1,72 @@
+From af258e54dc3654dbe326dcdf022b277e8872072a Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:10 +0100
+Subject: [PATCH 208/246] migration: push qemu_savevm_state_cancel out of
+ qemu_savevm_state_*
+
+This is useful, because it lets us keep the cancellation callbacks
+inside the big lock while pushing the others out.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ savevm.c | 15 ++++-----------
+ 1 file changed, 4 insertions(+), 11 deletions(-)
+
+diff --git a/savevm.c b/savevm.c
+index a8a53ef..4302903 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -1621,17 +1621,11 @@ int qemu_savevm_state_begin(QEMUFile *f,
+ 
+         ret = se->ops->save_live_setup(f, se->opaque);
+         if (ret < 0) {
+-            qemu_savevm_state_cancel();
+             return ret;
+         }
+     }
+     ret = qemu_file_get_error(f);
+-    if (ret != 0) {
+-        qemu_savevm_state_cancel();
+-    }
+-
+     return ret;
+-
+ }
+ 
+ /*
+@@ -1677,9 +1671,6 @@ int qemu_savevm_state_iterate(QEMUFile *f)
+         return ret;
+     }
+     ret = qemu_file_get_error(f);
+-    if (ret != 0) {
+-        qemu_savevm_state_cancel();
+-    }
+     return ret;
+ }
+ 
+@@ -1778,8 +1769,7 @@ static int qemu_savevm_state(QEMUFile *f)
+     };
+ 
+     if (qemu_savevm_state_blocked(NULL)) {
+-        ret = -EINVAL;
+-        goto out;
++        return -EINVAL;
+     }
+ 
+     ret = qemu_savevm_state_begin(f, &params);
+@@ -1798,6 +1788,9 @@ out:
+     if (ret == 0) {
+         ret = qemu_file_get_error(f);
+     }
++    if (ret != 0) {
++        qemu_savevm_state_cancel();
++    }
+ 
+     return ret;
+ }
+-- 
+1.8.2.1
+
diff --git a/0209-block-migration-remove-useless-calls-to-blk_mig_clea.patch b/0209-block-migration-remove-useless-calls-to-blk_mig_clea.patch
new file mode 100644
index 0000000..0ab5021
--- /dev/null
+++ b/0209-block-migration-remove-useless-calls-to-blk_mig_clea.patch
@@ -0,0 +1,106 @@
+From d00dba1bf360ad47957774923dfd2c07ee9cdec0 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:11 +0100
+Subject: [PATCH 209/246] block-migration: remove useless calls to
+ blk_mig_cleanup
+
+Now that the cancel callback is called consistently for all errors,
+we can avoid doing its work in the other callbacks.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ block-migration.c | 26 ++++++++------------------
+ 1 file changed, 8 insertions(+), 18 deletions(-)
+
+diff --git a/block-migration.c b/block-migration.c
+index 43ab202..e6c917d 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -524,16 +524,10 @@ static int block_save_setup(QEMUFile *f, void *opaque)
+     set_dirty_tracking(1);
+ 
+     ret = flush_blks(f);
+-    if (ret) {
+-        blk_mig_cleanup();
+-        return ret;
+-    }
+-
+     blk_mig_reset_dirty_cursor();
+-
+     qemu_put_be64(f, BLK_MIG_FLAG_EOS);
+ 
+-    return 0;
++    return ret;
+ }
+ 
+ static int block_save_iterate(QEMUFile *f, void *opaque)
+@@ -546,7 +540,6 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+ 
+     ret = flush_blks(f);
+     if (ret) {
+-        blk_mig_cleanup();
+         return ret;
+     }
+ 
+@@ -564,20 +557,18 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+             }
+         } else {
+             ret = blk_mig_save_dirty_block(f, 1);
++            if (ret < 0) {
++                return ret;
++            }
+             if (ret != 0) {
+                 /* no more dirty blocks */
+                 break;
+             }
+         }
+     }
+-    if (ret < 0) {
+-        blk_mig_cleanup();
+-        return ret;
+-    }
+ 
+     ret = flush_blks(f);
+     if (ret) {
+-        blk_mig_cleanup();
+         return ret;
+     }
+ 
+@@ -595,7 +586,6 @@ static int block_save_complete(QEMUFile *f, void *opaque)
+ 
+     ret = flush_blks(f);
+     if (ret) {
+-        blk_mig_cleanup();
+         return ret;
+     }
+ 
+@@ -607,12 +597,11 @@ static int block_save_complete(QEMUFile *f, void *opaque)
+ 
+     do {
+         ret = blk_mig_save_dirty_block(f, 0);
++        if (ret < 0) {
++            return ret;
++        }
+     } while (ret == 0);
+ 
+-    blk_mig_cleanup();
+-    if (ret < 0) {
+-        return ret;
+-    }
+     /* report completion */
+     qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
+ 
+@@ -620,6 +609,7 @@ static int block_save_complete(QEMUFile *f, void *opaque)
+ 
+     qemu_put_be64(f, BLK_MIG_FLAG_EOS);
+ 
++    blk_mig_cleanup();
+     return 0;
+ }
+ 
+-- 
+1.8.2.1
+
diff --git a/0210-qemu-file-pass-errno-from-qemu_fflush-via-f-last_err.patch b/0210-qemu-file-pass-errno-from-qemu_fflush-via-f-last_err.patch
new file mode 100644
index 0000000..a666d8c
--- /dev/null
+++ b/0210-qemu-file-pass-errno-from-qemu_fflush-via-f-last_err.patch
@@ -0,0 +1,87 @@
+From 64774c81205e77bd55d69b6a116f0ef5f61929ba Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:12 +0100
+Subject: [PATCH 210/246] qemu-file: pass errno from qemu_fflush via
+ f->last_error
+
+This is done by almost all callers of qemu_fflush, move the code
+directly to qemu_fflush.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ savevm.c | 25 ++++++++++++-------------
+ 1 file changed, 12 insertions(+), 13 deletions(-)
+
+diff --git a/savevm.c b/savevm.c
+index 4302903..a681177 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -453,13 +453,13 @@ static void qemu_file_set_error(QEMUFile *f, int ret)
+ /** Flushes QEMUFile buffer
+  *
+  */
+-static int qemu_fflush(QEMUFile *f)
++static void qemu_fflush(QEMUFile *f)
+ {
+     int ret = 0;
+ 
+-    if (!f->ops->put_buffer)
+-        return 0;
+-
++    if (!f->ops->put_buffer) {
++        return;
++    }
+     if (f->is_write && f->buf_index > 0) {
+         ret = f->ops->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
+         if (ret >= 0) {
+@@ -467,7 +467,9 @@ static int qemu_fflush(QEMUFile *f)
+         }
+         f->buf_index = 0;
+     }
+-    return ret;
++    if (ret < 0) {
++        qemu_file_set_error(f, ret);
++    }
+ }
+ 
+ static void qemu_fill_buffer(QEMUFile *f)
+@@ -518,7 +520,8 @@ int qemu_get_fd(QEMUFile *f)
+ int qemu_fclose(QEMUFile *f)
+ {
+     int ret;
+-    ret = qemu_fflush(f);
++    qemu_fflush(f);
++    ret = qemu_file_get_error(f);
+ 
+     if (f->ops->close) {
+         int ret2 = f->ops->close(f->opaque);
+@@ -560,9 +563,8 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
+         buf += l;
+         size -= l;
+         if (f->buf_index >= IO_BUF_SIZE) {
+-            int ret = qemu_fflush(f);
+-            if (ret < 0) {
+-                qemu_file_set_error(f, ret);
++            qemu_fflush(f);
++            if (qemu_file_get_error(f)) {
+                 break;
+             }
+         }
+@@ -584,10 +586,7 @@ void qemu_put_byte(QEMUFile *f, int v)
+     f->buf[f->buf_index++] = v;
+     f->is_write = 1;
+     if (f->buf_index >= IO_BUF_SIZE) {
+-        int ret = qemu_fflush(f);
+-        if (ret < 0) {
+-            qemu_file_set_error(f, ret);
+-        }
++        qemu_fflush(f);
+     }
+ }
+ 
+-- 
+1.8.2.1
+
diff --git a/0211-migration-use-qemu_file_set_error-to-pass-error-code.patch b/0211-migration-use-qemu_file_set_error-to-pass-error-code.patch
new file mode 100644
index 0000000..00ea4b2
--- /dev/null
+++ b/0211-migration-use-qemu_file_set_error-to-pass-error-code.patch
@@ -0,0 +1,145 @@
+From 8b3e57abc68b37922399034c92dd4a10890c2c0e Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:13 +0100
+Subject: [PATCH 211/246] migration: use qemu_file_set_error to pass error
+ codes back to qemu_savevm_state
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/sysemu/sysemu.h |  6 +++---
+ savevm.c                | 44 ++++++++++++++++++--------------------------
+ 2 files changed, 21 insertions(+), 29 deletions(-)
+
+diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
+index 1d9599e..28a9221 100644
+--- a/include/sysemu/sysemu.h
++++ b/include/sysemu/sysemu.h
+@@ -73,10 +73,10 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict);
+ void qemu_announce_self(void);
+ 
+ bool qemu_savevm_state_blocked(Error **errp);
+-int qemu_savevm_state_begin(QEMUFile *f,
+-                            const MigrationParams *params);
++void qemu_savevm_state_begin(QEMUFile *f,
++                             const MigrationParams *params);
+ int qemu_savevm_state_iterate(QEMUFile *f);
+-int qemu_savevm_state_complete(QEMUFile *f);
++void qemu_savevm_state_complete(QEMUFile *f);
+ void qemu_savevm_state_cancel(void);
+ uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size);
+ int qemu_loadvm_state(QEMUFile *f);
+diff --git a/savevm.c b/savevm.c
+index a681177..a1690b4 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -1579,8 +1579,8 @@ bool qemu_savevm_state_blocked(Error **errp)
+     return false;
+ }
+ 
+-int qemu_savevm_state_begin(QEMUFile *f,
+-                            const MigrationParams *params)
++void qemu_savevm_state_begin(QEMUFile *f,
++                             const MigrationParams *params)
+ {
+     SaveStateEntry *se;
+     int ret;
+@@ -1620,11 +1620,10 @@ int qemu_savevm_state_begin(QEMUFile *f,
+ 
+         ret = se->ops->save_live_setup(f, se->opaque);
+         if (ret < 0) {
+-            return ret;
++            qemu_file_set_error(f, ret);
++            break;
+         }
+     }
+-    ret = qemu_file_get_error(f);
+-    return ret;
+ }
+ 
+ /*
+@@ -1658,6 +1657,9 @@ int qemu_savevm_state_iterate(QEMUFile *f)
+         ret = se->ops->save_live_iterate(f, se->opaque);
+         trace_savevm_section_end(se->section_id);
+ 
++        if (ret < 0) {
++            qemu_file_set_error(f, ret);
++        }
+         if (ret <= 0) {
+             /* Do not proceed to the next vmstate before this one reported
+                completion of the current stage. This serializes the migration
+@@ -1666,14 +1668,10 @@ int qemu_savevm_state_iterate(QEMUFile *f)
+             break;
+         }
+     }
+-    if (ret != 0) {
+-        return ret;
+-    }
+-    ret = qemu_file_get_error(f);
+     return ret;
+ }
+ 
+-int qemu_savevm_state_complete(QEMUFile *f)
++void qemu_savevm_state_complete(QEMUFile *f)
+ {
+     SaveStateEntry *se;
+     int ret;
+@@ -1697,7 +1695,8 @@ int qemu_savevm_state_complete(QEMUFile *f)
+         ret = se->ops->save_live_complete(f, se->opaque);
+         trace_savevm_section_end(se->section_id);
+         if (ret < 0) {
+-            return ret;
++            qemu_file_set_error(f, ret);
++            return;
+         }
+     }
+ 
+@@ -1725,8 +1724,6 @@ int qemu_savevm_state_complete(QEMUFile *f)
+     }
+ 
+     qemu_put_byte(f, QEMU_VM_EOF);
+-
+-    return qemu_file_get_error(f);
+ }
+ 
+ uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size)
+@@ -1771,26 +1768,21 @@ static int qemu_savevm_state(QEMUFile *f)
+         return -EINVAL;
+     }
+ 
+-    ret = qemu_savevm_state_begin(f, &params);
+-    if (ret < 0)
+-        goto out;
+-
+-    do {
+-        ret = qemu_savevm_state_iterate(f);
+-        if (ret < 0)
+-            goto out;
+-    } while (ret == 0);
+-
+-    ret = qemu_savevm_state_complete(f);
++    qemu_savevm_state_begin(f, &params);
++    while (qemu_file_get_error(f) == 0) {
++        if (qemu_savevm_state_iterate(f) > 0) {
++            break;
++        }
++    }
+ 
+-out:
++    ret = qemu_file_get_error(f);
+     if (ret == 0) {
++        qemu_savevm_state_complete(f);
+         ret = qemu_file_get_error(f);
+     }
+     if (ret != 0) {
+         qemu_savevm_state_cancel();
+     }
+-
+     return ret;
+ }
+ 
+-- 
+1.8.2.1
+
diff --git a/0212-qemu-file-temporarily-expose-qemu_file_set_error-and.patch b/0212-qemu-file-temporarily-expose-qemu_file_set_error-and.patch
new file mode 100644
index 0000000..6fcc69b
--- /dev/null
+++ b/0212-qemu-file-temporarily-expose-qemu_file_set_error-and.patch
@@ -0,0 +1,71 @@
+From 5d4b7aa9dee156a613086d343987220c99adddd9 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:14 +0100
+Subject: [PATCH 212/246] qemu-file: temporarily expose qemu_file_set_error and
+ qemu_fflush
+
+Right now, migration cannot entirely rely on QEMUFile's automatic
+drop of I/O after an error, because it does its "real" I/O outside
+the put_buffer callback.  To fix this until buffering is gone, expose
+qemu_file_set_error which we will use in buffered_flush.
+
+Similarly, buffered_flush is not a complete flush because some data may
+still reside in the QEMUFile's own buffer.  This somewhat complicates the
+process of closing the migration thread.  Again, when buffering is gone
+buffered_flush will disappear and calling qemu_fflush will not be needed;
+in the meanwhile, we expose the function for use in migration.c.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/qemu-file.h | 2 ++
+ savevm.c                      | 4 ++--
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
+index 46fc11d..5e0c287 100644
+--- a/include/migration/qemu-file.h
++++ b/include/migration/qemu-file.h
+@@ -82,6 +82,7 @@ QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+ int qemu_get_fd(QEMUFile *f);
+ int qemu_fclose(QEMUFile *f);
+ int64_t qemu_ftell(QEMUFile *f);
++void qemu_fflush(QEMUFile *f);
+ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
+ void qemu_put_byte(QEMUFile *f, int v);
+ 
+@@ -113,6 +114,7 @@ int qemu_file_rate_limit(QEMUFile *f);
+ int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
+ int64_t qemu_file_get_rate_limit(QEMUFile *f);
+ int qemu_file_get_error(QEMUFile *f);
++void qemu_file_set_error(QEMUFile *f, int ret);
+ 
+ static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
+ {
+diff --git a/savevm.c b/savevm.c
+index a1690b4..e10a045 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -443,7 +443,7 @@ int qemu_file_get_error(QEMUFile *f)
+     return f->last_error;
+ }
+ 
+-static void qemu_file_set_error(QEMUFile *f, int ret)
++void qemu_file_set_error(QEMUFile *f, int ret)
+ {
+     if (f->last_error == 0) {
+         f->last_error = ret;
+@@ -453,7 +453,7 @@ static void qemu_file_set_error(QEMUFile *f, int ret)
+ /** Flushes QEMUFile buffer
+  *
+  */
+-static void qemu_fflush(QEMUFile *f)
++void qemu_fflush(QEMUFile *f)
+ {
+     int ret = 0;
+ 
+-- 
+1.8.2.1
+
diff --git a/0213-migration-flush-all-data-to-fd-when-buffered_flush-i.patch b/0213-migration-flush-all-data-to-fd-when-buffered_flush-i.patch
new file mode 100644
index 0000000..8bb77b5
--- /dev/null
+++ b/0213-migration-flush-all-data-to-fd-when-buffered_flush-i.patch
@@ -0,0 +1,32 @@
+From 0c1da6466596bc25328f896161f06622899cce48 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:15 +0100
+Subject: [PATCH 213/246] migration: flush all data to fd when buffered_flush
+ is called
+
+Including data that resided in the QEMUFile's own buffer.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/migration.c b/migration.c
+index 739e38c..1027b40 100644
+--- a/migration.c
++++ b/migration.c
+@@ -525,6 +525,8 @@ static ssize_t buffered_flush(MigrationState *s)
+ 
+     DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size);
+ 
++    qemu_fflush(s->file);
++
+     while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) {
+         size_t to_send = MIN(s->buffer_size - offset, s->xfer_limit - s->bytes_xfer);
+         ret = migrate_fd_put_buffer(s, s->buffer + offset, to_send);
+-- 
+1.8.2.1
+
diff --git a/0214-migration-use-qemu_file_set_error.patch b/0214-migration-use-qemu_file_set_error.patch
new file mode 100644
index 0000000..bbdee36
--- /dev/null
+++ b/0214-migration-use-qemu_file_set_error.patch
@@ -0,0 +1,82 @@
+From a00d2c8014dbf2553c7bbd69a025f7e3992d25be Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:16 +0100
+Subject: [PATCH 214/246] migration: use qemu_file_set_error
+
+Remove the return value of buffered_flush, pass it via the error code
+of s->file.  Once this is done, the error can be retrieved simply
+via migrate_fd_close's call to qemu_fclose.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 22 ++++++----------------
+ 1 file changed, 6 insertions(+), 16 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 1027b40..da5f175 100644
+--- a/migration.c
++++ b/migration.c
+@@ -518,7 +518,7 @@ int64_t migrate_xbzrle_cache_size(void)
+ /* migration thread support */
+ 
+ 
+-static ssize_t buffered_flush(MigrationState *s)
++static void buffered_flush(MigrationState *s)
+ {
+     size_t offset = 0;
+     ssize_t ret = 0;
+@@ -545,9 +545,8 @@ static ssize_t buffered_flush(MigrationState *s)
+     s->buffer_size -= offset;
+ 
+     if (ret < 0) {
+-        return ret;
++        qemu_file_set_error(s->file, ret);
+     }
+-    return offset;
+ }
+ 
+ static int buffered_put_buffer(void *opaque, const uint8_t *buf,
+@@ -586,25 +585,15 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf,
+ static int buffered_close(void *opaque)
+ {
+     MigrationState *s = opaque;
+-    ssize_t ret = 0;
+-    int ret2;
+ 
+     DPRINTF("closing\n");
+ 
+     s->xfer_limit = INT_MAX;
+     while (!qemu_file_get_error(s->file) && s->buffer_size) {
+-        ret = buffered_flush(s);
+-        if (ret < 0) {
+-            break;
+-        }
+-    }
+-
+-    ret2 = migrate_fd_close(s);
+-    if (ret >= 0) {
+-        ret = ret2;
++        buffered_flush(s);
+     }
+     s->complete = true;
+-    return ret;
++    return migrate_fd_close(s);
+ }
+ 
+ static int buffered_get_fd(void *opaque)
+@@ -750,7 +739,8 @@ static void *buffered_file_thread(void *opaque)
+             g_usleep((initial_time + BUFFER_DELAY - current_time)*1000);
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+-        ret = buffered_flush(s);
++        buffered_flush(s);
++        ret = qemu_file_get_error(s->file);
+     }
+ 
+     if (ret < 0) {
+-- 
+1.8.2.1
+
diff --git a/0215-migration-simplify-error-handling.patch b/0215-migration-simplify-error-handling.patch
new file mode 100644
index 0000000..c00ca9c
--- /dev/null
+++ b/0215-migration-simplify-error-handling.patch
@@ -0,0 +1,142 @@
+From fd038161f3313522eb0faea2a58adcb3766e5efd Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:17 +0100
+Subject: [PATCH 215/246] migration: simplify error handling
+
+Always use qemu_file_get_error to detect errors, since that is how
+QEMUFile itself drops I/O after an error occurs.  There is no need
+to propagate and check return values all the time.
+
+Also remove the "complete" member, since we know that it is set (via
+migrate_fd_cleanup) only when the state changes.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/migration.h |  1 -
+ migration.c                   | 46 +++++++++++++------------------------------
+ 2 files changed, 14 insertions(+), 33 deletions(-)
+
+diff --git a/include/migration/migration.h b/include/migration/migration.h
+index d121409..3e680af 100644
+--- a/include/migration/migration.h
++++ b/include/migration/migration.h
+@@ -54,7 +54,6 @@ struct MigrationState
+     int64_t dirty_bytes_rate;
+     bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+     int64_t xbzrle_cache_size;
+-    bool complete;
+ };
+ 
+ void process_incoming_migration(QEMUFile *f);
+diff --git a/migration.c b/migration.c
+index da5f175..41a592c 100644
+--- a/migration.c
++++ b/migration.c
+@@ -525,6 +525,10 @@ static void buffered_flush(MigrationState *s)
+ 
+     DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size);
+ 
++    if (qemu_file_get_error(s->file)) {
++        s->buffer_size = 0;
++        return;
++    }
+     qemu_fflush(s->file);
+ 
+     while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) {
+@@ -592,7 +596,6 @@ static int buffered_close(void *opaque)
+     while (!qemu_file_get_error(s->file) && s->buffer_size) {
+         buffered_flush(s);
+     }
+-    s->complete = true;
+     return migrate_fd_close(s);
+ }
+ 
+@@ -656,37 +659,21 @@ static void *buffered_file_thread(void *opaque)
+     int64_t sleep_time = 0;
+     int64_t max_size = 0;
+     bool last_round = false;
+-    int ret;
+ 
+     qemu_mutex_lock_iothread();
+     DPRINTF("beginning savevm\n");
+-    ret = qemu_savevm_state_begin(s->file, &s->params);
+-    qemu_mutex_unlock_iothread();
++    qemu_savevm_state_begin(s->file, &s->params);
+ 
+-    while (ret >= 0) {
++    while (s->state == MIG_STATE_ACTIVE) {
+         int64_t current_time;
+         uint64_t pending_size;
+ 
+-        qemu_mutex_lock_iothread();
+-        if (s->state != MIG_STATE_ACTIVE) {
+-            DPRINTF("put_ready returning because of non-active state\n");
+-            qemu_mutex_unlock_iothread();
+-            break;
+-        }
+-        if (s->complete) {
+-            qemu_mutex_unlock_iothread();
+-            break;
+-        }
+         if (s->bytes_xfer < s->xfer_limit) {
+             DPRINTF("iterate\n");
+             pending_size = qemu_savevm_state_pending(s->file, max_size);
+             DPRINTF("pending size %lu max %lu\n", pending_size, max_size);
+             if (pending_size && pending_size >= max_size) {
+-                ret = qemu_savevm_state_iterate(s->file);
+-                if (ret < 0) {
+-                    qemu_mutex_unlock_iothread();
+-                    break;
+-                }
++                qemu_savevm_state_iterate(s->file);
+             } else {
+                 int old_vm_running = runstate_is_running();
+                 int64_t start_time, end_time;
+@@ -695,13 +682,8 @@ static void *buffered_file_thread(void *opaque)
+                 start_time = qemu_get_clock_ms(rt_clock);
+                 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+                 vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+-                ret = qemu_savevm_state_complete(s->file);
+-                if (ret < 0) {
+-                    qemu_mutex_unlock_iothread();
+-                    break;
+-                } else {
+-                    migrate_fd_completed(s);
+-                }
++                qemu_savevm_state_complete(s->file);
++                migrate_fd_completed(s);
+                 end_time = qemu_get_clock_ms(rt_clock);
+                 s->total_time = end_time - s->total_time;
+                 s->downtime = end_time - start_time;
+@@ -740,12 +722,13 @@ static void *buffered_file_thread(void *opaque)
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+         buffered_flush(s);
+-        ret = qemu_file_get_error(s->file);
++        qemu_mutex_lock_iothread();
++        if (qemu_file_get_error(s->file)) {
++            migrate_fd_error(s);
++        }
+     }
+ 
+-    if (ret < 0) {
+-        migrate_fd_error(s);
+-    }
++    qemu_mutex_unlock_iothread();
+     g_free(s->buffer);
+     return NULL;
+ }
+@@ -770,7 +753,6 @@ void migrate_fd_connect(MigrationState *s)
+     s->expected_downtime = max_downtime/1000000;
+ 
+     s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
+-    s->complete = false;
+ 
+     s->file = qemu_fopen_ops(s, &buffered_file_ops);
+ 
+-- 
+1.8.2.1
+
diff --git a/0216-migration-do-not-nest-flushing-of-device-data.patch b/0216-migration-do-not-nest-flushing-of-device-data.patch
new file mode 100644
index 0000000..dadb189
--- /dev/null
+++ b/0216-migration-do-not-nest-flushing-of-device-data.patch
@@ -0,0 +1,154 @@
+From 10a7d96875e75f249789c4e66578360740b6277f Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:18 +0100
+Subject: [PATCH 216/246] migration: do not nest flushing of device data
+
+Completion of migration is currently done with a "nested" loop that
+invokes buffered_flush: migrate_fd_completed is called by
+buffered_file_thread, which calls migrate_fd_cleanup, which calls
+buffered_close (via qemu_fclose), which flushes the buffer.
+
+Simplify this, by reusing the buffered_flush call of buffered_file_thread.
+Then if qemu_savevm_state_complete was called, and the buffer is empty
+(including the QEMUFile buffer, for which we need the previous patch), we
+are done.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 55 ++++++++++++++++++++++++-------------------------------
+ 1 file changed, 24 insertions(+), 31 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 41a592c..57fceb6d 100644
+--- a/migration.c
++++ b/migration.c
+@@ -262,41 +262,34 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+ 
+ static void migrate_fd_cleanup(MigrationState *s)
+ {
+-    int ret = 0;
+-
+     if (s->file) {
+         DPRINTF("closing file\n");
+-        ret = qemu_fclose(s->file);
++        qemu_fclose(s->file);
+         s->file = NULL;
+     }
+ 
+     assert(s->fd == -1);
+-    if (ret < 0 && s->state == MIG_STATE_ACTIVE) {
+-        s->state = MIG_STATE_ERROR;
+-    }
++    assert(s->state != MIG_STATE_ACTIVE);
+ 
+-    if (s->state != MIG_STATE_ACTIVE) {
++    if (s->state != MIG_STATE_COMPLETED) {
+         qemu_savevm_state_cancel();
+     }
++
++    notifier_list_notify(&migration_state_notifiers, s);
+ }
+ 
+ void migrate_fd_error(MigrationState *s)
+ {
+     DPRINTF("setting error state\n");
+     s->state = MIG_STATE_ERROR;
+-    notifier_list_notify(&migration_state_notifiers, s);
+     migrate_fd_cleanup(s);
+ }
+ 
+ static void migrate_fd_completed(MigrationState *s)
+ {
+     DPRINTF("setting completed state\n");
++    s->state = MIG_STATE_COMPLETED;
+     migrate_fd_cleanup(s);
+-    if (s->state == MIG_STATE_ACTIVE) {
+-        s->state = MIG_STATE_COMPLETED;
+-        runstate_set(RUN_STATE_POSTMIGRATE);
+-    }
+-    notifier_list_notify(&migration_state_notifiers, s);
+ }
+ 
+ static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data,
+@@ -326,8 +319,6 @@ static void migrate_fd_cancel(MigrationState *s)
+     DPRINTF("cancelling migration\n");
+ 
+     s->state = MIG_STATE_CANCELLED;
+-    notifier_list_notify(&migration_state_notifiers, s);
+-
+     migrate_fd_cleanup(s);
+ }
+ 
+@@ -592,10 +583,6 @@ static int buffered_close(void *opaque)
+ 
+     DPRINTF("closing\n");
+ 
+-    s->xfer_limit = INT_MAX;
+-    while (!qemu_file_get_error(s->file) && s->buffer_size) {
+-        buffered_flush(s);
+-    }
+     return migrate_fd_close(s);
+ }
+ 
+@@ -658,6 +645,8 @@ static void *buffered_file_thread(void *opaque)
+     int64_t initial_time = qemu_get_clock_ms(rt_clock);
+     int64_t sleep_time = 0;
+     int64_t max_size = 0;
++    int64_t start_time = initial_time;
++    bool old_vm_running = false;
+     bool last_round = false;
+ 
+     qemu_mutex_lock_iothread();
+@@ -675,23 +664,13 @@ static void *buffered_file_thread(void *opaque)
+             if (pending_size && pending_size >= max_size) {
+                 qemu_savevm_state_iterate(s->file);
+             } else {
+-                int old_vm_running = runstate_is_running();
+-                int64_t start_time, end_time;
+-
+                 DPRINTF("done iterating\n");
+                 start_time = qemu_get_clock_ms(rt_clock);
+                 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
++                old_vm_running = runstate_is_running();
+                 vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
++                s->xfer_limit = INT_MAX;
+                 qemu_savevm_state_complete(s->file);
+-                migrate_fd_completed(s);
+-                end_time = qemu_get_clock_ms(rt_clock);
+-                s->total_time = end_time - s->total_time;
+-                s->downtime = end_time - start_time;
+-                if (s->state != MIG_STATE_COMPLETED) {
+-                    if (old_vm_running) {
+-                        vm_start();
+-                    }
+-                }
+                 last_round = true;
+             }
+         }
+@@ -725,6 +704,20 @@ static void *buffered_file_thread(void *opaque)
+         qemu_mutex_lock_iothread();
+         if (qemu_file_get_error(s->file)) {
+             migrate_fd_error(s);
++        } else if (last_round && s->buffer_size == 0) {
++            migrate_fd_completed(s);
++        }
++    }
++
++    if (s->state == MIG_STATE_COMPLETED) {
++        int64_t end_time = qemu_get_clock_ms(rt_clock);
++        s->total_time = end_time - s->total_time;
++        s->downtime = end_time - start_time;
++        runstate_set(RUN_STATE_POSTMIGRATE);
++    } else {
++        if (old_vm_running) {
++            assert(last_round);
++            vm_start();
+         }
+     }
+ 
+-- 
+1.8.2.1
+
diff --git a/0217-migration-add-migrate_set_state-tracepoint.patch b/0217-migration-add-migrate_set_state-tracepoint.patch
new file mode 100644
index 0000000..eaa8362
--- /dev/null
+++ b/0217-migration-add-migrate_set_state-tracepoint.patch
@@ -0,0 +1,83 @@
+From 00c79950d1190667daf58d4aa536aede816376a1 Mon Sep 17 00:00:00 2001
+From: Kazuya Saito <saito.kazuya at jp.fujitsu.com>
+Date: Fri, 22 Feb 2013 17:36:19 +0100
+Subject: [PATCH 217/246] migration: add migrate_set_state tracepoint
+
+Signed-off-by: Kazuya Saito <saito.kazuya at jp.fujitsu.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c  | 9 ++++++++-
+ trace-events | 3 +++
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/migration.c b/migration.c
+index 57fceb6d..c0a9239 100644
+--- a/migration.c
++++ b/migration.c
+@@ -23,6 +23,7 @@
+ #include "migration/block.h"
+ #include "qemu/thread.h"
+ #include "qmp-commands.h"
++#include "trace.h"
+ 
+ //#define DEBUG_MIGRATION
+ 
+@@ -282,6 +283,7 @@ void migrate_fd_error(MigrationState *s)
+ {
+     DPRINTF("setting error state\n");
+     s->state = MIG_STATE_ERROR;
++    trace_migrate_set_state(MIG_STATE_ERROR);
+     migrate_fd_cleanup(s);
+ }
+ 
+@@ -289,6 +291,7 @@ static void migrate_fd_completed(MigrationState *s)
+ {
+     DPRINTF("setting completed state\n");
+     s->state = MIG_STATE_COMPLETED;
++    trace_migrate_set_state(MIG_STATE_COMPLETED);
+     migrate_fd_cleanup(s);
+ }
+ 
+@@ -319,6 +322,7 @@ static void migrate_fd_cancel(MigrationState *s)
+     DPRINTF("cancelling migration\n");
+ 
+     s->state = MIG_STATE_CANCELLED;
++    trace_migrate_set_state(MIG_STATE_CANCELLED);
+     migrate_fd_cleanup(s);
+ }
+ 
+@@ -377,8 +381,9 @@ static MigrationState *migrate_init(const MigrationParams *params)
+ 
+     s->bandwidth_limit = bandwidth_limit;
+     s->state = MIG_STATE_SETUP;
+-    s->total_time = qemu_get_clock_ms(rt_clock);
++    trace_migrate_set_state(MIG_STATE_SETUP);
+ 
++    s->total_time = qemu_get_clock_ms(rt_clock);
+     return s;
+ }
+ 
+@@ -738,6 +743,8 @@ static const QEMUFileOps buffered_file_ops = {
+ void migrate_fd_connect(MigrationState *s)
+ {
+     s->state = MIG_STATE_ACTIVE;
++    trace_migrate_set_state(MIG_STATE_ACTIVE);
++
+     s->bytes_xfer = 0;
+     s->buffer = NULL;
+     s->buffer_size = 0;
+diff --git a/trace-events b/trace-events
+index 167f481..614c4ef 100644
+--- a/trace-events
++++ b/trace-events
+@@ -1091,3 +1091,6 @@ css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc,
+ # hw/s390x/virtio-ccw.c
+ virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"
+ virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)"
++
++# migration.c
++migrate_set_state(int new_state) "new state %d"
+-- 
+1.8.2.1
+
diff --git a/0218-migration-prepare-to-access-s-state-outside-critical.patch b/0218-migration-prepare-to-access-s-state-outside-critical.patch
new file mode 100644
index 0000000..9561f07
--- /dev/null
+++ b/0218-migration-prepare-to-access-s-state-outside-critical.patch
@@ -0,0 +1,128 @@
+From 5378a79abf77509ea47d75d8984644f3ba2ff209 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:20 +0100
+Subject: [PATCH 218/246] migration: prepare to access s->state outside
+ critical sections
+
+Accessing s->state outside the big QEMU lock will simplify a bit the
+locking/unlocking of the iothread lock.
+
+We need to keep the lock in migrate_fd_error and migrate_fd_completed,
+however, because they call migrate_fd_cleanup.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 33 +++++++++++++++++++++------------
+ 1 file changed, 21 insertions(+), 12 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index c0a9239..e844b2c 100644
+--- a/migration.c
++++ b/migration.c
+@@ -279,19 +279,25 @@ static void migrate_fd_cleanup(MigrationState *s)
+     notifier_list_notify(&migration_state_notifiers, s);
+ }
+ 
++static void migrate_finish_set_state(MigrationState *s, int new_state)
++{
++    if (__sync_val_compare_and_swap(&s->state, MIG_STATE_ACTIVE,
++                                    new_state) == new_state) {
++        trace_migrate_set_state(new_state);
++    }
++}
++
+ void migrate_fd_error(MigrationState *s)
+ {
+     DPRINTF("setting error state\n");
+-    s->state = MIG_STATE_ERROR;
+-    trace_migrate_set_state(MIG_STATE_ERROR);
++    migrate_finish_set_state(s, MIG_STATE_ERROR);
+     migrate_fd_cleanup(s);
+ }
+ 
+ static void migrate_fd_completed(MigrationState *s)
+ {
+     DPRINTF("setting completed state\n");
+-    s->state = MIG_STATE_COMPLETED;
+-    trace_migrate_set_state(MIG_STATE_COMPLETED);
++    migrate_finish_set_state(s, MIG_STATE_COMPLETED);
+     migrate_fd_cleanup(s);
+ }
+ 
+@@ -316,13 +322,9 @@ static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data,
+ 
+ static void migrate_fd_cancel(MigrationState *s)
+ {
+-    if (s->state != MIG_STATE_ACTIVE)
+-        return;
+-
+     DPRINTF("cancelling migration\n");
+ 
+-    s->state = MIG_STATE_CANCELLED;
+-    trace_migrate_set_state(MIG_STATE_CANCELLED);
++    migrate_finish_set_state(s, MIG_STATE_CANCELLED);
+     migrate_fd_cleanup(s);
+ }
+ 
+@@ -657,12 +659,14 @@ static void *buffered_file_thread(void *opaque)
+     qemu_mutex_lock_iothread();
+     DPRINTF("beginning savevm\n");
+     qemu_savevm_state_begin(s->file, &s->params);
++    qemu_mutex_unlock_iothread();
+ 
+     while (s->state == MIG_STATE_ACTIVE) {
+         int64_t current_time;
+         uint64_t pending_size;
+ 
+         if (s->bytes_xfer < s->xfer_limit) {
++            qemu_mutex_lock_iothread();
+             DPRINTF("iterate\n");
+             pending_size = qemu_savevm_state_pending(s->file, max_size);
+             DPRINTF("pending size %lu max %lu\n", pending_size, max_size);
+@@ -678,8 +682,9 @@ static void *buffered_file_thread(void *opaque)
+                 qemu_savevm_state_complete(s->file);
+                 last_round = true;
+             }
++            qemu_mutex_unlock_iothread();
+         }
+-        qemu_mutex_unlock_iothread();
++
+         current_time = qemu_get_clock_ms(rt_clock);
+         if (current_time >= initial_time + BUFFER_DELAY) {
+             uint64_t transferred_bytes = s->bytes_xfer;
+@@ -706,14 +711,18 @@ static void *buffered_file_thread(void *opaque)
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+         buffered_flush(s);
+-        qemu_mutex_lock_iothread();
+         if (qemu_file_get_error(s->file)) {
++            qemu_mutex_lock_iothread();
+             migrate_fd_error(s);
++            qemu_mutex_unlock_iothread();
+         } else if (last_round && s->buffer_size == 0) {
++            qemu_mutex_lock_iothread();
+             migrate_fd_completed(s);
++            qemu_mutex_unlock_iothread();
+         }
+     }
+ 
++    qemu_mutex_lock_iothread();
+     if (s->state == MIG_STATE_COMPLETED) {
+         int64_t end_time = qemu_get_clock_ms(rt_clock);
+         s->total_time = end_time - s->total_time;
+@@ -725,8 +734,8 @@ static void *buffered_file_thread(void *opaque)
+             vm_start();
+         }
+     }
+-
+     qemu_mutex_unlock_iothread();
++
+     g_free(s->buffer);
+     return NULL;
+ }
+-- 
+1.8.2.1
+
diff --git a/0219-migration-cleanup-migration-including-thread-in-the-.patch b/0219-migration-cleanup-migration-including-thread-in-the-.patch
new file mode 100644
index 0000000..cbea94f
--- /dev/null
+++ b/0219-migration-cleanup-migration-including-thread-in-the-.patch
@@ -0,0 +1,131 @@
+From f3940c04a0436c4d2291df4118494154ea7463b5 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:21 +0100
+Subject: [PATCH 219/246] migration: cleanup migration (including thread) in
+ the iothread
+
+Perform final cleanup in a bottom half, and add joining the thread to
+the series of cleanup actions.
+
+migrate_fd_error remains for connection error, but it doesn't need
+to cleanup anything anymore.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/migration.h |  1 +
+ migration.c                   | 38 ++++++++++++++++++++------------------
+ 2 files changed, 21 insertions(+), 18 deletions(-)
+
+diff --git a/include/migration/migration.h b/include/migration/migration.h
+index 3e680af..ed20bed 100644
+--- a/include/migration/migration.h
++++ b/include/migration/migration.h
+@@ -38,6 +38,7 @@ struct MigrationState
+     size_t buffer_size;
+     size_t buffer_capacity;
+     QemuThread thread;
++    QEMUBH *cleanup_bh;
+ 
+     QEMUFile *file;
+     int fd;
+diff --git a/migration.c b/migration.c
+index e844b2c..437475b 100644
+--- a/migration.c
++++ b/migration.c
+@@ -261,8 +261,13 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+ 
+ /* shared migration helpers */
+ 
+-static void migrate_fd_cleanup(MigrationState *s)
++static void migrate_fd_cleanup(void *opaque)
+ {
++    MigrationState *s = opaque;
++
++    qemu_bh_delete(s->cleanup_bh);
++    s->cleanup_bh = NULL;
++
+     if (s->file) {
+         DPRINTF("closing file\n");
+         qemu_fclose(s->file);
+@@ -290,15 +295,10 @@ static void migrate_finish_set_state(MigrationState *s, int new_state)
+ void migrate_fd_error(MigrationState *s)
+ {
+     DPRINTF("setting error state\n");
+-    migrate_finish_set_state(s, MIG_STATE_ERROR);
+-    migrate_fd_cleanup(s);
+-}
+-
+-static void migrate_fd_completed(MigrationState *s)
+-{
+-    DPRINTF("setting completed state\n");
+-    migrate_finish_set_state(s, MIG_STATE_COMPLETED);
+-    migrate_fd_cleanup(s);
++    assert(s->file == NULL);
++    s->state = MIG_STATE_ERROR;
++    trace_migrate_set_state(MIG_STATE_ERROR);
++    notifier_list_notify(&migration_state_notifiers, s);
+ }
+ 
+ static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data,
+@@ -325,7 +325,6 @@ static void migrate_fd_cancel(MigrationState *s)
+     DPRINTF("cancelling migration\n");
+ 
+     migrate_finish_set_state(s, MIG_STATE_CANCELLED);
+-    migrate_fd_cleanup(s);
+ }
+ 
+ int migrate_fd_close(MigrationState *s)
+@@ -590,6 +589,11 @@ static int buffered_close(void *opaque)
+ 
+     DPRINTF("closing\n");
+ 
++    qemu_mutex_unlock_iothread();
++    qemu_thread_join(&s->thread);
++    qemu_mutex_lock_iothread();
++    assert(s->state != MIG_STATE_ACTIVE);
++
+     return migrate_fd_close(s);
+ }
+ 
+@@ -712,13 +716,9 @@ static void *buffered_file_thread(void *opaque)
+         }
+         buffered_flush(s);
+         if (qemu_file_get_error(s->file)) {
+-            qemu_mutex_lock_iothread();
+-            migrate_fd_error(s);
+-            qemu_mutex_unlock_iothread();
++            migrate_finish_set_state(s, MIG_STATE_ERROR);
+         } else if (last_round && s->buffer_size == 0) {
+-            qemu_mutex_lock_iothread();
+-            migrate_fd_completed(s);
+-            qemu_mutex_unlock_iothread();
++            migrate_finish_set_state(s, MIG_STATE_COMPLETED);
+         }
+     }
+ 
+@@ -734,6 +734,7 @@ static void *buffered_file_thread(void *opaque)
+             vm_start();
+         }
+     }
++    qemu_bh_schedule(s->cleanup_bh);
+     qemu_mutex_unlock_iothread();
+ 
+     g_free(s->buffer);
+@@ -763,9 +764,10 @@ void migrate_fd_connect(MigrationState *s)
+ 
+     s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
+ 
++    s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
+     s->file = qemu_fopen_ops(s, &buffered_file_ops);
+ 
+     qemu_thread_create(&s->thread, buffered_file_thread, s,
+-                       QEMU_THREAD_DETACHED);
++                       QEMU_THREAD_JOINABLE);
+     notifier_list_notify(&migration_state_notifiers, s);
+ }
+-- 
+1.8.2.1
+
diff --git a/0220-block-migration-remove-variables-that-are-never-read.patch b/0220-block-migration-remove-variables-that-are-never-read.patch
new file mode 100644
index 0000000..928f721
--- /dev/null
+++ b/0220-block-migration-remove-variables-that-are-never-read.patch
@@ -0,0 +1,72 @@
+From 9fdbad6e2d4c5bc85daddabe74b3e26337c11219 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:22 +0100
+Subject: [PATCH 220/246] block-migration: remove variables that are never read
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ block-migration.c | 13 -------------
+ 1 file changed, 13 deletions(-)
+
+diff --git a/block-migration.c b/block-migration.c
+index e6c917d..e72f322 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -50,7 +50,6 @@ typedef struct BlkMigDevState {
+     int64_t cur_dirty;
+     int64_t completed_sectors;
+     int64_t total_sectors;
+-    int64_t dirty;
+     QSIMPLEQ_ENTRY(BlkMigDevState) entry;
+     unsigned long *aio_bitmap;
+ } BlkMigDevState;
+@@ -78,7 +77,6 @@ typedef struct BlkMigState {
+     int64_t total_sector_sum;
+     int prev_progress;
+     int bulk_completed;
+-    long double prev_time_offset;
+ } BlkMigState;
+ 
+ static BlkMigState block_mig_state;
+@@ -179,13 +177,10 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
+ 
+ static void blk_mig_read_cb(void *opaque, int ret)
+ {
+-    long double curr_time = qemu_get_clock_ns(rt_clock);
+     BlkMigBlock *blk = opaque;
+ 
+     blk->ret = ret;
+ 
+-    block_mig_state.prev_time_offset = curr_time;
+-
+     QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
+     bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0);
+ 
+@@ -236,10 +231,6 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+     blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
+     qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
+ 
+-    if (block_mig_state.submitted == 0) {
+-        block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
+-    }
+-
+     blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
+                                 nr_sectors, blk_mig_read_cb, blk);
+     block_mig_state.submitted++;
+@@ -382,10 +373,6 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
+                 blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
+                 qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
+ 
+-                if (block_mig_state.submitted == 0) {
+-                    block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock);
+-                }
+-
+                 blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
+                                             nr_sectors, blk_mig_read_cb, blk);
+                 block_mig_state.submitted++;
+-- 
+1.8.2.1
+
diff --git a/0221-block-migration-small-preparatory-changes-for-lockin.patch b/0221-block-migration-small-preparatory-changes-for-lockin.patch
new file mode 100644
index 0000000..80a584b
--- /dev/null
+++ b/0221-block-migration-small-preparatory-changes-for-lockin.patch
@@ -0,0 +1,91 @@
+From 50897e0513dd4854402e3d26d3a95860cabba5d2 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:23 +0100
+Subject: [PATCH 221/246] block-migration: small preparatory changes for
+ locking
+
+Some small changes that will simplify the positioning of lock/unlock
+primitives.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ block-migration.c | 26 +++++++++++++++-----------
+ 1 file changed, 15 insertions(+), 11 deletions(-)
+
+diff --git a/block-migration.c b/block-migration.c
+index e72f322..9a40edd 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -231,9 +231,10 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+     blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
+     qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
+ 
++    block_mig_state.submitted++;
++
+     blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
+                                 nr_sectors, blk_mig_read_cb, blk);
+-    block_mig_state.submitted++;
+ 
+     bdrv_reset_dirty(bs, cur_sector, nr_sectors);
+     bmds->cur_sector = cur_sector + nr_sectors;
+@@ -440,9 +441,10 @@ static int flush_blks(QEMUFile *f)
+             ret = blk->ret;
+             break;
+         }
+-        blk_send(f, blk);
+ 
+         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
++        blk_send(f, blk);
++
+         g_free(blk->buf);
+         g_free(blk);
+ 
+@@ -542,15 +544,16 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+                 /* finished saving bulk on all devices */
+                 block_mig_state.bulk_completed = 1;
+             }
++            ret = 0;
+         } else {
+             ret = blk_mig_save_dirty_block(f, 1);
+-            if (ret < 0) {
+-                return ret;
+-            }
+-            if (ret != 0) {
+-                /* no more dirty blocks */
+-                break;
+-            }
++        }
++        if (ret < 0) {
++            return ret;
++        }
++        if (ret != 0) {
++            /* no more dirty blocks */
++            break;
+         }
+     }
+ 
+@@ -560,7 +563,6 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+     }
+ 
+     qemu_put_be64(f, BLK_MIG_FLAG_EOS);
+-
+     return qemu_ftell(f) - last_ftell;
+ }
+ 
+@@ -603,7 +605,9 @@ static int block_save_complete(QEMUFile *f, void *opaque)
+ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
+ {
+     /* Estimate pending number of bytes to send */
+-    uint64_t pending = get_remaining_dirty() +
++    uint64_t pending;
++
++    pending = get_remaining_dirty() +
+                        block_mig_state.submitted * BLOCK_SIZE +
+                        block_mig_state.read_done * BLOCK_SIZE;
+ 
+-- 
+1.8.2.1
+
diff --git a/0222-block-migration-document-usage-of-state-across-threa.patch b/0222-block-migration-document-usage-of-state-across-threa.patch
new file mode 100644
index 0000000..1170d5c
--- /dev/null
+++ b/0222-block-migration-document-usage-of-state-across-threa.patch
@@ -0,0 +1,78 @@
+From 79d609fcbb20cd8fb41d61362778b4f491caa5c8 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:24 +0100
+Subject: [PATCH 222/246] block-migration: document usage of state across
+ threads
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ block-migration.c | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/block-migration.c b/block-migration.c
+index 9a40edd..d62a8b8 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -43,18 +43,24 @@
+ #endif
+ 
+ typedef struct BlkMigDevState {
++    /* Written during setup phase.  Can be read without a lock.  */
+     BlockDriverState *bs;
+-    int bulk_completed;
+     int shared_base;
+-    int64_t cur_sector;
+-    int64_t cur_dirty;
+-    int64_t completed_sectors;
+     int64_t total_sectors;
+     QSIMPLEQ_ENTRY(BlkMigDevState) entry;
++
++    /* Only used by migration thread.  Does not need a lock.  */
++    int bulk_completed;
++    int64_t cur_sector;
++    int64_t cur_dirty;
++
++    /* Protected by iothread lock.  */
+     unsigned long *aio_bitmap;
++    int64_t completed_sectors;
+ } BlkMigDevState;
+ 
+ typedef struct BlkMigBlock {
++    /* Only used by migration thread.  */
+     uint8_t *buf;
+     BlkMigDevState *bmds;
+     int64_t sector;
+@@ -62,19 +68,26 @@ typedef struct BlkMigBlock {
+     struct iovec iov;
+     QEMUIOVector qiov;
+     BlockDriverAIOCB *aiocb;
++
++    /* Protected by iothread lock.  */
+     int ret;
+     QSIMPLEQ_ENTRY(BlkMigBlock) entry;
+ } BlkMigBlock;
+ 
+ typedef struct BlkMigState {
++    /* Written during setup phase.  Can be read without a lock.  */
+     int blk_enable;
+     int shared_base;
+     QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
++    int64_t total_sector_sum;
++
++    /* Protected by iothread lock.  */
+     QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
+     int submitted;
+     int read_done;
++
++    /* Only used by migration thread.  Does not need a lock.  */
+     int transferred;
+-    int64_t total_sector_sum;
+     int prev_progress;
+     int bulk_completed;
+ } BlkMigState;
+-- 
+1.8.2.1
+
diff --git a/0223-block-migration-add-lock.patch b/0223-block-migration-add-lock.patch
new file mode 100644
index 0000000..a748526
--- /dev/null
+++ b/0223-block-migration-add-lock.patch
@@ -0,0 +1,281 @@
+From a9043cabd68e72aebb35259f420a89cf0021ee40 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:25 +0100
+Subject: [PATCH 223/246] block-migration: add lock
+
+Some state is shared between the block migration code and its AIO
+callbacks.  Once block migration will run outside the iothread,
+the block migration code and the AIO callbacks will be able to
+run concurrently.  Protect the critical sections with a separate
+lock.  Do the same for completed_sectors, which can be used from
+the monitor.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ block-migration.c     | 54 ++++++++++++++++++++++++++++++++++++++++++++++++---
+ include/qemu/atomic.h |  1 +
+ 2 files changed, 52 insertions(+), 3 deletions(-)
+
+diff --git a/block-migration.c b/block-migration.c
+index d62a8b8..b726c6c 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -54,7 +54,7 @@ typedef struct BlkMigDevState {
+     int64_t cur_sector;
+     int64_t cur_dirty;
+ 
+-    /* Protected by iothread lock.  */
++    /* Protected by block migration lock.  */
+     unsigned long *aio_bitmap;
+     int64_t completed_sectors;
+ } BlkMigDevState;
+@@ -69,7 +69,7 @@ typedef struct BlkMigBlock {
+     QEMUIOVector qiov;
+     BlockDriverAIOCB *aiocb;
+ 
+-    /* Protected by iothread lock.  */
++    /* Protected by block migration lock.  */
+     int ret;
+     QSIMPLEQ_ENTRY(BlkMigBlock) entry;
+ } BlkMigBlock;
+@@ -81,7 +81,7 @@ typedef struct BlkMigState {
+     QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
+     int64_t total_sector_sum;
+ 
+-    /* Protected by iothread lock.  */
++    /* Protected by lock.  */
+     QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
+     int submitted;
+     int read_done;
+@@ -90,10 +90,23 @@ typedef struct BlkMigState {
+     int transferred;
+     int prev_progress;
+     int bulk_completed;
++
++    /* Lock must be taken _inside_ the iothread lock.  */
++    QemuMutex lock;
+ } BlkMigState;
+ 
+ static BlkMigState block_mig_state;
+ 
++static void blk_mig_lock(void)
++{
++    qemu_mutex_lock(&block_mig_state.lock);
++}
++
++static void blk_mig_unlock(void)
++{
++    qemu_mutex_unlock(&block_mig_state.lock);
++}
++
+ static void blk_send(QEMUFile *f, BlkMigBlock * blk)
+ {
+     int len;
+@@ -120,9 +133,11 @@ uint64_t blk_mig_bytes_transferred(void)
+     BlkMigDevState *bmds;
+     uint64_t sum = 0;
+ 
++    blk_mig_lock();
+     QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
+         sum += bmds->completed_sectors;
+     }
++    blk_mig_unlock();
+     return sum << BDRV_SECTOR_BITS;
+ }
+ 
+@@ -142,6 +157,9 @@ uint64_t blk_mig_bytes_total(void)
+     return sum << BDRV_SECTOR_BITS;
+ }
+ 
++
++/* Called with migration lock held.  */
++
+ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
+ {
+     int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
+@@ -154,6 +172,8 @@ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
+     }
+ }
+ 
++/* Called with migration lock held.  */
++
+ static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
+                              int nb_sectors, int set)
+ {
+@@ -188,10 +208,13 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
+     bmds->aio_bitmap = g_malloc0(bitmap_size);
+ }
+ 
++/* Never hold migration lock when yielding to the main loop!  */
++
+ static void blk_mig_read_cb(void *opaque, int ret)
+ {
+     BlkMigBlock *blk = opaque;
+ 
++    blk_mig_lock();
+     blk->ret = ret;
+ 
+     QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
+@@ -200,6 +223,7 @@ static void blk_mig_read_cb(void *opaque, int ret)
+     block_mig_state.submitted--;
+     block_mig_state.read_done++;
+     assert(block_mig_state.submitted >= 0);
++    blk_mig_unlock();
+ }
+ 
+ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+@@ -244,7 +268,9 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+     blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
+     qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
+ 
++    blk_mig_lock();
+     block_mig_state.submitted++;
++    blk_mig_unlock();
+ 
+     blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
+                                 nr_sectors, blk_mig_read_cb, blk);
+@@ -366,8 +392,12 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
+     int ret = -EIO;
+ 
+     for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
++        blk_mig_lock();
+         if (bmds_aio_inflight(bmds, sector)) {
++            blk_mig_unlock();
+             bdrv_drain_all();
++        } else {
++            blk_mig_unlock();
+         }
+         if (bdrv_get_dirty(bmds->bs, sector)) {
+ 
+@@ -389,8 +419,11 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
+ 
+                 blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov,
+                                             nr_sectors, blk_mig_read_cb, blk);
++
++                blk_mig_lock();
+                 block_mig_state.submitted++;
+                 bmds_set_aio_inflight(bmds, sector, nr_sectors, 1);
++                blk_mig_unlock();
+             } else {
+                 ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors);
+                 if (ret < 0) {
+@@ -446,6 +479,7 @@ static int flush_blks(QEMUFile *f)
+             __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
+             block_mig_state.transferred);
+ 
++    blk_mig_lock();
+     while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
+         if (qemu_file_rate_limit(f)) {
+             break;
+@@ -456,7 +490,9 @@ static int flush_blks(QEMUFile *f)
+         }
+ 
+         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
++        blk_mig_unlock();
+         blk_send(f, blk);
++        blk_mig_lock();
+ 
+         g_free(blk->buf);
+         g_free(blk);
+@@ -465,6 +501,7 @@ static int flush_blks(QEMUFile *f)
+         block_mig_state.transferred++;
+         assert(block_mig_state.read_done >= 0);
+     }
++    blk_mig_unlock();
+ 
+     DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
+             block_mig_state.submitted, block_mig_state.read_done,
+@@ -493,6 +530,7 @@ static void blk_mig_cleanup(void)
+ 
+     set_dirty_tracking(0);
+ 
++    blk_mig_lock();
+     while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
+         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
+         bdrv_set_in_use(bmds->bs, 0);
+@@ -506,6 +544,7 @@ static void blk_mig_cleanup(void)
+         g_free(blk->buf);
+         g_free(blk);
+     }
++    blk_mig_unlock();
+ }
+ 
+ static void block_migration_cancel(void *opaque)
+@@ -548,9 +587,11 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+     blk_mig_reset_dirty_cursor();
+ 
+     /* control the rate of transfer */
++    blk_mig_lock();
+     while ((block_mig_state.submitted +
+             block_mig_state.read_done) * BLOCK_SIZE <
+            qemu_file_get_rate_limit(f)) {
++        blk_mig_unlock();
+         if (block_mig_state.bulk_completed == 0) {
+             /* first finish the bulk phase */
+             if (blk_mig_save_bulked_block(f) == 0) {
+@@ -564,11 +605,13 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+         if (ret < 0) {
+             return ret;
+         }
++        blk_mig_lock();
+         if (ret != 0) {
+             /* no more dirty blocks */
+             break;
+         }
+     }
++    blk_mig_unlock();
+ 
+     ret = flush_blks(f);
+     if (ret) {
+@@ -595,7 +638,9 @@ static int block_save_complete(QEMUFile *f, void *opaque)
+ 
+     /* we know for sure that save bulk is completed and
+        all async read completed */
++    blk_mig_lock();
+     assert(block_mig_state.submitted == 0);
++    blk_mig_unlock();
+ 
+     do {
+         ret = blk_mig_save_dirty_block(f, 0);
+@@ -620,6 +665,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
+     /* Estimate pending number of bytes to send */
+     uint64_t pending;
+ 
++    blk_mig_lock();
+     pending = get_remaining_dirty() +
+                        block_mig_state.submitted * BLOCK_SIZE +
+                        block_mig_state.read_done * BLOCK_SIZE;
+@@ -628,6 +674,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
+     if (pending == 0 && !block_mig_state.bulk_completed) {
+         pending = BLOCK_SIZE;
+     }
++    blk_mig_unlock();
+ 
+     DPRINTF("Enter save live pending  %" PRIu64 "\n", pending);
+     return pending;
+@@ -739,6 +786,7 @@ void blk_mig_init(void)
+ {
+     QSIMPLEQ_INIT(&block_mig_state.bmds_list);
+     QSIMPLEQ_INIT(&block_mig_state.blk_list);
++    qemu_mutex_init(&block_mig_state.lock);
+ 
+     register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers,
+                          &block_mig_state);
+diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
+index 96a194b..10becb6 100644
+--- a/include/qemu/atomic.h
++++ b/include/qemu/atomic.h
+@@ -16,6 +16,7 @@
+  */
+ #define smp_wmb()   barrier()
+ #define smp_rmb()   barrier()
++
+ /*
+  * We use GCC builtin if it's available, as that can use
+  * mfence on 32 bit as well, e.g. if built with -march=pentium-m.
+-- 
+1.8.2.1
+
diff --git a/0224-migration-reorder-SaveVMHandlers-members.patch b/0224-migration-reorder-SaveVMHandlers-members.patch
new file mode 100644
index 0000000..4f17f02
--- /dev/null
+++ b/0224-migration-reorder-SaveVMHandlers-members.patch
@@ -0,0 +1,42 @@
+From 3d91104155abc46db41f0588bdbcfbd34aa007af Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:26 +0100
+Subject: [PATCH 224/246] migration: reorder SaveVMHandlers members
+
+This groups together the callbacks that later will have similar
+locking rules.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/vmstate.h | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
+index f27276c..6229569 100644
+--- a/include/migration/vmstate.h
++++ b/include/migration/vmstate.h
+@@ -32,13 +32,15 @@ typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
+ typedef struct SaveVMHandlers {
+     void (*set_params)(const MigrationParams *params, void * opaque);
+     SaveStateHandler *save_state;
++
+     int (*save_live_setup)(QEMUFile *f, void *opaque);
+-    int (*save_live_iterate)(QEMUFile *f, void *opaque);
++    void (*cancel)(void *opaque);
+     int (*save_live_complete)(QEMUFile *f, void *opaque);
++    bool (*is_active)(void *opaque);
++    int (*save_live_iterate)(QEMUFile *f, void *opaque);
+     uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size);
+-    void (*cancel)(void *opaque);
++
+     LoadStateHandler *load_state;
+-    bool (*is_active)(void *opaque);
+ } SaveVMHandlers;
+ 
+ int register_savevm(DeviceState *dev,
+-- 
+1.8.2.1
+
diff --git a/0225-migration-run-pending-iterate-callbacks-out-of-big-l.patch b/0225-migration-run-pending-iterate-callbacks-out-of-big-l.patch
new file mode 100644
index 0000000..d6670ea
--- /dev/null
+++ b/0225-migration-run-pending-iterate-callbacks-out-of-big-l.patch
@@ -0,0 +1,268 @@
+From f873c5525a98cbf9ae06ebef1229b6810bb3186a Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:27 +0100
+Subject: [PATCH 225/246] migration: run pending/iterate callbacks out of big
+ lock
+
+This makes it possible to do blocking writes directly to the socket,
+with no buffer in the middle.  For RAM, only the migration_bitmap_sync()
+call needs the iothread lock.  For block migration, it is needed by
+the block layer (including bdrv_drain_all and dirty bitmap access),
+but because some code is shared between iterate and complete, all of
+mig_save_device_dirty is run with the lock taken.
+
+In the savevm case, the iterate callback runs within the big lock.
+This is annoying because it complicates the rules.  Luckily we do not
+need to do anything about it: the RAM iterate callback does not need
+the iothread lock, and block migration never runs during savevm.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ arch_init.c                 |  4 ++++
+ block-migration.c           | 37 +++++++++++++++++++++++++++++++++++--
+ include/migration/vmstate.h | 11 +++++++++++
+ migration.c                 |  4 ++--
+ 4 files changed, 52 insertions(+), 4 deletions(-)
+
+diff --git a/arch_init.c b/arch_init.c
+index 8daeafa..32b4378 100644
+--- a/arch_init.c
++++ b/arch_init.c
+@@ -379,6 +379,8 @@ static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
+     return ret;
+ }
+ 
++/* Needs iothread lock! */
++
+ static void migration_bitmap_sync(void)
+ {
+     RAMBlock *block;
+@@ -690,7 +692,9 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
+     remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
+ 
+     if (remaining_size < max_size) {
++        qemu_mutex_lock_iothread();
+         migration_bitmap_sync();
++        qemu_mutex_unlock_iothread();
+         remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
+     }
+     return remaining_size;
+diff --git a/block-migration.c b/block-migration.c
+index b726c6c..8da5f86 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -107,6 +107,10 @@ static void blk_mig_unlock(void)
+     qemu_mutex_unlock(&block_mig_state.lock);
+ }
+ 
++/* Must run outside of the iothread lock during the bulk phase,
++ * or the VM will stall.
++ */
++
+ static void blk_send(QEMUFile *f, BlkMigBlock * blk)
+ {
+     int len;
+@@ -226,6 +230,8 @@ static void blk_mig_read_cb(void *opaque, int ret)
+     blk_mig_unlock();
+ }
+ 
++/* Called with no lock taken.  */
++
+ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+ {
+     int64_t total_sectors = bmds->total_sectors;
+@@ -235,11 +241,13 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+     int nr_sectors;
+ 
+     if (bmds->shared_base) {
++        qemu_mutex_lock_iothread();
+         while (cur_sector < total_sectors &&
+                !bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH,
+                                   &nr_sectors)) {
+             cur_sector += nr_sectors;
+         }
++        qemu_mutex_unlock_iothread();
+     }
+ 
+     if (cur_sector >= total_sectors) {
+@@ -272,15 +280,19 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
+     block_mig_state.submitted++;
+     blk_mig_unlock();
+ 
++    qemu_mutex_lock_iothread();
+     blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
+                                 nr_sectors, blk_mig_read_cb, blk);
+ 
+     bdrv_reset_dirty(bs, cur_sector, nr_sectors);
+-    bmds->cur_sector = cur_sector + nr_sectors;
++    qemu_mutex_unlock_iothread();
+ 
++    bmds->cur_sector = cur_sector + nr_sectors;
+     return (bmds->cur_sector >= total_sectors);
+ }
+ 
++/* Called with iothread lock taken.  */
++
+ static void set_dirty_tracking(int enable)
+ {
+     BlkMigDevState *bmds;
+@@ -336,6 +348,8 @@ static void init_blk_migration(QEMUFile *f)
+     bdrv_iterate(init_blk_migration_it, NULL);
+ }
+ 
++/* Called with no lock taken.  */
++
+ static int blk_mig_save_bulked_block(QEMUFile *f)
+ {
+     int64_t completed_sector_sum = 0;
+@@ -382,6 +396,8 @@ static void blk_mig_reset_dirty_cursor(void)
+     }
+ }
+ 
++/* Called with iothread lock taken.  */
++
+ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
+                                  int is_async)
+ {
+@@ -451,7 +467,9 @@ error:
+     return ret;
+ }
+ 
+-/* return value:
++/* Called with iothread lock taken.
++ *
++ * return value:
+  * 0: too much data for max_downtime
+  * 1: few enough data for max_downtime
+ */
+@@ -470,6 +488,8 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async)
+     return ret;
+ }
+ 
++/* Called with no locks taken.  */
++
+ static int flush_blks(QEMUFile *f)
+ {
+     BlkMigBlock *blk;
+@@ -509,6 +529,8 @@ static int flush_blks(QEMUFile *f)
+     return ret;
+ }
+ 
++/* Called with iothread lock taken.  */
++
+ static int64_t get_remaining_dirty(void)
+ {
+     BlkMigDevState *bmds;
+@@ -521,6 +543,8 @@ static int64_t get_remaining_dirty(void)
+     return dirty << BDRV_SECTOR_BITS;
+ }
+ 
++/* Called with iothread lock taken.  */
++
+ static void blk_mig_cleanup(void)
+ {
+     BlkMigDevState *bmds;
+@@ -600,7 +624,12 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+             }
+             ret = 0;
+         } else {
++            /* Always called with iothread lock taken for
++             * simplicity, block_save_complete also calls it.
++             */
++            qemu_mutex_lock_iothread();
+             ret = blk_mig_save_dirty_block(f, 1);
++            qemu_mutex_unlock_iothread();
+         }
+         if (ret < 0) {
+             return ret;
+@@ -622,6 +651,8 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+     return qemu_ftell(f) - last_ftell;
+ }
+ 
++/* Called with iothread lock taken.  */
++
+ static int block_save_complete(QEMUFile *f, void *opaque)
+ {
+     int ret;
+@@ -665,6 +696,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
+     /* Estimate pending number of bytes to send */
+     uint64_t pending;
+ 
++    qemu_mutex_lock_iothread();
+     blk_mig_lock();
+     pending = get_remaining_dirty() +
+                        block_mig_state.submitted * BLOCK_SIZE +
+@@ -675,6 +707,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
+         pending = BLOCK_SIZE;
+     }
+     blk_mig_unlock();
++    qemu_mutex_unlock_iothread();
+ 
+     DPRINTF("Enter save live pending  %" PRIu64 "\n", pending);
+     return pending;
+diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
+index 6229569..5f803f5 100644
+--- a/include/migration/vmstate.h
++++ b/include/migration/vmstate.h
+@@ -30,14 +30,25 @@ typedef void SaveStateHandler(QEMUFile *f, void *opaque);
+ typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
+ 
+ typedef struct SaveVMHandlers {
++    /* This runs inside the iothread lock.  */
+     void (*set_params)(const MigrationParams *params, void * opaque);
+     SaveStateHandler *save_state;
+ 
+     int (*save_live_setup)(QEMUFile *f, void *opaque);
+     void (*cancel)(void *opaque);
+     int (*save_live_complete)(QEMUFile *f, void *opaque);
++
++    /* This runs both outside and inside the iothread lock.  */
+     bool (*is_active)(void *opaque);
++
++    /* This runs outside the iothread lock in the migration case, and
++     * within the lock in the savevm case.  The callback had better only
++     * use data that is local to the migration thread or protected
++     * by other locks.
++     */
+     int (*save_live_iterate)(QEMUFile *f, void *opaque);
++
++    /* This runs outside the iothread lock!  */
+     uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size);
+ 
+     LoadStateHandler *load_state;
+diff --git a/migration.c b/migration.c
+index 437475b..87b5009 100644
+--- a/migration.c
++++ b/migration.c
+@@ -670,7 +670,6 @@ static void *buffered_file_thread(void *opaque)
+         uint64_t pending_size;
+ 
+         if (s->bytes_xfer < s->xfer_limit) {
+-            qemu_mutex_lock_iothread();
+             DPRINTF("iterate\n");
+             pending_size = qemu_savevm_state_pending(s->file, max_size);
+             DPRINTF("pending size %lu max %lu\n", pending_size, max_size);
+@@ -678,6 +677,7 @@ static void *buffered_file_thread(void *opaque)
+                 qemu_savevm_state_iterate(s->file);
+             } else {
+                 DPRINTF("done iterating\n");
++                qemu_mutex_lock_iothread();
+                 start_time = qemu_get_clock_ms(rt_clock);
+                 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+                 old_vm_running = runstate_is_running();
+@@ -685,8 +685,8 @@ static void *buffered_file_thread(void *opaque)
+                 s->xfer_limit = INT_MAX;
+                 qemu_savevm_state_complete(s->file);
+                 last_round = true;
++                qemu_mutex_unlock_iothread();
+             }
+-            qemu_mutex_unlock_iothread();
+         }
+ 
+         current_time = qemu_get_clock_ms(rt_clock);
+-- 
+1.8.2.1
+
diff --git a/0226-migration-run-setup-callbacks-out-of-big-lock.patch b/0226-migration-run-setup-callbacks-out-of-big-lock.patch
new file mode 100644
index 0000000..b7746b9
--- /dev/null
+++ b/0226-migration-run-setup-callbacks-out-of-big-lock.patch
@@ -0,0 +1,119 @@
+From 4418176da1e72e62c06b87bc39f4dc3688e9a4cf Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:28 +0100
+Subject: [PATCH 226/246] migration: run setup callbacks out of big lock
+
+Only the migration_bitmap_sync() call needs the iothread lock.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ arch_init.c                 | 10 ++++++----
+ block-migration.c           |  2 ++
+ include/migration/vmstate.h |  2 +-
+ migration.c                 |  2 --
+ savevm.c                    |  3 +++
+ 5 files changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/arch_init.c b/arch_init.c
+index 32b4378..6089c53 100644
+--- a/arch_init.c
++++ b/arch_init.c
+@@ -570,10 +570,6 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
+     bitmap_set(migration_bitmap, 0, ram_pages);
+     migration_dirty_pages = ram_pages;
+ 
+-    qemu_mutex_lock_ramlist();
+-    bytes_transferred = 0;
+-    reset_ram_globals();
+-
+     if (migrate_use_xbzrle()) {
+         XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
+                                   TARGET_PAGE_SIZE,
+@@ -587,8 +583,14 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
+         acct_clear();
+     }
+ 
++    qemu_mutex_lock_iothread();
++    qemu_mutex_lock_ramlist();
++    bytes_transferred = 0;
++    reset_ram_globals();
++
+     memory_global_dirty_log_start();
+     migration_bitmap_sync();
++    qemu_mutex_unlock_iothread();
+ 
+     qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
+ 
+diff --git a/block-migration.c b/block-migration.c
+index 8da5f86..2fd7699 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -583,10 +583,12 @@ static int block_save_setup(QEMUFile *f, void *opaque)
+     DPRINTF("Enter save live setup submitted %d transferred %d\n",
+             block_mig_state.submitted, block_mig_state.transferred);
+ 
++    qemu_mutex_lock_iothread();
+     init_blk_migration(f);
+ 
+     /* start track dirty blocks */
+     set_dirty_tracking(1);
++    qemu_mutex_unlock_iothread();
+ 
+     ret = flush_blks(f);
+     blk_mig_reset_dirty_cursor();
+diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
+index 5f803f5..abc3b47 100644
+--- a/include/migration/vmstate.h
++++ b/include/migration/vmstate.h
+@@ -34,7 +34,6 @@ typedef struct SaveVMHandlers {
+     void (*set_params)(const MigrationParams *params, void * opaque);
+     SaveStateHandler *save_state;
+ 
+-    int (*save_live_setup)(QEMUFile *f, void *opaque);
+     void (*cancel)(void *opaque);
+     int (*save_live_complete)(QEMUFile *f, void *opaque);
+ 
+@@ -49,6 +48,7 @@ typedef struct SaveVMHandlers {
+     int (*save_live_iterate)(QEMUFile *f, void *opaque);
+ 
+     /* This runs outside the iothread lock!  */
++    int (*save_live_setup)(QEMUFile *f, void *opaque);
+     uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size);
+ 
+     LoadStateHandler *load_state;
+diff --git a/migration.c b/migration.c
+index 87b5009..7c1d4df 100644
+--- a/migration.c
++++ b/migration.c
+@@ -660,10 +660,8 @@ static void *buffered_file_thread(void *opaque)
+     bool old_vm_running = false;
+     bool last_round = false;
+ 
+-    qemu_mutex_lock_iothread();
+     DPRINTF("beginning savevm\n");
+     qemu_savevm_state_begin(s->file, &s->params);
+-    qemu_mutex_unlock_iothread();
+ 
+     while (s->state == MIG_STATE_ACTIVE) {
+         int64_t current_time;
+diff --git a/savevm.c b/savevm.c
+index e10a045..7c7774e 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -1768,7 +1768,10 @@ static int qemu_savevm_state(QEMUFile *f)
+         return -EINVAL;
+     }
+ 
++    qemu_mutex_unlock_iothread();
+     qemu_savevm_state_begin(f, &params);
++    qemu_mutex_lock_iothread();
++
+     while (qemu_file_get_error(f) == 0) {
+         if (qemu_savevm_state_iterate(f) > 0) {
+             break;
+-- 
+1.8.2.1
+
diff --git a/0227-migration-yay-buffering-is-gone.patch b/0227-migration-yay-buffering-is-gone.patch
new file mode 100644
index 0000000..c7c6dd7
--- /dev/null
+++ b/0227-migration-yay-buffering-is-gone.patch
@@ -0,0 +1,178 @@
+From 7b88ce8fc64774035975391bbab68e59810fe07b Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:29 +0100
+Subject: [PATCH 227/246] migration: yay, buffering is gone
+
+Buffering was needed because blocking writes could take a long time
+and starve other threads seeking to grab the big QEMU mutex.
+
+Now that all writes (except within _complete callbacks) are done
+outside the big QEMU mutex, we do not need buffering at all.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/migration.h |  3 --
+ migration.c                   | 79 ++++++++++++-------------------------------
+ savevm.c                      |  1 +
+ 3 files changed, 22 insertions(+), 61 deletions(-)
+
+diff --git a/include/migration/migration.h b/include/migration/migration.h
+index ed20bed..cec8643 100644
+--- a/include/migration/migration.h
++++ b/include/migration/migration.h
+@@ -34,9 +34,6 @@ struct MigrationState
+     int64_t bandwidth_limit;
+     size_t bytes_xfer;
+     size_t xfer_limit;
+-    uint8_t *buffer;
+-    size_t buffer_size;
+-    size_t buffer_capacity;
+     QemuThread thread;
+     QEMUBH *cleanup_bh;
+ 
+diff --git a/migration.c b/migration.c
+index 7c1d4df..62a7f8e 100644
+--- a/migration.c
++++ b/migration.c
+@@ -514,73 +514,41 @@ int64_t migrate_xbzrle_cache_size(void)
+ 
+ /* migration thread support */
+ 
+-
+-static void buffered_flush(MigrationState *s)
+-{
+-    size_t offset = 0;
+-    ssize_t ret = 0;
+-
+-    DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size);
+-
+-    if (qemu_file_get_error(s->file)) {
+-        s->buffer_size = 0;
+-        return;
+-    }
+-    qemu_fflush(s->file);
+-
+-    while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) {
+-        size_t to_send = MIN(s->buffer_size - offset, s->xfer_limit - s->bytes_xfer);
+-        ret = migrate_fd_put_buffer(s, s->buffer + offset, to_send);
+-        if (ret <= 0) {
+-            DPRINTF("error flushing data, %zd\n", ret);
+-            break;
+-        } else {
+-            DPRINTF("flushed %zd byte(s)\n", ret);
+-            offset += ret;
+-            s->bytes_xfer += ret;
+-        }
+-    }
+-
+-    DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size);
+-    memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
+-    s->buffer_size -= offset;
+-
+-    if (ret < 0) {
+-        qemu_file_set_error(s->file, ret);
+-    }
+-}
+-
+ static int buffered_put_buffer(void *opaque, const uint8_t *buf,
+                                int64_t pos, int size)
+ {
+     MigrationState *s = opaque;
+-    ssize_t error;
++    ssize_t ret;
++    size_t sent;
+ 
+     DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
+ 
+-    error = qemu_file_get_error(s->file);
+-    if (error) {
+-        DPRINTF("flush when error, bailing: %s\n", strerror(-error));
+-        return error;
++    ret = qemu_file_get_error(s->file);
++    if (ret) {
++        DPRINTF("flush when error, bailing: %s\n", strerror(-ret));
++        return ret;
+     }
+ 
+     if (size <= 0) {
+         return size;
+     }
+ 
+-    if (size > (s->buffer_capacity - s->buffer_size)) {
+-        DPRINTF("increasing buffer capacity from %zu by %zu\n",
+-                s->buffer_capacity, size + 1024);
+-
+-        s->buffer_capacity += size + 1024;
+-
+-        s->buffer = g_realloc(s->buffer, s->buffer_capacity);
++    sent = 0;
++    while (size) {
++        ret = migrate_fd_put_buffer(s, buf, size);
++        if (ret <= 0) {
++            DPRINTF("error flushing data, %zd\n", ret);
++            return ret;
++        } else {
++            DPRINTF("flushed %zd byte(s)\n", ret);
++            sent += ret;
++            buf += ret;
++            size -= ret;
++            s->bytes_xfer += ret;
++        }
+     }
+ 
+-    memcpy(s->buffer + s->buffer_size, buf, size);
+-    s->buffer_size += size;
+-
+-    return size;
++    return sent;
+ }
+ 
+ static int buffered_close(void *opaque)
+@@ -712,10 +680,9 @@ static void *buffered_file_thread(void *opaque)
+             g_usleep((initial_time + BUFFER_DELAY - current_time)*1000);
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+-        buffered_flush(s);
+         if (qemu_file_get_error(s->file)) {
+             migrate_finish_set_state(s, MIG_STATE_ERROR);
+-        } else if (last_round && s->buffer_size == 0) {
++        } else if (last_round) {
+             migrate_finish_set_state(s, MIG_STATE_COMPLETED);
+         }
+     }
+@@ -735,7 +702,6 @@ static void *buffered_file_thread(void *opaque)
+     qemu_bh_schedule(s->cleanup_bh);
+     qemu_mutex_unlock_iothread();
+ 
+-    g_free(s->buffer);
+     return NULL;
+ }
+ 
+@@ -754,9 +720,6 @@ void migrate_fd_connect(MigrationState *s)
+     trace_migrate_set_state(MIG_STATE_ACTIVE);
+ 
+     s->bytes_xfer = 0;
+-    s->buffer = NULL;
+-    s->buffer_size = 0;
+-    s->buffer_capacity = 0;
+     /* This is a best 1st approximation. ns to ms */
+     s->expected_downtime = max_downtime/1000000;
+ 
+diff --git a/savevm.c b/savevm.c
+index 7c7774e..ce10295 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -1724,6 +1724,7 @@ void qemu_savevm_state_complete(QEMUFile *f)
+     }
+ 
+     qemu_put_byte(f, QEMU_VM_EOF);
++    qemu_fflush(f);
+ }
+ 
+ uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size)
+-- 
+1.8.2.1
+
diff --git a/0228-Rename-buffered_-to-migration_.patch b/0228-Rename-buffered_-to-migration_.patch
new file mode 100644
index 0000000..1545d3d
--- /dev/null
+++ b/0228-Rename-buffered_-to-migration_.patch
@@ -0,0 +1,116 @@
+From 15a0127c8f5146f9e88faf839b7818807497b1e5 Mon Sep 17 00:00:00 2001
+From: Juan Quintela <quintela at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:30 +0100
+Subject: [PATCH 228/246] Rename buffered_ to migration_
+
+This is consistent once that we have moved everything to migration.c
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 32 ++++++++++++++++----------------
+ 1 file changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 62a7f8e..71c6c10 100644
+--- a/migration.c
++++ b/migration.c
+@@ -514,7 +514,7 @@ int64_t migrate_xbzrle_cache_size(void)
+ 
+ /* migration thread support */
+ 
+-static int buffered_put_buffer(void *opaque, const uint8_t *buf,
++static int migration_put_buffer(void *opaque, const uint8_t *buf,
+                                int64_t pos, int size)
+ {
+     MigrationState *s = opaque;
+@@ -551,7 +551,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf,
+     return sent;
+ }
+ 
+-static int buffered_close(void *opaque)
++static int migration_close(void *opaque)
+ {
+     MigrationState *s = opaque;
+ 
+@@ -565,7 +565,7 @@ static int buffered_close(void *opaque)
+     return migrate_fd_close(s);
+ }
+ 
+-static int buffered_get_fd(void *opaque)
++static int migration_get_fd(void *opaque)
+ {
+     MigrationState *s = opaque;
+ 
+@@ -578,7 +578,7 @@ static int buffered_get_fd(void *opaque)
+  *   1: Time to stop
+  *   negative: There has been an error
+  */
+-static int buffered_rate_limit(void *opaque)
++static int migration_rate_limit(void *opaque)
+ {
+     MigrationState *s = opaque;
+     int ret;
+@@ -595,7 +595,7 @@ static int buffered_rate_limit(void *opaque)
+     return 0;
+ }
+ 
+-static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate)
++static int64_t migration_set_rate_limit(void *opaque, int64_t new_rate)
+ {
+     MigrationState *s = opaque;
+     if (qemu_file_get_error(s->file)) {
+@@ -611,14 +611,14 @@ out:
+     return s->xfer_limit;
+ }
+ 
+-static int64_t buffered_get_rate_limit(void *opaque)
++static int64_t migration_get_rate_limit(void *opaque)
+ {
+     MigrationState *s = opaque;
+ 
+     return s->xfer_limit;
+ }
+ 
+-static void *buffered_file_thread(void *opaque)
++static void *migration_thread(void *opaque)
+ {
+     MigrationState *s = opaque;
+     int64_t initial_time = qemu_get_clock_ms(rt_clock);
+@@ -705,13 +705,13 @@ static void *buffered_file_thread(void *opaque)
+     return NULL;
+ }
+ 
+-static const QEMUFileOps buffered_file_ops = {
+-    .get_fd =         buffered_get_fd,
+-    .put_buffer =     buffered_put_buffer,
+-    .close =          buffered_close,
+-    .rate_limit =     buffered_rate_limit,
+-    .get_rate_limit = buffered_get_rate_limit,
+-    .set_rate_limit = buffered_set_rate_limit,
++static const QEMUFileOps migration_file_ops = {
++    .get_fd =         migration_get_fd,
++    .put_buffer =     migration_put_buffer,
++    .close =          migration_close,
++    .rate_limit =     migration_rate_limit,
++    .get_rate_limit = migration_get_rate_limit,
++    .set_rate_limit = migration_set_rate_limit,
+ };
+ 
+ void migrate_fd_connect(MigrationState *s)
+@@ -726,9 +726,9 @@ void migrate_fd_connect(MigrationState *s)
+     s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
+ 
+     s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
+-    s->file = qemu_fopen_ops(s, &buffered_file_ops);
++    s->file = qemu_fopen_ops(s, &migration_file_ops);
+ 
+-    qemu_thread_create(&s->thread, buffered_file_thread, s,
++    qemu_thread_create(&s->thread, migration_thread, s,
+                        QEMU_THREAD_JOINABLE);
+     notifier_list_notify(&migration_state_notifiers, s);
+ }
+-- 
+1.8.2.1
+
diff --git a/0229-qemu-file-make-qemu_fflush-and-qemu_file_set_error-p.patch b/0229-qemu-file-make-qemu_fflush-and-qemu_file_set_error-p.patch
new file mode 100644
index 0000000..6806e4d
--- /dev/null
+++ b/0229-qemu-file-make-qemu_fflush-and-qemu_file_set_error-p.patch
@@ -0,0 +1,60 @@
+From 6c3c2d1af9dbc147b7975e490cbf860502ed93e5 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:31 +0100
+Subject: [PATCH 229/246] qemu-file: make qemu_fflush and qemu_file_set_error
+ private again
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/qemu-file.h | 2 --
+ savevm.c                      | 4 ++--
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
+index 5e0c287..46fc11d 100644
+--- a/include/migration/qemu-file.h
++++ b/include/migration/qemu-file.h
+@@ -82,7 +82,6 @@ QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+ int qemu_get_fd(QEMUFile *f);
+ int qemu_fclose(QEMUFile *f);
+ int64_t qemu_ftell(QEMUFile *f);
+-void qemu_fflush(QEMUFile *f);
+ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
+ void qemu_put_byte(QEMUFile *f, int v);
+ 
+@@ -114,7 +113,6 @@ int qemu_file_rate_limit(QEMUFile *f);
+ int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
+ int64_t qemu_file_get_rate_limit(QEMUFile *f);
+ int qemu_file_get_error(QEMUFile *f);
+-void qemu_file_set_error(QEMUFile *f, int ret);
+ 
+ static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
+ {
+diff --git a/savevm.c b/savevm.c
+index ce10295..fef2ab9 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -443,7 +443,7 @@ int qemu_file_get_error(QEMUFile *f)
+     return f->last_error;
+ }
+ 
+-void qemu_file_set_error(QEMUFile *f, int ret)
++static void qemu_file_set_error(QEMUFile *f, int ret)
+ {
+     if (f->last_error == 0) {
+         f->last_error = ret;
+@@ -453,7 +453,7 @@ void qemu_file_set_error(QEMUFile *f, int ret)
+ /** Flushes QEMUFile buffer
+  *
+  */
+-void qemu_fflush(QEMUFile *f)
++static void qemu_fflush(QEMUFile *f)
+ {
+     int ret = 0;
+ 
+-- 
+1.8.2.1
+
diff --git a/0230-migration-eliminate-last_round.patch b/0230-migration-eliminate-last_round.patch
new file mode 100644
index 0000000..14857b2
--- /dev/null
+++ b/0230-migration-eliminate-last_round.patch
@@ -0,0 +1,69 @@
+From 70ae4fa3b1eb5b327a8375bcdd04c5d837f16d6f Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:32 +0100
+Subject: [PATCH 230/246] migration: eliminate last_round
+
+We will go around the loop exactly once after setting last_round.
+Eliminate the variable altogether.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 71c6c10..a888f36 100644
+--- a/migration.c
++++ b/migration.c
+@@ -626,7 +626,6 @@ static void *migration_thread(void *opaque)
+     int64_t max_size = 0;
+     int64_t start_time = initial_time;
+     bool old_vm_running = false;
+-    bool last_round = false;
+ 
+     DPRINTF("beginning savevm\n");
+     qemu_savevm_state_begin(s->file, &s->params);
+@@ -650,8 +649,11 @@ static void *migration_thread(void *opaque)
+                 vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+                 s->xfer_limit = INT_MAX;
+                 qemu_savevm_state_complete(s->file);
+-                last_round = true;
+                 qemu_mutex_unlock_iothread();
++                if (!qemu_file_get_error(s->file)) {
++                    migrate_finish_set_state(s, MIG_STATE_COMPLETED);
++                    break;
++                }
+             }
+         }
+ 
+@@ -675,15 +677,13 @@ static void *migration_thread(void *opaque)
+             sleep_time = 0;
+             initial_time = current_time;
+         }
+-        if (!last_round && (s->bytes_xfer >= s->xfer_limit)) {
++        if (s->bytes_xfer >= s->xfer_limit) {
+             /* usleep expects microseconds */
+             g_usleep((initial_time + BUFFER_DELAY - current_time)*1000);
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+         if (qemu_file_get_error(s->file)) {
+             migrate_finish_set_state(s, MIG_STATE_ERROR);
+-        } else if (last_round) {
+-            migrate_finish_set_state(s, MIG_STATE_COMPLETED);
+         }
+     }
+ 
+@@ -695,7 +695,6 @@ static void *migration_thread(void *opaque)
+         runstate_set(RUN_STATE_POSTMIGRATE);
+     } else {
+         if (old_vm_running) {
+-            assert(last_round);
+             vm_start();
+         }
+     }
+-- 
+1.8.2.1
+
diff --git a/0231-migration-detect-error-before-sleeping.patch b/0231-migration-detect-error-before-sleeping.patch
new file mode 100644
index 0000000..088e930
--- /dev/null
+++ b/0231-migration-detect-error-before-sleeping.patch
@@ -0,0 +1,41 @@
+From 853560d2513e360ca0dc690fba8a55ad7da31312 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:33 +0100
+Subject: [PATCH 231/246] migration: detect error before sleeping
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index a888f36..35c3455 100644
+--- a/migration.c
++++ b/migration.c
+@@ -657,6 +657,10 @@ static void *migration_thread(void *opaque)
+             }
+         }
+ 
++        if (qemu_file_get_error(s->file)) {
++            migrate_finish_set_state(s, MIG_STATE_ERROR);
++            break;
++        }
+         current_time = qemu_get_clock_ms(rt_clock);
+         if (current_time >= initial_time + BUFFER_DELAY) {
+             uint64_t transferred_bytes = s->bytes_xfer;
+@@ -682,9 +686,6 @@ static void *migration_thread(void *opaque)
+             g_usleep((initial_time + BUFFER_DELAY - current_time)*1000);
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+         }
+-        if (qemu_file_get_error(s->file)) {
+-            migrate_finish_set_state(s, MIG_STATE_ERROR);
+-        }
+     }
+ 
+     qemu_mutex_lock_iothread();
+-- 
+1.8.2.1
+
diff --git a/0232-migration-remove-useless-qemu_file_get_error-check.patch b/0232-migration-remove-useless-qemu_file_get_error-check.patch
new file mode 100644
index 0000000..16d555d
--- /dev/null
+++ b/0232-migration-remove-useless-qemu_file_get_error-check.patch
@@ -0,0 +1,35 @@
+From f4f1096175be8a34f16fb3e39dfde22e4566d0c6 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:34 +0100
+Subject: [PATCH 232/246] migration: remove useless qemu_file_get_error check
+
+migration_put_buffer is never called if there has been an error.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 35c3455..d75beca 100644
+--- a/migration.c
++++ b/migration.c
+@@ -523,12 +523,6 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf,
+ 
+     DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
+ 
+-    ret = qemu_file_get_error(s->file);
+-    if (ret) {
+-        DPRINTF("flush when error, bailing: %s\n", strerror(-ret));
+-        return ret;
+-    }
+-
+     if (size <= 0) {
+         return size;
+     }
+-- 
+1.8.2.1
+
diff --git a/0233-migration-use-qemu_file_rate_limit-consistently.patch b/0233-migration-use-qemu_file_rate_limit-consistently.patch
new file mode 100644
index 0000000..f741e5f
--- /dev/null
+++ b/0233-migration-use-qemu_file_rate_limit-consistently.patch
@@ -0,0 +1,38 @@
+From b806155b3d8c4ba206d90d2337fb682a446ed08c Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:35 +0100
+Subject: [PATCH 233/246] migration: use qemu_file_rate_limit consistently
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index d75beca..ae2c83c 100644
+--- a/migration.c
++++ b/migration.c
+@@ -628,7 +628,7 @@ static void *migration_thread(void *opaque)
+         int64_t current_time;
+         uint64_t pending_size;
+ 
+-        if (s->bytes_xfer < s->xfer_limit) {
++        if (!qemu_file_rate_limit(s->file)) {
+             DPRINTF("iterate\n");
+             pending_size = qemu_savevm_state_pending(s->file, max_size);
+             DPRINTF("pending size %lu max %lu\n", pending_size, max_size);
+@@ -675,7 +675,7 @@ static void *migration_thread(void *opaque)
+             sleep_time = 0;
+             initial_time = current_time;
+         }
+-        if (s->bytes_xfer >= s->xfer_limit) {
++        if (qemu_file_rate_limit(s->file)) {
+             /* usleep expects microseconds */
+             g_usleep((initial_time + BUFFER_DELAY - current_time)*1000);
+             sleep_time += qemu_get_clock_ms(rt_clock) - current_time;
+-- 
+1.8.2.1
+
diff --git a/0234-migration-merge-qemu_popen_cmd-with-qemu_popen.patch b/0234-migration-merge-qemu_popen_cmd-with-qemu_popen.patch
new file mode 100644
index 0000000..cdc4866
--- /dev/null
+++ b/0234-migration-merge-qemu_popen_cmd-with-qemu_popen.patch
@@ -0,0 +1,105 @@
+From d168927f61149c211e156be639be1cf8399bf30e Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:36 +0100
+Subject: [PATCH 234/246] migration: merge qemu_popen_cmd with qemu_popen
+
+There is no reason for outgoing exec migration to do popen manually
+anymore (the reason used to be that we needed the FILE* to make it
+non-blocking).  Use qemu_popen_cmd.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/qemu-file.h |  1 -
+ migration-exec.c              | 10 ++++------
+ savevm.c                      | 22 ++++++++--------------
+ 3 files changed, 12 insertions(+), 21 deletions(-)
+
+diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
+index 46fc11d..987e719 100644
+--- a/include/migration/qemu-file.h
++++ b/include/migration/qemu-file.h
+@@ -77,7 +77,6 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
+ QEMUFile *qemu_fopen(const char *filename, const char *mode);
+ QEMUFile *qemu_fdopen(int fd, const char *mode);
+ QEMUFile *qemu_fopen_socket(int fd);
+-QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
+ QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+ int qemu_get_fd(QEMUFile *f);
+ int qemu_fclose(QEMUFile *f);
+diff --git a/migration-exec.c b/migration-exec.c
+index a051a6e..5dc7313 100644
+--- a/migration-exec.c
++++ b/migration-exec.c
+@@ -59,19 +59,17 @@ static int exec_close(MigrationState *s)
+ 
+ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
+ {
+-    FILE *f;
+-
+-    f = popen(command, "w");
++    QEMUFile *f;
++    f = qemu_popen_cmd(command, "w");
+     if (f == NULL) {
+         error_setg_errno(errp, errno, "failed to popen the migration target");
+         return;
+     }
+ 
+-    s->fd = fileno(f);
++    s->opaque = f;
++    s->fd = qemu_get_fd(f);
+     assert(s->fd != -1);
+ 
+-    s->opaque = qemu_popen(f, "w");
+-
+     s->close = exec_close;
+     s->get_error = file_errno;
+     s->write = file_write;
+diff --git a/savevm.c b/savevm.c
+index fef2ab9..38699de 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -275,11 +275,17 @@ static const QEMUFileOps stdio_pipe_write_ops = {
+     .close =      stdio_pclose
+ };
+ 
+-QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
++QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
+ {
++    FILE *stdio_file;
+     QEMUFileStdio *s;
+ 
+-    if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
++    stdio_file = popen(command, mode);
++    if (stdio_file == NULL) {
++        return NULL;
++    }
++
++    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
+         fprintf(stderr, "qemu_popen: Argument validity check failed\n");
+         return NULL;
+     }
+@@ -296,18 +302,6 @@ QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
+     return s->file;
+ }
+ 
+-QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
+-{
+-    FILE *popen_file;
+-
+-    popen_file = popen(command, mode);
+-    if(popen_file == NULL) {
+-        return NULL;
+-    }
+-
+-    return qemu_popen(popen_file, mode);
+-}
+-
+ static const QEMUFileOps stdio_file_read_ops = {
+     .get_fd =     stdio_get_fd,
+     .get_buffer = stdio_get_buffer,
+-- 
+1.8.2.1
+
diff --git a/0235-qemu-file-fsync-a-writable-stdio-QEMUFile.patch b/0235-qemu-file-fsync-a-writable-stdio-QEMUFile.patch
new file mode 100644
index 0000000..203444a
--- /dev/null
+++ b/0235-qemu-file-fsync-a-writable-stdio-QEMUFile.patch
@@ -0,0 +1,47 @@
+From 1b98be7980ca1ac4a5ea1b140e09594c74824204 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:37 +0100
+Subject: [PATCH 235/246] qemu-file: fsync a writable stdio QEMUFile
+
+This is what fd_close does.  Prepare for switching to a QEMUFile.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ savevm.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/savevm.c b/savevm.c
+index 38699de..1d49fde 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -256,6 +256,24 @@ static int stdio_fclose(void *opaque)
+ {
+     QEMUFileStdio *s = opaque;
+     int ret = 0;
++
++    if (s->file->ops->put_buffer) {
++        int fd = fileno(s->stdio_file);
++        struct stat st;
++
++        ret = fstat(fd, &st);
++        if (ret == 0 && S_ISREG(st.st_mode)) {
++            /*
++             * If the file handle is a regular file make sure the
++             * data is flushed to disk before signaling success.
++             */
++            ret = fsync(fd);
++            if (ret != 0) {
++                ret = -errno;
++                return ret;
++            }
++        }
++    }
+     if (fclose(s->stdio_file) == EOF) {
+         ret = -errno;
+     }
+-- 
+1.8.2.1
+
diff --git a/0236-qemu-file-check-exit-status-when-closing-a-pipe-QEMU.patch b/0236-qemu-file-check-exit-status-when-closing-a-pipe-QEMU.patch
new file mode 100644
index 0000000..09707a6
--- /dev/null
+++ b/0236-qemu-file-check-exit-status-when-closing-a-pipe-QEMU.patch
@@ -0,0 +1,68 @@
+From 0755b0d7d8d94d566945d1016ca7a61a5913f4ae Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:38 +0100
+Subject: [PATCH 236/246] qemu-file: check exit status when closing a pipe
+ QEMUFile
+
+This is what exec_close does.  Move this to the underlying QEMUFile.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/qemu/osdep.h | 7 +++++++
+ migration-exec.c     | 4 ----
+ savevm.c             | 3 +++
+ 3 files changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
+index 87d3b9c..df24400 100644
+--- a/include/qemu/osdep.h
++++ b/include/qemu/osdep.h
+@@ -9,6 +9,13 @@
+ #include <sys/signal.h>
+ #endif
+ 
++#ifndef _WIN32
++#include <sys/wait.h>
++#else
++#define WIFEXITED(x)   1
++#define WEXITSTATUS(x) (x)
++#endif
++
+ #include <sys/time.h>
+ 
+ #if defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10
+diff --git a/migration-exec.c b/migration-exec.c
+index 5dc7313..a2b5f8d 100644
+--- a/migration-exec.c
++++ b/migration-exec.c
+@@ -50,10 +50,6 @@ static int exec_close(MigrationState *s)
+     ret = qemu_fclose(s->opaque);
+     s->opaque = NULL;
+     s->fd = -1;
+-    if (ret >= 0 && !(WIFEXITED(ret) && WEXITSTATUS(ret) == 0)) {
+-        /* close succeeded, but non-zero exit code: */
+-        ret = -EIO; /* fake errno value */
+-    }
+     return ret;
+ }
+ 
+diff --git a/savevm.c b/savevm.c
+index 1d49fde..6d6f1f1 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -247,6 +247,9 @@ static int stdio_pclose(void *opaque)
+     ret = pclose(s->stdio_file);
+     if (ret == -1) {
+         ret = -errno;
++    } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
++        /* close succeeded, but non-zero exit code: */
++        ret = -EIO; /* fake errno value */
+     }
+     g_free(s);
+     return ret;
+-- 
+1.8.2.1
+
diff --git a/0237-qemu-file-add-writable-socket-QEMUFile.patch b/0237-qemu-file-add-writable-socket-QEMUFile.patch
new file mode 100644
index 0000000..9d9b8f0
--- /dev/null
+++ b/0237-qemu-file-add-writable-socket-QEMUFile.patch
@@ -0,0 +1,113 @@
+From dcda429cd8f860b774686d69ee640c82bbfa9db4 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:39 +0100
+Subject: [PATCH 237/246] qemu-file: add writable socket QEMUFile
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/qemu-file.h |  2 +-
+ migration-tcp.c               |  2 +-
+ migration-unix.c              |  2 +-
+ savevm.c                      | 33 +++++++++++++++++++++++++++++++--
+ 4 files changed, 34 insertions(+), 5 deletions(-)
+
+diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
+index 987e719..25e8461 100644
+--- a/include/migration/qemu-file.h
++++ b/include/migration/qemu-file.h
+@@ -76,7 +76,7 @@ typedef struct QEMUFileOps {
+ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
+ QEMUFile *qemu_fopen(const char *filename, const char *mode);
+ QEMUFile *qemu_fdopen(int fd, const char *mode);
+-QEMUFile *qemu_fopen_socket(int fd);
++QEMUFile *qemu_fopen_socket(int fd, const char *mode);
+ QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+ int qemu_get_fd(QEMUFile *f);
+ int qemu_fclose(QEMUFile *f);
+diff --git a/migration-tcp.c b/migration-tcp.c
+index 59e3b7e..a748195 100644
+--- a/migration-tcp.c
++++ b/migration-tcp.c
+@@ -95,7 +95,7 @@ static void tcp_accept_incoming_migration(void *opaque)
+         goto out;
+     }
+ 
+-    f = qemu_fopen_socket(c);
++    f = qemu_fopen_socket(c, "rb");
+     if (f == NULL) {
+         fprintf(stderr, "could not qemu_fopen socket\n");
+         goto out;
+diff --git a/migration-unix.c b/migration-unix.c
+index 0ca2a21..d078f43 100644
+--- a/migration-unix.c
++++ b/migration-unix.c
+@@ -95,7 +95,7 @@ static void unix_accept_incoming_migration(void *opaque)
+         goto out;
+     }
+ 
+-    f = qemu_fopen_socket(c);
++    f = qemu_fopen_socket(c, "rb");
+     if (f == NULL) {
+         fprintf(stderr, "could not qemu_fopen socket\n");
+         goto out;
+diff --git a/savevm.c b/savevm.c
+index 6d6f1f1..76c88c7 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -198,6 +198,18 @@ static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
+     return len;
+ }
+ 
++static int socket_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size)
++{
++    QEMUFileSocket *s = opaque;
++    ssize_t len;
++
++    len = qemu_send_full(s->fd, buf, size, 0);
++    if (len < size) {
++        len = -socket_error();
++    }
++    return len;
++}
++
+ static int socket_close(void *opaque)
+ {
+     QEMUFileSocket *s = opaque;
+@@ -369,12 +381,29 @@ static const QEMUFileOps socket_read_ops = {
+     .close =      socket_close
+ };
+ 
+-QEMUFile *qemu_fopen_socket(int fd)
++static const QEMUFileOps socket_write_ops = {
++    .get_fd =     socket_get_fd,
++    .put_buffer = socket_put_buffer,
++    .close =      socket_close
++};
++
++QEMUFile *qemu_fopen_socket(int fd, const char *mode)
+ {
+     QEMUFileSocket *s = g_malloc0(sizeof(QEMUFileSocket));
+ 
++    if (mode == NULL ||
++        (mode[0] != 'r' && mode[0] != 'w') ||
++        mode[1] != 'b' || mode[2] != 0) {
++        fprintf(stderr, "qemu_fopen: Argument validity check failed\n");
++        return NULL;
++    }
++
+     s->fd = fd;
+-    s->file = qemu_fopen_ops(s, &socket_read_ops);
++    if (mode[0] == 'w') {
++        s->file = qemu_fopen_ops(s, &socket_write_ops);
++    } else {
++        s->file = qemu_fopen_ops(s, &socket_read_ops);
++    }
+     return s->file;
+ }
+ 
+-- 
+1.8.2.1
+
diff --git a/0238-qemu-file-simplify-and-export-qemu_ftell.patch b/0238-qemu-file-simplify-and-export-qemu_ftell.patch
new file mode 100644
index 0000000..4681914
--- /dev/null
+++ b/0238-qemu-file-simplify-and-export-qemu_ftell.patch
@@ -0,0 +1,75 @@
+From 6690c2eb2a183f2853742e20a0d2a6fb0c39ae65 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:40 +0100
+Subject: [PATCH 238/246] qemu-file: simplify and export qemu_ftell
+
+Force a flush when qemu_ftell is called.  This simplifies the buffer magic
+(it also breaks qemu_ftell for input QEMUFiles, but we never use it).
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ savevm.c | 20 ++++++++------------
+ 1 file changed, 8 insertions(+), 12 deletions(-)
+
+diff --git a/savevm.c b/savevm.c
+index 76c88c7..c60ace3 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -119,8 +119,8 @@ struct QEMUFile {
+     void *opaque;
+     int is_write;
+ 
+-    int64_t buf_offset; /* start of buffer when writing, end of buffer
+-                           when reading */
++    int64_t pos; /* start of buffer when writing, end of buffer
++                    when reading */
+     int buf_index;
+     int buf_size; /* 0 when writing */
+     uint8_t buf[IO_BUF_SIZE];
+@@ -505,9 +505,9 @@ static void qemu_fflush(QEMUFile *f)
+         return;
+     }
+     if (f->is_write && f->buf_index > 0) {
+-        ret = f->ops->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index);
++        ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index);
+         if (ret >= 0) {
+-            f->buf_offset += f->buf_index;
++            f->pos += f->buf_index;
+         }
+         f->buf_index = 0;
+     }
+@@ -534,11 +534,11 @@ static void qemu_fill_buffer(QEMUFile *f)
+     f->buf_index = 0;
+     f->buf_size = pending;
+ 
+-    len = f->ops->get_buffer(f->opaque, f->buf + pending, f->buf_offset,
++    len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos,
+                         IO_BUF_SIZE - pending);
+     if (len > 0) {
+         f->buf_size += len;
+-        f->buf_offset += len;
++        f->pos += len;
+     } else if (len == 0) {
+         qemu_file_set_error(f, -EIO);
+     } else if (len != -EAGAIN)
+@@ -718,12 +718,8 @@ int qemu_get_byte(QEMUFile *f)
+ 
+ int64_t qemu_ftell(QEMUFile *f)
+ {
+-    /* buf_offset excludes buffer for writing but includes it for reading */
+-    if (f->is_write) {
+-        return f->buf_offset + f->buf_index;
+-    } else {
+-        return f->buf_offset - f->buf_size + f->buf_index;
+-    }
++    qemu_fflush(f);
++    return f->pos;
+ }
+ 
+ int qemu_file_rate_limit(QEMUFile *f)
+-- 
+1.8.2.1
+
diff --git a/0239-migration-use-QEMUFile-for-migration-channel-lifetim.patch b/0239-migration-use-QEMUFile-for-migration-channel-lifetim.patch
new file mode 100644
index 0000000..1d20a07
--- /dev/null
+++ b/0239-migration-use-QEMUFile-for-migration-channel-lifetim.patch
@@ -0,0 +1,278 @@
+From aa1e9e2e0165a02552ae87e88ec76d3fe17c407b Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:41 +0100
+Subject: [PATCH 239/246] migration: use QEMUFile for migration channel
+ lifetime
+
+As a start, use QEMUFile to store the destination and close it.
+qemu_get_fd gets a file descriptor that will be used by the write
+callbacks.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/migration.h |  7 ++++---
+ migration-exec.c              | 21 ++-------------------
+ migration-fd.c                | 35 +++--------------------------------
+ migration-tcp.c               | 19 +++----------------
+ migration-unix.c              | 19 +++----------------
+ migration.c                   |  8 +++++---
+ savevm.c                      |  1 +
+ 7 files changed, 21 insertions(+), 89 deletions(-)
+
+diff --git a/include/migration/migration.h b/include/migration/migration.h
+index cec8643..1f8f305 100644
+--- a/include/migration/migration.h
++++ b/include/migration/migration.h
+@@ -38,12 +38,13 @@ struct MigrationState
+     QEMUBH *cleanup_bh;
+ 
+     QEMUFile *file;
++    QEMUFile *migration_file;
++
+     int fd;
+-    int state;
+     int (*get_error)(MigrationState *s);
+-    int (*close)(MigrationState *s);
+     int (*write)(MigrationState *s, const void *buff, size_t size);
+-    void *opaque;
++
++    int state;
+     MigrationParams params;
+     int64_t total_time;
+     int64_t downtime;
+diff --git a/migration-exec.c b/migration-exec.c
+index a2b5f8d..8c3f720 100644
+--- a/migration-exec.c
++++ b/migration-exec.c
+@@ -43,33 +43,16 @@ static int file_write(MigrationState *s, const void * buf, size_t size)
+     return write(s->fd, buf, size);
+ }
+ 
+-static int exec_close(MigrationState *s)
+-{
+-    int ret = 0;
+-    DPRINTF("exec_close\n");
+-    ret = qemu_fclose(s->opaque);
+-    s->opaque = NULL;
+-    s->fd = -1;
+-    return ret;
+-}
+-
+ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
+ {
+-    QEMUFile *f;
+-    f = qemu_popen_cmd(command, "w");
+-    if (f == NULL) {
++    s->migration_file = qemu_popen_cmd(command, "w");
++    if (s->migration_file == NULL) {
+         error_setg_errno(errp, errno, "failed to popen the migration target");
+         return;
+     }
+ 
+-    s->opaque = f;
+-    s->fd = qemu_get_fd(f);
+-    assert(s->fd != -1);
+-
+-    s->close = exec_close;
+     s->get_error = file_errno;
+     s->write = file_write;
+-
+     migrate_fd_connect(s);
+ }
+ 
+diff --git a/migration-fd.c b/migration-fd.c
+index a99e0e3..4636457 100644
+--- a/migration-fd.c
++++ b/migration-fd.c
+@@ -40,45 +40,16 @@ static int fd_write(MigrationState *s, const void * buf, size_t size)
+     return write(s->fd, buf, size);
+ }
+ 
+-static int fd_close(MigrationState *s)
+-{
+-    struct stat st;
+-    int ret;
+-
+-    DPRINTF("fd_close\n");
+-    ret = fstat(s->fd, &st);
+-    if (ret == 0 && S_ISREG(st.st_mode)) {
+-        /*
+-         * If the file handle is a regular file make sure the
+-         * data is flushed to disk before signaling success.
+-         */
+-        ret = fsync(s->fd);
+-        if (ret != 0) {
+-            ret = -errno;
+-            perror("migration-fd: fsync");
+-            return ret;
+-        }
+-    }
+-    ret = close(s->fd);
+-    s->fd = -1;
+-    if (ret != 0) {
+-        ret = -errno;
+-        perror("migration-fd: close");
+-    }
+-    return ret;
+-}
+-
+ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
+ {
+-    s->fd = monitor_get_fd(cur_mon, fdname, errp);
+-    if (s->fd == -1) {
++    int fd = monitor_get_fd(cur_mon, fdname, errp);
++    if (fd == -1) {
+         return;
+     }
++    s->migration_file = qemu_fdopen(fd, "wb");
+ 
+     s->get_error = fd_errno;
+     s->write = fd_write;
+-    s->close = fd_close;
+-
+     migrate_fd_connect(s);
+ }
+ 
+diff --git a/migration-tcp.c b/migration-tcp.c
+index a748195..1e8e004 100644
+--- a/migration-tcp.c
++++ b/migration-tcp.c
+@@ -39,28 +39,17 @@ static int socket_write(MigrationState *s, const void * buf, size_t size)
+     return send(s->fd, buf, size, 0);
+ }
+ 
+-static int tcp_close(MigrationState *s)
+-{
+-    int r = 0;
+-    DPRINTF("tcp_close\n");
+-    if (closesocket(s->fd) < 0) {
+-        r = -socket_error();
+-    }
+-    return r;
+-}
+-
+ static void tcp_wait_for_connect(int fd, void *opaque)
+ {
+     MigrationState *s = opaque;
+ 
+     if (fd < 0) {
+         DPRINTF("migrate connect error\n");
+-        s->fd = -1;
++        s->migration_file = NULL;
+         migrate_fd_error(s);
+     } else {
+         DPRINTF("migrate connect success\n");
+-        s->fd = fd;
+-        qemu_set_block(s->fd);
++        s->migration_file = qemu_fopen_socket(fd, "wb");
+         migrate_fd_connect(s);
+     }
+ }
+@@ -69,9 +58,7 @@ void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Erro
+ {
+     s->get_error = socket_errno;
+     s->write = socket_write;
+-    s->close = tcp_close;
+-
+-    s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
++    inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
+ }
+ 
+ static void tcp_accept_incoming_migration(void *opaque)
+diff --git a/migration-unix.c b/migration-unix.c
+index d078f43..11917f4 100644
+--- a/migration-unix.c
++++ b/migration-unix.c
+@@ -39,28 +39,17 @@ static int unix_write(MigrationState *s, const void * buf, size_t size)
+     return write(s->fd, buf, size);
+ }
+ 
+-static int unix_close(MigrationState *s)
+-{
+-    int r = 0;
+-    DPRINTF("unix_close\n");
+-    if (close(s->fd) < 0) {
+-        r = -errno;
+-    }
+-    return r;
+-}
+-
+ static void unix_wait_for_connect(int fd, void *opaque)
+ {
+     MigrationState *s = opaque;
+ 
+     if (fd < 0) {
+         DPRINTF("migrate connect error\n");
+-        s->fd = -1;
++        s->migration_file = NULL;
+         migrate_fd_error(s);
+     } else {
+         DPRINTF("migrate connect success\n");
+-        s->fd = fd;
+-        qemu_set_block(s->fd);
++        s->migration_file = qemu_fopen_socket(fd, "wb");
+         migrate_fd_connect(s);
+     }
+ }
+@@ -69,9 +58,7 @@ void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **
+ {
+     s->get_error = unix_errno;
+     s->write = unix_write;
+-    s->close = unix_close;
+-
+-    s->fd = unix_nonblocking_connect(path, unix_wait_for_connect, s, errp);
++    unix_nonblocking_connect(path, unix_wait_for_connect, s, errp);
+ }
+ 
+ static void unix_accept_incoming_migration(void *opaque)
+diff --git a/migration.c b/migration.c
+index ae2c83c..fa630ed 100644
+--- a/migration.c
++++ b/migration.c
+@@ -274,7 +274,7 @@ static void migrate_fd_cleanup(void *opaque)
+         s->file = NULL;
+     }
+ 
+-    assert(s->fd == -1);
++    assert(s->migration_file == NULL);
+     assert(s->state != MIG_STATE_ACTIVE);
+ 
+     if (s->state != MIG_STATE_COMPLETED) {
+@@ -330,8 +330,9 @@ static void migrate_fd_cancel(MigrationState *s)
+ int migrate_fd_close(MigrationState *s)
+ {
+     int rc = 0;
+-    if (s->fd != -1) {
+-        rc = s->close(s);
++    if (s->migration_file != NULL) {
++        rc = qemu_fclose(s->migration_file);
++        s->migration_file = NULL;
+         s->fd = -1;
+     }
+     return rc;
+@@ -720,6 +721,7 @@ void migrate_fd_connect(MigrationState *s)
+     s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
+ 
+     s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
++    s->fd = qemu_get_fd(s->migration_file);
+     s->file = qemu_fopen_ops(s, &migration_file_ops);
+ 
+     qemu_thread_create(&s->thread, migration_thread, s,
+diff --git a/savevm.c b/savevm.c
+index c60ace3..43963ce 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -400,6 +400,7 @@ QEMUFile *qemu_fopen_socket(int fd, const char *mode)
+ 
+     s->fd = fd;
+     if (mode[0] == 'w') {
++        qemu_set_block(s->fd);
+         s->file = qemu_fopen_ops(s, &socket_write_ops);
+     } else {
+         s->file = qemu_fopen_ops(s, &socket_read_ops);
+-- 
+1.8.2.1
+
diff --git a/0240-migration-use-QEMUFile-for-writing-outgoing-migratio.patch b/0240-migration-use-QEMUFile-for-writing-outgoing-migratio.patch
new file mode 100644
index 0000000..36c0edc
--- /dev/null
+++ b/0240-migration-use-QEMUFile-for-writing-outgoing-migratio.patch
@@ -0,0 +1,254 @@
+From 16a0242081586af3bfb38b0b710fc9fd3b681143 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:42 +0100
+Subject: [PATCH 240/246] migration: use QEMUFile for writing outgoing
+ migration data
+
+Second, drop the file descriptor indirection, and write directly to the
+QEMUFile.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/migration.h |  4 ----
+ migration-exec.c              | 12 -----------
+ migration-fd.c                | 12 -----------
+ migration-tcp.c               | 12 -----------
+ migration-unix.c              | 12 -----------
+ migration.c                   | 46 ++++++++-----------------------------------
+ 6 files changed, 8 insertions(+), 90 deletions(-)
+
+diff --git a/include/migration/migration.h b/include/migration/migration.h
+index 1f8f305..ae94706 100644
+--- a/include/migration/migration.h
++++ b/include/migration/migration.h
+@@ -40,10 +40,6 @@ struct MigrationState
+     QEMUFile *file;
+     QEMUFile *migration_file;
+ 
+-    int fd;
+-    int (*get_error)(MigrationState *s);
+-    int (*write)(MigrationState *s, const void *buff, size_t size);
+-
+     int state;
+     MigrationParams params;
+     int64_t total_time;
+diff --git a/migration-exec.c b/migration-exec.c
+index 8c3f720..1c539de 100644
+--- a/migration-exec.c
++++ b/migration-exec.c
+@@ -33,16 +33,6 @@
+     do { } while (0)
+ #endif
+ 
+-static int file_errno(MigrationState *s)
+-{
+-    return errno;
+-}
+-
+-static int file_write(MigrationState *s, const void * buf, size_t size)
+-{
+-    return write(s->fd, buf, size);
+-}
+-
+ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
+ {
+     s->migration_file = qemu_popen_cmd(command, "w");
+@@ -51,8 +41,6 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error
+         return;
+     }
+ 
+-    s->get_error = file_errno;
+-    s->write = file_write;
+     migrate_fd_connect(s);
+ }
+ 
+diff --git a/migration-fd.c b/migration-fd.c
+index 4636457..07c758a 100644
+--- a/migration-fd.c
++++ b/migration-fd.c
+@@ -30,16 +30,6 @@
+     do { } while (0)
+ #endif
+ 
+-static int fd_errno(MigrationState *s)
+-{
+-    return errno;
+-}
+-
+-static int fd_write(MigrationState *s, const void * buf, size_t size)
+-{
+-    return write(s->fd, buf, size);
+-}
+-
+ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
+ {
+     int fd = monitor_get_fd(cur_mon, fdname, errp);
+@@ -48,8 +38,6 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **
+     }
+     s->migration_file = qemu_fdopen(fd, "wb");
+ 
+-    s->get_error = fd_errno;
+-    s->write = fd_write;
+     migrate_fd_connect(s);
+ }
+ 
+diff --git a/migration-tcp.c b/migration-tcp.c
+index 1e8e004..5ea4f3d 100644
+--- a/migration-tcp.c
++++ b/migration-tcp.c
+@@ -29,16 +29,6 @@
+     do { } while (0)
+ #endif
+ 
+-static int socket_errno(MigrationState *s)
+-{
+-    return socket_error();
+-}
+-
+-static int socket_write(MigrationState *s, const void * buf, size_t size)
+-{
+-    return send(s->fd, buf, size, 0);
+-}
+-
+ static void tcp_wait_for_connect(int fd, void *opaque)
+ {
+     MigrationState *s = opaque;
+@@ -56,8 +46,6 @@ static void tcp_wait_for_connect(int fd, void *opaque)
+ 
+ void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp)
+ {
+-    s->get_error = socket_errno;
+-    s->write = socket_write;
+     inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
+ }
+ 
+diff --git a/migration-unix.c b/migration-unix.c
+index 11917f4..64bfa31 100644
+--- a/migration-unix.c
++++ b/migration-unix.c
+@@ -29,16 +29,6 @@
+     do { } while (0)
+ #endif
+ 
+-static int unix_errno(MigrationState *s)
+-{
+-    return errno;
+-}
+-
+-static int unix_write(MigrationState *s, const void * buf, size_t size)
+-{
+-    return write(s->fd, buf, size);
+-}
+-
+ static void unix_wait_for_connect(int fd, void *opaque)
+ {
+     MigrationState *s = opaque;
+@@ -56,8 +46,6 @@ static void unix_wait_for_connect(int fd, void *opaque)
+ 
+ void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp)
+ {
+-    s->get_error = unix_errno;
+-    s->write = unix_write;
+     unix_nonblocking_connect(path, unix_wait_for_connect, s, errp);
+ }
+ 
+diff --git a/migration.c b/migration.c
+index fa630ed..26ba6c9 100644
+--- a/migration.c
++++ b/migration.c
+@@ -301,25 +301,6 @@ void migrate_fd_error(MigrationState *s)
+     notifier_list_notify(&migration_state_notifiers, s);
+ }
+ 
+-static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data,
+-                                     size_t size)
+-{
+-    ssize_t ret;
+-
+-    if (s->state != MIG_STATE_ACTIVE) {
+-        return -EIO;
+-    }
+-
+-    do {
+-        ret = s->write(s, data, size);
+-    } while (ret == -1 && ((s->get_error(s)) == EINTR));
+-
+-    if (ret == -1)
+-        ret = -(s->get_error(s));
+-
+-    return ret;
+-}
+-
+ static void migrate_fd_cancel(MigrationState *s)
+ {
+     DPRINTF("cancelling migration\n");
+@@ -333,7 +314,6 @@ int migrate_fd_close(MigrationState *s)
+     if (s->migration_file != NULL) {
+         rc = qemu_fclose(s->migration_file);
+         s->migration_file = NULL;
+-        s->fd = -1;
+     }
+     return rc;
+ }
+@@ -519,8 +499,7 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf,
+                                int64_t pos, int size)
+ {
+     MigrationState *s = opaque;
+-    ssize_t ret;
+-    size_t sent;
++    int ret;
+ 
+     DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
+ 
+@@ -528,22 +507,14 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf,
+         return size;
+     }
+ 
+-    sent = 0;
+-    while (size) {
+-        ret = migrate_fd_put_buffer(s, buf, size);
+-        if (ret <= 0) {
+-            DPRINTF("error flushing data, %zd\n", ret);
+-            return ret;
+-        } else {
+-            DPRINTF("flushed %zd byte(s)\n", ret);
+-            sent += ret;
+-            buf += ret;
+-            size -= ret;
+-            s->bytes_xfer += ret;
+-        }
++    qemu_put_buffer(s->migration_file, buf, size);
++    ret = qemu_file_get_error(s->migration_file);
++    if (ret) {
++        return ret;
+     }
+ 
+-    return sent;
++    s->bytes_xfer += size;
++    return size;
+ }
+ 
+ static int migration_close(void *opaque)
+@@ -564,7 +535,7 @@ static int migration_get_fd(void *opaque)
+ {
+     MigrationState *s = opaque;
+ 
+-    return s->fd;
++    return qemu_get_fd(s->migration_file);
+ }
+ 
+ /*
+@@ -721,7 +692,6 @@ void migrate_fd_connect(MigrationState *s)
+     s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
+ 
+     s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
+-    s->fd = qemu_get_fd(s->migration_file);
+     s->file = qemu_fopen_ops(s, &migration_file_ops);
+ 
+     qemu_thread_create(&s->thread, migration_thread, s,
+-- 
+1.8.2.1
+
diff --git a/0241-migration-use-qemu_ftell-to-compute-bandwidth.patch b/0241-migration-use-qemu_ftell-to-compute-bandwidth.patch
new file mode 100644
index 0000000..8f4eac6
--- /dev/null
+++ b/0241-migration-use-qemu_ftell-to-compute-bandwidth.patch
@@ -0,0 +1,47 @@
+From 75a2c8fdbeb4eb8fbe66e6b12a13994bf80bb08b Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:43 +0100
+Subject: [PATCH 241/246] migration: use qemu_ftell to compute bandwidth
+
+Prepare for when s->bytes_xfer will be removed.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/migration.c b/migration.c
+index 26ba6c9..def1e9e 100644
+--- a/migration.c
++++ b/migration.c
+@@ -589,6 +589,7 @@ static void *migration_thread(void *opaque)
+     MigrationState *s = opaque;
+     int64_t initial_time = qemu_get_clock_ms(rt_clock);
+     int64_t sleep_time = 0;
++    int64_t initial_bytes = 0;
+     int64_t max_size = 0;
+     int64_t start_time = initial_time;
+     bool old_vm_running = false;
+@@ -629,7 +630,7 @@ static void *migration_thread(void *opaque)
+         }
+         current_time = qemu_get_clock_ms(rt_clock);
+         if (current_time >= initial_time + BUFFER_DELAY) {
+-            uint64_t transferred_bytes = s->bytes_xfer;
++            uint64_t transferred_bytes = qemu_ftell(s->file) - initial_bytes;
+             uint64_t time_spent = current_time - initial_time - sleep_time;
+             double bandwidth = transferred_bytes / time_spent;
+             max_size = bandwidth * migrate_max_downtime() / 1000000;
+@@ -646,6 +647,7 @@ static void *migration_thread(void *opaque)
+             s->bytes_xfer = 0;
+             sleep_time = 0;
+             initial_time = current_time;
++            initial_bytes = qemu_ftell(s->file);
+         }
+         if (qemu_file_rate_limit(s->file)) {
+             /* usleep expects microseconds */
+-- 
+1.8.2.1
+
diff --git a/0242-migration-small-changes-around-rate-limiting.patch b/0242-migration-small-changes-around-rate-limiting.patch
new file mode 100644
index 0000000..4f10bc7
--- /dev/null
+++ b/0242-migration-small-changes-around-rate-limiting.patch
@@ -0,0 +1,80 @@
+From ac64f1634590c63facd49747946d4c90975ed7be Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:44 +0100
+Subject: [PATCH 242/246] migration: small changes around rate-limiting
+
+This patch extracts a few small changes from the next patch, which
+are unrelated to adding generic rate-limiting functionality to
+QEMUFile.  Make migration_set_rate_limit a simple accessor, and
+use qemu_file_set_rate_limit consistently.  Also fix a typo where
+INT_MAX should have been SIZE_MAX.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index def1e9e..5c7d04f 100644
+--- a/migration.c
++++ b/migration.c
+@@ -462,10 +462,15 @@ void qmp_migrate_set_speed(int64_t value, Error **errp)
+     if (value < 0) {
+         value = 0;
+     }
++    if (value > SIZE_MAX) {
++        value = SIZE_MAX;
++    }
+ 
+     s = migrate_get_current();
+     s->bandwidth_limit = value;
+-    qemu_file_set_rate_limit(s->file, s->bandwidth_limit);
++    if (s->file) {
++        qemu_file_set_rate_limit(s->file, s->bandwidth_limit / XFER_LIMIT_RATIO);
++    }
+ }
+ 
+ void qmp_migrate_set_downtime(double value, Error **errp)
+@@ -567,11 +572,8 @@ static int64_t migration_set_rate_limit(void *opaque, int64_t new_rate)
+     if (qemu_file_get_error(s->file)) {
+         goto out;
+     }
+-    if (new_rate > SIZE_MAX) {
+-        new_rate = SIZE_MAX;
+-    }
+ 
+-    s->xfer_limit = new_rate / XFER_LIMIT_RATIO;
++    s->xfer_limit = new_rate;
+ 
+ out:
+     return s->xfer_limit;
+@@ -614,7 +616,7 @@ static void *migration_thread(void *opaque)
+                 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+                 old_vm_running = runstate_is_running();
+                 vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+-                s->xfer_limit = INT_MAX;
++                qemu_file_set_rate_limit(s->file, INT_MAX);
+                 qemu_savevm_state_complete(s->file);
+                 qemu_mutex_unlock_iothread();
+                 if (!qemu_file_get_error(s->file)) {
+@@ -691,11 +693,12 @@ void migrate_fd_connect(MigrationState *s)
+     /* This is a best 1st approximation. ns to ms */
+     s->expected_downtime = max_downtime/1000000;
+ 
+-    s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO;
+-
+     s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
+     s->file = qemu_fopen_ops(s, &migration_file_ops);
+ 
++    qemu_file_set_rate_limit(s->file,
++                             s->bandwidth_limit / XFER_LIMIT_RATIO);
++
+     qemu_thread_create(&s->thread, migration_thread, s,
+                        QEMU_THREAD_JOINABLE);
+     notifier_list_notify(&migration_state_notifiers, s);
+-- 
+1.8.2.1
+
diff --git a/0243-migration-move-rate-limiting-to-QEMUFile.patch b/0243-migration-move-rate-limiting-to-QEMUFile.patch
new file mode 100644
index 0000000..a97b1d7
--- /dev/null
+++ b/0243-migration-move-rate-limiting-to-QEMUFile.patch
@@ -0,0 +1,272 @@
+From 61af111810219339d4029bb9a35ff930feb3ec49 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:45 +0100
+Subject: [PATCH 243/246] migration: move rate limiting to QEMUFile
+
+Rate limiting is now simply a byte counter; client call
+qemu_file_rate_limit() manually to determine if they have to exit.
+So it is possible and simple to move the functionality to QEMUFile.
+
+This makes the remaining functionality of s->file redundant;
+in the next patch we can remove it and write directly to s->migration_file.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ docs/migration.txt            | 20 +----------------
+ include/migration/qemu-file.h | 18 ++-------------
+ migration.c                   | 51 +------------------------------------------
+ savevm.c                      | 31 ++++++++++++++------------
+ 4 files changed, 21 insertions(+), 99 deletions(-)
+
+diff --git a/docs/migration.txt b/docs/migration.txt
+index f3ddd2f..0719a55 100644
+--- a/docs/migration.txt
++++ b/docs/migration.txt
+@@ -55,10 +55,7 @@ QEMUFile with:
+ QEMUFile *qemu_fopen_ops(void *opaque,
+                          QEMUFilePutBufferFunc *put_buffer,
+                          QEMUFileGetBufferFunc *get_buffer,
+-                         QEMUFileCloseFunc *close,
+-                         QEMUFileRateLimit *rate_limit,
+-                         QEMUFileSetRateLimit *set_rate_limit,
+-                         QEMUFileGetRateLimit *get_rate_limit);
++                         QEMUFileCloseFunc *close);
+ 
+ The functions have the following functionality:
+ 
+@@ -80,24 +77,9 @@ Close a file and return an error code.
+ 
+ typedef int (QEMUFileCloseFunc)(void *opaque);
+ 
+-Called to determine if the file has exceeded its bandwidth allocation.  The
+-bandwidth capping is a soft limit, not a hard limit.
+-
+-typedef int (QEMUFileRateLimit)(void *opaque);
+-
+-Called to change the current bandwidth allocation. This function must return
+-the new actual bandwidth. It should be new_rate if everything goes OK, and
+-the old rate otherwise.
+-
+-typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate);
+-typedef size_t (QEMUFileGetRateLimit)(void *opaque);
+-
+ You can use any internal state that you need using the opaque void *
+ pointer that is passed to all functions.
+ 
+-The rate limiting functions are used to limit the bandwidth used by
+-QEMU migration.
+-
+ The important functions for us are put_buffer()/get_buffer() that
+ allow to write/read a buffer into the QEMUFile.
+ 
+diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h
+index 25e8461..df81261 100644
+--- a/include/migration/qemu-file.h
++++ b/include/migration/qemu-file.h
+@@ -51,26 +51,11 @@ typedef int (QEMUFileCloseFunc)(void *opaque);
+  */
+ typedef int (QEMUFileGetFD)(void *opaque);
+ 
+-/* Called to determine if the file has exceeded its bandwidth allocation.  The
+- * bandwidth capping is a soft limit, not a hard limit.
+- */
+-typedef int (QEMUFileRateLimit)(void *opaque);
+-
+-/* Called to change the current bandwidth allocation. This function must return
+- * the new actual bandwidth. It should be new_rate if everything goes ok, and
+- * the old rate otherwise
+- */
+-typedef int64_t (QEMUFileSetRateLimit)(void *opaque, int64_t new_rate);
+-typedef int64_t (QEMUFileGetRateLimit)(void *opaque);
+-
+ typedef struct QEMUFileOps {
+     QEMUFilePutBufferFunc *put_buffer;
+     QEMUFileGetBufferFunc *get_buffer;
+     QEMUFileCloseFunc *close;
+     QEMUFileGetFD *get_fd;
+-    QEMUFileRateLimit *rate_limit;
+-    QEMUFileSetRateLimit *set_rate_limit;
+-    QEMUFileGetRateLimit *get_rate_limit;
+ } QEMUFileOps;
+ 
+ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops);
+@@ -109,7 +94,8 @@ unsigned int qemu_get_be32(QEMUFile *f);
+ uint64_t qemu_get_be64(QEMUFile *f);
+ 
+ int qemu_file_rate_limit(QEMUFile *f);
+-int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
++void qemu_file_reset_rate_limit(QEMUFile *f);
++void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate);
+ int64_t qemu_file_get_rate_limit(QEMUFile *f);
+ int qemu_file_get_error(QEMUFile *f);
+ 
+diff --git a/migration.c b/migration.c
+index 5c7d04f..ea84008 100644
+--- a/migration.c
++++ b/migration.c
+@@ -518,7 +518,6 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf,
+         return ret;
+     }
+ 
+-    s->bytes_xfer += size;
+     return size;
+ }
+ 
+@@ -543,49 +542,6 @@ static int migration_get_fd(void *opaque)
+     return qemu_get_fd(s->migration_file);
+ }
+ 
+-/*
+- * The meaning of the return values is:
+- *   0: We can continue sending
+- *   1: Time to stop
+- *   negative: There has been an error
+- */
+-static int migration_rate_limit(void *opaque)
+-{
+-    MigrationState *s = opaque;
+-    int ret;
+-
+-    ret = qemu_file_get_error(s->file);
+-    if (ret) {
+-        return ret;
+-    }
+-
+-    if (s->bytes_xfer >= s->xfer_limit) {
+-        return 1;
+-    }
+-
+-    return 0;
+-}
+-
+-static int64_t migration_set_rate_limit(void *opaque, int64_t new_rate)
+-{
+-    MigrationState *s = opaque;
+-    if (qemu_file_get_error(s->file)) {
+-        goto out;
+-    }
+-
+-    s->xfer_limit = new_rate;
+-
+-out:
+-    return s->xfer_limit;
+-}
+-
+-static int64_t migration_get_rate_limit(void *opaque)
+-{
+-    MigrationState *s = opaque;
+-
+-    return s->xfer_limit;
+-}
+-
+ static void *migration_thread(void *opaque)
+ {
+     MigrationState *s = opaque;
+@@ -646,7 +602,7 @@ static void *migration_thread(void *opaque)
+                 s->expected_downtime = s->dirty_bytes_rate / bandwidth;
+             }
+ 
+-            s->bytes_xfer = 0;
++            qemu_file_reset_rate_limit(s->file);
+             sleep_time = 0;
+             initial_time = current_time;
+             initial_bytes = qemu_ftell(s->file);
+@@ -679,9 +635,6 @@ static const QEMUFileOps migration_file_ops = {
+     .get_fd =         migration_get_fd,
+     .put_buffer =     migration_put_buffer,
+     .close =          migration_close,
+-    .rate_limit =     migration_rate_limit,
+-    .get_rate_limit = migration_get_rate_limit,
+-    .set_rate_limit = migration_set_rate_limit,
+ };
+ 
+ void migrate_fd_connect(MigrationState *s)
+@@ -689,10 +642,8 @@ void migrate_fd_connect(MigrationState *s)
+     s->state = MIG_STATE_ACTIVE;
+     trace_migrate_set_state(MIG_STATE_ACTIVE);
+ 
+-    s->bytes_xfer = 0;
+     /* This is a best 1st approximation. ns to ms */
+     s->expected_downtime = max_downtime/1000000;
+-
+     s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
+     s->file = qemu_fopen_ops(s, &migration_file_ops);
+ 
+diff --git a/savevm.c b/savevm.c
+index 43963ce..e9471a5 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -119,6 +119,9 @@ struct QEMUFile {
+     void *opaque;
+     int is_write;
+ 
++    int64_t bytes_xfer;
++    int64_t xfer_limit;
++
+     int64_t pos; /* start of buffer when writing, end of buffer
+                     when reading */
+     int buf_index;
+@@ -479,7 +482,6 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops)
+     f->opaque = opaque;
+     f->ops = ops;
+     f->is_write = 0;
+-
+     return f;
+ }
+ 
+@@ -605,6 +607,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)
+         memcpy(f->buf + f->buf_index, buf, l);
+         f->is_write = 1;
+         f->buf_index += l;
++        f->bytes_xfer += l;
+         buf += l;
+         size -= l;
+         if (f->buf_index >= IO_BUF_SIZE) {
+@@ -725,28 +728,28 @@ int64_t qemu_ftell(QEMUFile *f)
+ 
+ int qemu_file_rate_limit(QEMUFile *f)
+ {
+-    if (f->ops->rate_limit)
+-        return f->ops->rate_limit(f->opaque);
+-
++    if (qemu_file_get_error(f)) {
++        return 1;
++    }
++    if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) {
++        return 1;
++    }
+     return 0;
+ }
+ 
+ int64_t qemu_file_get_rate_limit(QEMUFile *f)
+ {
+-    if (f->ops->get_rate_limit)
+-        return f->ops->get_rate_limit(f->opaque);
+-
+-    return 0;
++    return f->xfer_limit;
+ }
+ 
+-int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate)
++void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit)
+ {
+-    /* any failed or completed migration keeps its state to allow probing of
+-     * migration data, but has no associated file anymore */
+-    if (f && f->ops->set_rate_limit)
+-        return f->ops->set_rate_limit(f->opaque, new_rate);
++    f->xfer_limit = limit;
++}
+ 
+-    return 0;
++void qemu_file_reset_rate_limit(QEMUFile *f)
++{
++    f->bytes_xfer = 0;
+ }
+ 
+ void qemu_put_be16(QEMUFile *f, unsigned int v)
+-- 
+1.8.2.1
+
diff --git a/0244-migration-move-contents-of-migration_close-to-migrat.patch b/0244-migration-move-contents-of-migration_close-to-migrat.patch
new file mode 100644
index 0000000..9b86465
--- /dev/null
+++ b/0244-migration-move-contents-of-migration_close-to-migrat.patch
@@ -0,0 +1,54 @@
+From 89c59de898603ea7ee0879f5e4244ab33dd4ec3d Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:46 +0100
+Subject: [PATCH 244/246] migration: move contents of migration_close to
+ migrate_fd_cleanup
+
+With this patch, the migration_file is not needed anymore.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 17 +++++++----------
+ 1 file changed, 7 insertions(+), 10 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index ea84008..949a5bc 100644
+--- a/migration.c
++++ b/migration.c
+@@ -272,6 +272,12 @@ static void migrate_fd_cleanup(void *opaque)
+         DPRINTF("closing file\n");
+         qemu_fclose(s->file);
+         s->file = NULL;
++
++        qemu_mutex_unlock_iothread();
++        qemu_thread_join(&s->thread);
++        qemu_mutex_lock_iothread();
++
++        migrate_fd_close(s);
+     }
+ 
+     assert(s->migration_file == NULL);
+@@ -523,16 +529,7 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf,
+ 
+ static int migration_close(void *opaque)
+ {
+-    MigrationState *s = opaque;
+-
+-    DPRINTF("closing\n");
+-
+-    qemu_mutex_unlock_iothread();
+-    qemu_thread_join(&s->thread);
+-    qemu_mutex_lock_iothread();
+-    assert(s->state != MIG_STATE_ACTIVE);
+-
+-    return migrate_fd_close(s);
++    return 0;
+ }
+ 
+ static int migration_get_fd(void *opaque)
+-- 
+1.8.2.1
+
diff --git a/0245-migration-eliminate-s-migration_file.patch b/0245-migration-eliminate-s-migration_file.patch
new file mode 100644
index 0000000..0705596
--- /dev/null
+++ b/0245-migration-eliminate-s-migration_file.patch
@@ -0,0 +1,198 @@
+From facf543c0113987a0fd9ec48138cd2da09c41efd Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:47 +0100
+Subject: [PATCH 245/246] migration: eliminate s->migration_file
+
+The indirection is useless now.  Backends can open s->file directly.
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ include/migration/migration.h |  2 --
+ migration-exec.c              |  4 ++--
+ migration-fd.c                |  2 +-
+ migration-tcp.c               |  4 ++--
+ migration-unix.c              |  4 ++--
+ migration.c                   | 51 ++++---------------------------------------
+ 6 files changed, 11 insertions(+), 56 deletions(-)
+
+diff --git a/include/migration/migration.h b/include/migration/migration.h
+index ae94706..bb617fd 100644
+--- a/include/migration/migration.h
++++ b/include/migration/migration.h
+@@ -36,9 +36,7 @@ struct MigrationState
+     size_t xfer_limit;
+     QemuThread thread;
+     QEMUBH *cleanup_bh;
+-
+     QEMUFile *file;
+-    QEMUFile *migration_file;
+ 
+     int state;
+     MigrationParams params;
+diff --git a/migration-exec.c b/migration-exec.c
+index 1c539de..deab4e3 100644
+--- a/migration-exec.c
++++ b/migration-exec.c
+@@ -35,8 +35,8 @@
+ 
+ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
+ {
+-    s->migration_file = qemu_popen_cmd(command, "w");
+-    if (s->migration_file == NULL) {
++    s->file = qemu_popen_cmd(command, "w");
++    if (s->file == NULL) {
+         error_setg_errno(errp, errno, "failed to popen the migration target");
+         return;
+     }
+diff --git a/migration-fd.c b/migration-fd.c
+index 07c758a..3d4613c 100644
+--- a/migration-fd.c
++++ b/migration-fd.c
+@@ -36,7 +36,7 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **
+     if (fd == -1) {
+         return;
+     }
+-    s->migration_file = qemu_fdopen(fd, "wb");
++    s->file = qemu_fdopen(fd, "wb");
+ 
+     migrate_fd_connect(s);
+ }
+diff --git a/migration-tcp.c b/migration-tcp.c
+index 5ea4f3d..b20ee58 100644
+--- a/migration-tcp.c
++++ b/migration-tcp.c
+@@ -35,11 +35,11 @@ static void tcp_wait_for_connect(int fd, void *opaque)
+ 
+     if (fd < 0) {
+         DPRINTF("migrate connect error\n");
+-        s->migration_file = NULL;
++        s->file = NULL;
+         migrate_fd_error(s);
+     } else {
+         DPRINTF("migrate connect success\n");
+-        s->migration_file = qemu_fopen_socket(fd, "wb");
++        s->file = qemu_fopen_socket(fd, "wb");
+         migrate_fd_connect(s);
+     }
+ }
+diff --git a/migration-unix.c b/migration-unix.c
+index 64bfa31..94b7022 100644
+--- a/migration-unix.c
++++ b/migration-unix.c
+@@ -35,11 +35,11 @@ static void unix_wait_for_connect(int fd, void *opaque)
+ 
+     if (fd < 0) {
+         DPRINTF("migrate connect error\n");
+-        s->migration_file = NULL;
++        s->file = NULL;
+         migrate_fd_error(s);
+     } else {
+         DPRINTF("migrate connect success\n");
+-        s->migration_file = qemu_fopen_socket(fd, "wb");
++        s->file = qemu_fopen_socket(fd, "wb");
+         migrate_fd_connect(s);
+     }
+ }
+diff --git a/migration.c b/migration.c
+index 949a5bc..68ce4c9 100644
+--- a/migration.c
++++ b/migration.c
+@@ -270,9 +270,6 @@ static void migrate_fd_cleanup(void *opaque)
+ 
+     if (s->file) {
+         DPRINTF("closing file\n");
+-        qemu_fclose(s->file);
+-        s->file = NULL;
+-
+         qemu_mutex_unlock_iothread();
+         qemu_thread_join(&s->thread);
+         qemu_mutex_lock_iothread();
+@@ -280,7 +277,7 @@ static void migrate_fd_cleanup(void *opaque)
+         migrate_fd_close(s);
+     }
+ 
+-    assert(s->migration_file == NULL);
++    assert(s->file == NULL);
+     assert(s->state != MIG_STATE_ACTIVE);
+ 
+     if (s->state != MIG_STATE_COMPLETED) {
+@@ -317,9 +314,9 @@ static void migrate_fd_cancel(MigrationState *s)
+ int migrate_fd_close(MigrationState *s)
+ {
+     int rc = 0;
+-    if (s->migration_file != NULL) {
+-        rc = qemu_fclose(s->migration_file);
+-        s->migration_file = NULL;
++    if (s->file != NULL) {
++        rc = qemu_fclose(s->file);
++        s->file = NULL;
+     }
+     return rc;
+ }
+@@ -506,39 +503,6 @@ int64_t migrate_xbzrle_cache_size(void)
+ 
+ /* migration thread support */
+ 
+-static int migration_put_buffer(void *opaque, const uint8_t *buf,
+-                               int64_t pos, int size)
+-{
+-    MigrationState *s = opaque;
+-    int ret;
+-
+-    DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos);
+-
+-    if (size <= 0) {
+-        return size;
+-    }
+-
+-    qemu_put_buffer(s->migration_file, buf, size);
+-    ret = qemu_file_get_error(s->migration_file);
+-    if (ret) {
+-        return ret;
+-    }
+-
+-    return size;
+-}
+-
+-static int migration_close(void *opaque)
+-{
+-    return 0;
+-}
+-
+-static int migration_get_fd(void *opaque)
+-{
+-    MigrationState *s = opaque;
+-
+-    return qemu_get_fd(s->migration_file);
+-}
+-
+ static void *migration_thread(void *opaque)
+ {
+     MigrationState *s = opaque;
+@@ -628,12 +592,6 @@ static void *migration_thread(void *opaque)
+     return NULL;
+ }
+ 
+-static const QEMUFileOps migration_file_ops = {
+-    .get_fd =         migration_get_fd,
+-    .put_buffer =     migration_put_buffer,
+-    .close =          migration_close,
+-};
+-
+ void migrate_fd_connect(MigrationState *s)
+ {
+     s->state = MIG_STATE_ACTIVE;
+@@ -642,7 +600,6 @@ void migrate_fd_connect(MigrationState *s)
+     /* This is a best 1st approximation. ns to ms */
+     s->expected_downtime = max_downtime/1000000;
+     s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s);
+-    s->file = qemu_fopen_ops(s, &migration_file_ops);
+ 
+     qemu_file_set_rate_limit(s->file,
+                              s->bandwidth_limit / XFER_LIMIT_RATIO);
+-- 
+1.8.2.1
+
diff --git a/0246-migration-inline-migrate_fd_close.patch b/0246-migration-inline-migrate_fd_close.patch
new file mode 100644
index 0000000..c969185
--- /dev/null
+++ b/0246-migration-inline-migrate_fd_close.patch
@@ -0,0 +1,50 @@
+From 9b421d01c4ffdf89ec93b84363357773d8e09083 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+Date: Fri, 22 Feb 2013 17:36:48 +0100
+Subject: [PATCH 246/246] migration: inline migrate_fd_close
+
+Reviewed-by: Orit Wasserman <owasserm at redhat.com>
+Reviewed-by: Juan Quintela <quintela at redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+Signed-off-by: Juan Quintela <quintela at redhat.com>
+---
+ migration.c | 14 ++------------
+ 1 file changed, 2 insertions(+), 12 deletions(-)
+
+diff --git a/migration.c b/migration.c
+index 68ce4c9..0aff06d 100644
+--- a/migration.c
++++ b/migration.c
+@@ -274,10 +274,10 @@ static void migrate_fd_cleanup(void *opaque)
+         qemu_thread_join(&s->thread);
+         qemu_mutex_lock_iothread();
+ 
+-        migrate_fd_close(s);
++        qemu_fclose(s->file);
++        s->file = NULL;
+     }
+ 
+-    assert(s->file == NULL);
+     assert(s->state != MIG_STATE_ACTIVE);
+ 
+     if (s->state != MIG_STATE_COMPLETED) {
+@@ -311,16 +311,6 @@ static void migrate_fd_cancel(MigrationState *s)
+     migrate_finish_set_state(s, MIG_STATE_CANCELLED);
+ }
+ 
+-int migrate_fd_close(MigrationState *s)
+-{
+-    int rc = 0;
+-    if (s->file != NULL) {
+-        rc = qemu_fclose(s->file);
+-        s->file = NULL;
+-    }
+-    return rc;
+-}
+-
+ void add_migration_state_change_notifier(Notifier *notify)
+ {
+     notifier_list_add(&migration_state_notifiers, notify);
+-- 
+1.8.2.1
+
diff --git a/qemu.spec b/qemu.spec
index c58ae55..69ce23a 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -131,7 +131,7 @@
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 1.4.1
-Release: 3%{?dist}
+Release: 4%{?dist}
 # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
@@ -199,6 +199,56 @@ Patch0106: 0106-docs-Fix-generating-qemu-doc.html-with-texinfo-5.patch
 # Fix crash with usbredir (bz #962826)
 Patch0107: 0107-usb-redir-Fix-crash-on-migration-with-no-client-conn.patch
 
+# qemu-km migration cleanup (bz #962954)
+# Moves migration notifiers to iothread, fixing spice assert
+Patch0200: 0200-ui-vnc-tls.c-fix-gnutls-warning.patch
+Patch0201: 0201-migration-change-initial-value-of-expected_downtime.patch
+Patch0202: 0202-migration-calculate-end-time-after-we-have-sent-the-.patch
+Patch0203: 0203-migration-don-t-account-sleep-time-for-calculating-b.patch
+Patch0204: 0204-migration-calculate-expected_downtime.patch
+Patch0205: 0205-migration-simplify-while-loop.patch
+Patch0206: 0206-migration-always-use-vm_stop_force_state.patch
+Patch0207: 0207-migration-move-more-error-handling-to-migrate_fd_cle.patch
+Patch0208: 0208-migration-push-qemu_savevm_state_cancel-out-of-qemu_.patch
+Patch0209: 0209-block-migration-remove-useless-calls-to-blk_mig_clea.patch
+Patch0210: 0210-qemu-file-pass-errno-from-qemu_fflush-via-f-last_err.patch
+Patch0211: 0211-migration-use-qemu_file_set_error-to-pass-error-code.patch
+Patch0212: 0212-qemu-file-temporarily-expose-qemu_file_set_error-and.patch
+Patch0213: 0213-migration-flush-all-data-to-fd-when-buffered_flush-i.patch
+Patch0214: 0214-migration-use-qemu_file_set_error.patch
+Patch0215: 0215-migration-simplify-error-handling.patch
+Patch0216: 0216-migration-do-not-nest-flushing-of-device-data.patch
+Patch0217: 0217-migration-add-migrate_set_state-tracepoint.patch
+Patch0218: 0218-migration-prepare-to-access-s-state-outside-critical.patch
+Patch0219: 0219-migration-cleanup-migration-including-thread-in-the-.patch
+Patch0220: 0220-block-migration-remove-variables-that-are-never-read.patch
+Patch0221: 0221-block-migration-small-preparatory-changes-for-lockin.patch
+Patch0222: 0222-block-migration-document-usage-of-state-across-threa.patch
+Patch0223: 0223-block-migration-add-lock.patch
+Patch0224: 0224-migration-reorder-SaveVMHandlers-members.patch
+Patch0225: 0225-migration-run-pending-iterate-callbacks-out-of-big-l.patch
+Patch0226: 0226-migration-run-setup-callbacks-out-of-big-lock.patch
+Patch0227: 0227-migration-yay-buffering-is-gone.patch
+Patch0228: 0228-Rename-buffered_-to-migration_.patch
+Patch0229: 0229-qemu-file-make-qemu_fflush-and-qemu_file_set_error-p.patch
+Patch0230: 0230-migration-eliminate-last_round.patch
+Patch0231: 0231-migration-detect-error-before-sleeping.patch
+Patch0232: 0232-migration-remove-useless-qemu_file_get_error-check.patch
+Patch0233: 0233-migration-use-qemu_file_rate_limit-consistently.patch
+Patch0234: 0234-migration-merge-qemu_popen_cmd-with-qemu_popen.patch
+Patch0235: 0235-qemu-file-fsync-a-writable-stdio-QEMUFile.patch
+Patch0236: 0236-qemu-file-check-exit-status-when-closing-a-pipe-QEMU.patch
+Patch0237: 0237-qemu-file-add-writable-socket-QEMUFile.patch
+Patch0238: 0238-qemu-file-simplify-and-export-qemu_ftell.patch
+Patch0239: 0239-migration-use-QEMUFile-for-migration-channel-lifetim.patch
+Patch0240: 0240-migration-use-QEMUFile-for-writing-outgoing-migratio.patch
+Patch0241: 0241-migration-use-qemu_ftell-to-compute-bandwidth.patch
+Patch0242: 0242-migration-small-changes-around-rate-limiting.patch
+Patch0243: 0243-migration-move-rate-limiting-to-QEMUFile.patch
+Patch0244: 0244-migration-move-contents-of-migration_close-to-migrat.patch
+Patch0245: 0245-migration-eliminate-s-migration_file.patch
+Patch0246: 0246-migration-inline-migrate_fd_close.patch
+
 BuildRequires: SDL-devel
 BuildRequires: zlib-devel
 BuildRequires: which
@@ -673,6 +723,54 @@ CAC emulation development files.
 # Fix crash with usbredir (bz #962826)
 %patch0107 -p1
 
+# qemu-km migration cleanup (bz #962954)
+%patch0200 -p1
+%patch0201 -p1
+%patch0202 -p1
+%patch0203 -p1
+%patch0204 -p1
+%patch0205 -p1
+%patch0206 -p1
+%patch0207 -p1
+%patch0208 -p1
+%patch0209 -p1
+%patch0210 -p1
+%patch0211 -p1
+%patch0212 -p1
+%patch0213 -p1
+%patch0214 -p1
+%patch0215 -p1
+%patch0216 -p1
+%patch0217 -p1
+%patch0218 -p1
+%patch0219 -p1
+%patch0220 -p1
+%patch0221 -p1
+%patch0222 -p1
+%patch0223 -p1
+%patch0224 -p1
+%patch0225 -p1
+%patch0226 -p1
+%patch0227 -p1
+%patch0228 -p1
+%patch0229 -p1
+%patch0230 -p1
+%patch0231 -p1
+%patch0232 -p1
+%patch0233 -p1
+%patch0234 -p1
+%patch0235 -p1
+%patch0236 -p1
+%patch0237 -p1
+%patch0238 -p1
+%patch0239 -p1
+%patch0240 -p1
+%patch0241 -p1
+%patch0242 -p1
+%patch0243 -p1
+%patch0244 -p1
+%patch0245 -p1
+%patch0246 -p1
 
 %build
 %if %{with kvmonly}
@@ -1288,6 +1386,9 @@ getent passwd qemu >/dev/null || \
 %endif
 
 %changelog
+* Wed May 22 2013 Alon Levy <alevy at redhat.com> - 2:1.4.1-4
+- Backport migration cleanup (bz #962954)
+
 * Thu May 16 2013 Paolo Bonzini <pbonzini at redhat.com> - 2:1.4.1-3
 - Drop loading of vhost-net module (bz #963198)
 


More information about the scm-commits mailing list