Re: [PATCH v3 0/6] migration: check required entries and sections are loaded

2023-11-07 Thread Juan Quintela
"Michael S. Tsirkin"  wrote:
> On Mon, Nov 06, 2023 at 03:35:54PM +0400, marcandre.lur...@redhat.com wrote:
>> From: Marc-André Lureau 
>> 
>> Hi,
>> 
>> Surprisingly, the migration code doesn't check that required migration 
>> entries
>> and subsections are loaded. Either optional or required sections are both
>> ignored when missing. According to the documentation a "newer QEMU that knows
>> about a subsection can (with care) load a stream from an older QEMU that 
>> didn't
>> send the subsection". I propose this behaviour to be limited to "optional"
>> sections only.
>> 
>> This series has a few preliminary fixes, add new checks that entries are
>> loaded once and required ones have been loaded, add some tests and
>> documentation update.
>> 
>> thanks
>
> I think this kind of thing is better deferred to the next release -
> unless you have something specific in mind this fixes?

I agree with you.

Later, Juan.

>> v3:
>>  - rebased, drop RFC status
>>  - switch from tracepoint + returning an error to report for missing
>>subsections, as we worry about potential regressions
>>  - add r-b tags
>> 
>> v2:
>>  - add "migration: rename vmstate_save_needed->vmstate_section_needed"
>>  - add "migration: set file error on subsection loading"
>>  - add subsection tests
>>  - update the documentation
>> 
>> Marc-André Lureau (6):
>>   block/fdc: 'phase' is not needed on load
>>   virtio: make endian_needed() work during loading
>>   migration: check required subsections are loaded, once
>>   migration: check required entries are loaded, once
>>   test-vmstate: add some subsection tests
>>   docs/migration: reflect the changes about needed subsections
>> 
>>  docs/devel/migration.rst  |  17 +++---
>>  hw/block/fdc.c|   5 ++
>>  hw/virtio/virtio.c|   6 +-
>>  migration/savevm.c|  43 ++
>>  migration/vmstate.c   |  40 -
>>  tests/unit/test-vmstate.c | 116 ++
>>  6 files changed, 215 insertions(+), 12 deletions(-)
>> 
>> -- 
>> 2.41.0




Re: [PULL 38/40] migration: Implement MigrateChannelList to qmp migration flow.

2023-11-06 Thread Juan Quintela
Peter Maydell  wrote:
> On Thu, 2 Nov 2023 at 11:46, Juan Quintela  wrote:
>>
>> From: Het Gala 
>>
>> Integrate MigrateChannelList with all transport backends
>> (socket, exec and rdma) for both src and dest migration
>> endpoints for qmp migration.
>>
>> For current series, limit the size of MigrateChannelList
>> to single element (single interface) as runtime check.
>>
>> Suggested-by: Aravind Retnakaran 
>> Signed-off-by: Het Gala 
>> Signed-off-by: Fabiano Rosas 
>> Reviewed-by: Juan Quintela 
>> Signed-off-by: Juan Quintela 
>> Message-ID: <20231023182053.8711-13-faro...@suse.de>
>
> Hi; after this migration pull there seem to be a lot of
> new Coverity issues in migration code. Could somebody
> take a look at them, please?


Hi

I received this, looking into it.

Later, Juan.

>
> Here's one in particular (CID 1523826, 1523828):
>
>> @@ -1927,35 +1933,38 @@ void qmp_migrate(const char *uri, bool has_channels,
>>  bool resume_requested;
>>  Error *local_err = NULL;
>>  MigrationState *s = migrate_get_current();
>> -g_autoptr(MigrationAddress) channel = NULL;
>> +MigrationChannel *channel = NULL;
>> +MigrationAddress *addr = NULL;
>
> 'channel' in this function used to be auto-freed, but now it is not...
>
>>
>>  /*
>>   * Having preliminary checks for uri and channel
>>   */
>> -if (has_channels) {
>> -error_setg(errp, "'channels' argument should not be set yet.");
>> -return;
>> -}
>> -
>>  if (uri && has_channels) {
>>  error_setg(errp, "'uri' and 'channels' arguments are mutually "
>> "exclusive; exactly one of the two should be present in "
>> "'migrate' qmp command ");
>>  return;
>> -}
>> -
>> -if (!uri && !has_channels) {
>> +} else if (channels) {
>> +/* To verify that Migrate channel list has only item */
>> +if (channels->next) {
>> +error_setg(errp, "Channel list has more than one entries");
>> +return;
>> +}
>> +channel = channels->value;
>> +} else if (uri) {
>> +/* caller uses the old URI syntax */
>> +if (!migrate_uri_parse(uri, , errp)) {
>> +return;
>> +}
>
> ...and here migrate_uri_parse() allocates memory which is
> returned into 'channel'...
>
>> +} else {
>>  error_setg(errp, "neither 'uri' or 'channels' argument are "
>> "specified in 'migrate' qmp command ");
>>  return;
>>  }
>> -
>> -if (!migrate_uri_parse(uri, , errp)) {
>> -return;
>> -}
>> +addr = channel->addr;
>>
>>  /* transport mechanism not suitable for migration? */
>> -if (!migration_channels_and_transport_compatible(channel, errp)) {
>> +if (!migration_channels_and_transport_compatible(addr, errp)) {
>>  return;
>>  }
>>
>> @@ -1972,8 +1981,8 @@ void qmp_migrate(const char *uri, bool has_channels,
>>  }
>>  }
>>
>> -if (channel->transport == MIGRATION_ADDRESS_TYPE_SOCKET) {
>> -SocketAddress *saddr = >u.socket;
>> +if (addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) {
>> +SocketAddress *saddr = >u.socket;
>>  if (saddr->type == SOCKET_ADDRESS_TYPE_INET ||
>>  saddr->type == SOCKET_ADDRESS_TYPE_UNIX ||
>>  saddr->type == SOCKET_ADDRESS_TYPE_VSOCK) {
>> @@ -1982,13 +1991,13 @@ void qmp_migrate(const char *uri, bool has_channels,
>>  fd_start_outgoing_migration(s, saddr->u.fd.str, _err);
>>  }
>>  #ifdef CONFIG_RDMA
>> -} else if (channel->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
>> -rdma_start_outgoing_migration(s, >u.rdma, _err);
>> +} else if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
>> +rdma_start_outgoing_migration(s, >u.rdma, _err);
>>  #endif
>> -} else if (channel->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
>> -exec_start_outgoing_migration(s, channel->u.exec.args, _err);
>> -} else if (channel->transport == MIGRATION_ADDRESS_TYPE_FILE) {
>> -file_start_outgoing_migration(s, >u.file, _err);
>> +} else if (addr->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
>> +exec_start_outgoing_migration(s, addr->u.exec.args, _err);
>> +} else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) {
>> +file_start_outgoing_migration(s, >u.file, _err);
>>  } else {
>>  error_setg(_err, QERR_INVALID_PARAMETER_VALUE, "uri",
>> "a valid migration protocol");
>
> ...which is leaked because we don't add any code for freeing
> channel to compensate for it no longer being autofreed.
>
> thanks
> -- PMM




[PULL 36/40] migration: New migrate and migrate-incoming argument 'channels'

2023-11-02 Thread Juan Quintela
From: Het Gala 

MigrateChannelList allows to connect accross multiple interfaces.
Add MigrateChannelList struct as argument to migration QAPIs.

We plan to include multiple channels in future, to connnect
multiple interfaces. Hence, we choose 'MigrateChannelList'
as the new argument over 'MigrateChannel' to make migration
QAPIs future proof.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Acked-by: Markus Armbruster 
Reviewed-by: Daniel P. Berrangé 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-10-faro...@suse.de>
---
 qapi/migration.json| 113 -
 migration/migration-hmp-cmds.c |   6 +-
 migration/migration.c  |  56 ++--
 system/vl.c|   2 +-
 4 files changed, 167 insertions(+), 10 deletions(-)

diff --git a/qapi/migration.json b/qapi/migration.json
index 182b150b87..975761eebd 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1641,6 +1641,34 @@
 'rdma': 'InetSocketAddress',
 'file': 'FileMigrationArgs' } }
 
+##
+# @MigrationChannelType:
+#
+# The migration channel-type request options.
+#
+# @main: Main outbound migration channel.
+#
+# Since 8.1
+##
+{ 'enum': 'MigrationChannelType',
+  'data': [ 'main' ] }
+
+##
+# @MigrationChannel:
+#
+# Migration stream channel parameters.
+#
+# @channel-type: Channel type for transfering packet information.
+#
+# @addr: Migration endpoint configuration on destination interface.
+#
+# Since 8.1
+##
+{ 'struct': 'MigrationChannel',
+  'data': {
+  'channel-type': 'MigrationChannelType',
+  'addr': 'MigrationAddress' } }
+
 ##
 # @migrate:
 #
@@ -1648,6 +1676,9 @@
 #
 # @uri: the Uniform Resource Identifier of the destination VM
 #
+# @channels: list of migration stream channels with each stream in the
+# list connected to a destination interface endpoint.
+#
 # @blk: do block migration (full disk copy)
 #
 # @inc: incremental disk copy migration
@@ -1677,13 +1708,57 @@
 # 3. The user Monitor's "detach" argument is invalid in QMP and should
 #not be used
 #
+# 4. The uri argument should have the Uniform Resource Identifier of
+#default destination VM. This connection will be bound to default
+#network.
+#
+# 5. For now, number of migration streams is restricted to one, i.e
+#number of items in 'channels' list is just 1.
+#
+# 6. The 'uri' and 'channels' arguments are mutually exclusive;
+#exactly one of the two should be present.
+#
 # Example:
 #
 # -> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } }
 # <- { "return": {} }
+# -> { "execute": "migrate",
+#  "arguments": {
+#  "channels": [ { "channel-type": "main",
+#  "addr": { "transport": "socket",
+#"type": "inet",
+#"host": "10.12.34.9",
+#"port": "1050" } } ] } }
+# <- { "return": {} }
+#
+# -> { "execute": "migrate",
+#  "arguments": {
+#  "channels": [ { "channel-type": "main",
+#  "addr": { "transport": "exec",
+#"args": [ "/bin/nc", "-p", "6000",
+#  "/some/sock" ] } } ] } }
+# <- { "return": {} }
+#
+# -> { "execute": "migrate",
+#  "arguments": {
+#  "channels": [ { "channel-type": "main",
+#  "addr": { "transport": "rdma",
+#"host": "10.12.34.9",
+#"port": "1050" } } ] } }
+# <- { "return": {} }
+#
+# -> { "execute": "migrate",
+#  "arguments": {
+#  "channels": [ { "channel-type": "main",
+#  "addr": { "transport": "file",
+#"filename": "/tmp/migfile",
+#"offset": "0x1000" } } ] } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate',
   'data': {'uri': 'str',
+   '*channels': [ 'MigrationChannel' ],
'*blk': { 'type': 'bool', 'features': [ 'deprecated' ] },
'*inc': { 'type': 'bool', 'features': [ 'deprecated' ] },
'*detach': 'bool', '*resume': 'bool' } }
@@ -1697,6 +1772,9 @

[PULL 35/40] migration: Convert the file backend to the new QAPI syntax

2023-11-02 Thread Juan Quintela
From: Fabiano Rosas 

Convert the file: URI to accept a FileMigrationArgs to be compatible
with the new migration QAPI.

Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-9-faro...@suse.de>
---
 migration/file.h  |  9 ++---
 migration/file.c  | 22 +++---
 migration/migration.c | 10 --
 3 files changed, 17 insertions(+), 24 deletions(-)

diff --git a/migration/file.h b/migration/file.h
index 3888a57105..37d6a08bfc 100644
--- a/migration/file.h
+++ b/migration/file.h
@@ -7,9 +7,12 @@
 
 #ifndef QEMU_MIGRATION_FILE_H
 #define QEMU_MIGRATION_FILE_H
-void file_start_incoming_migration(const char *filename, Error **errp);
 
-void file_start_outgoing_migration(MigrationState *s, const char *filename,
-   Error **errp);
+#include "qapi/qapi-types-migration.h"
+
+void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp);
+
+void file_start_outgoing_migration(MigrationState *s,
+   FileMigrationArgs *file_args, Error **errp);
 int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp);
 #endif
diff --git a/migration/file.c b/migration/file.c
index ec069ef329..5d4975f43e 100644
--- a/migration/file.c
+++ b/migration/file.c
@@ -36,20 +36,16 @@ int file_parse_offset(char *filespec, uint64_t *offsetp, 
Error **errp)
 return 0;
 }
 
-void file_start_outgoing_migration(MigrationState *s, const char *filespec,
-   Error **errp)
+void file_start_outgoing_migration(MigrationState *s,
+   FileMigrationArgs *file_args, Error **errp)
 {
-g_autofree char *filename = g_strdup(filespec);
 g_autoptr(QIOChannelFile) fioc = NULL;
-uint64_t offset = 0;
+g_autofree char *filename = g_strdup(file_args->filename);
+uint64_t offset = file_args->offset;
 QIOChannel *ioc;
 
 trace_migration_file_outgoing(filename);
 
-if (file_parse_offset(filename, , errp)) {
-return;
-}
-
 fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC,
  0600, errp);
 if (!fioc) {
@@ -73,19 +69,15 @@ static gboolean file_accept_incoming_migration(QIOChannel 
*ioc,
 return G_SOURCE_REMOVE;
 }
 
-void file_start_incoming_migration(const char *filespec, Error **errp)
+void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp)
 {
-g_autofree char *filename = g_strdup(filespec);
+g_autofree char *filename = g_strdup(file_args->filename);
 QIOChannelFile *fioc = NULL;
-uint64_t offset = 0;
+uint64_t offset = file_args->offset;
 QIOChannel *ioc;
 
 trace_migration_file_incoming(filename);
 
-if (file_parse_offset(filename, , errp)) {
-return;
-}
-
 fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp);
 if (!fioc) {
 return;
diff --git a/migration/migration.c b/migration/migration.c
index 0911fb310c..04037b340c 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -508,7 +508,6 @@ static bool migrate_uri_parse(const char *uri,
 
 static void qemu_start_incoming_migration(const char *uri, Error **errp)
 {
-const char *p = NULL;
 g_autoptr(MigrationAddress) channel = NULL;
 MigrationIncomingState *mis = migration_incoming_get_current();
 
@@ -551,8 +550,8 @@ static void qemu_start_incoming_migration(const char *uri, 
Error **errp)
 #endif
 } else if (channel->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
 exec_start_incoming_migration(channel->u.exec.args, errp);
-} else if (strstart(uri, "file:", )) {
-file_start_incoming_migration(p, errp);
+} else if (channel->transport == MIGRATION_ADDRESS_TYPE_FILE) {
+file_start_incoming_migration(>u.file, errp);
 } else {
 error_setg(errp, "unknown migration protocol: %s", uri);
 }
@@ -1900,7 +1899,6 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
 bool resume_requested;
 Error *local_err = NULL;
 MigrationState *s = migrate_get_current();
-const char *p = NULL;
 g_autoptr(MigrationAddress) channel = NULL;
 
 /* URI is not suitable for migration? */
@@ -1940,8 +1938,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
 #endif
 } else if (channel->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
 exec_start_outgoing_migration(s, channel->u.exec.args, _err);
-} else if (strstart(uri, "file:", )) {
-file_start_outgoing_migration(s, p, _err);
+} else if (channel->transport == MIGRATION_ADDRESS_TYPE_FILE) {
+file_start_outgoing_migration(s, >u.file, _err);
 } else {
 error_setg(_err, QERR_INVALID_PARAMETER_VALUE, "uri",
"a valid migration protocol");
-- 
2.41.0




[PULL 24/40] cpr: reboot mode

2023-11-02 Thread Juan Quintela
From: Steve Sistare 

Add the cpr-reboot migration mode.  Usage:

$ qemu-system-$arch -monitor stdio ...
QEMU 8.1.50 monitor - type 'help' for more information
(qemu) migrate_set_capability x-ignore-shared on
(qemu) migrate_set_parameter mode cpr-reboot
(qemu) migrate -d file:vm.state
(qemu) info status
VM status: paused (postmigrate)
(qemu) quit

$ qemu-system-$arch -monitor stdio -incoming defer ...
QEMU 8.1.50 monitor - type 'help' for more information
(qemu) migrate_set_capability x-ignore-shared on
(qemu) migrate_set_parameter mode cpr-reboot
(qemu) migrate_incoming file:vm.state
(qemu) info status
VM status: running

In this mode, the migrate command saves state to a file, allowing one
to quit qemu, reboot to an updated kernel, and restart an updated version
of qemu.  The caller must specify a migration URI that writes to and reads
from a file.  Unlike normal mode, the use of certain local storage options
does not block the migration, but the caller must not modify guest block
devices between the quit and restart.  To avoid saving guest RAM to the
file, the memory backend must be shared, and the @x-ignore-shared migration
capability must be set.  Guest RAM must be non-volatile across reboot, such
as by backing it with a dax device, but this is not enforced.  The restarted
qemu arguments must match those used to initially start qemu, plus the
-incoming option.

Signed-off-by: Steve Sistare 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <1698263069-406971-6-git-send-email-steven.sist...@oracle.com>
---
 qapi/migration.json  | 15 ++-
 hw/core/qdev-properties-system.c |  2 +-
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/qapi/migration.json b/qapi/migration.json
index 47c02a9346..3daeffc95d 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -636,9 +636,22 @@
 #
 # @normal: the original form of migration. (since 8.2)
 #
+# @cpr-reboot: The migrate command saves state to a file, allowing one to
+#  quit qemu, reboot to an updated kernel, and restart an updated
+#  version of qemu.  The caller must specify a migration URI
+#  that writes to and reads from a file.  Unlike normal mode,
+#  the use of certain local storage options does not block the
+#  migration, but the caller must not modify guest block devices
+#  between the quit and restart.  To avoid saving guest RAM to the
+#  file, the memory backend must be shared, and the 
@x-ignore-shared
+#  migration capability must be set.  Guest RAM must be 
non-volatile
+#  across reboot, such as by backing it with a dax device, but this
+#  is not enforced.  The restarted qemu arguments must match those
+#  used to initially start qemu, plus the -incoming option.
+#  (since 8.2)
 ##
 { 'enum': 'MigMode',
-  'data': [ 'normal' ] }
+  'data': [ 'normal', 'cpr-reboot' ] }
 
 ##
 # @BitmapMigrationBitmapAliasTransform:
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index b9179e8917..2f1dbb3fd7 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -680,7 +680,7 @@ QEMU_BUILD_BUG_ON(sizeof(MigMode) != sizeof(int));
 const PropertyInfo qdev_prop_mig_mode = {
 .name = "MigMode",
 .description = "mig_mode values, "
-   "normal",
+   "normal,cpr-reboot",
 .enum_table = _lookup,
 .get = qdev_propinfo_get_enum,
 .set = qdev_propinfo_set_enum,
-- 
2.41.0




[PULL 33/40] migration: convert rdma backend to accept MigrateAddress

2023-11-02 Thread Juan Quintela
From: Het Gala 

RDMA based transport backend for 'migrate'/'migrate-incoming' QAPIs
accept new wire protocol of MigrateAddress struct.

It is achived by parsing 'uri' string and storing migration parameters
required for RDMA connection into well defined InetSocketAddress struct.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Reviewed-by: Daniel P. Berrangé 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-7-faro...@suse.de>
---
 migration/rdma.h  |  6 --
 migration/migration.c |  8 
 migration/rdma.c  | 33 +++--
 3 files changed, 19 insertions(+), 28 deletions(-)

diff --git a/migration/rdma.h b/migration/rdma.h
index 30b15b4466..a8d27f33b8 100644
--- a/migration/rdma.h
+++ b/migration/rdma.h
@@ -14,15 +14,17 @@
  *
  */
 
+#include "qemu/sockets.h"
+
 #ifndef QEMU_MIGRATION_RDMA_H
 #define QEMU_MIGRATION_RDMA_H
 
 #include "exec/memory.h"
 
-void rdma_start_outgoing_migration(void *opaque, const char *host_port,
+void rdma_start_outgoing_migration(void *opaque, InetSocketAddress *host_port,
Error **errp);
 
-void rdma_start_incoming_migration(const char *host_port, Error **errp);
+void rdma_start_incoming_migration(InetSocketAddress *host_port, Error **errp);
 
 /*
  * Constants used by rdma return codes
diff --git a/migration/migration.c b/migration/migration.c
index 846877135a..8c26672630 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -534,7 +534,7 @@ static void qemu_start_incoming_migration(const char *uri, 
Error **errp)
 fd_start_incoming_migration(saddr->u.fd.str, errp);
 }
 #ifdef CONFIG_RDMA
-} else if (strstart(uri, "rdma:", )) {
+} else if (channel->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
 if (migrate_compress()) {
 error_setg(errp, "RDMA and compression can't be used together");
 return;
@@ -547,7 +547,7 @@ static void qemu_start_incoming_migration(const char *uri, 
Error **errp)
 error_setg(errp, "RDMA and multifd can't be used together");
 return;
 }
-rdma_start_incoming_migration(p, errp);
+rdma_start_incoming_migration(>u.rdma, errp);
 #endif
 } else if (strstart(uri, "exec:", )) {
 exec_start_incoming_migration(p, errp);
@@ -1935,8 +1935,8 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
 fd_start_outgoing_migration(s, saddr->u.fd.str, _err);
 }
 #ifdef CONFIG_RDMA
-} else if (strstart(uri, "rdma:", )) {
-rdma_start_outgoing_migration(s, p, _err);
+} else if (channel->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
+rdma_start_outgoing_migration(s, >u.rdma, _err);
 #endif
 } else if (strstart(uri, "exec:", )) {
 exec_start_outgoing_migration(s, p, _err);
diff --git a/migration/rdma.c b/migration/rdma.c
index 2938db4f64..6a29e53daf 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -289,7 +289,6 @@ typedef struct RDMALocalBlocks {
 typedef struct RDMAContext {
 char *host;
 int port;
-char *host_port;
 
 RDMAWorkRequestData wr_data[RDMA_WRID_MAX];
 
@@ -2431,9 +2430,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma)
 rdma->channel = NULL;
 }
 g_free(rdma->host);
-g_free(rdma->host_port);
 rdma->host = NULL;
-rdma->host_port = NULL;
 }
 
 
@@ -2723,28 +2720,16 @@ static void qemu_rdma_return_path_dest_init(RDMAContext 
*rdma_return_path,
 rdma_return_path->is_return_path = true;
 }
 
-static RDMAContext *qemu_rdma_data_init(const char *host_port, Error **errp)
+static RDMAContext *qemu_rdma_data_init(InetSocketAddress *saddr, Error **errp)
 {
 RDMAContext *rdma = NULL;
-InetSocketAddress *addr;
 
 rdma = g_new0(RDMAContext, 1);
 rdma->current_index = -1;
 rdma->current_chunk = -1;
 
-addr = g_new(InetSocketAddress, 1);
-if (!inet_parse(addr, host_port, NULL)) {
-rdma->port = atoi(addr->port);
-rdma->host = g_strdup(addr->host);
-rdma->host_port = g_strdup(host_port);
-} else {
-error_setg(errp, "RDMA ERROR: bad RDMA migration address '%s'",
-   host_port);
-g_free(rdma);
-rdma = NULL;
-}
-
-qapi_free_InetSocketAddress(addr);
+rdma->host = g_strdup(saddr->host);
+rdma->port = atoi(saddr->port);
 return rdma;
 }
 
@@ -3353,6 +3338,7 @@ static int qemu_rdma_accept(RDMAContext *rdma)
 .private_data_len = sizeof(cap),
  };
 RDMAContext *rdma_return_path = NULL;
+g_autoptr(InetSocketAddress) isock = g_new0(InetSocketAddress, 1);
 struct rdma_cm_event *cm_event;
 struct ibv_context *verbs;

[PULL 40/40] migration: modify test_multifd_tcp_none() to use new QAPI syntax.

2023-11-02 Thread Juan Quintela
From: Het Gala 

modify multifd tcp common test to incorporate the new QAPI
syntax defined.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-15-faro...@suse.de>
---
 tests/qtest/migration-test.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 047b7194df..e803b46039 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -1310,7 +1310,12 @@ static int migrate_postcopy_prepare(QTestState 
**from_ptr,
 
 migrate_prepare_for_dirty_mem(from);
 qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
- "  'arguments': { 'uri': 'tcp:127.0.0.1:0' }}");
+ "  'arguments': { "
+ "  'channels': [ { 'channel-type': 'main',"
+ "  'addr': { 'transport': 'socket',"
+ "'type': 'inet',"
+ "'host': '127.0.0.1',"
+ "'port': '0' } } ] } }");
 
 /* Wait for the first serial output from the source */
 wait_for_serial("src_serial");
-- 
2.41.0




[PULL 34/40] migration: convert exec backend to accept MigrateAddress.

2023-11-02 Thread Juan Quintela
From: Het Gala 

Exec transport backend for 'migrate'/'migrate-incoming' QAPIs accept
new wire protocol of MigrateAddress struct.

It is achived by parsing 'uri' string and storing migration parameters
required for exec connection into strList struct.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-8-faro...@suse.de>
---
 migration/exec.h  |  4 +--
 migration/exec.c  | 73 +++
 migration/migration.c |  8 ++---
 3 files changed, 59 insertions(+), 26 deletions(-)

diff --git a/migration/exec.h b/migration/exec.h
index 736cd71028..3107f205e3 100644
--- a/migration/exec.h
+++ b/migration/exec.h
@@ -23,8 +23,8 @@
 #ifdef WIN32
 const char *exec_get_cmd_path(void);
 #endif
-void exec_start_incoming_migration(const char *host_port, Error **errp);
+void exec_start_incoming_migration(strList *host_port, Error **errp);
 
-void exec_start_outgoing_migration(MigrationState *s, const char *host_port,
+void exec_start_outgoing_migration(MigrationState *s, strList *host_port,
Error **errp);
 #endif
diff --git a/migration/exec.c b/migration/exec.c
index 32f5143dfd..47d2f3b8fb 100644
--- a/migration/exec.c
+++ b/migration/exec.c
@@ -39,20 +39,51 @@ const char *exec_get_cmd_path(void)
 }
 #endif
 
-void exec_start_outgoing_migration(MigrationState *s, const char *command, 
Error **errp)
+/* provides the length of strList */
+static int
+str_list_length(strList *list)
+{
+int len = 0;
+strList *elem;
+
+for (elem = list; elem != NULL; elem = elem->next) {
+len++;
+}
+
+return len;
+}
+
+static void
+init_exec_array(strList *command, char **argv, Error **errp)
+{
+int i = 0;
+strList *lst;
+
+for (lst = command; lst; lst = lst->next) {
+argv[i++] = lst->value;
+}
+
+argv[i] = NULL;
+return;
+}
+
+void exec_start_outgoing_migration(MigrationState *s, strList *command,
+   Error **errp)
 {
 QIOChannel *ioc;
 
-#ifdef WIN32
-const char *argv[] = { exec_get_cmd_path(), "/c", command, NULL };
-#else
-const char *argv[] = { "/bin/sh", "-c", command, NULL };
-#endif
+int length = str_list_length(command);
+g_auto(GStrv) argv = (char **) g_new0(const char *, length + 1);
 
-trace_migration_exec_outgoing(command);
-ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
-O_RDWR,
-errp));
+init_exec_array(command, argv, errp);
+g_autofree char *new_command = g_strjoinv(" ", (char **)argv);
+
+trace_migration_exec_outgoing(new_command);
+ioc = QIO_CHANNEL(
+qio_channel_command_new_spawn(
+(const char * const *) g_steal_pointer(),
+O_RDWR,
+errp));
 if (!ioc) {
 return;
 }
@@ -71,20 +102,22 @@ static gboolean exec_accept_incoming_migration(QIOChannel 
*ioc,
 return G_SOURCE_REMOVE;
 }
 
-void exec_start_incoming_migration(const char *command, Error **errp)
+void exec_start_incoming_migration(strList *command, Error **errp)
 {
 QIOChannel *ioc;
 
-#ifdef WIN32
-const char *argv[] = { exec_get_cmd_path(), "/c", command, NULL };
-#else
-const char *argv[] = { "/bin/sh", "-c", command, NULL };
-#endif
+int length = str_list_length(command);
+g_auto(GStrv) argv = (char **) g_new0(const char *, length + 1);
 
-trace_migration_exec_incoming(command);
-ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
-O_RDWR,
-errp));
+init_exec_array(command, argv, errp);
+g_autofree char *new_command = g_strjoinv(" ", (char **)argv);
+
+trace_migration_exec_incoming(new_command);
+ioc = QIO_CHANNEL(
+qio_channel_command_new_spawn(
+(const char * const *) g_steal_pointer(),
+O_RDWR,
+errp));
 if (!ioc) {
 return;
 }
diff --git a/migration/migration.c b/migration/migration.c
index 8c26672630..0911fb310c 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -549,8 +549,8 @@ static void qemu_start_incoming_migration(const char *uri, 
Error **errp)
 }
 rdma_start_incoming_migration(>u.rdma, errp);
 #endif
-} else if (strstart(uri, "exec:", )) {
-exec_start_incoming_migration(p, errp);
+} else if (channel->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
+exec_start_incoming_migration(channel->u.exec.args, errp);
 } else if (strstart(uri, "file:", )) {
 file_start_incoming_m

[PULL 39/40] migration: Implement MigrateChannelList to hmp migration flow.

2023-11-02 Thread Juan Quintela
From: Het Gala 

Integrate MigrateChannelList with all transport backends
(socket, exec and rdma) for both src and dest migration
endpoints for hmp migration.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Signed-off-by: Fabiano Rosas 
Message-ID: <20231023182053.8711-14-faro...@suse.de>
Signed-off-by: Juan Quintela 
---
 migration/migration.h  |  3 ++-
 migration/migration-hmp-cmds.c | 23 +--
 migration/migration.c  |  5 ++---
 3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/migration/migration.h b/migration/migration.h
index af8c965b7f..cf2c9c88e0 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -520,7 +520,8 @@ bool check_dirty_bitmap_mig_alias_map(const 
BitmapMigrationNodeAliasList *bbm,
   Error **errp);
 
 void migrate_add_address(SocketAddress *address);
-
+bool migrate_uri_parse(const char *uri, MigrationChannel **channel,
+   Error **errp);
 int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque);
 
 #define qemu_ram_foreach_block \
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 6ec778a990..86ae832176 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -451,9 +451,18 @@ void hmp_migrate_incoming(Monitor *mon, const QDict *qdict)
 {
 Error *err = NULL;
 const char *uri = qdict_get_str(qdict, "uri");
+MigrationChannelList *caps = NULL;
+g_autoptr(MigrationChannel) channel = NULL;
 
-qmp_migrate_incoming(uri, false, NULL, );
+if (!migrate_uri_parse(uri, , )) {
+goto end;
+}
+QAPI_LIST_PREPEND(caps, g_steal_pointer());
 
+qmp_migrate_incoming(NULL, true, caps, );
+qapi_free_MigrationChannelList(caps);
+
+end:
 hmp_handle_error(mon, err);
 }
 
@@ -753,6 +762,8 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
 bool resume = qdict_get_try_bool(qdict, "resume", false);
 const char *uri = qdict_get_str(qdict, "uri");
 Error *err = NULL;
+MigrationChannelList *caps = NULL;
+g_autoptr(MigrationChannel) channel = NULL;
 
 if (inc) {
 warn_report("option '-i' is deprecated;"
@@ -764,12 +775,20 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
 " use blockdev-mirror with NBD instead");
 }
 
-qmp_migrate(uri, false, NULL, !!blk, blk, !!inc, inc,
+if (!migrate_uri_parse(uri, , )) {
+hmp_handle_error(mon, err);
+return;
+}
+QAPI_LIST_PREPEND(caps, g_steal_pointer());
+
+qmp_migrate(NULL, true, caps, !!blk, blk, !!inc, inc,
  false, false, true, resume, );
 if (hmp_handle_error(mon, err)) {
 return;
 }
 
+qapi_free_MigrationChannelList(caps);
+
 if (!detach) {
 HMPMigrationStatus *status;
 
diff --git a/migration/migration.c b/migration/migration.c
index 10a6f2fb12..28a34c9068 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -457,9 +457,8 @@ void migrate_add_address(SocketAddress *address)
   QAPI_CLONE(SocketAddress, address));
 }
 
-static bool migrate_uri_parse(const char *uri,
-  MigrationChannel **channel,
-  Error **errp)
+bool migrate_uri_parse(const char *uri, MigrationChannel **channel,
+   Error **errp)
 {
 g_autoptr(MigrationChannel) val = g_new0(MigrationChannel, 1);
 g_autoptr(MigrationAddress) addr = g_new0(MigrationAddress, 1);
-- 
2.41.0




[PULL 19/40] migration: Add tracepoints for downtime checkpoints

2023-11-02 Thread Juan Quintela
From: Peter Xu 

This patch is inspired by Joao Martin's patch here:

https://lore.kernel.org/r/20230926161841.98464-1-joao.m.mart...@oracle.com

Add tracepoints for major downtime checkpoints on both src and dst.  They
share the same tracepoint with a string showing its stage.

Besides the checkpoints in the previous patch, this patch also added
destination checkpoints.

On src, we have these checkpoints added:

  - src-downtime-start: right before vm stops on src
  - src-vm-stopped: after vm is fully stopped
  - src-iterable-saved: after all iterables saved (END sections)
  - src-non-iterable-saved: after all non-iterable saved (FULL sections)
  - src-downtime-stop: migration fully completed

On dst, we have these checkpoints added:

  - dst-precopy-loadvm-completes: after loadvm all done for precopy
  - dst-precopy-bh-*: record BH steps to resume VM for precopy
  - dst-postcopy-bh-*: record BH steps to resume VM for postcopy

On dst side, we don't have a good way to trace total time consumed by
iterable or non-iterable for now.  We can mark it by 1st time receiving a
FULL / END section, but rather than that let's just rely on the other
tracepoints added for vmstates to back up the information.

With this patch, one can enable "vmstate_downtime*" tracepoints and it'll
enable all tracepoints for downtime measurements necessary.

Drop loadvm_postcopy_handle_run_bh() tracepoint alongside, because they
service the same purpose, which was only for postcopy.  We then have
unified prefix for all downtime relevant tracepoints.

Co-developed-by: Joao Martins 
Signed-off-by: Peter Xu 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231030163346.765724-6-pet...@redhat.com>
---
 migration/migration.c  | 16 +++-
 migration/savevm.c | 14 +-
 migration/trace-events |  2 +-
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 3e38294485..c334b9effd 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -103,6 +103,7 @@ static int close_return_path_on_source(MigrationState *s);
 
 static void migration_downtime_start(MigrationState *s)
 {
+trace_vmstate_downtime_checkpoint("src-downtime-start");
 s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 }
 
@@ -117,6 +118,8 @@ static void migration_downtime_end(MigrationState *s)
 if (!s->downtime) {
 s->downtime = now - s->downtime_start;
 }
+
+trace_vmstate_downtime_checkpoint("src-downtime-end");
 }
 
 static bool migration_needs_multiple_sockets(void)
@@ -151,7 +154,11 @@ static gint page_request_addr_cmp(gconstpointer ap, 
gconstpointer bp)
 
 int migration_stop_vm(RunState state)
 {
-return vm_stop_force_state(state);
+int ret = vm_stop_force_state(state);
+
+trace_vmstate_downtime_checkpoint("src-vm-stopped");
+
+return ret;
 }
 
 void migration_object_init(void)
@@ -495,6 +502,8 @@ static void process_incoming_migration_bh(void *opaque)
 Error *local_err = NULL;
 MigrationIncomingState *mis = opaque;
 
+trace_vmstate_downtime_checkpoint("dst-precopy-bh-enter");
+
 /* If capability late_block_activate is set:
  * Only fire up the block code now if we're going to restart the
  * VM, else 'cont' will do it.
@@ -520,6 +529,8 @@ static void process_incoming_migration_bh(void *opaque)
  */
 qemu_announce_self(>announce_timer, migrate_announce_params());
 
+trace_vmstate_downtime_checkpoint("dst-precopy-bh-announced");
+
 multifd_load_shutdown();
 
 dirty_bitmap_mig_before_vm_start();
@@ -537,6 +548,7 @@ static void process_incoming_migration_bh(void *opaque)
 } else {
 runstate_set(global_state_get_runstate());
 }
+trace_vmstate_downtime_checkpoint("dst-precopy-bh-vm-started");
 /*
  * This must happen after any state changes since as soon as an external
  * observer sees this event they might start to prod at the VM assuming
@@ -571,6 +583,8 @@ process_incoming_migration_co(void *opaque)
 ret = qemu_loadvm_state(mis->from_src_file);
 mis->loadvm_co = NULL;
 
+trace_vmstate_downtime_checkpoint("dst-precopy-loadvm-completed");
+
 ps = postcopy_state_get();
 trace_process_incoming_migration_co_end(ret, ps);
 if (ps != POSTCOPY_INCOMING_NONE) {
diff --git a/migration/savevm.c b/migration/savevm.c
index 99ce42b6f3..bc98c2ea6f 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1526,6 +1526,8 @@ int qemu_savevm_state_complete_precopy_iterable(QEMUFile 
*f, bool in_postcopy)
 end_ts_each - start_ts_each);
 }
 
+trace_vmstate_downtime_checkpoint("src-iterable-saved");
+
 return 0;
 }
 
@@ -1592,6 +1594,8 @@ int 
qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
 json_writer_free(vmdesc);
 ms->vmdesc = NULL;
 
+  

[PULL 38/40] migration: Implement MigrateChannelList to qmp migration flow.

2023-11-02 Thread Juan Quintela
From: Het Gala 

Integrate MigrateChannelList with all transport backends
(socket, exec and rdma) for both src and dest migration
endpoints for qmp migration.

For current series, limit the size of MigrateChannelList
to single element (single interface) as runtime check.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-13-faro...@suse.de>
---
 migration/migration.c | 101 +++---
 1 file changed, 55 insertions(+), 46 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 70725a89ab..10a6f2fb12 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -458,9 +458,10 @@ void migrate_add_address(SocketAddress *address)
 }
 
 static bool migrate_uri_parse(const char *uri,
-  MigrationAddress **channel,
+  MigrationChannel **channel,
   Error **errp)
 {
+g_autoptr(MigrationChannel) val = g_new0(MigrationChannel, 1);
 g_autoptr(MigrationAddress) addr = g_new0(MigrationAddress, 1);
 SocketAddress *saddr = NULL;
 InetSocketAddress *isock = >u.rdma;
@@ -505,7 +506,9 @@ static bool migrate_uri_parse(const char *uri,
 return false;
 }
 
-*channel = g_steal_pointer();
+val->channel_type = MIGRATION_CHANNEL_TYPE_MAIN;
+val->addr = g_steal_pointer();
+*channel = g_steal_pointer();
 return true;
 }
 
@@ -513,44 +516,47 @@ static void qemu_start_incoming_migration(const char 
*uri, bool has_channels,
   MigrationChannelList *channels,
   Error **errp)
 {
-g_autoptr(MigrationAddress) channel = NULL;
+MigrationChannel *channel = NULL;
+MigrationAddress *addr = NULL;
 MigrationIncomingState *mis = migration_incoming_get_current();
 
 /*
  * Having preliminary checks for uri and channel
  */
-if (has_channels) {
-error_setg(errp, "'channels' argument should not be set yet.");
-return;
-}
-
 if (uri && has_channels) {
 error_setg(errp, "'uri' and 'channels' arguments are mutually "
"exclusive; exactly one of the two should be present in "
"'migrate-incoming' qmp command ");
 return;
-}
-
-if (!uri && !has_channels) {
+} else if (channels) {
+/* To verify that Migrate channel list has only item */
+if (channels->next) {
+error_setg(errp, "Channel list has more than one entries");
+return;
+}
+channel = channels->value;
+} else if (uri) {
+/* caller uses the old URI syntax */
+if (!migrate_uri_parse(uri, , errp)) {
+return;
+}
+} else {
 error_setg(errp, "neither 'uri' or 'channels' argument are "
"specified in 'migrate-incoming' qmp command ");
 return;
 }
-
-if (uri && !migrate_uri_parse(uri, , errp)) {
-return;
-}
+addr = channel->addr;
 
 /* transport mechanism not suitable for migration? */
-if (!migration_channels_and_transport_compatible(channel, errp)) {
+if (!migration_channels_and_transport_compatible(addr, errp)) {
 return;
 }
 
 migrate_set_state(>state, MIGRATION_STATUS_NONE,
   MIGRATION_STATUS_SETUP);
 
-if (channel->transport == MIGRATION_ADDRESS_TYPE_SOCKET) {
-SocketAddress *saddr = >u.socket;
+if (addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) {
+SocketAddress *saddr = >u.socket;
 if (saddr->type == SOCKET_ADDRESS_TYPE_INET ||
 saddr->type == SOCKET_ADDRESS_TYPE_UNIX ||
 saddr->type == SOCKET_ADDRESS_TYPE_VSOCK) {
@@ -559,7 +565,7 @@ static void qemu_start_incoming_migration(const char *uri, 
bool has_channels,
 fd_start_incoming_migration(saddr->u.fd.str, errp);
 }
 #ifdef CONFIG_RDMA
-} else if (channel->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
+} else if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) {
 if (migrate_compress()) {
 error_setg(errp, "RDMA and compression can't be used together");
 return;
@@ -572,12 +578,12 @@ static void qemu_start_incoming_migration(const char 
*uri, bool has_channels,
 error_setg(errp, "RDMA and multifd can't be used together");
 return;
 }
-rdma_start_incoming_migration(>u.rdma, errp);
+rdma_start_incoming_migration(>u.rdma, errp);
 #endif
-} else if (channel->transport == MIGRATION_ADDRESS_TYPE_EXEC) {
-exec_start_incoming_migration(channel->u.exec.args, errp);
-  

[PULL 30/40] migration: New QAPI type 'MigrateAddress'

2023-11-02 Thread Juan Quintela
From: Het Gala 

This patch introduces well defined MigrateAddress struct
and its related child objects.

The existing argument of 'migrate' and 'migrate-incoming' QAPI
- 'uri' is of type string. The current implementation follows
double encoding scheme for fetching migration parameters like
'uri' and this is not an ideal design.

Motive for intoducing struct level design is to prevent double
encoding of QAPI arguments, as Qemu should be able to directly
use the QAPI arguments without any level of encoding.

Note: this commit only adds the type, and actual uses comes
in later commits.

Fabiano fixed for "file" transport.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Reviewed-by: Juan Quintela 
Reviewed-by: Daniel P. Berrangé 
Acked-by: Markus Armbruster 
Signed-off-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-2-faro...@suse.de>
Message-Id: <20231023182053.8711-3-faro...@suse.de>
---
 qapi/migration.json | 57 +
 1 file changed, 57 insertions(+)

diff --git a/qapi/migration.json b/qapi/migration.json
index 3daeffc95d..182b150b87 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1584,6 +1584,63 @@
 ##
 { 'command': 'migrate-continue', 'data': {'state': 'MigrationStatus'} }
 
+##
+# @MigrationAddressType:
+#
+# The migration stream transport mechanisms.
+#
+# @socket: Migrate via socket.
+#
+# @exec: Direct the migration stream to another process.
+#
+# @rdma: Migrate via RDMA.
+#
+# @file: Direct the migration stream to a file.
+#
+# Since 8.2
+##
+{ 'enum': 'MigrationAddressType',
+  'data': [ 'socket', 'exec', 'rdma', 'file' ] }
+
+##
+# @FileMigrationArgs:
+#
+# @filename: The file to receive the migration stream
+#
+# @offset: The file offset where the migration stream will start
+#
+# Since 8.2
+##
+{ 'struct': 'FileMigrationArgs',
+  'data': { 'filename': 'str',
+'offset': 'uint64' } }
+
+##
+# @MigrationExecCommand:
+#
+# @args: command (list head) and arguments to execute.
+#
+# Since 8.2
+##
+{ 'struct': 'MigrationExecCommand',
+  'data': {'args': [ 'str' ] } }
+
+##
+# @MigrationAddress:
+#
+# Migration endpoint configuration.
+#
+# Since 8.2
+##
+{ 'union': 'MigrationAddress',
+  'base': { 'transport' : 'MigrationAddressType'},
+  'discriminator': 'transport',
+  'data': {
+'socket': 'SocketAddress',
+'exec': 'MigrationExecCommand',
+'rdma': 'InetSocketAddress',
+'file': 'FileMigrationArgs' } }
+
 ##
 # @migrate:
 #
-- 
2.41.0




[PULL 37/40] migration: modify migration_channels_and_uri_compatible() for new QAPI syntax

2023-11-02 Thread Juan Quintela
From: Het Gala 

migration_channels_and_uri_compatible() check for transport mechanism
suitable for multifd migration gets executed when the caller calls old
uri syntax. It needs it to be run when using the modern MigrateChannel
QAPI syntax too.

After URI -> 'MigrateChannel' :
migration_channels_and_uri_compatible() ->
migration_channels_and_transport_compatible() passes object as argument
and check for valid transport mechanism.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Reviewed-by: Daniel P. Berrangé 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-12-faro...@suse.de>
---
 migration/migration.c | 33 ++---
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index a9cd5e2d5d..70725a89ab 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -128,17 +128,20 @@ static bool migration_needs_multiple_sockets(void)
 return migrate_multifd() || migrate_postcopy_preempt();
 }
 
-static bool uri_supports_multi_channels(const char *uri)
+static bool transport_supports_multi_channels(SocketAddress *saddr)
 {
-return strstart(uri, "tcp:", NULL) || strstart(uri, "unix:", NULL) ||
-   strstart(uri, "vsock:", NULL);
+return saddr->type == SOCKET_ADDRESS_TYPE_INET ||
+   saddr->type == SOCKET_ADDRESS_TYPE_UNIX ||
+   saddr->type == SOCKET_ADDRESS_TYPE_VSOCK;
 }
 
 static bool
-migration_channels_and_uri_compatible(const char *uri, Error **errp)
+migration_channels_and_transport_compatible(MigrationAddress *addr,
+Error **errp)
 {
 if (migration_needs_multiple_sockets() &&
-!uri_supports_multi_channels(uri)) {
+(addr->transport == MIGRATION_ADDRESS_TYPE_SOCKET) &&
+!transport_supports_multi_channels(>u.socket)) {
 error_setg(errp, "Migration requires multi-channel URIs (e.g. tcp)");
 return false;
 }
@@ -534,15 +537,15 @@ static void qemu_start_incoming_migration(const char 
*uri, bool has_channels,
 return;
 }
 
-/* URI is not suitable for migration? */
-if (!migration_channels_and_uri_compatible(uri, errp)) {
-return;
-}
-
 if (uri && !migrate_uri_parse(uri, , errp)) {
 return;
 }
 
+/* transport mechanism not suitable for migration? */
+if (!migration_channels_and_transport_compatible(channel, errp)) {
+return;
+}
+
 migrate_set_state(>state, MIGRATION_STATUS_NONE,
   MIGRATION_STATUS_SETUP);
 
@@ -1947,15 +1950,15 @@ void qmp_migrate(const char *uri, bool has_channels,
 return;
 }
 
-/* URI is not suitable for migration? */
-if (!migration_channels_and_uri_compatible(uri, errp)) {
-return;
-}
-
 if (!migrate_uri_parse(uri, , errp)) {
 return;
 }
 
+/* transport mechanism not suitable for migration? */
+if (!migration_channels_and_transport_compatible(channel, errp)) {
+return;
+}
+
 resume_requested = has_resume && resume;
 if (!migrate_prepare(s, has_blk && blk, has_inc && inc,
  resume_requested, errp)) {
-- 
2.41.0




[PULL 31/40] migration: convert migration 'uri' into 'MigrateAddress'

2023-11-02 Thread Juan Quintela
From: Het Gala 

This patch parses 'migrate' and 'migrate-incoming' QAPI's 'uri'
string containing migration connection related information
and stores them inside well defined 'MigrateAddress' struct.

Fabiano fixed for "file" transport.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Daniel P. Berrangé 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-4-faro...@suse.de>
Message-ID: <20231023182053.8711-5-faro...@suse.de>
---
 migration/exec.h  |  4 +++
 migration/file.h  |  1 +
 migration/exec.c  |  1 -
 migration/file.c  |  2 +-
 migration/migration.c | 63 +++
 5 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/migration/exec.h b/migration/exec.h
index b210ffde7a..736cd71028 100644
--- a/migration/exec.h
+++ b/migration/exec.h
@@ -19,6 +19,10 @@
 
 #ifndef QEMU_MIGRATION_EXEC_H
 #define QEMU_MIGRATION_EXEC_H
+
+#ifdef WIN32
+const char *exec_get_cmd_path(void);
+#endif
 void exec_start_incoming_migration(const char *host_port, Error **errp);
 
 void exec_start_outgoing_migration(MigrationState *s, const char *host_port,
diff --git a/migration/file.h b/migration/file.h
index 90fa4849e0..3888a57105 100644
--- a/migration/file.h
+++ b/migration/file.h
@@ -11,4 +11,5 @@ void file_start_incoming_migration(const char *filename, 
Error **errp);
 
 void file_start_outgoing_migration(MigrationState *s, const char *filename,
Error **errp);
+int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp);
 #endif
diff --git a/migration/exec.c b/migration/exec.c
index 2bf882bbe1..32f5143dfd 100644
--- a/migration/exec.c
+++ b/migration/exec.c
@@ -27,7 +27,6 @@
 #include "qemu/cutils.h"
 
 #ifdef WIN32
-const char *exec_get_cmd_path(void);
 const char *exec_get_cmd_path(void)
 {
 g_autofree char *detected_path = g_new(char, MAX_PATH);
diff --git a/migration/file.c b/migration/file.c
index cf5b1bf365..ec069ef329 100644
--- a/migration/file.c
+++ b/migration/file.c
@@ -19,7 +19,7 @@
 
 /* Remove the offset option from @filespec and return it in @offsetp. */
 
-static int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp)
+int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp)
 {
 char *option = strstr(filespec, OFFSET_OPTION);
 int ret;
diff --git a/migration/migration.c b/migration/migration.c
index ce9b7692ad..a1bace259e 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -66,6 +66,7 @@
 #include "sysemu/qtest.h"
 #include "options.h"
 #include "sysemu/dirtylimit.h"
+#include "qemu/sockets.h"
 
 static NotifierList migration_state_notifiers =
 NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
@@ -453,9 +454,62 @@ void migrate_add_address(SocketAddress *address)
   QAPI_CLONE(SocketAddress, address));
 }
 
+static bool migrate_uri_parse(const char *uri,
+  MigrationAddress **channel,
+  Error **errp)
+{
+g_autoptr(MigrationAddress) addr = g_new0(MigrationAddress, 1);
+SocketAddress *saddr = NULL;
+InetSocketAddress *isock = >u.rdma;
+strList **tail = >u.exec.args;
+
+if (strstart(uri, "exec:", NULL)) {
+addr->transport = MIGRATION_ADDRESS_TYPE_EXEC;
+#ifdef WIN32
+QAPI_LIST_APPEND(tail, g_strdup(exec_get_cmd_path()));
+QAPI_LIST_APPEND(tail, g_strdup("/c"));
+#else
+QAPI_LIST_APPEND(tail, g_strdup("/bin/sh"));
+QAPI_LIST_APPEND(tail, g_strdup("-c"));
+#endif
+QAPI_LIST_APPEND(tail, g_strdup(uri + strlen("exec:")));
+} else if (strstart(uri, "rdma:", NULL)) {
+if (inet_parse(isock, uri + strlen("rdma:"), errp)) {
+qapi_free_InetSocketAddress(isock);
+return false;
+}
+addr->transport = MIGRATION_ADDRESS_TYPE_RDMA;
+} else if (strstart(uri, "tcp:", NULL) ||
+strstart(uri, "unix:", NULL) ||
+strstart(uri, "vsock:", NULL) ||
+strstart(uri, "fd:", NULL)) {
+addr->transport = MIGRATION_ADDRESS_TYPE_SOCKET;
+saddr = socket_parse(uri, errp);
+if (!saddr) {
+return false;
+}
+addr->u.socket.type = saddr->type;
+addr->u.socket.u = saddr->u;
+} else if (strstart(uri, "file:", NULL)) {
+addr->transport = MIGRATION_ADDRESS_TYPE_FILE;
+addr->u.file.filename = g_strdup(uri + strlen("file:"));
+if (file_parse_offset(addr->u.file.filename, >u.file.offset,
+  errp)) {
+return false;
+}
+} else {
+error_setg(errp, "unknown migration 

[PULL 32/40] migration: convert socket backend to accept MigrateAddress

2023-11-02 Thread Juan Quintela
From: Het Gala 

Socket transport backend for 'migrate'/'migrate-incoming' QAPIs accept
new wire protocol of MigrateAddress struct.

It is achived by parsing 'uri' string and storing migration parameters
required for socket connection into well defined SocketAddress struct.

Suggested-by: Aravind Retnakaran 
Signed-off-by: Het Gala 
Reviewed-by: Daniel P. Berrangé 
Signed-off-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231023182053.8711-6-faro...@suse.de>
---
 migration/socket.h|  7 ---
 migration/migration.c | 30 ++
 migration/socket.c| 39 +--
 3 files changed, 31 insertions(+), 45 deletions(-)

diff --git a/migration/socket.h b/migration/socket.h
index dc54df4e6c..5e4c33b8ea 100644
--- a/migration/socket.h
+++ b/migration/socket.h
@@ -19,13 +19,14 @@
 
 #include "io/channel.h"
 #include "io/task.h"
+#include "qemu/sockets.h"
 
 void socket_send_channel_create(QIOTaskFunc f, void *data);
 QIOChannel *socket_send_channel_create_sync(Error **errp);
 int socket_send_channel_destroy(QIOChannel *send);
 
-void socket_start_incoming_migration(const char *str, Error **errp);
+void socket_start_incoming_migration(SocketAddress *saddr, Error **errp);
 
-void socket_start_outgoing_migration(MigrationState *s, const char *str,
- Error **errp);
+void socket_start_outgoing_migration(MigrationState *s,
+ SocketAddress *saddr, Error **errp);
 #endif
diff --git a/migration/migration.c b/migration/migration.c
index a1bace259e..846877135a 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -524,10 +524,15 @@ static void qemu_start_incoming_migration(const char 
*uri, Error **errp)
 migrate_set_state(>state, MIGRATION_STATUS_NONE,
   MIGRATION_STATUS_SETUP);
 
-if (strstart(uri, "tcp:", ) ||
-strstart(uri, "unix:", NULL) ||
-strstart(uri, "vsock:", NULL)) {
-socket_start_incoming_migration(p ? p : uri, errp);
+if (channel->transport == MIGRATION_ADDRESS_TYPE_SOCKET) {
+SocketAddress *saddr = >u.socket;
+if (saddr->type == SOCKET_ADDRESS_TYPE_INET ||
+saddr->type == SOCKET_ADDRESS_TYPE_UNIX ||
+saddr->type == SOCKET_ADDRESS_TYPE_VSOCK) {
+socket_start_incoming_migration(saddr, errp);
+} else if (saddr->type == SOCKET_ADDRESS_TYPE_FD) {
+fd_start_incoming_migration(saddr->u.fd.str, errp);
+}
 #ifdef CONFIG_RDMA
 } else if (strstart(uri, "rdma:", )) {
 if (migrate_compress()) {
@@ -546,8 +551,6 @@ static void qemu_start_incoming_migration(const char *uri, 
Error **errp)
 #endif
 } else if (strstart(uri, "exec:", )) {
 exec_start_incoming_migration(p, errp);
-} else if (strstart(uri, "fd:", )) {
-fd_start_incoming_migration(p, errp);
 } else if (strstart(uri, "file:", )) {
 file_start_incoming_migration(p, errp);
 } else {
@@ -1922,18 +1925,21 @@ void qmp_migrate(const char *uri, bool has_blk, bool 
blk,
 }
 }
 
-if (strstart(uri, "tcp:", ) ||
-strstart(uri, "unix:", NULL) ||
-strstart(uri, "vsock:", NULL)) {
-socket_start_outgoing_migration(s, p ? p : uri, _err);
+if (channel->transport == MIGRATION_ADDRESS_TYPE_SOCKET) {
+SocketAddress *saddr = >u.socket;
+if (saddr->type == SOCKET_ADDRESS_TYPE_INET ||
+saddr->type == SOCKET_ADDRESS_TYPE_UNIX ||
+saddr->type == SOCKET_ADDRESS_TYPE_VSOCK) {
+socket_start_outgoing_migration(s, saddr, _err);
+} else if (saddr->type == SOCKET_ADDRESS_TYPE_FD) {
+fd_start_outgoing_migration(s, saddr->u.fd.str, _err);
+}
 #ifdef CONFIG_RDMA
 } else if (strstart(uri, "rdma:", )) {
 rdma_start_outgoing_migration(s, p, _err);
 #endif
 } else if (strstart(uri, "exec:", )) {
 exec_start_outgoing_migration(s, p, _err);
-} else if (strstart(uri, "fd:", )) {
-fd_start_outgoing_migration(s, p, _err);
 } else if (strstart(uri, "file:", )) {
 file_start_outgoing_migration(s, p, _err);
 } else {
diff --git a/migration/socket.c b/migration/socket.c
index 1b6f5baefb..98e3ea1514 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -28,6 +28,8 @@
 #include "trace.h"
 #include "postcopy-ram.h"
 #include "options.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-sockets.h"
 
 struct SocketOutgoingArgs {
 SocketAddress *saddr;
@@ -108,19 +110,19 @@ out:
 object_unref(OBJECT(sioc));
 }
 
-static void
-socket_start_outgoing_mi

[PULL 29/40] migration: Change ram_dirty_bitmap_reload() retval to bool

2023-11-02 Thread Juan Quintela
From: Peter Xu 

Now we have a Error** passed into the return path thread stack, which is
even clearer than an int retval.  Change ram_dirty_bitmap_reload() and the
callers to use a bool instead to replace errnos.

Suggested-by: Philippe Mathieu-Daudé 
Signed-off-by: Peter Xu 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231017202633.296756-5-pet...@redhat.com>
---
 migration/ram.h   |  2 +-
 migration/migration.c | 18 +-
 migration/ram.c   | 24 
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/migration/ram.h b/migration/ram.h
index 6e2c2c1950..9b937a446b 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -71,7 +71,7 @@ void ramblock_recv_bitmap_set(RAMBlock *rb, void *host_addr);
 void ramblock_recv_bitmap_set_range(RAMBlock *rb, void *host_addr, size_t nr);
 int64_t ramblock_recv_bitmap_send(QEMUFile *file,
   const char *block_name);
-int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb, Error **errp);
+bool ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb, Error **errp);
 bool ramblock_page_is_discarded(RAMBlock *rb, ram_addr_t start);
 void postcopy_preempt_shutdown_file(MigrationState *s);
 void *postcopy_preempt_thread(void *opaque);
diff --git a/migration/migration.c b/migration/migration.c
index e875ea0d6b..ce9b7692ad 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1971,29 +1971,29 @@ migrate_handle_rp_req_pages(MigrationState *ms, const 
char* rbname,
 ram_save_queue_pages(rbname, start, len, errp);
 }
 
-static int migrate_handle_rp_recv_bitmap(MigrationState *s, char *block_name,
- Error **errp)
+static bool migrate_handle_rp_recv_bitmap(MigrationState *s, char *block_name,
+  Error **errp)
 {
 RAMBlock *block = qemu_ram_block_by_name(block_name);
 
 if (!block) {
 error_setg(errp, "MIG_RP_MSG_RECV_BITMAP has invalid block name '%s'",
block_name);
-return -EINVAL;
+return false;
 }
 
 /* Fetch the received bitmap and refresh the dirty bitmap */
 return ram_dirty_bitmap_reload(s, block, errp);
 }
 
-static int migrate_handle_rp_resume_ack(MigrationState *s,
-uint32_t value, Error **errp)
+static bool migrate_handle_rp_resume_ack(MigrationState *s,
+ uint32_t value, Error **errp)
 {
 trace_source_return_path_thread_resume_ack(value);
 
 if (value != MIGRATION_RESUME_ACK_VALUE) {
 error_setg(errp, "illegal resume_ack value %"PRIu32, value);
-return -1;
+return false;
 }
 
 /* Now both sides are active. */
@@ -2003,7 +2003,7 @@ static int migrate_handle_rp_resume_ack(MigrationState *s,
 /* Notify send thread that time to continue send pages */
 migration_rp_kick(s);
 
-return 0;
+return true;
 }
 
 /*
@@ -2154,14 +2154,14 @@ static void *source_return_path_thread(void *opaque)
 }
 /* Format: len (1B) + idstr (<255B). This ends the idstr. */
 buf[buf[0] + 1] = '\0';
-if (migrate_handle_rp_recv_bitmap(ms, (char *)(buf + 1), )) {
+if (!migrate_handle_rp_recv_bitmap(ms, (char *)(buf + 1), )) {
 goto out;
 }
 break;
 
 case MIG_RP_MSG_RESUME_ACK:
 tmp32 = ldl_be_p(buf);
-if (migrate_handle_rp_resume_ack(ms, tmp32, )) {
+if (!migrate_handle_rp_resume_ack(ms, tmp32, )) {
 goto out;
 }
 break;
diff --git a/migration/ram.c b/migration/ram.c
index 929cba08f4..a0f3b86663 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -4113,10 +4113,11 @@ static int ram_dirty_bitmap_sync_all(MigrationState *s, 
RAMState *rs)
  * Read the received bitmap, revert it as the initial dirty bitmap.
  * This is only used when the postcopy migration is paused but wants
  * to resume from a middle point.
+ *
+ * Returns true if succeeded, false for errors.
  */
-int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block, Error **errp)
+bool ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *block, Error **errp)
 {
-int ret = -EINVAL;
 /* from_dst_file is always valid because we're within rp_thread */
 QEMUFile *file = s->rp_state.from_dst_file;
 g_autofree unsigned long *le_bitmap = NULL;
@@ -4130,7 +4131,7 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock 
*block, Error **errp)
 if (s->state != MIGRATION_STATUS_POSTCOPY_RECOVER) {
 error_setg(errp, "Reload bitmap in incorrect state %s",
MigrationStatus_str(s->state));
-return -EINVAL;
+return false;
 }
 
 /*
@@ -4148,24 +4149,23 @@ int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock 
*block, Error **errp)
 if

[PULL 25/40] tests/qtest: migration: add reboot mode test

2023-11-02 Thread Juan Quintela
From: Steve Sistare 

[ Maintainer note:

I put the test as flaky because our CI has problems with shared
memory.  We will remove the flaky bits as soon as we get a solution.
]

Signed-off-by: Steve Sistare 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <1698263069-406971-7-git-send-email-steven.sist...@oracle.com>
---
 tests/qtest/migration-test.c | 33 +
 1 file changed, 33 insertions(+)

diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index bc70a14642..b7ebc23903 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -2026,6 +2026,31 @@ static void test_precopy_file_offset_bad(void)
 test_file_common(, false);
 }
 
+static void *test_mode_reboot_start(QTestState *from, QTestState *to)
+{
+migrate_set_parameter_str(from, "mode", "cpr-reboot");
+migrate_set_parameter_str(to, "mode", "cpr-reboot");
+
+migrate_set_capability(from, "x-ignore-shared", true);
+migrate_set_capability(to, "x-ignore-shared", true);
+
+return NULL;
+}
+
+static void test_mode_reboot(void)
+{
+g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+   FILE_TEST_FILENAME);
+MigrateCommon args = {
+.start.use_shmem = true,
+.connect_uri = uri,
+.listen_uri = "defer",
+.start_hook = test_mode_reboot_start
+};
+
+test_file_common(, true);
+}
+
 static void test_precopy_tcp_plain(void)
 {
 MigrateCommon args = {
@@ -3096,6 +3121,14 @@ int main(int argc, char **argv)
 qtest_add_func("/migration/precopy/file/offset/bad",
test_precopy_file_offset_bad);
 
+/*
+ * Our CI system has problems with shared memory.
+ * Don't run this test until we find a workaround.
+ */
+if (getenv("QEMU_TEST_FLAKY_TESTS")) {
+qtest_add_func("/migration/mode/reboot", test_mode_reboot);
+}
+
 #ifdef CONFIG_GNUTLS
 qtest_add_func("/migration/precopy/unix/tls/psk",
test_precopy_unix_tls_psk);
-- 
2.41.0




[PULL 22/40] cpr: relax blockdev migration blockers

2023-11-02 Thread Juan Quintela
From: Steve Sistare 

Some blockdevs block migration because they do not support sharing across
hosts and/or do not support dirty bitmaps.  These prohibitions do not apply
if the old and new qemu processes do not run concurrently, and if new qemu
starts on the same host as old, which is the case for cpr.  Narrow the scope
of these blockers so they only apply to normal mode.  They will not block
cpr modes when they are added in subsequent patches.

No functional change until a new mode is added.

Signed-off-by: Steve Sistare 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <1698263069-406971-4-git-send-email-steven.sist...@oracle.com>
---
 block/parallels.c | 2 +-
 block/qcow.c  | 2 +-
 block/vdi.c   | 2 +-
 block/vhdx.c  | 2 +-
 block/vmdk.c  | 2 +-
 block/vpc.c   | 2 +-
 block/vvfat.c | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/block/parallels.c b/block/parallels.c
index 1d695ce7fb..6318dd02e7 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -1369,7 +1369,7 @@ static int parallels_open(BlockDriverState *bs, QDict 
*options, int flags,
bdrv_get_device_or_node_name(bs));
 bdrv_graph_rdunlock_main_loop();
 
-ret = migrate_add_blocker(>migration_blocker, errp);
+ret = migrate_add_blocker_normal(>migration_blocker, errp);
 if (ret < 0) {
 goto fail;
 }
diff --git a/block/qcow.c b/block/qcow.c
index fdd4c83948..eab68e387c 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -307,7 +307,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, 
int flags,
bdrv_get_device_or_node_name(bs));
 bdrv_graph_rdunlock_main_loop();
 
-ret = migrate_add_blocker(>migration_blocker, errp);
+ret = migrate_add_blocker_normal(>migration_blocker, errp);
 if (ret < 0) {
 goto fail;
 }
diff --git a/block/vdi.c b/block/vdi.c
index fd7e365383..c647d72895 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -498,7 +498,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, 
int flags,
bdrv_get_device_or_node_name(bs));
 bdrv_graph_rdunlock_main_loop();
 
-ret = migrate_add_blocker(>migration_blocker, errp);
+ret = migrate_add_blocker_normal(>migration_blocker, errp);
 if (ret < 0) {
 goto fail_free_bmap;
 }
diff --git a/block/vhdx.c b/block/vhdx.c
index e37f8c0926..a9d08742f9 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1096,7 +1096,7 @@ static int vhdx_open(BlockDriverState *bs, QDict 
*options, int flags,
 error_setg(>migration_blocker, "The vhdx format used by node '%s' "
"does not support live migration",
bdrv_get_device_or_node_name(bs));
-ret = migrate_add_blocker(>migration_blocker, errp);
+ret = migrate_add_blocker_normal(>migration_blocker, errp);
 if (ret < 0) {
 goto fail;
 }
diff --git a/block/vmdk.c b/block/vmdk.c
index 1335d39e16..85864b8045 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1386,7 +1386,7 @@ static int vmdk_open(BlockDriverState *bs, QDict 
*options, int flags,
 error_setg(>migration_blocker, "The vmdk format used by node '%s' "
"does not support live migration",
bdrv_get_device_or_node_name(bs));
-ret = migrate_add_blocker(>migration_blocker, errp);
+ret = migrate_add_blocker_normal(>migration_blocker, errp);
 if (ret < 0) {
 goto fail;
 }
diff --git a/block/vpc.c b/block/vpc.c
index c30cf8689a..aa1a48ae0e 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -452,7 +452,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, 
int flags,
bdrv_get_device_or_node_name(bs));
 bdrv_graph_rdunlock_main_loop();
 
-ret = migrate_add_blocker(>migration_blocker, errp);
+ret = migrate_add_blocker_normal(>migration_blocker, errp);
 if (ret < 0) {
 goto fail;
 }
diff --git a/block/vvfat.c b/block/vvfat.c
index 266e036dcd..9d050ba3ae 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1268,7 +1268,7 @@ static int vvfat_open(BlockDriverState *bs, QDict 
*options, int flags,
"The vvfat (rw) format used by node '%s' "
"does not support live migration",
bdrv_get_device_or_node_name(bs));
-ret = migrate_add_blocker(>migration_blocker, errp);
+ret = migrate_add_blocker_normal(>migration_blocker, errp);
 if (ret < 0) {
 goto fail;
 }
-- 
2.41.0




[PULL 27/40] migration: Allow network to fail even during recovery

2023-11-02 Thread Juan Quintela
From: Peter Xu 

Normally the postcopy recover phase should only exist for a super short
period, that's the duration when QEMU is trying to recover from an
interrupted postcopy migration, during which handshake will be carried out
for continuing the procedure with state changes from PAUSED -> RECOVER ->
POSTCOPY_ACTIVE again.

Here RECOVER phase should be super small, that happens right after the
admin specified a new but working network link for QEMU to reconnect to
dest QEMU.

However there can still be case where the channel is broken in this small
RECOVER window.

If it happens, with current code there's no way the src QEMU can got kicked
out of RECOVER stage. No way either to retry the recover in another channel
when established.

This patch allows the RECOVER phase to fail itself too - we're mostly
ready, just some small things missing, e.g. properly kick the main
migration thread out when sleeping on rp_sem when we found that we're at
RECOVER stage.  When this happens, it fails the RECOVER itself, and
rollback to PAUSED stage.  Then the user can retry another round of
recovery.

To make it even stronger, teach QMP command migrate-pause to explicitly
kick src/dst QEMU out when needed, so even if for some reason the migration
thread didn't got kicked out already by a failing rethrn-path thread, the
admin can also kick it out.

This will be an super, super corner case, but still try to cover that.

One can try to test this with two proxy channels for migration:

  (a) socat unix-listen:/tmp/src.sock,reuseaddr,fork tcp:localhost:1
  (b) socat tcp-listen:1,reuseaddr,fork unix:/tmp/dst.sock

So the migration channel will be:

  (a)  (b)
  src -> /tmp/src.sock -> tcp:1 -> /tmp/dst.sock -> dst

Then to make QEMU hang at RECOVER stage, one can do below:

  (1) stop the postcopy using QMP command postcopy-pause
  (2) kill the 2nd proxy (b)
  (3) try to recover the postcopy using /tmp/src.sock on src
  (4) src QEMU will go into RECOVER stage but won't be able to continue
  from there, because the channel is actually broken at (b)

Before this patch, step (4) will make src QEMU stuck in RECOVER stage,
without a way to kick the QEMU out or continue the postcopy again.  After
this patch, (4) will quickly fail qemu and bounce back to PAUSED stage.

Admin can also kick QEMU from (4) into PAUSED when needed using
migrate-pause when needed.

After bouncing back to PAUSED stage, one can recover again.

Reported-by: Xiaohui Li 
Reviewed-by: Fabiano Rosas 
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2111332
Reviewed-by: Juan Quintela 
Signed-off-by: Peter Xu 
Signed-off-by: Juan Quintela 
Message-ID: <20231017202633.296756-3-pet...@redhat.com>
---
 migration/migration.h |  8 --
 migration/migration.c | 63 +++
 migration/ram.c   |  4 ++-
 3 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/migration/migration.h b/migration/migration.h
index 615b517594..af8c965b7f 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -494,6 +494,7 @@ int migrate_init(MigrationState *s, Error **errp);
 bool migration_is_blocked(Error **errp);
 /* True if outgoing migration has entered postcopy phase */
 bool migration_in_postcopy(void);
+bool migration_postcopy_is_alive(int state);
 MigrationState *migrate_get_current(void);
 
 uint64_t ram_get_total_transferred_pages(void);
@@ -534,8 +535,11 @@ void migration_populate_vfio_info(MigrationInfo *info);
 void migration_reset_vfio_bytes_transferred(void);
 void postcopy_temp_page_reset(PostcopyTmpPage *tmp_page);
 
-/* Migration thread waiting for return path thread. */
-void migration_rp_wait(MigrationState *s);
+/*
+ * Migration thread waiting for return path thread.  Return non-zero if an
+ * error is detected.
+ */
+int migration_rp_wait(MigrationState *s);
 /*
  * Kick the migration thread waiting for return path messages.  NOTE: the
  * name can be slightly confusing (when read as "kick the rp thread"), just
diff --git a/migration/migration.c b/migration/migration.c
index 455ddc896a..e875ea0d6b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1393,6 +1393,17 @@ bool migration_in_postcopy(void)
 }
 }
 
+bool migration_postcopy_is_alive(int state)
+{
+switch (state) {
+case MIGRATION_STATUS_POSTCOPY_ACTIVE:
+case MIGRATION_STATUS_POSTCOPY_RECOVER:
+return true;
+default:
+return false;
+}
+}
+
 bool migration_in_postcopy_after_devices(MigrationState *s)
 {
 return migration_in_postcopy() && s->postcopy_after_devices;
@@ -1673,8 +1684,15 @@ void qmp_migrate_pause(Error **errp)
 MigrationIncomingState *mis = migration_incoming_get_current();
 int ret = 0;
 
-if (ms->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) {
+if (migration_postcopy_is_alive(ms->state)) {
 /* Source side, during postcopy */
+Error *error = NULL;
+
+  

[PULL 20/40] migration: mode parameter

2023-11-02 Thread Juan Quintela
From: Steve Sistare 

Create a mode migration parameter that can be used to select alternate
migration algorithms.  The default mode is normal, representing the
current migration algorithm, and does not need to be explicitly set.

No functional change until a new mode is added, except that the mode is
shown by the 'info migrate' command.

Signed-off-by: Steve Sistare 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <1698263069-406971-2-git-send-email-steven.sist...@oracle.com>
---
 qapi/migration.json | 27 ---
 include/hw/qdev-properties-system.h |  4 
 include/migration/misc.h|  1 +
 migration/options.h |  1 +
 hw/core/qdev-properties-system.c| 14 ++
 migration/migration-hmp-cmds.c  |  9 +
 migration/options.c | 21 +
 7 files changed, 74 insertions(+), 3 deletions(-)

diff --git a/qapi/migration.json b/qapi/migration.json
index e6610af428..47c02a9346 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -631,6 +631,15 @@
   'data': [ 'none', 'zlib',
 { 'name': 'zstd', 'if': 'CONFIG_ZSTD' } ] }
 
+##
+# @MigMode:
+#
+# @normal: the original form of migration. (since 8.2)
+#
+##
+{ 'enum': 'MigMode',
+  'data': [ 'normal' ] }
+
 ##
 # @BitmapMigrationBitmapAliasTransform:
 #
@@ -849,6 +858,9 @@
 # @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
 # Defaults to 1.  (Since 8.1)
 #
+# @mode: Migration mode. See description in @MigMode. Default is 'normal'.
+#(Since 8.2)
+#
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
@@ -881,7 +893,8 @@
'multifd-zlib-level', 'multifd-zstd-level',
'block-bitmap-mapping',
{ 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
-   'vcpu-dirty-limit'] }
+   'vcpu-dirty-limit',
+   'mode'] }
 
 ##
 # @MigrateSetParameters:
@@ -1033,6 +1046,9 @@
 # @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
 # Defaults to 1.  (Since 8.1)
 #
+# @mode: Migration mode. See description in @MigMode. Default is 'normal'.
+#(Since 8.2)
+#
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
@@ -1085,7 +1101,8 @@
 '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
 '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
 'features': [ 'unstable' ] },
-'*vcpu-dirty-limit': 'uint64'} }
+'*vcpu-dirty-limit': 'uint64',
+'*mode': 'MigMode'} }
 
 ##
 # @migrate-set-parameters:
@@ -1257,6 +1274,9 @@
 # @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration.
 # Defaults to 1.  (Since 8.1)
 #
+# @mode: Migration mode. See description in @MigMode. Default is 'normal'.
+#(Since 8.2)
+#
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
@@ -1306,7 +1326,8 @@
 '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
 '*x-vcpu-dirty-limit-period': { 'type': 'uint64',
 'features': [ 'unstable' ] },
-'*vcpu-dirty-limit': 'uint64'} }
+'*vcpu-dirty-limit': 'uint64',
+'*mode': 'MigMode'} }
 
 ##
 # @query-migrate-parameters:
diff --git a/include/hw/qdev-properties-system.h 
b/include/hw/qdev-properties-system.h
index e4f8a13afc..91f7a2452d 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -7,6 +7,7 @@ extern const PropertyInfo qdev_prop_chr;
 extern const PropertyInfo qdev_prop_macaddr;
 extern const PropertyInfo qdev_prop_reserved_region;
 extern const PropertyInfo qdev_prop_multifd_compression;
+extern const PropertyInfo qdev_prop_mig_mode;
 extern const PropertyInfo qdev_prop_losttickpolicy;
 extern const PropertyInfo qdev_prop_blockdev_on_error;
 extern const PropertyInfo qdev_prop_bios_chs_trans;
@@ -42,6 +43,9 @@ extern const PropertyInfo qdev_prop_cpus390entitlement;
 #define DEFINE_PROP_MULTIFD_COMPRESSION(_n, _s, _f, _d) \
 DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_multifd_compression, \
MultiFDCompression)
+#define DEFINE_PROP_MIG_MODE(_n, _s, _f, _d) \
+DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_mig_mode, \
+   MigMode)
 #define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
 DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
 LostTickPolicy)
diff --git a/include/migration/misc.h b/include/migration/misc.h
index 673ac490fb..1bc8902e6d 100644
--- a/include/migration/misc.h
+++ b/include/migration/misc.h
@@ -15,6 +15,7 @@
 #define MIGRATION_MISC_H
 
 #include "qemu/notify.h"
+#include "qapi/qapi-types-migration.h"
 #include "qapi/qapi-types-net.h"
 
 /* migration/ram.c */
diff --git a/migration/options.h b/migration/options.h

[PULL 12/40] migration: Use vmstate_register_any() for audio

2023-11-02 Thread Juan Quintela
We can have more than one audio backend.

void audio_init_audiodevs(void)
{
AudiodevListEntry *e;

QSIMPLEQ_FOREACH(e, , next) {
audio_init(e->dev, _fatal);
}
}

Reviewed-by: Stefan Berger 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-12-quint...@redhat.com>
---
 audio/audio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/audio/audio.c b/audio/audio.c
index e9815d6812..f91e05b72c 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1781,7 +1781,7 @@ static AudioState *audio_init(Audiodev *dev, Error **errp)
 
 QTAILQ_INSERT_TAIL(_states, s, list);
 QLIST_INIT (>card_head);
-vmstate_register (NULL, 0, _audio, s);
+vmstate_register_any(NULL, _audio, s);
 return s;
 
 out:
-- 
2.41.0




[PULL 17/40] migration: Add per vmstate downtime tracepoints

2023-11-02 Thread Juan Quintela
From: Peter Xu 

We have a bunch of savevm_section* tracepoints, they're good to analyze
migration stream, but not always suitable if someone would like to analyze
the migration downtime.  Two major problems:

  - savevm_section* tracepoints are dumping all sections, we only care
about the sections that contribute to the downtime

  - They don't have an identifier to show the type of sections, so no way
to filter downtime information either easily.

We can add type into the tracepoints, but instead of doing so, this patch
kept them untouched, instead of adding a bunch of downtime specific
tracepoints, so one can enable "vmstate_downtime*" tracepoints and get a
full picture of how the downtime is distributed across iterative and
non-iterative vmstate save/load.

Note that here both save() and load() need to be traced, because both of
them may contribute to the downtime.  The contribution is not a simple "add
them together", though: consider when the src is doing a save() of device1
while the dest can be load()ing for device2, so they can happen
concurrently.

Tracking both sides make sense because device load() and save() can be
imbalanced, one device can save() super fast, but load() super slow, vice
versa.  We can't figure that out without tracing both.

Signed-off-by: Peter Xu 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231030163346.765724-4-pet...@redhat.com>
---
 migration/savevm.c | 49 ++
 migration/trace-events |  2 ++
 2 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/migration/savevm.c b/migration/savevm.c
index 2095ddd6f8..99ce42b6f3 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1491,6 +1491,7 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f)
 static
 int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy)
 {
+int64_t start_ts_each, end_ts_each;
 SaveStateEntry *se;
 int ret;
 
@@ -1507,6 +1508,8 @@ int qemu_savevm_state_complete_precopy_iterable(QEMUFile 
*f, bool in_postcopy)
 continue;
 }
 }
+
+start_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
 trace_savevm_section_start(se->idstr, se->section_id);
 
 save_section_header(f, se, QEMU_VM_SECTION_END);
@@ -1518,6 +1521,9 @@ int qemu_savevm_state_complete_precopy_iterable(QEMUFile 
*f, bool in_postcopy)
 qemu_file_set_error(f, ret);
 return -1;
 }
+end_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
+trace_vmstate_downtime_save("iterable", se->idstr, se->instance_id,
+end_ts_each - start_ts_each);
 }
 
 return 0;
@@ -1528,6 +1534,7 @@ int 
qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
 bool inactivate_disks)
 {
 MigrationState *ms = migrate_get_current();
+int64_t start_ts_each, end_ts_each;
 JSONWriter *vmdesc = ms->vmdesc;
 int vmdesc_len;
 SaveStateEntry *se;
@@ -1539,11 +1546,17 @@ int 
qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
 continue;
 }
 
+start_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
+
 ret = vmstate_save(f, se, vmdesc);
 if (ret) {
 qemu_file_set_error(f, ret);
 return ret;
 }
+
+end_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
+trace_vmstate_downtime_save("non-iterable", se->idstr, se->instance_id,
+end_ts_each - start_ts_each);
 }
 
 if (inactivate_disks) {
@@ -2537,9 +2550,12 @@ static bool check_section_footer(QEMUFile *f, 
SaveStateEntry *se)
 }
 
 static int
-qemu_loadvm_section_start_full(QEMUFile *f, MigrationIncomingState *mis)
+qemu_loadvm_section_start_full(QEMUFile *f, MigrationIncomingState *mis,
+   uint8_t type)
 {
+bool trace_downtime = (type == QEMU_VM_SECTION_FULL);
 uint32_t instance_id, version_id, section_id;
+int64_t start_ts, end_ts;
 SaveStateEntry *se;
 char idstr[256];
 int ret;
@@ -2588,12 +2604,23 @@ qemu_loadvm_section_start_full(QEMUFile *f, 
MigrationIncomingState *mis)
 return -EINVAL;
 }
 
+if (trace_downtime) {
+start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
+}
+
 ret = vmstate_load(f, se);
 if (ret < 0) {
 error_report("error while loading state for instance 0x%"PRIx32" of"
  " device '%s'", instance_id, idstr);
 return ret;
 }
+
+if (trace_downtime) {
+end_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
+trace_vmstate_downtime_load("non-iterable", se->idstr,
+se->instance_id, end_ts - start_ts);
+}
+
 if (!check_sectio

[PULL 28/40] tests/migration-test: Add a test for postcopy hangs during RECOVER

2023-11-02 Thread Juan Quintela
From: Fabiano Rosas 

To do so, create two paired sockets, but make them not providing real data.
Feed those fake sockets to src/dst QEMUs for recovery to let them go into
RECOVER stage without going out.  Test that we can always kick it out and
recover again with the right ports.

This patch is based on Fabiano's version here:

https://lore.kernel.org/r/877cowmdu0@suse.de

Signed-off-by: Fabiano Rosas 
[peterx: write commit message, remove case 1, fix bugs, and more]
Signed-off-by: Peter Xu 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231017202633.296756-4-pet...@redhat.com>
---
 tests/qtest/migration-test.c | 110 +--
 1 file changed, 104 insertions(+), 6 deletions(-)

diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index b7ebc23903..047b7194df 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -728,6 +728,7 @@ typedef struct {
 /* Postcopy specific fields */
 void *postcopy_data;
 bool postcopy_preempt;
+bool postcopy_recovery_test_fail;
 } MigrateCommon;
 
 static int test_migrate_start(QTestState **from, QTestState **to,
@@ -1404,6 +1405,80 @@ static void test_postcopy_preempt_tls_psk(void)
 }
 #endif
 
+static void wait_for_postcopy_status(QTestState *one, const char *status)
+{
+wait_for_migration_status(one, status,
+  (const char * []) { "failed", "active",
+  "completed", NULL });
+}
+
+#ifndef _WIN32
+static void postcopy_recover_fail(QTestState *from, QTestState *to)
+{
+int ret, pair1[2], pair2[2];
+char c;
+
+/* Create two unrelated socketpairs */
+ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair1);
+g_assert_cmpint(ret, ==, 0);
+
+ret = qemu_socketpair(PF_LOCAL, SOCK_STREAM, 0, pair2);
+g_assert_cmpint(ret, ==, 0);
+
+/*
+ * Give the guests unpaired ends of the sockets, so they'll all blocked
+ * at reading.  This mimics a wrong channel established.
+ */
+qtest_qmp_fds_assert_success(from, [0], 1,
+ "{ 'execute': 'getfd',"
+ "  'arguments': { 'fdname': 'fd-mig' }}");
+qtest_qmp_fds_assert_success(to, [0], 1,
+ "{ 'execute': 'getfd',"
+ "  'arguments': { 'fdname': 'fd-mig' }}");
+
+/*
+ * Write the 1st byte as QEMU_VM_COMMAND (0x8) for the dest socket, to
+ * emulate the 1st byte of a real recovery, but stops from there to
+ * keep dest QEMU in RECOVER.  This is needed so that we can kick off
+ * the recover process on dest QEMU (by triggering the G_IO_IN event).
+ *
+ * NOTE: this trick is not needed on src QEMUs, because src doesn't
+ * rely on an pre-existing G_IO_IN event, so it will always trigger the
+ * upcoming recovery anyway even if it can read nothing.
+ */
+#define QEMU_VM_COMMAND  0x08
+c = QEMU_VM_COMMAND;
+ret = send(pair2[1], , 1, 0);
+g_assert_cmpint(ret, ==, 1);
+
+migrate_recover(to, "fd:fd-mig");
+migrate_qmp(from, "fd:fd-mig", "{'resume': true}");
+
+/*
+ * Make sure both QEMU instances will go into RECOVER stage, then test
+ * kicking them out using migrate-pause.
+ */
+wait_for_postcopy_status(from, "postcopy-recover");
+wait_for_postcopy_status(to, "postcopy-recover");
+
+/*
+ * This would be issued by the admin upon noticing the hang, we should
+ * make sure we're able to kick this out.
+ */
+migrate_pause(from);
+wait_for_postcopy_status(from, "postcopy-paused");
+
+/* Do the same test on dest */
+migrate_pause(to);
+wait_for_postcopy_status(to, "postcopy-paused");
+
+close(pair1[0]);
+close(pair1[1]);
+close(pair2[0]);
+close(pair2[1]);
+}
+#endif /* _WIN32 */
+
 static void test_postcopy_recovery_common(MigrateCommon *args)
 {
 QTestState *from, *to;
@@ -1439,9 +1514,19 @@ static void test_postcopy_recovery_common(MigrateCommon 
*args)
  * migrate-recover command can only succeed if destination machine
  * is in the paused state
  */
-wait_for_migration_status(to, "postcopy-paused",
-  (const char * []) { "failed", "active",
-  "completed", NULL });
+wait_for_postcopy_status(to, "postcopy-paused");
+wait_for_postcopy_status(from, "postcopy-paused");
+
+#ifndef _WIN32
+if (args->postcopy_recovery_test_fail) {
+/*
+ * Test when a wrong socket specified for recover, and then the
+ * ability to kick it out, and continue with a correct socket.
+ */
+postcopy_re

[PULL 21/40] migration: per-mode blockers

2023-11-02 Thread Juan Quintela
From: Steve Sistare 

Extend the blocker interface so that a blocker can be registered for
one or more migration modes.  The existing interfaces register a
blocker for all modes, and the new interfaces take a varargs list
of modes.

Internally, maintain a separate blocker list per mode.  The same Error
object may be added to multiple lists.  When a block is deleted, it is
removed from every list, and the Error is freed.

No functional change until a new mode is added.

Signed-off-by: Steve Sistare 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <1698263069-406971-3-git-send-email-steven.sist...@oracle.com>
---
 include/migration/blocker.h | 44 +++--
 migration/migration.c   | 95 -
 stubs/migr-blocker.c| 10 
 3 files changed, 132 insertions(+), 17 deletions(-)

diff --git a/include/migration/blocker.h b/include/migration/blocker.h
index b048f301b4..a687ac0efe 100644
--- a/include/migration/blocker.h
+++ b/include/migration/blocker.h
@@ -14,8 +14,12 @@
 #ifndef MIGRATION_BLOCKER_H
 #define MIGRATION_BLOCKER_H
 
+#include "qapi/qapi-types-migration.h"
+
+#define MIG_MODE_ALL MIG_MODE__MAX
+
 /**
- * @migrate_add_blocker - prevent migration from proceeding
+ * @migrate_add_blocker - prevent all modes of migration from proceeding
  *
  * @reasonp - address of an error to be returned whenever migration is 
attempted
  *
@@ -30,8 +34,8 @@
 int migrate_add_blocker(Error **reasonp, Error **errp);
 
 /**
- * @migrate_add_blocker_internal - prevent migration from proceeding without
- * only-migrate implications
+ * @migrate_add_blocker_internal - prevent all modes of migration from
+ * proceeding, but ignore -only-migratable
  *
  * @reasonp - address of an error to be returned whenever migration is 
attempted
  *
@@ -50,7 +54,7 @@ int migrate_add_blocker(Error **reasonp, Error **errp);
 int migrate_add_blocker_internal(Error **reasonp, Error **errp);
 
 /**
- * @migrate_del_blocker - remove a blocking error from migration and free it.
+ * @migrate_del_blocker - remove a migration blocker from all modes and free 
it.
  *
  * @reasonp - address of the error blocking migration
  *
@@ -58,4 +62,36 @@ int migrate_add_blocker_internal(Error **reasonp, Error 
**errp);
  */
 void migrate_del_blocker(Error **reasonp);
 
+/**
+ * @migrate_add_blocker_normal - prevent normal migration mode from proceeding
+ *
+ * @reasonp - address of an error to be returned whenever migration is 
attempted
+ *
+ * @errp - [out] The reason (if any) we cannot block migration right now.
+ *
+ * @returns - 0 on success, -EBUSY/-EACCES on failure, with errp set.
+ *
+ * *@reasonp is freed and set to NULL if failure is returned.
+ * On success, the caller must not free @reasonp, except by
+ *   calling migrate_del_blocker.
+ */
+int migrate_add_blocker_normal(Error **reasonp, Error **errp);
+
+/**
+ * @migrate_add_blocker_modes - prevent some modes of migration from proceeding
+ *
+ * @reasonp - address of an error to be returned whenever migration is 
attempted
+ *
+ * @errp - [out] The reason (if any) we cannot block migration right now.
+ *
+ * @mode - one or more migration modes to be blocked.  The list is terminated
+ * by -1 or MIG_MODE_ALL.  For the latter, all modes are blocked.
+ *
+ * @returns - 0 on success, -EBUSY/-EACCES on failure, with errp set.
+ *
+ * *@reasonp is freed and set to NULL if failure is returned.
+ * On success, the caller must not free *@reasonp before the blocker is 
removed.
+ */
+int migrate_add_blocker_modes(Error **reasonp, Error **errp, MigMode mode, 
...);
+
 #endif
diff --git a/migration/migration.c b/migration/migration.c
index c334b9effd..11c1490090 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -92,7 +92,7 @@ enum mig_rp_message_type {
 static MigrationState *current_migration;
 static MigrationIncomingState *current_incoming;
 
-static GSList *migration_blockers;
+static GSList *migration_blockers[MIG_MODE__MAX];
 
 static bool migration_object_check(MigrationState *ms, Error **errp);
 static int migration_maybe_pause(MigrationState *s,
@@ -1043,7 +1043,7 @@ static void fill_source_migration_info(MigrationInfo 
*info)
 {
 MigrationState *s = migrate_get_current();
 int state = qatomic_read(>state);
-GSList *cur_blocker = migration_blockers;
+GSList *cur_blocker = migration_blockers[migrate_mode()];
 
 info->blocked_reasons = NULL;
 
@@ -1507,38 +1507,105 @@ int migrate_init(MigrationState *s, Error **errp)
 return 0;
 }
 
-int migrate_add_blocker_internal(Error **reasonp, Error **errp)
+static bool is_busy(Error **reasonp, Error **errp)
 {
+ERRP_GUARD();
+
 /* Snapshots are similar to migrations, so check RUN_STATE_SAVE_VM too. */
 if (runstate_check(RUN_STATE_SAVE_VM) || !migration_is_idle()) {
 error_propagate_prepend(errp, *reasonp,
   

[PULL 13/40] migration: Use vmstate_register_any() for eeprom93xx

2023-11-02 Thread Juan Quintela
We can have more than one eeprom93xx.
For instance:

e100_nic_realize() -> eeprom93xx_new()

Reviewed-by: Stefan Berger 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-13-quint...@redhat.com>
---
 hw/nvram/eeprom93xx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/nvram/eeprom93xx.c b/hw/nvram/eeprom93xx.c
index 1081e2cc0d..57d63638d7 100644
--- a/hw/nvram/eeprom93xx.c
+++ b/hw/nvram/eeprom93xx.c
@@ -321,7 +321,7 @@ eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
 /* Output DO is tristate, read results in 1. */
 eeprom->eedo = 1;
 logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
-vmstate_register(VMSTATE_IF(dev), 0, _eeprom, eeprom);
+vmstate_register_any(VMSTATE_IF(dev), _eeprom, eeprom);
 return eeprom;
 }
 
-- 
2.41.0




[PULL 26/40] migration: Refactor error handling in source return path

2023-11-02 Thread Juan Quintela
From: Peter Xu 

rp_state.error was a boolean used to show error happened in return path
thread.  That's not only duplicating error reporting (migrate_set_error),
but also not good enough in that we only do error_report() and set it to
true, we never can keep a history of the exact error and show it in
query-migrate.

To make this better, a few things done:

  - Use error_setg() rather than error_report() across the whole lifecycle
of return path thread, keeping the error in an Error*.

  - With above, no need to have mark_source_rp_bad(), remove it, alongside
with rp_state.error itself.

  - Use migrate_set_error() to apply that captured error to the global
migration object when error occured in this thread.

  - Do the same when detected qemufile error in source return path

We need to re-export qemu_file_get_error_obj() to do the last one.

Signed-off-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231017202633.296756-2-pet...@redhat.com>
---
 migration/migration.h  |   1 -
 migration/qemu-file.h  |   1 +
 migration/ram.h|   5 +-
 migration/migration.c  | 121 ++---
 migration/qemu-file.c  |   2 +-
 migration/ram.c|  41 +++---
 migration/trace-events |   4 +-
 7 files changed, 80 insertions(+), 95 deletions(-)

diff --git a/migration/migration.h b/migration/migration.h
index 5944107ad5..615b517594 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -308,7 +308,6 @@ struct MigrationState {
 /* Protected by qemu_file_lock */
 QEMUFile *from_dst_file;
 QemuThreadrp_thread;
-bool  error;
 /*
  * We can also check non-zero of rp_thread, but there's no "official"
  * way to do this, so this bool makes it slightly more elegant.
diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index 1774116f79..8aec9fabf7 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -68,6 +68,7 @@ int coroutine_mixed_fn qemu_peek_byte(QEMUFile *f, int 
offset);
 void qemu_file_skip(QEMUFile *f, int size);
 int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp);
 void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err);
+int qemu_file_get_error_obj(QEMUFile *f, Error **errp);
 void qemu_file_set_error(QEMUFile *f, int ret);
 int qemu_file_shutdown(QEMUFile *f);
 QEMUFile *qemu_file_get_return_path(QEMUFile *f);
diff --git a/migration/ram.h b/migration/ram.h
index 9f3ad1ee81..6e2c2c1950 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -50,7 +50,8 @@ uint64_t ram_bytes_total(void);
 void mig_throttle_counter_reset(void);
 
 uint64_t ram_pagesize_summary(void);
-int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len);
+int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len,
+ Error **errp);
 void ram_postcopy_migrated_memory_release(MigrationState *ms);
 /* For outgoing discard bitmap */
 void ram_postcopy_send_discard_bitmap(MigrationState *ms);
@@ -70,7 +71,7 @@ void ramblock_recv_bitmap_set(RAMBlock *rb, void *host_addr);
 void ramblock_recv_bitmap_set_range(RAMBlock *rb, void *host_addr, size_t nr);
 int64_t ramblock_recv_bitmap_send(QEMUFile *file,
   const char *block_name);
-int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb);
+int ram_dirty_bitmap_reload(MigrationState *s, RAMBlock *rb, Error **errp);
 bool ramblock_page_is_discarded(RAMBlock *rb, ram_addr_t start);
 void postcopy_preempt_shutdown_file(MigrationState *s);
 void *postcopy_preempt_thread(void *opaque);
diff --git a/migration/migration.c b/migration/migration.c
index 11c1490090..455ddc896a 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -99,7 +99,7 @@ static int migration_maybe_pause(MigrationState *s,
  int *current_active_state,
  int new_state);
 static void migrate_fd_cancel(MigrationState *s);
-static int close_return_path_on_source(MigrationState *s);
+static bool close_return_path_on_source(MigrationState *s);
 
 static void migration_downtime_start(MigrationState *s)
 {
@@ -1475,7 +1475,6 @@ int migrate_init(MigrationState *s, Error **errp)
 s->to_dst_file = NULL;
 s->state = MIGRATION_STATUS_NONE;
 s->rp_state.from_dst_file = NULL;
-s->rp_state.error = false;
 s->mbps = 0.0;
 s->pages_per_second = 0.0;
 s->downtime = 0;
@@ -1883,16 +1882,6 @@ void qmp_migrate_continue(MigrationStatus state, Error 
**errp)
 qemu_sem_post(>pause_sem);
 }
 
-/* migration thread support */
-/*
- * Something bad happened to the RP stream, mark an error
- * The caller shall print or trace something to indicate why
- */
-static void mark_source_rp_bad(MigrationState *s)
-{
-s->rp_state.error = true;
-}
-
 void migration_rp_wait(MigrationState

[PULL 23/40] cpr: relax vhost migration blockers

2023-11-02 Thread Juan Quintela
From: Steve Sistare 

vhost blocks migration if logging is not supported to track dirty
memory, and vhost-user blocks it if the log cannot be saved to a shm fd.

vhost-vdpa blocks migration if both hosts do not support all the device's
features using a shadow VQ, for tracking requests and dirty memory.

vhost-scsi blocks migration if storage cannot be shared across hosts,
or if state cannot be migrated.

None of these conditions apply if the old and new qemu processes do
not run concurrently, and if new qemu starts on the same host as old,
which is the case for cpr.

Narrow the scope of these blockers so they only apply to normal mode.
They will not block cpr modes when they are added in subsequent patches.

No functional change until a new mode is added.

Signed-off-by: Steve Sistare 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <1698263069-406971-5-git-send-email-steven.sist...@oracle.com>
---
 hw/scsi/vhost-scsi.c | 2 +-
 hw/virtio/vhost.c| 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 5d9e06a9bb..3126df9e1d 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -210,7 +210,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error 
**errp)
 "When external environment supports it (Orchestrator migrates "
 "target SCSI device state or use shared storage over network), 
"
 "set 'migratable' property to true to enable migration.");
-if (migrate_add_blocker(>migration_blocker, errp) < 0) {
+if (migrate_add_blocker_normal(>migration_blocker, errp) < 0) {
 goto free_virtio;
 }
 }
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index aa7b272452..9c9ae7109e 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1527,7 +1527,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
 }
 
 if (hdev->migration_blocker != NULL) {
-r = migrate_add_blocker(>migration_blocker, errp);
+r = migrate_add_blocker_normal(>migration_blocker, errp);
 if (r < 0) {
 goto fail_busyloop;
 }
-- 
2.41.0




[PULL 15/40] migration: Set downtime_start even for postcopy

2023-11-02 Thread Juan Quintela
From: Peter Xu 

Postcopy calculates its downtime separately.  It always sets
MigrationState.downtime properly, but not MigrationState.downtime_start.

Make postcopy do the same as other modes on properly recording the
timestamp when the VM is going to be stopped.  Drop the temporary variable
in postcopy_start() along the way.

Signed-off-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231030163346.765724-2-pet...@redhat.com>
---
 migration/migration.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 6abcbefd9c..6dcdc5be2b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2126,7 +2126,6 @@ static int postcopy_start(MigrationState *ms, Error 
**errp)
 int ret;
 QIOChannelBuffer *bioc;
 QEMUFile *fb;
-int64_t time_at_stop = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 uint64_t bandwidth = migrate_max_postcopy_bandwidth();
 bool restart_block = false;
 int cur_state = MIGRATION_STATUS_ACTIVE;
@@ -2148,6 +2147,8 @@ static int postcopy_start(MigrationState *ms, Error 
**errp)
 qemu_mutex_lock_iothread();
 trace_postcopy_start_set_run();
 
+ms->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+
 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
 global_state_store();
 ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
@@ -2250,7 +2251,7 @@ static int postcopy_start(MigrationState *ms, Error 
**errp)
 ms->postcopy_after_devices = true;
 migration_call_notifiers(ms);
 
-ms->downtime =  qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - time_at_stop;
+ms->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - ms->downtime_start;
 
 qemu_mutex_unlock_iothread();
 
-- 
2.41.0




[PULL 14/40] migration: Use vmstate_register_any() for vmware_vga

2023-11-02 Thread Juan Quintela
I have no idea if we can have more than one vmware_vga device, so play
it safe.

Reviewed-by: Stefan Berger 
Reviewed-by: Thomas Huth 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-14-quint...@redhat.com>
---
 hw/display/vmware_vga.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 09591fbd39..7490d43881 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1264,7 +1264,7 @@ static void vmsvga_init(DeviceState *dev, struct 
vmsvga_state_s *s,
 
 vga_common_init(>vga, OBJECT(dev), _fatal);
 vga_init(>vga, OBJECT(dev), address_space, io, true);
-vmstate_register(NULL, 0, _vga_common, >vga);
+vmstate_register_any(NULL, _vga_common, >vga);
 s->new_depth = 32;
 }
 
-- 
2.41.0




[PULL 10/40] migration: Check in savevm_state_handler_insert for dups

2023-11-02 Thread Juan Quintela
From: Peter Xu 

Before finally register one SaveStateEntry, we detect for duplicated
entries.  This could be helpful to notify us asap instead of get
silent migration failures which could be hard to diagnose.

For example, this patch will generate a message like this (if without
previous fixes on x2apic) as long as we wants to boot a VM instance
with "-smp 200,maxcpus=288,sockets=2,cores=72,threads=2" and QEMU will
bail out even before VM starts:

savevm_state_handler_insert: Detected duplicate SaveStateEntry: id=apic, 
instance_id=0x0

Suggested-by: Dr. David Alan Gilbert 
Signed-off-by: Peter Xu 
Reviewed-by: Juan Quintela 
Reviewed-by: Dr. David Alan Gilbert 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-10-quint...@redhat.com>
---
 migration/savevm.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/migration/savevm.c b/migration/savevm.c
index c7596c3e9b..2095ddd6f8 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -237,6 +237,8 @@ static SaveState savevm_state = {
 .global_section_id = 0,
 };
 
+static SaveStateEntry *find_se(const char *idstr, uint32_t instance_id);
+
 static bool should_validate_capability(int capability)
 {
 assert(capability >= 0 && capability < MIGRATION_CAPABILITY__MAX);
@@ -716,6 +718,18 @@ static void savevm_state_handler_insert(SaveStateEntry 
*nse)
 
 assert(priority <= MIG_PRI_MAX);
 
+/*
+ * This should never happen otherwise migration will probably fail
+ * silently somewhere because we can be wrongly applying one
+ * object properties upon another one.  Bail out ASAP.
+ */
+if (find_se(nse->idstr, nse->instance_id)) {
+error_report("%s: Detected duplicate SaveStateEntry: "
+ "id=%s, instance_id=0x%"PRIx32, __func__,
+ nse->idstr, nse->instance_id);
+exit(EXIT_FAILURE);
+}
+
 for (i = priority - 1; i >= 0; i--) {
 se = savevm_state.handler_pri_head[i];
 if (se != NULL) {
-- 
2.41.0




[PULL 18/40] migration: migration_stop_vm() helper

2023-11-02 Thread Juan Quintela
From: Peter Xu 

Provide a helper for non-COLO use case of migration to stop a VM.  This
prepares for adding some downtime relevant tracepoints to migration, where
they may or may not apply to COLO.

Signed-off-by: Peter Xu 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231030163346.765724-5-pet...@redhat.com>
---
 migration/migration.h |  2 ++
 migration/migration.c | 11 ---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/migration/migration.h b/migration/migration.h
index ae82004892..5944107ad5 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -544,4 +544,6 @@ void migration_rp_wait(MigrationState *s);
  */
 void migration_rp_kick(MigrationState *s);
 
+int migration_stop_vm(RunState state);
+
 #endif
diff --git a/migration/migration.c b/migration/migration.c
index 8aac0c753e..3e38294485 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -149,6 +149,11 @@ static gint page_request_addr_cmp(gconstpointer ap, 
gconstpointer bp)
 return (a > b) - (a < b);
 }
 
+int migration_stop_vm(RunState state)
+{
+return vm_stop_force_state(state);
+}
+
 void migration_object_init(void)
 {
 /* This can only be called once. */
@@ -2169,7 +2174,7 @@ static int postcopy_start(MigrationState *ms, Error 
**errp)
 
 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
 global_state_store();
-ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+ret = migration_stop_vm(RUN_STATE_FINISH_MIGRATE);
 if (ret < 0) {
 goto fail;
 }
@@ -2371,7 +2376,7 @@ static int migration_completion_precopy(MigrationState *s,
 s->vm_old_state = runstate_get();
 global_state_store();
 
-ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+ret = migration_stop_vm(RUN_STATE_FINISH_MIGRATE);
 trace_migration_completion_vm_stop(ret);
 if (ret < 0) {
 goto out_unlock;
@@ -3222,7 +3227,7 @@ static void *bg_migration_thread(void *opaque)
 
 global_state_store();
 /* Forcibly stop VM before saving state of vCPUs and devices */
-if (vm_stop_force_state(RUN_STATE_PAUSED)) {
+if (migration_stop_vm(RUN_STATE_PAUSED)) {
 goto fail;
 }
 /*
-- 
2.41.0




[PULL 03/40] hw/s390x/s390-stattrib: Simplify handling of the "migration-enabled" property

2023-11-02 Thread Juan Quintela
From: Thomas Huth 

There's no need for dedicated handlers here if they don't do anything
special.

Acked-by: David Hildenbrand 
Reviewed-by: Eric Farman 
Acked-by: Juan Quintela 
Signed-off-by: Thomas Huth 
Signed-off-by: Juan Quintela 
Message-ID: <20231020150554.664422-3-th...@redhat.com>
---
 hw/s390x/s390-stattrib.c | 27 +++
 1 file changed, 7 insertions(+), 20 deletions(-)

diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index 220e845d12..4f1ab57437 100644
--- a/hw/s390x/s390-stattrib.c
+++ b/hw/s390x/s390-stattrib.c
@@ -13,6 +13,7 @@
 #include "qemu/units.h"
 #include "migration/qemu-file.h"
 #include "migration/register.h"
+#include "hw/qdev-properties.h"
 #include "hw/s390x/storage-attributes.h"
 #include "qemu/error-report.h"
 #include "exec/ram_addr.h"
@@ -340,6 +341,11 @@ static void s390_stattrib_realize(DeviceState *dev, Error 
**errp)
 }
 }
 
+static Property s390_stattrib_props[] = {
+DEFINE_PROP_BOOL("migration-enabled", S390StAttribState, 
migration_enabled, true),
+DEFINE_PROP_END_OF_LIST(),
+};
+
 static void s390_stattrib_class_init(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
@@ -347,22 +353,7 @@ static void s390_stattrib_class_init(ObjectClass *oc, void 
*data)
 dc->hotpluggable = false;
 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 dc->realize = s390_stattrib_realize;
-}
-
-static inline bool s390_stattrib_get_migration_enabled(Object *obj,
-   Error **errp)
-{
-S390StAttribState *s = S390_STATTRIB(obj);
-
-return s->migration_enabled;
-}
-
-static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value,
-Error **errp)
-{
-S390StAttribState *s = S390_STATTRIB(obj);
-
-s->migration_enabled = value;
+device_class_set_props(dc, s390_stattrib_props);
 }
 
 static SaveVMHandlers savevm_s390_stattrib_handlers = {
@@ -383,10 +374,6 @@ static void s390_stattrib_instance_init(Object *obj)
 register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
  _s390_stattrib_handlers, sas);
 
-object_property_add_bool(obj, "migration-enabled",
- s390_stattrib_get_migration_enabled,
- s390_stattrib_set_migration_enabled);
-object_property_set_bool(obj, "migration-enabled", true, NULL);
 sas->migration_cur_gfn = 0;
 }
 
-- 
2.41.0




[PULL 11/40] migration: Improve example and documentation of vmstate_register()

2023-11-02 Thread Juan Quintela
Reviewed-by: Stefan Berger 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-11-quint...@redhat.com>
---
 docs/devel/migration.rst | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index be913630c3..240eb16d90 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -167,13 +167,17 @@ An example (from hw/input/pckbd.c)
   }
   };
 
-We are declaring the state with name "pckbd".
-The ``version_id`` is 3, and the fields are 4 uint8_t in a KBDState structure.
-We registered this with:
+We are declaring the state with name "pckbd".  The ``version_id`` is
+3, and there are 4 uint8_t fields in the KBDState structure.  We
+registered this ``VMSTATEDescription`` with one of the following
+functions.  The first one will generate a device ``instance_id``
+different for each registration.  Use the second one if you already
+have an id that is different for each instance of the device:
 
 .. code:: c
 
-vmstate_register(NULL, 0, _kbd, s);
+vmstate_register_any(NULL, _kbd, s);
+vmstate_register(NULL, instance_id, _kbd, s);
 
 For devices that are ``qdev`` based, we can register the device in the class
 init function:
-- 
2.41.0




[PULL 16/40] migration: Add migration_downtime_start|end() helpers

2023-11-02 Thread Juan Quintela
From: Peter Xu 

Unify the three users on recording downtimes with the same pair of helpers.

Signed-off-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231030163346.765724-3-pet...@redhat.com>
---
 migration/migration.c | 37 -
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index 6dcdc5be2b..8aac0c753e 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -101,6 +101,24 @@ static int migration_maybe_pause(MigrationState *s,
 static void migrate_fd_cancel(MigrationState *s);
 static int close_return_path_on_source(MigrationState *s);
 
+static void migration_downtime_start(MigrationState *s)
+{
+s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+}
+
+static void migration_downtime_end(MigrationState *s)
+{
+int64_t now = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+
+/*
+ * If downtime already set, should mean that postcopy already set it,
+ * then that should be the real downtime already.
+ */
+if (!s->downtime) {
+s->downtime = now - s->downtime_start;
+}
+}
+
 static bool migration_needs_multiple_sockets(void)
 {
 return migrate_multifd() || migrate_postcopy_preempt();
@@ -2147,7 +2165,7 @@ static int postcopy_start(MigrationState *ms, Error 
**errp)
 qemu_mutex_lock_iothread();
 trace_postcopy_start_set_run();
 
-ms->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+migration_downtime_start(ms);
 
 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
 global_state_store();
@@ -2251,7 +2269,7 @@ static int postcopy_start(MigrationState *ms, Error 
**errp)
 ms->postcopy_after_devices = true;
 migration_call_notifiers(ms);
 
-ms->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - ms->downtime_start;
+migration_downtime_end(ms);
 
 qemu_mutex_unlock_iothread();
 
@@ -2347,7 +2365,7 @@ static int migration_completion_precopy(MigrationState *s,
 int ret;
 
 qemu_mutex_lock_iothread();
-s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+migration_downtime_start(s);
 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
 
 s->vm_old_state = runstate_get();
@@ -2704,15 +2722,8 @@ static void migration_calculate_complete(MigrationState 
*s)
 int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 int64_t transfer_time;
 
+migration_downtime_end(s);
 s->total_time = end_time - s->start_time;
-if (!s->downtime) {
-/*
- * It's still not set, so we are precopy migration.  For
- * postcopy, downtime is calculated during postcopy_start().
- */
-s->downtime = end_time - s->downtime_start;
-}
-
 transfer_time = s->total_time - s->setup_time;
 if (transfer_time) {
 s->mbps = ((double) bytes * 8.0) / transfer_time / 1000;
@@ -3131,7 +3142,7 @@ static void bg_migration_vm_start_bh(void *opaque)
 s->vm_start_bh = NULL;
 
 vm_start();
-s->downtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - s->downtime_start;
+migration_downtime_end(s);
 }
 
 /**
@@ -3198,7 +3209,7 @@ static void *bg_migration_thread(void *opaque)
 s->setup_time = qemu_clock_get_ms(QEMU_CLOCK_HOST) - setup_start;
 
 trace_migration_thread_setup_complete();
-s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+migration_downtime_start(s);
 
 qemu_mutex_lock_iothread();
 
-- 
2.41.0




[PULL 09/40] migration: Hack to maintain backwards compatibility for ppc

2023-11-02 Thread Juan Quintela
Current code does:
- register pre_2_10_vmstate_dummy_icp with "icp/server" and instance
  dependinfg on cpu number
- for newer machines, it register vmstate_icp with "icp/server" name
  and instance 0
- now it unregisters "icp/server" for the 1st instance.

This is wrong at many levels:
- we shouldn't have two VMSTATEDescriptions with the same name
- In case this is the only solution that we can came with, it needs to
  be:
  * register pre_2_10_vmstate_dummy_icp
  * unregister pre_2_10_vmstate_dummy_icp
  * register real vmstate_icp

Created vmstate_replace_hack_for_ppc() with warnings left and right
that it is a hack.

CC: Cedric Le Goater 
CC: Daniel Henrique Barboza 
CC: David Gibson 
CC: Greg Kurz 

Reviewed-by: Nicholas Piggin 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-8-quint...@redhat.com>
---
 include/migration/vmstate.h | 11 +++
 hw/intc/xics.c  | 18 --
 hw/ppc/spapr.c  | 25 +++--
 migration/savevm.c  | 18 ++
 4 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1ea97ccf2d..9821918631 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -1230,6 +1230,17 @@ static inline int vmstate_register(VMStateIf *obj, int 
instance_id,
   opaque, -1, 0, NULL);
 }
 
+/**
+ * vmstate_replace_hack_for_ppc() - ppc used to abuse vmstate_register
+ *
+ * Don't even think about using this function in new code.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int vmstate_replace_hack_for_ppc(VMStateIf *obj, int instance_id,
+ const VMStateDescription *vmsd,
+ void *opaque);
+
 /**
  * vmstate_register_any() - legacy function to register state
  * serialisation description and let the function choose the id
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index c7f8abd71e..c77e986136 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -335,8 +335,22 @@ static void icp_realize(DeviceState *dev, Error **errp)
 return;
 }
 }
-
-vmstate_register(NULL, icp->cs->cpu_index, _icp_server, icp);
+/*
+ * The way that pre_2_10_icp is handling is really, really hacky.
+ * We used to have here this call:
+ *
+ * vmstate_register(NULL, icp->cs->cpu_index, _icp_server, icp);
+ *
+ * But we were doing:
+ * pre_2_10_vmstate_register_dummy_icp()
+ * this vmstate_register()
+ * pre_2_10_vmstate_unregister_dummy_icp()
+ *
+ * So for a short amount of time we had to vmstate entries with
+ * the same name.  This fixes it.
+ */
+vmstate_replace_hack_for_ppc(NULL, icp->cs->cpu_index,
+ _icp_server, icp);
 }
 
 static void icp_unrealize(DeviceState *dev)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index b25093be28..df09aa9d6a 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -143,6 +143,11 @@ static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
 }
 
 static const VMStateDescription pre_2_10_vmstate_dummy_icp = {
+/*
+ * Hack ahead.  We can't have two devices with the same name and
+ * instance id.  So I rename this to pass make check.
+ * Real help from people who knows the hardware is needed.
+ */
 .name = "icp/server",
 .version_id = 1,
 .minimum_version_id = 1,
@@ -155,16 +160,32 @@ static const VMStateDescription 
pre_2_10_vmstate_dummy_icp = {
 },
 };
 
+/*
+ * See comment in hw/intc/xics.c:icp_realize()
+ *
+ * You have to remove vmstate_replace_hack_for_ppc() when you remove
+ * the machine types that need the following function.
+ */
 static void pre_2_10_vmstate_register_dummy_icp(int i)
 {
 vmstate_register(NULL, i, _2_10_vmstate_dummy_icp,
  (void *)(uintptr_t) i);
 }
 
+/*
+ * See comment in hw/intc/xics.c:icp_realize()
+ *
+ * You have to remove vmstate_replace_hack_for_ppc() when you remove
+ * the machine types that need the following function.
+ */
 static void pre_2_10_vmstate_unregister_dummy_icp(int i)
 {
-vmstate_unregister(NULL, _2_10_vmstate_dummy_icp,
-   (void *)(uintptr_t) i);
+/*
+ * This used to be:
+ *
+ *vmstate_unregister(NULL, _2_10_vmstate_dummy_icp,
+ *  (void *)(uintptr_t) i);
+ */
 }
 
 int spapr_max_server_number(SpaprMachineState *spapr)
diff --git a/migration/savevm.c b/migration/savevm.c
index c7835e9c73..c7596c3e9b 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -846,6 +846,24 @@ static void vmstate_check(const VMStateDescription *vmsd)
 }
 }
 
+/*
+ * See comment in hw/intc/xics.c:icp_realize()
+ *
+ * This function can be removed when
+ * pre_2_10_vmstate_register_dummy_icp() is removed.
+ */
+int vmstate_replace_hack_for_ppc(VMStateI

[PULL 00/40] Migration 20231102 patches

2023-11-02 Thread Juan Quintela
The following changes since commit 6c9ae1ce82b65faa3f266fd103729878cf11e07e:

  Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging 
(2023-11-01 06:58:11 +0900)

are available in the Git repository at:

  https://gitlab.com/juan.quintela/qemu.git tags/migration-20231102-pull-request

for you to fetch changes up to 8e3766eefbb4036cbc280c1f1a0d28537929f7fb:

  migration: modify test_multifd_tcp_none() to use new QAPI syntax. (2023-11-02 
11:35:04 +0100)


Migration Pull request (20231102)

Hi

In this pull request:

- migration reboot mode (steve)
  * I disabled the test because our CI don't like programs using so
much shared memory.  Searching for a fix.
- test for postcopy recover (fabiano)
- MigrateAddress QAPI (het)
- better return path error handling (peter)
- traces for downtime (peter)
- vmstate_register() check for duplicates (juan)
  thomas find better solutions for s390x and ipmi.
  now also works on s390x

Please, apply.



Fabiano Rosas (2):
  tests/migration-test: Add a test for postcopy hangs during RECOVER
  migration: Convert the file backend to the new QAPI syntax

Het Gala (10):
  migration: New QAPI type 'MigrateAddress'
  migration: convert migration 'uri' into 'MigrateAddress'
  migration: convert socket backend to accept MigrateAddress
  migration: convert rdma backend to accept MigrateAddress
  migration: convert exec backend to accept MigrateAddress.
  migration: New migrate and migrate-incoming argument 'channels'
  migration: modify migration_channels_and_uri_compatible() for new QAPI
syntax
  migration: Implement MigrateChannelList to qmp migration flow.
  migration: Implement MigrateChannelList to hmp migration flow.
  migration: modify test_multifd_tcp_none() to use new QAPI syntax.

Juan Quintela (9):
  migration: Create vmstate_register_any()
  migration: Use vmstate_register_any()
  migration: Use vmstate_register_any() for isa-ide
  migration: Use VMSTATE_INSTANCE_ID_ANY for slirp
  migration: Hack to maintain backwards compatibility for ppc
  migration: Improve example and documentation of vmstate_register()
  migration: Use vmstate_register_any() for audio
  migration: Use vmstate_register_any() for eeprom93xx
  migration: Use vmstate_register_any() for vmware_vga

Peter Xu (9):
  migration: Check in savevm_state_handler_insert for dups
  migration: Set downtime_start even for postcopy
  migration: Add migration_downtime_start|end() helpers
  migration: Add per vmstate downtime tracepoints
  migration: migration_stop_vm() helper
  migration: Add tracepoints for downtime checkpoints
  migration: Refactor error handling in source return path
  migration: Allow network to fail even during recovery
  migration: Change ram_dirty_bitmap_reload() retval to bool

Steve Sistare (6):
  migration: mode parameter
  migration: per-mode blockers
  cpr: relax blockdev migration blockers
  cpr: relax vhost migration blockers
  cpr: reboot mode
  tests/qtest: migration: add reboot mode test

Thomas Huth (4):
  hw/ipmi: Don't call vmstate_register() from instance_init() functions
  hw/s390x/s390-skeys: Don't call register_savevm_live() during
instance_init()
  hw/s390x/s390-stattrib: Simplify handling of the "migration-enabled"
property
  hw/s390x/s390-stattrib: Don't call register_savevm_live() during
instance_init()

 docs/devel/migration.rst|  12 +-
 qapi/migration.json | 210 ++-
 include/hw/qdev-properties-system.h |   4 +
 include/migration/blocker.h |  44 ++-
 include/migration/misc.h|   1 +
 include/migration/vmstate.h |  28 ++
 migration/exec.h|   8 +-
 migration/file.h|  10 +-
 migration/migration.h   |  14 +-
 migration/options.h |   1 +
 migration/qemu-file.h   |   1 +
 migration/ram.h |   5 +-
 migration/rdma.h|   6 +-
 migration/socket.h  |   7 +-
 audio/audio.c   |   2 +-
 backends/dbus-vmstate.c |   3 +-
 backends/tpm/tpm_emulator.c |   3 +-
 block/parallels.c   |   2 +-
 block/qcow.c|   2 +-
 block/vdi.c |   2 +-
 block/vhdx.c|   2 +-
 block/vmdk.c|   2 +-
 block/vpc.c |   2 +-
 block/vvfat.c   |   2 +-
 hw/core/qdev-properties-system.c|  14 +
 hw/display/vmware_vga.c |   2 +-
 hw/i2c/core.c   |   2 +-
 hw/ide/isa.c|   2 +-
 hw/input/adb.c  |   2 +-
 hw/input/ads7846.c  |   2 +-
 hw/input/stellaris_input.c  |   3 +-
 hw/intc/xics.c  |  18 +-
 hw/ipmi/ipmi_bmc_extern.c   |  29 +

[PULL 08/40] migration: Use VMSTATE_INSTANCE_ID_ANY for slirp

2023-11-02 Thread Juan Quintela
Each user network conection create a new slirp instance.  We register
more than one slirp instance for number 0.

qemu-system-x86_64: -netdev user,id=hs1: savevm_state_handler_insert: Detected 
duplicate SaveStateEntry: id=slirp, instance_id=0x0
Broken pipe
../../../../../mnt/code/qemu/full/tests/qtest/libqtest.c:195: kill_qemu() tried 
to terminate QEMU process but encountered exit status 1 (expected 0)
Aborted (core dumped)

Reviewed-by: Stefan Berger 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-6-quint...@redhat.com>
---
 net/slirp.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/slirp.c b/net/slirp.c
index c33b3e02e7..25b49c4526 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -46,6 +46,7 @@
 #include "qapi/qmp/qdict.h"
 #include "util.h"
 #include "migration/register.h"
+#include "migration/vmstate.h"
 #include "migration/qemu-file-types.h"
 
 static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
@@ -659,8 +660,8 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
  * specific version?
  */
 g_assert(slirp_state_version() == 4);
-register_savevm_live("slirp", 0, slirp_state_version(),
- _slirp_state, s->slirp);
+register_savevm_live("slirp", VMSTATE_INSTANCE_ID_ANY,
+ slirp_state_version(), _slirp_state, s->slirp);
 
 s->poll_notifier.notify = net_slirp_poll_notify;
 main_loop_poll_add_notifier(>poll_notifier);
-- 
2.41.0




[PULL 07/40] migration: Use vmstate_register_any() for isa-ide

2023-11-02 Thread Juan Quintela
Otherwise qom-test fails.

ok 4 /i386/qom/x-remote
qemu-system-i386: savevm_state_handler_insert: Detected duplicate 
SaveStateEntry: id=isa-ide, instance_id=0x0
Broken pipe
../../../../../mnt/code/qemu/full/tests/qtest/libqtest.c:195: kill_qemu() tried 
to terminate QEMU process but encountered exit status 1 (expected 0)
Aborted (core dumped)
$

Reviewed-by: Stefan Berger 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-4-quint...@redhat.com>
---
 hw/ide/isa.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 95053e026f..ea60c08116 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -73,7 +73,7 @@ static void isa_ide_realizefn(DeviceState *dev, Error **errp)
 ide_bus_init(>bus, sizeof(s->bus), dev, 0, 2);
 ide_init_ioport(>bus, isadev, s->iobase, s->iobase2);
 ide_bus_init_output_irq(>bus, isa_get_irq(isadev, s->irqnum));
-vmstate_register(VMSTATE_IF(dev), 0, _ide_isa, s);
+vmstate_register_any(VMSTATE_IF(dev), _ide_isa, s);
 ide_bus_register_restart_cb(>bus);
 }
 
-- 
2.41.0




[PULL 05/40] migration: Create vmstate_register_any()

2023-11-02 Thread Juan Quintela
We have lots of cases where we are using an instance_id==0 when we
should be using VMSTATE_INSTANCE_ID_ANY (-1).  Basically everything
that can have more than one needs to have a proper instance_id or -1
and the system will take one for it.

vmstate_register_any(): We register with -1.

Reviewed-by: Stefan Berger 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-2-quint...@redhat.com>
---
 include/migration/vmstate.h | 17 +
 1 file changed, 17 insertions(+)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1af181877c..1ea97ccf2d 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -1230,6 +1230,23 @@ static inline int vmstate_register(VMStateIf *obj, int 
instance_id,
   opaque, -1, 0, NULL);
 }
 
+/**
+ * vmstate_register_any() - legacy function to register state
+ * serialisation description and let the function choose the id
+ *
+ * New code shouldn't be using this function as QOM-ified devices have
+ * dc->vmsd to store the serialisation description.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static inline int vmstate_register_any(VMStateIf *obj,
+   const VMStateDescription *vmsd,
+   void *opaque)
+{
+return vmstate_register_with_alias_id(obj, VMSTATE_INSTANCE_ID_ANY, vmsd,
+  opaque, -1, 0, NULL);
+}
+
 void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
 void *opaque);
 
-- 
2.41.0




[PULL 06/40] migration: Use vmstate_register_any()

2023-11-02 Thread Juan Quintela
This are the easiest cases, where we were already using
VMSTATE_INSTANCE_ID_ANY.

Reviewed-by: Stefan Berger 
Signed-off-by: Juan Quintela 
Message-ID: <20231020090731.28701-3-quint...@redhat.com>
---
 backends/dbus-vmstate.c | 3 +--
 backends/tpm/tpm_emulator.c | 3 +--
 hw/i2c/core.c   | 2 +-
 hw/input/adb.c  | 2 +-
 hw/input/ads7846.c  | 2 +-
 hw/input/stellaris_input.c  | 3 +--
 hw/net/eepro100.c   | 3 +--
 hw/pci/pci.c| 2 +-
 hw/ppc/spapr_nvdimm.c   | 3 +--
 hw/timer/arm_timer.c| 2 +-
 hw/virtio/virtio-mem.c  | 4 ++--
 11 files changed, 12 insertions(+), 17 deletions(-)

diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c
index 57369ec0f2..a9d8cb0acd 100644
--- a/backends/dbus-vmstate.c
+++ b/backends/dbus-vmstate.c
@@ -426,8 +426,7 @@ dbus_vmstate_complete(UserCreatable *uc, Error **errp)
 return;
 }
 
-if (vmstate_register(VMSTATE_IF(self), VMSTATE_INSTANCE_ID_ANY,
- _vmstate, self) < 0) {
+if (vmstate_register_any(VMSTATE_IF(self), _vmstate, self) < 0) {
 error_setg(errp, "Failed to register vmstate");
 }
 }
diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index bf1a90f5d7..f7f1b4ad7a 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -975,8 +975,7 @@ static void tpm_emulator_inst_init(Object *obj)
 qemu_add_vm_change_state_handler(tpm_emulator_vm_state_change,
  tpm_emu);
 
-vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
- _tpm_emulator, obj);
+vmstate_register_any(NULL, _tpm_emulator, obj);
 }
 
 /*
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index bed594fe59..879a1d45cb 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -64,7 +64,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
 bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name));
 QLIST_INIT(>current_devs);
 QSIMPLEQ_INIT(>pending_masters);
-vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, _i2c_bus, bus);
+vmstate_register_any(NULL, _i2c_bus, bus);
 return bus;
 }
 
diff --git a/hw/input/adb.c b/hw/input/adb.c
index 214ae6f42b..8aed0da2cd 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -247,7 +247,7 @@ static void adb_bus_realize(BusState *qbus, Error **errp)
 adb_bus->autopoll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, adb_autopoll,
adb_bus);
 
-vmstate_register(NULL, -1, _adb_bus, adb_bus);
+vmstate_register_any(NULL, _adb_bus, adb_bus);
 }
 
 static void adb_bus_unrealize(BusState *qbus)
diff --git a/hw/input/ads7846.c b/hw/input/ads7846.c
index dc0998ac79..91116c6bdb 100644
--- a/hw/input/ads7846.c
+++ b/hw/input/ads7846.c
@@ -158,7 +158,7 @@ static void ads7846_realize(SSIPeripheral *d, Error **errp)
 
 ads7846_int_update(s);
 
-vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, _ads7846, s);
+vmstate_register_any(NULL, _ads7846, s);
 }
 
 static void ads7846_class_init(ObjectClass *klass, void *data)
diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c
index e6ee5e11f1..a58721c8cd 100644
--- a/hw/input/stellaris_input.c
+++ b/hw/input/stellaris_input.c
@@ -88,6 +88,5 @@ void stellaris_gamepad_init(int n, qemu_irq *irq, const int 
*keycode)
 }
 s->num_buttons = n;
 qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
-vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
- _stellaris_gamepad, s);
+vmstate_register_any(NULL, _stellaris_gamepad, s);
 }
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index dc07984ae9..94ce9e18ff 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -1883,8 +1883,7 @@ static void e100_nic_realize(PCIDevice *pci_dev, Error 
**errp)
 
 s->vmstate = g_memdup(_eepro100, sizeof(vmstate_eepro100));
 s->vmstate->name = qemu_get_queue(s->nic)->model;
-vmstate_register(VMSTATE_IF(_dev->qdev), VMSTATE_INSTANCE_ID_ANY,
- s->vmstate, s);
+vmstate_register_any(VMSTATE_IF(_dev->qdev), s->vmstate, s);
 }
 
 static void eepro100_instance_init(Object *obj)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 7d09e1a39d..885c04b6f5 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -147,7 +147,7 @@ static void pci_bus_realize(BusState *qbus, Error **errp)
 bus->machine_done.notify = pcibus_machine_done;
 qemu_add_machine_init_done_notifier(>machine_done);
 
-vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, _pcibus, bus);
+vmstate_register_any(NULL, _pcibus, bus);
 }
 
 static void pcie_bus_realize(BusState *qbus, Error **errp)
diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c
index b2f009c816..ad7afe7544 100644
--- a/hw/ppc/spapr_nvdimm.c
+++ b/hw/ppc/spapr_nvdimm.c
@@ -876,8 +876,7 @@ static void spapr_nvdimm_realize(NVDIMMDevice *dimm, Error 
**errp)
 s_nvdim

[PULL 04/40] hw/s390x/s390-stattrib: Don't call register_savevm_live() during instance_init()

2023-11-02 Thread Juan Quintela
From: Thomas Huth 

We must not call register_savevm_live() from an instance_init() function
(since this could be called multiple times during device introspection).
Move this to the realize() function instead.

Acked-by: David Hildenbrand 
Reviewed-by: Eric Farman 
Signed-off-by: Juan Quintela 
Signed-off-by: Thomas Huth 
Signed-off-by: Juan Quintela 
Message-ID: <20231020150554.664422-4-th...@redhat.com>
---
 hw/s390x/s390-stattrib.c | 29 +++--
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index 4f1ab57437..c483b62a9b 100644
--- a/hw/s390x/s390-stattrib.c
+++ b/hw/s390x/s390-stattrib.c
@@ -331,6 +331,17 @@ static const TypeInfo qemu_s390_stattrib_info = {
 
 /* Generic abstract object: */
 
+static SaveVMHandlers savevm_s390_stattrib_handlers = {
+.save_setup = cmma_save_setup,
+.save_live_iterate = cmma_save_iterate,
+.save_live_complete_precopy = cmma_save_complete,
+.state_pending_exact = cmma_state_pending,
+.state_pending_estimate = cmma_state_pending,
+.save_cleanup = cmma_save_cleanup,
+.load_state = cmma_load,
+.is_active = cmma_active,
+};
+
 static void s390_stattrib_realize(DeviceState *dev, Error **errp)
 {
 bool ambiguous = false;
@@ -338,7 +349,11 @@ static void s390_stattrib_realize(DeviceState *dev, Error 
**errp)
 object_resolve_path_type("", TYPE_S390_STATTRIB, );
 if (ambiguous) {
 error_setg(errp, "storage_attributes device already exists");
+return;
 }
+
+register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
+ _s390_stattrib_handlers, dev);
 }
 
 static Property s390_stattrib_props[] = {
@@ -356,24 +371,10 @@ static void s390_stattrib_class_init(ObjectClass *oc, 
void *data)
 device_class_set_props(dc, s390_stattrib_props);
 }
 
-static SaveVMHandlers savevm_s390_stattrib_handlers = {
-.save_setup = cmma_save_setup,
-.save_live_iterate = cmma_save_iterate,
-.save_live_complete_precopy = cmma_save_complete,
-.state_pending_exact = cmma_state_pending,
-.state_pending_estimate = cmma_state_pending,
-.save_cleanup = cmma_save_cleanup,
-.load_state = cmma_load,
-.is_active = cmma_active,
-};
-
 static void s390_stattrib_instance_init(Object *obj)
 {
 S390StAttribState *sas = S390_STATTRIB(obj);
 
-register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
- _s390_stattrib_handlers, sas);
-
 sas->migration_cur_gfn = 0;
 }
 
-- 
2.41.0




[PULL 02/40] hw/s390x/s390-skeys: Don't call register_savevm_live() during instance_init()

2023-11-02 Thread Juan Quintela
From: Thomas Huth 

Since the instance_init() function immediately tries to set the
property to "true", the s390_skeys_set_migration_enabled() tries
to register a savevm handler during instance_init(). However,
instance_init() functions can be called multiple times, e.g. for
introspection of devices. That means multiple instances of devices
can be created during runtime (which is fine as long as they all
don't get realized, too), so the "Prevent double registration of
savevm handler" check in the s390_skeys_set_migration_enabled()
function does not work at all as expected (since there could be
more than one instance).

Thus we must not call register_savevm_live() from an instance_init()
function at all. Move this to the realize() function instead. This
way we can also get rid of the property getter and setter functions
completely, simplifying the code along the way quite a bit.

Acked-by: David Hildenbrand 
Reviewed-by: Eric Farman 
Acked-by: Juan Quintela 
Signed-off-by: Thomas Huth 
Signed-off-by: Juan Quintela 
Message-ID: <20231020150554.664422-2-th...@redhat.com>
---
 hw/s390x/s390-skeys.c | 36 +---
 1 file changed, 9 insertions(+), 27 deletions(-)

diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index 5024faf411..8f5159d85d 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -12,6 +12,7 @@
 #include "qemu/osdep.h"
 #include "qemu/units.h"
 #include "hw/boards.h"
+#include "hw/qdev-properties.h"
 #include "hw/s390x/storage-keys.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-misc-target.h"
@@ -432,58 +433,39 @@ static int s390_storage_keys_load(QEMUFile *f, void 
*opaque, int version_id)
 return ret;
 }
 
-static inline bool s390_skeys_get_migration_enabled(Object *obj, Error **errp)
-{
-S390SKeysState *ss = S390_SKEYS(obj);
-
-return ss->migration_enabled;
-}
-
 static SaveVMHandlers savevm_s390_storage_keys = {
 .save_state = s390_storage_keys_save,
 .load_state = s390_storage_keys_load,
 };
 
-static inline void s390_skeys_set_migration_enabled(Object *obj, bool value,
-Error **errp)
+static void s390_skeys_realize(DeviceState *dev, Error **errp)
 {
-S390SKeysState *ss = S390_SKEYS(obj);
-
-/* Prevent double registration of savevm handler */
-if (ss->migration_enabled == value) {
-return;
-}
-
-ss->migration_enabled = value;
+S390SKeysState *ss = S390_SKEYS(dev);
 
 if (ss->migration_enabled) {
 register_savevm_live(TYPE_S390_SKEYS, 0, 1,
  _s390_storage_keys, ss);
-} else {
-unregister_savevm(VMSTATE_IF(ss), TYPE_S390_SKEYS, ss);
 }
 }
 
-static void s390_skeys_instance_init(Object *obj)
-{
-object_property_add_bool(obj, "migration-enabled",
- s390_skeys_get_migration_enabled,
- s390_skeys_set_migration_enabled);
-object_property_set_bool(obj, "migration-enabled", true, NULL);
-}
+static Property s390_skeys_props[] = {
+DEFINE_PROP_BOOL("migration-enabled", S390SKeysState, migration_enabled, 
true),
+DEFINE_PROP_END_OF_LIST(),
+};
 
 static void s390_skeys_class_init(ObjectClass *oc, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS(oc);
 
 dc->hotpluggable = false;
+dc->realize = s390_skeys_realize;
+device_class_set_props(dc, s390_skeys_props);
 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 }
 
 static const TypeInfo s390_skeys_info = {
 .name  = TYPE_S390_SKEYS,
 .parent= TYPE_DEVICE,
-.instance_init = s390_skeys_instance_init,
 .instance_size = sizeof(S390SKeysState),
 .class_init= s390_skeys_class_init,
 .class_size= sizeof(S390SKeysClass),
-- 
2.41.0




[PULL 01/40] hw/ipmi: Don't call vmstate_register() from instance_init() functions

2023-11-02 Thread Juan Quintela
From: Thomas Huth 

instance_init() can be called multiple times, e.g. during introspection
of the device. We should not install the vmstate handlers here. Do it
in the realize() function instead.

Signed-off-by: Thomas Huth 
Reviewed-by: Juan Quintela 
Acked-by: Corey Minyard 
Signed-off-by: Juan Quintela 
Message-ID: <20231020145554.662751-1-th...@redhat.com>
---
 hw/ipmi/ipmi_bmc_extern.c | 29 ---
 hw/ipmi/isa_ipmi_bt.c | 34 +-
 hw/ipmi/isa_ipmi_kcs.c| 50 +++
 3 files changed, 57 insertions(+), 56 deletions(-)

diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c
index e232d35ba2..2117dad35a 100644
--- a/hw/ipmi/ipmi_bmc_extern.c
+++ b/hw/ipmi/ipmi_bmc_extern.c
@@ -453,19 +453,6 @@ static void ipmi_bmc_extern_handle_reset(IPMIBmc *b)
 continue_send(ibe);
 }
 
-static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
-{
-IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
-
-if (!qemu_chr_fe_backend_connected(>chr)) {
-error_setg(errp, "IPMI external bmc requires chardev attribute");
-return;
-}
-
-qemu_chr_fe_set_handlers(>chr, can_receive, receive,
- chr_event, NULL, ibe, NULL, true);
-}
-
 static int ipmi_bmc_extern_post_migrate(void *opaque, int version_id)
 {
 IPMIBmcExtern *ibe = opaque;
@@ -499,12 +486,26 @@ static const VMStateDescription vmstate_ipmi_bmc_extern = 
{
 }
 };
 
+static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp)
+{
+IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(dev);
+
+if (!qemu_chr_fe_backend_connected(>chr)) {
+error_setg(errp, "IPMI external bmc requires chardev attribute");
+return;
+}
+
+qemu_chr_fe_set_handlers(>chr, can_receive, receive,
+ chr_event, NULL, ibe, NULL, true);
+
+vmstate_register(NULL, 0, _ipmi_bmc_extern, ibe);
+}
+
 static void ipmi_bmc_extern_init(Object *obj)
 {
 IPMIBmcExtern *ibe = IPMI_BMC_EXTERN(obj);
 
 ibe->extern_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, extern_timeout, ibe);
-vmstate_register(NULL, 0, _ipmi_bmc_extern, ibe);
 }
 
 static void ipmi_bmc_extern_finalize(Object *obj)
diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c
index a83e7243d6..aec064d3cd 100644
--- a/hw/ipmi/isa_ipmi_bt.c
+++ b/hw/ipmi/isa_ipmi_bt.c
@@ -68,6 +68,21 @@ static void isa_ipmi_bt_lower_irq(IPMIBT *ib)
 qemu_irq_lower(iib->irq);
 }
 
+static const VMStateDescription vmstate_ISAIPMIBTDevice = {
+.name = TYPE_IPMI_INTERFACE_PREFIX "isa-bt",
+.version_id = 2,
+.minimum_version_id = 2,
+/*
+ * Version 1 had messed up the array transfer, it's not even usable
+ * because it used VMSTATE_VBUFFER_UINT32, but it did not transfer
+ * the buffer length, so random things would happen.
+ */
+.fields  = (VMStateField[]) {
+VMSTATE_STRUCT(bt, ISAIPMIBTDevice, 1, vmstate_IPMIBT, IPMIBT),
+VMSTATE_END_OF_LIST()
+}
+};
+
 static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
 {
 Error *err = NULL;
@@ -102,30 +117,15 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error 
**errp)
 qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length);
 
 isa_register_ioport(isadev, >bt.io, iib->bt.io_base);
-}
 
-static const VMStateDescription vmstate_ISAIPMIBTDevice = {
-.name = TYPE_IPMI_INTERFACE_PREFIX "isa-bt",
-.version_id = 2,
-.minimum_version_id = 2,
-/*
- * Version 1 had messed up the array transfer, it's not even usable
- * because it used VMSTATE_VBUFFER_UINT32, but it did not transfer
- * the buffer length, so random things would happen.
- */
-.fields  = (VMStateField[]) {
-VMSTATE_STRUCT(bt, ISAIPMIBTDevice, 1, vmstate_IPMIBT, IPMIBT),
-VMSTATE_END_OF_LIST()
-}
-};
+vmstate_register(NULL, 0, _ISAIPMIBTDevice, dev);
+}
 
 static void isa_ipmi_bt_init(Object *obj)
 {
 ISAIPMIBTDevice *iib = ISA_IPMI_BT(obj);
 
 ipmi_bmc_find_and_link(obj, (Object **) >bt.bmc);
-
-vmstate_register(NULL, 0, _ISAIPMIBTDevice, iib);
 }
 
 static void *isa_ipmi_bt_get_backend_data(IPMIInterface *ii)
diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c
index b2ed70b9da..b5dcb64616 100644
--- a/hw/ipmi/isa_ipmi_kcs.c
+++ b/hw/ipmi/isa_ipmi_kcs.c
@@ -67,6 +67,24 @@ static void isa_ipmi_kcs_lower_irq(IPMIKCS *ik)
 qemu_irq_lower(iik->irq);
 }
 
+static bool vmstate_kcs_before_version2(void *opaque, int version)
+{
+return version <= 1;
+}
+
+static const VMStateDescription vmstate_ISAIPMIKCSDevice = {
+.name = TYPE_IPMI_INTERFACE,
+.version_id = 2,
+.minimum_version_id = 1,
+.fields  = (VMStateField[]) {
+VMSTATE_VSTRUCT_TEST(kcs, ISAIPMIKCSDevice, 
vmstate_kcs_before_version2,
+ 0, vmstate_IPMIK

[PULL 25/38] migration: Deprecate old compression method

2023-10-31 Thread Juan Quintela
Acked-by: Stefan Hajnoczi 
Acked-by: Peter Xu 
Reviewed-by: Markus Armbruster 
Signed-off-by: Juan Quintela 
Message-ID: <20231018115513.2163-6-quint...@redhat.com>
---
 docs/about/deprecated.rst |  8 +
 qapi/migration.json   | 63 ++-
 migration/options.c   | 13 
 3 files changed, 64 insertions(+), 20 deletions(-)

diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 35c8d7d1d4..ecccd5d3fc 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -496,3 +496,11 @@ devices or none.
 Please see "QMP invocation for live storage migration with
 ``blockdev-mirror`` + NBD" in docs/interop/live-block-operations.rst
 for a detailed explanation.
+
+old compression method (since 8.2)
+''
+
+Compression method fails too much.  Too many races.  We are going to
+remove it if nobody fixes it.  For starters, migration-test
+compression tests are disabled becase they fail randomly.  If you need
+compression, use multifd compression methods.
diff --git a/qapi/migration.json b/qapi/migration.json
index e3b00a215b..e6610af428 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -272,6 +272,10 @@
 # Features:
 #
 # @deprecated: Member @disk is deprecated because block migration is.
+# Member @compression is deprecated because it is unreliable and
+# untested.  It is recommended to use multifd migration, which
+# offers an alternative compression implementation that is
+# reliable and tested.
 #
 # Since: 0.14
 ##
@@ -289,7 +293,7 @@
'*blocked-reasons': ['str'],
'*postcopy-blocktime': 'uint32',
'*postcopy-vcpu-blocktime': ['uint32'],
-   '*compression': 'CompressionStats',
+   '*compression': { 'type': 'CompressionStats', 'features': [ 
'deprecated' ] },
'*socket-address': ['SocketAddress'],
'*dirty-limit-throttle-time-per-round': 'uint64',
'*dirty-limit-ring-full-time': 'uint64'} }
@@ -530,7 +534,10 @@
 # Features:
 #
 # @deprecated: Member @block is deprecated.  Use blockdev-mirror with
-# NBD instead.
+# NBD instead.  Member @compression is deprecated because it is
+# unreliable and untested.  It is recommended to use multifd
+# migration, which offers an alternative compression
+# implementation that is reliable and tested.
 #
 # @unstable: Members @x-colo and @x-ignore-shared are experimental.
 #
@@ -538,7 +545,8 @@
 ##
 { 'enum': 'MigrationCapability',
   'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks',
-   'compress', 'events', 'postcopy-ram',
+   { 'name': 'compress', 'features': [ 'deprecated' ] },
+   'events', 'postcopy-ram',
{ 'name': 'x-colo', 'features': [ 'unstable' ] },
'release-ram',
{ 'name': 'block', 'features': [ 'deprecated' ] },
@@ -844,7 +852,9 @@
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
-# blockdev-mirror with NBD instead.
+# blockdev-mirror with NBD instead.  Members @compress-level,
+# @compress-threads, @decompress-threads and @compress-wait-thread
+# are deprecated because @compression is deprecated.
 #
 # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
 # are experimental.
@@ -854,8 +864,11 @@
 { 'enum': 'MigrationParameter',
   'data': ['announce-initial', 'announce-max',
'announce-rounds', 'announce-step',
-   'compress-level', 'compress-threads', 'decompress-threads',
-   'compress-wait-thread', 'throttle-trigger-threshold',
+   { 'name': 'compress-level', 'features': [ 'deprecated' ] },
+   { 'name': 'compress-threads', 'features': [ 'deprecated' ] },
+   { 'name': 'decompress-threads', 'features': [ 'deprecated' ] },
+   { 'name': 'compress-wait-thread', 'features': [ 'deprecated' ] },
+   'throttle-trigger-threshold',
'cpu-throttle-initial', 'cpu-throttle-increment',
'cpu-throttle-tailslow',
'tls-creds', 'tls-hostname', 'tls-authz', 'max-bandwidth',
@@ -1023,7 +1036,9 @@
 # Features:
 #
 # @deprecated: Member @block-incremental is deprecated.  Use
-# blockdev-mirror with NBD instead.
+# blockdev-mirror with NBD instead.  Members @compress-level,
+# @compress-threads, @decompress-threads and @compress-wait-thread
+# are deprecated because @compression is deprecated.
 #
 # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
 # are experimental.
@@ -1038,10 +1053,14 @@
 '*announce-max': 'size',
 '*announce-rounds': 'size',
 '*announce-step': 'size',
-'*compress-level': 'uint8',
-'*compress-threads': 'uint8',
-'*compress-wait-thread': 'bool',
-'*decompress-threads': 'uint8',
+'*compress-level': { 'type': 'uint8',
+  

[PULL 24/38] migration: Deprecate block migration

2023-10-31 Thread Juan Quintela
It is obsolete.  It is better to use driver-mirror with NBD instead.

CC: Kevin Wolf 
CC: Eric Blake 
CC: Stefan Hajnoczi 
CC: Hanna Czenczek 

Acked-by: Stefan Hajnoczi 
Reviewed-by: Markus Armbruster 
Signed-off-by: Juan Quintela 
Message-ID: <20231018115513.2163-5-quint...@redhat.com>
---
 docs/about/deprecated.rst | 10 ++
 qapi/migration.json   | 29 -
 migration/block.c |  3 +++
 migration/options.c   |  9 -
 4 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index c1613468e6..35c8d7d1d4 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -486,3 +486,13 @@ Use blockdev-mirror with NBD instead.
 As an intermediate step the ``blk`` functionality can be achieved by
 setting the ``block`` migration capability to ``true``.  But this
 capability is also deprecated.
+
+block migration (since 8.2)
+'''
+
+Block migration is too inflexible.  It needs to migrate all block
+devices or none.
+
+Please see "QMP invocation for live storage migration with
+``blockdev-mirror`` + NBD" in docs/interop/live-block-operations.rst
+for a detailed explanation.
diff --git a/qapi/migration.json b/qapi/migration.json
index 3765c2b662..e3b00a215b 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -269,11 +269,15 @@
 # average memory load of the virtual CPU indirectly.  Note that
 # zero means guest doesn't dirty memory.  (Since 8.1)
 #
+# Features:
+#
+# @deprecated: Member @disk is deprecated because block migration is.
+#
 # Since: 0.14
 ##
 { 'struct': 'MigrationInfo',
   'data': {'*status': 'MigrationStatus', '*ram': 'MigrationStats',
-   '*disk': 'MigrationStats',
+   '*disk': { 'type': 'MigrationStats', 'features': [ 'deprecated' ] },
'*vfio': 'VfioStats',
'*xbzrle-cache': 'XBZRLECacheStats',
'*total-time': 'int',
@@ -525,6 +529,9 @@
 #
 # Features:
 #
+# @deprecated: Member @block is deprecated.  Use blockdev-mirror with
+# NBD instead.
+#
 # @unstable: Members @x-colo and @x-ignore-shared are experimental.
 #
 # Since: 1.2
@@ -534,7 +541,8 @@
'compress', 'events', 'postcopy-ram',
{ 'name': 'x-colo', 'features': [ 'unstable' ] },
'release-ram',
-   'block', 'return-path', 'pause-before-switchover', 'multifd',
+   { 'name': 'block', 'features': [ 'deprecated' ] },
+   'return-path', 'pause-before-switchover', 'multifd',
'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
{ 'name': 'x-ignore-shared', 'features': [ 'unstable' ] },
'validate-uuid', 'background-snapshot',
@@ -835,6 +843,9 @@
 #
 # Features:
 #
+# @deprecated: Member @block-incremental is deprecated.  Use
+# blockdev-mirror with NBD instead.
+#
 # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
 # are experimental.
 #
@@ -850,7 +861,7 @@
'tls-creds', 'tls-hostname', 'tls-authz', 'max-bandwidth',
'avail-switchover-bandwidth', 'downtime-limit',
{ 'name': 'x-checkpoint-delay', 'features': [ 'unstable' ] },
-   'block-incremental',
+   { 'name': 'block-incremental', 'features': [ 'deprecated' ] },
'multifd-channels',
'xbzrle-cache-size', 'max-postcopy-bandwidth',
'max-cpu-throttle', 'multifd-compression',
@@ -1011,6 +1022,9 @@
 #
 # Features:
 #
+# @deprecated: Member @block-incremental is deprecated.  Use
+# blockdev-mirror with NBD instead.
+#
 # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
 # are experimental.
 #
@@ -1040,7 +1054,8 @@
 '*downtime-limit': 'uint64',
 '*x-checkpoint-delay': { 'type': 'uint32',
  'features': [ 'unstable' ] },
-'*block-incremental': 'bool',
+'*block-incremental': { 'type': 'bool',
+'features': [ 'deprecated' ] },
 '*multifd-channels': 'uint8',
 '*xbzrle-cache-size': 'size',
 '*max-postcopy-bandwidth': 'size',
@@ -1225,6 +1240,9 @@
 #
 # Features:
 #
+# @deprecated: Member @block-incremental is deprecated.  Use
+# blockdev-mirror with NBD instead.
+#
 # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period
 # are experimental.
 #
@@ -1251,7 +1269,8 @@
 '*downtime-limit': 'uint64',
 '*x-checkpoint-delay': { 'type': 'uint32',
  'features': [ 'unstable' ] },
-'*block-incremental': 'bool',
+'*block-incremental': { 'type': 'bool',
+'features': [ 'deprecated' ] },
 '*multifd-channels': 'uint8',
 '*xbzrle-cache-size': 'size',
 '*max-postcopy-bandwidth': 'size',
diff --git a/migration/block.c b/m

[PULL 13/38] migration: Create compress_update_rates()

2023-10-31 Thread Juan Quintela
So we can move more compression_counters stuff to ram-compress.c.
Create compression_counters struct to add the stuff that was on
MigrationState.

Reviewed-by: Lukas Straub 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-8-quint...@redhat.com>
---
 migration/ram-compress.h |  1 +
 migration/ram.h  |  1 -
 migration/ram-compress.c | 42 +++-
 migration/ram.c  | 29 +--
 4 files changed, 43 insertions(+), 30 deletions(-)

diff --git a/migration/ram-compress.h b/migration/ram-compress.h
index b228640092..76dacd3ec7 100644
--- a/migration/ram-compress.h
+++ b/migration/ram-compress.h
@@ -71,5 +71,6 @@ void decompress_data_with_multi_threads(QEMUFile *f, void 
*host, int len);
 void populate_compress(MigrationInfo *info);
 uint64_t ram_compressed_pages(void);
 void update_compress_thread_counts(const CompressParam *param, int bytes_xmit);
+void compress_update_rates(uint64_t page_count);
 
 #endif
diff --git a/migration/ram.h b/migration/ram.h
index 3f724b2f02..9f3ad1ee81 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -34,7 +34,6 @@
 #include "io/channel.h"
 
 extern XBZRLECacheStats xbzrle_counters;
-extern CompressionStats compression_counters;
 
 /* Should be holding either ram_list.mutex, or the RCU lock. */
 #define RAMBLOCK_FOREACH_NOT_IGNORED(block)\
diff --git a/migration/ram-compress.c b/migration/ram-compress.c
index f56e1f8e69..af42cab0fe 100644
--- a/migration/ram-compress.c
+++ b/migration/ram-compress.c
@@ -41,7 +41,20 @@
 #include "ram.h"
 #include "migration-stats.h"
 
-CompressionStats compression_counters;
+static struct {
+int64_t pages;
+int64_t busy;
+double busy_rate;
+int64_t compressed_size;
+double compression_rate;
+/* compression statistics since the beginning of the period */
+/* amount of count that no free thread to compress data */
+uint64_t compress_thread_busy_prev;
+/* amount bytes after compression */
+uint64_t compressed_size_prev;
+/* amount of compressed pages */
+uint64_t compress_pages_prev;
+} compression_counters;
 
 static CompressParam *comp_param;
 static QemuThread *compress_threads;
@@ -518,3 +531,30 @@ void update_compress_thread_counts(const CompressParam 
*param, int bytes_xmit)
 compression_counters.pages++;
 }
 
+void compress_update_rates(uint64_t page_count)
+{
+if (!migrate_compress()) {
+return;
+}
+compression_counters.busy_rate = (double)(compression_counters.busy -
+compression_counters.compress_thread_busy_prev) / page_count;
+compression_counters.compress_thread_busy_prev =
+compression_counters.busy;
+
+double compressed_size = compression_counters.compressed_size -
+compression_counters.compressed_size_prev;
+if (compressed_size) {
+double uncompressed_size = (compression_counters.pages -
+compression_counters.compress_pages_prev) *
+qemu_target_page_size();
+
+/* Compression-Ratio = Uncompressed-size / Compressed-size */
+compression_counters.compression_rate =
+uncompressed_size / compressed_size;
+
+compression_counters.compress_pages_prev =
+compression_counters.pages;
+compression_counters.compressed_size_prev =
+compression_counters.compressed_size;
+}
+}
diff --git a/migration/ram.c b/migration/ram.c
index 46209388ec..f7daf2226e 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -369,13 +369,6 @@ struct RAMState {
 bool xbzrle_started;
 /* Are we on the last stage of migration */
 bool last_stage;
-/* compression statistics since the beginning of the period */
-/* amount of count that no free thread to compress data */
-uint64_t compress_thread_busy_prev;
-/* amount bytes after compression */
-uint64_t compressed_size_prev;
-/* amount of compressed pages */
-uint64_t compress_pages_prev;
 
 /* total handled target pages at the beginning of period */
 uint64_t target_page_count_prev;
@@ -945,7 +938,6 @@ uint64_t ram_get_total_transferred_pages(void)
 static void migration_update_rates(RAMState *rs, int64_t end_time)
 {
 uint64_t page_count = rs->target_page_count - rs->target_page_count_prev;
-double compressed_size;
 
 /* calculate period counters */
 stat64_set(_stats.dirty_pages_rate,
@@ -973,26 +965,7 @@ static void migration_update_rates(RAMState *rs, int64_t 
end_time)
 rs->xbzrle_pages_prev = xbzrle_counters.pages;
 rs->xbzrle_bytes_prev = xbzrle_counters.bytes;
 }
-
-if (migrate_compress()) {
-compression_counters.busy_rate = (double)(compression_counters.busy -
-rs->compress_thread_busy_prev) / page_count;
-rs->compress_thread_busy_prev = compression_counters.busy;
-
-

[PULL 16/38] migration: Merge flush_compressed_data() and compress_flush_data()

2023-10-31 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-11-quint...@redhat.com>
---
 migration/ram-compress.h |  1 -
 migration/ram-compress.c | 17 ++---
 2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/migration/ram-compress.h b/migration/ram-compress.h
index 7ba01e2882..e222887fb7 100644
--- a/migration/ram-compress.h
+++ b/migration/ram-compress.h
@@ -59,7 +59,6 @@ typedef struct CompressParam CompressParam;
 void compress_threads_save_cleanup(void);
 int compress_threads_save_setup(void);
 
-void flush_compressed_data(int (send_queued_data(CompressParam *)));
 bool compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset,
   int (send_queued_data(CompressParam *)));
 
diff --git a/migration/ram-compress.c b/migration/ram-compress.c
index 1443a1cb45..036e44085b 100644
--- a/migration/ram-compress.c
+++ b/migration/ram-compress.c
@@ -241,10 +241,14 @@ static inline void compress_reset_result(CompressParam 
*param)
 param->offset = 0;
 }
 
-void flush_compressed_data(int (send_queued_data(CompressParam *)))
+void compress_flush_data(void)
 {
 int thread_count = migrate_compress_threads();
 
+if (!migrate_compress()) {
+return;
+}
+
 qemu_mutex_lock(_done_lock);
 for (int i = 0; i < thread_count; i++) {
 while (!comp_param[i].done) {
@@ -257,7 +261,7 @@ void flush_compressed_data(int 
(send_queued_data(CompressParam *)))
 qemu_mutex_lock(_param[i].mutex);
 if (!comp_param[i].quit) {
 CompressParam *param = _param[i];
-send_queued_data(param);
+compress_send_queued_data(param);
 assert(qemu_file_buffer_empty(param->file));
 compress_reset_result(param);
 }
@@ -558,12 +562,3 @@ void compress_update_rates(uint64_t page_count)
 compression_counters.compressed_size;
 }
 }
-
-void compress_flush_data(void)
-{
-if (!migrate_compress()) {
-return;
-}
-
-flush_compressed_data(compress_send_queued_data);
-}
-- 
2.41.0




[PULL 31/38] qemu_file: Remove unused qemu_file_transferred()

2023-10-31 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-6-quint...@redhat.com>
---
 migration/qemu-file.h | 18 --
 migration/qemu-file.c |  7 ---
 2 files changed, 25 deletions(-)

diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index a29c37b0d0..8b71152754 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -33,24 +33,6 @@ QEMUFile *qemu_file_new_input(QIOChannel *ioc);
 QEMUFile *qemu_file_new_output(QIOChannel *ioc);
 int qemu_fclose(QEMUFile *f);
 
-/*
- * qemu_file_transferred:
- *
- * Report the total number of bytes transferred with
- * this file.
- *
- * For writable files, any pending buffers will be
- * flushed, so the reported value will be equal to
- * the number of bytes transferred on the wire.
- *
- * For readable files, the reported value will be
- * equal to the number of bytes transferred on the
- * wire.
- *
- * Returns: the total bytes transferred
- */
-uint64_t qemu_file_transferred(QEMUFile *f);
-
 /*
  * qemu_file_transferred_noflush:
  *
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 641ab703cc..efa5f11033 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -632,13 +632,6 @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 return ret;
 }
 
-uint64_t qemu_file_transferred(QEMUFile *f)
-{
-g_assert(qemu_file_is_writable(f));
-qemu_fflush(f);
-return stat64_get(_stats.qemu_file_transferred);
-}
-
 void qemu_put_be16(QEMUFile *f, unsigned int v)
 {
 qemu_put_byte(f, v >> 8);
-- 
2.41.0




[PULL 38/38] qemu-file: Make qemu_fflush() return errors

2023-10-31 Thread Juan Quintela
This let us simplify code of this shape.

   qemu_fflush(f);
   int ret = qemu_file_get_error(f);
   if (ret) {
  return ret;
   }

into:

   int ret = qemu_fflush(f);
   if (ret) {
  return ret;
   }

I updated all callers where there is any error check.
qemu_fclose() don't need to check for f->last_error because
qemu_fflush() returns it at the beggining of the function.

Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 

Message-ID: <20231025091117.6342-13-quint...@redhat.com>
Signed-off-by: Juan Quintela 
---
 migration/qemu-file.h |  2 +-
 migration/colo.c  | 11 +++
 migration/migration.c |  7 +--
 migration/qemu-file.c | 23 +++
 migration/ram.c   | 22 +++---
 migration/rdma.c  |  4 +---
 migration/savevm.c|  3 +--
 7 files changed, 21 insertions(+), 51 deletions(-)

diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index 1b2f6b8d8f..1774116f79 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -71,7 +71,7 @@ void qemu_file_set_error_obj(QEMUFile *f, int ret, Error 
*err);
 void qemu_file_set_error(QEMUFile *f, int ret);
 int qemu_file_shutdown(QEMUFile *f);
 QEMUFile *qemu_file_get_return_path(QEMUFile *f);
-void qemu_fflush(QEMUFile *f);
+int qemu_fflush(QEMUFile *f);
 void qemu_file_set_blocking(QEMUFile *f, bool block);
 int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size);
 
diff --git a/migration/colo.c b/migration/colo.c
index 72f4f7b37e..4447e34914 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -314,9 +314,7 @@ static void colo_send_message(QEMUFile *f, COLOMessage msg,
 return;
 }
 qemu_put_be32(f, msg);
-qemu_fflush(f);
-
-ret = qemu_file_get_error(f);
+ret = qemu_fflush(f);
 if (ret < 0) {
 error_setg_errno(errp, -ret, "Can't send COLO message");
 }
@@ -335,9 +333,7 @@ static void colo_send_message_value(QEMUFile *f, 
COLOMessage msg,
 return;
 }
 qemu_put_be64(f, value);
-qemu_fflush(f);
-
-ret = qemu_file_get_error(f);
+ret = qemu_fflush(f);
 if (ret < 0) {
 error_setg_errno(errp, -ret, "Failed to send value for message:%s",
  COLOMessage_str(msg));
@@ -483,8 +479,7 @@ static int colo_do_checkpoint_transaction(MigrationState *s,
 }
 
 qemu_put_buffer(s->to_dst_file, bioc->data, bioc->usage);
-qemu_fflush(s->to_dst_file);
-ret = qemu_file_get_error(s->to_dst_file);
+ret = qemu_fflush(s->to_dst_file);
 if (ret < 0) {
 goto out;
 }
diff --git a/migration/migration.c b/migration/migration.c
index aa7b791833..6abcbefd9c 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -305,12 +305,7 @@ static int migrate_send_rp_message(MigrationIncomingState 
*mis,
 qemu_put_be16(mis->to_src_file, (unsigned int)message_type);
 qemu_put_be16(mis->to_src_file, len);
 qemu_put_buffer(mis->to_src_file, data, len);
-qemu_fflush(mis->to_src_file);
-
-/* It's possible that qemu file got error during sending */
-ret = qemu_file_get_error(mis->to_src_file);
-
-return ret;
+return qemu_fflush(mis->to_src_file);
 }
 
 /* Request one page from the source VM at the given start address.
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 7e738743ce..d64500310d 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -262,14 +262,14 @@ static void qemu_iovec_release_ram(QEMUFile *f)
  * This will flush all pending data. If data was only partially flushed, it
  * will set an error state.
  */
-void qemu_fflush(QEMUFile *f)
+int qemu_fflush(QEMUFile *f)
 {
 if (!qemu_file_is_writable(f)) {
-return;
+return f->last_error;
 }
 
-if (qemu_file_get_error(f)) {
-return;
+if (f->last_error) {
+return f->last_error;
 }
 if (f->iovcnt > 0) {
 Error *local_error = NULL;
@@ -287,6 +287,7 @@ void qemu_fflush(QEMUFile *f)
 
 f->buf_index = 0;
 f->iovcnt = 0;
+return f->last_error;
 }
 
 /*
@@ -353,22 +354,12 @@ static ssize_t coroutine_mixed_fn 
qemu_fill_buffer(QEMUFile *f)
  */
 int qemu_fclose(QEMUFile *f)
 {
-int ret, ret2;
-qemu_fflush(f);
-ret = qemu_file_get_error(f);
-
-ret2 = qio_channel_close(f->ioc, NULL);
+int ret = qemu_fflush(f);
+int ret2 = qio_channel_close(f->ioc, NULL);
 if (ret >= 0) {
 ret = ret2;
 }
 g_clear_pointer(>ioc, object_unref);
-
-/* If any error was spotted before closing, we should report it
- * instead of the close() return value.
- */
-if (f->last_error) {
-ret = f->last_error;
-}
 error_free(f->last_error_obj);
 g_free(f);
 trace_qemu_file_fclose();
diff --git a/migration/ram.c b/migration/ram.c
index cec9bd31d9..34724e8fe8 100644
--- a/migration/ram.c
+++ b/

[PULL 30/38] migration: Use the number of transferred bytes directly

2023-10-31 Thread Juan Quintela
We only use migration_transferred_bytes() to calculate the rate_limit,
for that we don't need to flush whatever is on the qemu_file buffer.
Remember that the buffer is really small (normal case is 32K if we use
iov's can be 64 * TARGET_PAGE_SIZE), so this is not relevant to
calculations.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-5-quint...@redhat.com>
---
 migration/migration-stats.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index 4cc989d975..1d9197b4c3 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -63,7 +63,7 @@ uint64_t migration_transferred_bytes(QEMUFile *f)
 {
 uint64_t multifd = stat64_get(_stats.multifd_bytes);
 uint64_t rdma = stat64_get(_stats.rdma_bytes);
-uint64_t qemu_file = qemu_file_transferred(f);
+uint64_t qemu_file = stat64_get(_stats.qemu_file_transferred);
 
 trace_migration_transferred_bytes(qemu_file, multifd, rdma);
 return qemu_file + multifd + rdma;
-- 
2.41.0




[PULL 26/38] migration: Stop migration immediately in RDMA error paths

2023-10-31 Thread Juan Quintela
From: Peter Xu 

In multiple places, RDMA errors are handled in a strange way, where it only
sets qemu_file_set_error() but not stop the migration immediately.

It's not obvious what will happen later if there is already an error.  Make
all such failures stop migration immediately.

Cc: Zhijian Li (Fujitsu) 
Cc: Markus Armbruster 
Cc: Juan Quintela 
Cc: Fabiano Rosas 
Reported-by: Thomas Huth 
Signed-off-by: Peter Xu 
Reviewed-by: Juan Quintela 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231024163933.516546-1-pet...@redhat.com>
---
 migration/ram.c | 21 ++---
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/migration/ram.c b/migration/ram.c
index 024dedb6b1..20e6153114 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -2973,11 +2973,13 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
 ret = rdma_registration_start(f, RAM_CONTROL_SETUP);
 if (ret < 0) {
 qemu_file_set_error(f, ret);
+return ret;
 }
 
 ret = rdma_registration_stop(f, RAM_CONTROL_SETUP);
 if (ret < 0) {
 qemu_file_set_error(f, ret);
+return ret;
 }
 
 migration_ops = g_malloc0(sizeof(MigrationOps));
@@ -3043,6 +3045,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
 ret = rdma_registration_start(f, RAM_CONTROL_ROUND);
 if (ret < 0) {
 qemu_file_set_error(f, ret);
+goto out;
 }
 
 t0 = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
@@ -3147,8 +3150,6 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
 rs->last_stage = !migration_in_colo_state();
 
 WITH_RCU_READ_LOCK_GUARD() {
-int rdma_reg_ret;
-
 if (!migration_in_postcopy()) {
 migration_bitmap_sync_precopy(rs, true);
 }
@@ -3156,6 +3157,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
 ret = rdma_registration_start(f, RAM_CONTROL_FINISH);
 if (ret < 0) {
 qemu_file_set_error(f, ret);
+return ret;
 }
 
 /* try transferring iterative blocks of memory */
@@ -3171,24 +3173,21 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
 break;
 }
 if (pages < 0) {
-ret = pages;
-break;
+qemu_mutex_unlock(>bitmap_mutex);
+return pages;
 }
 }
 qemu_mutex_unlock(>bitmap_mutex);
 
 compress_flush_data();
 
-rdma_reg_ret = rdma_registration_stop(f, RAM_CONTROL_FINISH);
-if (rdma_reg_ret < 0) {
-qemu_file_set_error(f, rdma_reg_ret);
+ret = rdma_registration_stop(f, RAM_CONTROL_FINISH);
+if (ret < 0) {
+qemu_file_set_error(f, ret);
+return ret;
 }
 }
 
-if (ret < 0) {
-return ret;
-}
-
 ret = multifd_send_sync_main(rs->pss[RAM_CHANNEL_PRECOPY].pss_channel);
 if (ret < 0) {
 return ret;
-- 
2.41.0




[PULL 28/38] qemu_file: Use a stat64 for qemu_file_transferred

2023-10-31 Thread Juan Quintela
This way we can read it from any thread.
I checked that it gives the same value as the current one.  We never
use two qemu_files at the same time.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-3-quint...@redhat.com>
---
 migration/migration-stats.h | 4 
 migration/qemu-file.c   | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index 2358caad63..b7795e7914 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -81,6 +81,10 @@ typedef struct {
  * Number of bytes sent during precopy stage.
  */
 Stat64 precopy_bytes;
+/*
+ * Number of bytes transferred with QEMUFile.
+ */
+Stat64 qemu_file_transferred;
 /*
  * Amount of transferred data at the start of current cycle.
  */
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 6814c562e6..384985f534 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -283,6 +283,7 @@ void qemu_fflush(QEMUFile *f)
 } else {
 uint64_t size = iov_size(f->iov, f->iovcnt);
 f->total_transferred += size;
+stat64_add(_stats.qemu_file_transferred, size);
 }
 
 qemu_iovec_release_ram(f);
@@ -623,7 +624,7 @@ int coroutine_mixed_fn qemu_get_byte(QEMUFile *f)
 
 uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 {
-uint64_t ret = f->total_transferred;
+uint64_t ret = stat64_get(_stats.qemu_file_transferred);
 int i;
 
 g_assert(qemu_file_is_writable(f));
@@ -639,7 +640,7 @@ uint64_t qemu_file_transferred(QEMUFile *f)
 {
 g_assert(qemu_file_is_writable(f));
 qemu_fflush(f);
-return f->total_transferred;
+return stat64_get(_stats.qemu_file_transferred);
 }
 
 void qemu_put_be16(QEMUFile *f, unsigned int v)
-- 
2.41.0




[PULL 22/38] migration: migrate 'inc' command option is deprecated.

2023-10-31 Thread Juan Quintela
Use blockdev-mirror with NBD instead.

Reviewed-by: Thomas Huth 
Acked-by: Stefan Hajnoczi 
Reviewed-by: Markus Armbruster 
Signed-off-by: Juan Quintela 
Message-ID: <20231018115513.2163-3-quint...@redhat.com>
---
 docs/about/deprecated.rst  | 8 
 qapi/migration.json| 8 +++-
 migration/migration-hmp-cmds.c | 5 +
 migration/migration.c  | 5 +
 4 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 4e0eb2fe02..1c8c8c34c4 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -469,3 +469,11 @@ Migration
 ``skipped`` field in Migration stats has been deprecated.  It hasn't
 been used for more than 10 years.
 
+``inc`` migrate command option (since 8.2)
+''
+
+Use blockdev-mirror with NBD instead.
+
+As an intermediate step the ``inc`` functionality can be achieved by
+setting the ``block-incremental`` migration parameter to ``true``.
+But this parameter is also deprecated.
diff --git a/qapi/migration.json b/qapi/migration.json
index db3df12d6c..fa7f4f2575 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1524,6 +1524,11 @@
 #
 # @resume: resume one paused migration, default "off". (since 3.0)
 #
+# Features:
+#
+# @deprecated: Member @inc is deprecated.  Use blockdev-mirror with
+# NBD instead.
+#
 # Returns: nothing on success
 #
 # Since: 0.14
@@ -1545,7 +1550,8 @@
 # <- { "return": {} }
 ##
 { 'command': 'migrate',
-  'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool',
+  'data': {'uri': 'str', '*blk': 'bool',
+   '*inc': { 'type': 'bool', 'features': [ 'deprecated' ] },
'*detach': 'bool', '*resume': 'bool' } }
 
 ##
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index a82597f18e..83176f5bae 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -745,6 +745,11 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
 const char *uri = qdict_get_str(qdict, "uri");
 Error *err = NULL;
 
+if (inc) {
+warn_report("option '-i' is deprecated;"
+" use blockdev-mirror with NBD instead");
+}
+
 qmp_migrate(uri, !!blk, blk, !!inc, inc,
 false, false, true, resume, );
 if (hmp_handle_error(mon, err)) {
diff --git a/migration/migration.c b/migration/migration.c
index 67547eb6a1..06a706ad90 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1620,6 +1620,11 @@ static bool migrate_prepare(MigrationState *s, bool blk, 
bool blk_inc,
 {
 Error *local_err = NULL;
 
+if (blk_inc) {
+warn_report("parameter 'inc' is deprecated;"
+" use blockdev-mirror with NBD instead");
+}
+
 if (resume) {
 if (s->state != MIGRATION_STATUS_POSTCOPY_PAUSED) {
 error_setg(errp, "Cannot resume if there is no "
-- 
2.41.0




[PULL 14/38] migration: Export send_queued_data()

2023-10-31 Thread Juan Quintela
This function is only used for compression.  So we rename it as
compress_send_queued_data().  We put it on ram-compress.h because we
are moving it later to ram-compress.c.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-9-quint...@redhat.com>
---
 migration/ram-compress.h | 1 +
 migration/ram.c  | 6 +++---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/migration/ram-compress.h b/migration/ram-compress.h
index 76dacd3ec7..636281ed97 100644
--- a/migration/ram-compress.h
+++ b/migration/ram-compress.h
@@ -72,5 +72,6 @@ void populate_compress(MigrationInfo *info);
 uint64_t ram_compressed_pages(void);
 void update_compress_thread_counts(const CompressParam *param, int bytes_xmit);
 void compress_update_rates(uint64_t page_count);
+int compress_send_queued_data(CompressParam *param);
 
 #endif
diff --git a/migration/ram.c b/migration/ram.c
index f7daf2226e..b6d485358e 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1264,7 +1264,7 @@ static int ram_save_multifd_page(QEMUFile *file, RAMBlock 
*block,
 return 1;
 }
 
-static int send_queued_data(CompressParam *param)
+int compress_send_queued_data(CompressParam *param)
 {
 PageSearchStatus *pss = _state->pss[RAM_CHANNEL_PRECOPY];
 MigrationState *ms = migrate_get_current();
@@ -1306,7 +1306,7 @@ static void ram_flush_compressed_data(void)
 return;
 }
 
-flush_compressed_data(send_queued_data);
+flush_compressed_data(compress_send_queued_data);
 }
 
 #define PAGE_ALL_CLEAN 0
@@ -2041,7 +2041,7 @@ static bool save_compress_page(RAMState *rs, 
PageSearchStatus *pss,
 }
 
 return compress_page_with_multi_thread(pss->block, offset,
-   send_queued_data);
+   compress_send_queued_data);
 }
 
 /**
-- 
2.41.0




[PULL 35/38] qemu-file: Simplify qemu_file_get_error()

2023-10-31 Thread Juan Quintela
If we pass a NULL error is the same that returning directly the value.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-10-quint...@redhat.com>
---
 migration/qemu-file.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 0158db2a54..7e738743ce 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -204,7 +204,7 @@ void qemu_file_set_error_obj(QEMUFile *f, int ret, Error 
*err)
  */
 int qemu_file_get_error(QEMUFile *f)
 {
-return qemu_file_get_error_obj(f, NULL);
+return f->last_error;
 }
 
 /*
-- 
2.41.0




[PULL 37/38] migration: Remove transferred atomic counter

2023-10-31 Thread Juan Quintela
After last commit, it is a write only variable.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-12-quint...@redhat.com>
---
 migration/migration-stats.h | 4 
 migration/multifd.c | 3 ---
 migration/ram.c | 1 -
 3 files changed, 8 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index 68f3939188..05290ade76 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -97,10 +97,6 @@ typedef struct {
  * Number of bytes sent through RDMA.
  */
 Stat64 rdma_bytes;
-/*
- * Total number of bytes transferred.
- */
-Stat64 transferred;
 /*
  * Number of pages transferred that were full of zeros.
  */
diff --git a/migration/multifd.c b/migration/multifd.c
index e2a45c667a..ec58c58082 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -188,7 +188,6 @@ static int multifd_send_initial_packet(MultiFDSendParams 
*p, Error **errp)
 return -1;
 }
 stat64_add(_stats.multifd_bytes, size);
-stat64_add(_stats.transferred, size);
 return 0;
 }
 
@@ -733,8 +732,6 @@ static void *multifd_send_thread(void *opaque)
 
 stat64_add(_stats.multifd_bytes,
p->next_packet_size + p->packet_len);
-stat64_add(_stats.transferred,
-   p->next_packet_size + p->packet_len);
 p->next_packet_size = 0;
 qemu_mutex_lock(>mutex);
 p->pending_job--;
diff --git a/migration/ram.c b/migration/ram.c
index 8dd36e3d2b..cec9bd31d9 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -448,7 +448,6 @@ void ram_transferred_add(uint64_t bytes)
 } else {
 stat64_add(_stats.downtime_bytes, bytes);
 }
-stat64_add(_stats.transferred, bytes);
 }
 
 struct MigrationOps {
-- 
2.41.0




[PULL 18/38] migration/ram: Fix compilation with -Wshadow=local

2023-10-31 Thread Juan Quintela
From: Thomas Huth 

Rename the variable here to avoid that it shadows a variable from
the beginning of the function scope. With this change the code now
successfully compiles with -Wshadow=local.

Signed-off-by: Thomas Huth 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231024092220.55305-1-th...@redhat.com>
---
 migration/ram.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/migration/ram.c b/migration/ram.c
index 6335564035..024dedb6b1 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3147,6 +3147,8 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
 rs->last_stage = !migration_in_colo_state();
 
 WITH_RCU_READ_LOCK_GUARD() {
+int rdma_reg_ret;
+
 if (!migration_in_postcopy()) {
 migration_bitmap_sync_precopy(rs, true);
 }
@@ -3177,9 +3179,9 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
 
 compress_flush_data();
 
-int ret = rdma_registration_stop(f, RAM_CONTROL_FINISH);
-if (ret < 0) {
-qemu_file_set_error(f, ret);
+rdma_reg_ret = rdma_registration_stop(f, RAM_CONTROL_FINISH);
+if (rdma_reg_ret < 0) {
+qemu_file_set_error(f, rdma_reg_ret);
 }
 }
 
-- 
2.41.0




[PULL 15/38] migration: Move ram_flush_compressed_data() to ram-compress.c

2023-10-31 Thread Juan Quintela
As we export it, rename it compress_flush_data().

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-10-quint...@redhat.com>
---
 migration/ram-compress.h |  1 +
 migration/ram-compress.c |  9 +
 migration/ram.c  | 17 -
 3 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/migration/ram-compress.h b/migration/ram-compress.h
index 636281ed97..7ba01e2882 100644
--- a/migration/ram-compress.h
+++ b/migration/ram-compress.h
@@ -73,5 +73,6 @@ uint64_t ram_compressed_pages(void);
 void update_compress_thread_counts(const CompressParam *param, int bytes_xmit);
 void compress_update_rates(uint64_t page_count);
 int compress_send_queued_data(CompressParam *param);
+void compress_flush_data(void);
 
 #endif
diff --git a/migration/ram-compress.c b/migration/ram-compress.c
index af42cab0fe..1443a1cb45 100644
--- a/migration/ram-compress.c
+++ b/migration/ram-compress.c
@@ -558,3 +558,12 @@ void compress_update_rates(uint64_t page_count)
 compression_counters.compressed_size;
 }
 }
+
+void compress_flush_data(void)
+{
+if (!migrate_compress()) {
+return;
+}
+
+flush_compressed_data(compress_send_queued_data);
+}
diff --git a/migration/ram.c b/migration/ram.c
index b6d485358e..849752ef29 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1300,15 +1300,6 @@ int compress_send_queued_data(CompressParam *param)
 return len;
 }
 
-static void ram_flush_compressed_data(void)
-{
-if (!migrate_compress()) {
-return;
-}
-
-flush_compressed_data(compress_send_queued_data);
-}
-
 #define PAGE_ALL_CLEAN 0
 #define PAGE_TRY_AGAIN 1
 #define PAGE_DIRTY_FOUND 2
@@ -1364,7 +1355,7 @@ static int find_dirty_block(RAMState *rs, 
PageSearchStatus *pss)
  * Also If xbzrle is on, stop using the data compression at this
  * point. In theory, xbzrle can do better than compression.
  */
-ram_flush_compressed_data();
+compress_flush_data();
 
 /* Hit the end of the list */
 pss->block = QLIST_FIRST_RCU(_list.blocks);
@@ -2036,7 +2027,7 @@ static bool save_compress_page(RAMState *rs, 
PageSearchStatus *pss,
  * much CPU resource.
  */
 if (pss->block != pss->last_sent_block) {
-ram_flush_compressed_data();
+compress_flush_data();
 return false;
 }
 
@@ -3083,7 +3074,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
  * page is sent in one chunk.
  */
 if (migrate_postcopy_ram()) {
-ram_flush_compressed_data();
+compress_flush_data();
 }
 
 /*
@@ -3184,7 +3175,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
 }
 qemu_mutex_unlock(>bitmap_mutex);
 
-ram_flush_compressed_data();
+compress_flush_data();
 
 int ret = rdma_registration_stop(f, RAM_CONTROL_FINISH);
 if (ret < 0) {
-- 
2.41.0




[PULL 33/38] migration: migration_transferred_bytes() don't need the QEMUFile

2023-10-31 Thread Juan Quintela
Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-8-quint...@redhat.com>
---
 migration/migration-stats.h | 4 +---
 migration/migration-stats.c | 6 +++---
 migration/migration.c   | 6 +++---
 3 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index b7795e7914..e3863bf9bb 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -137,11 +137,9 @@ void migration_rate_set(uint64_t new_rate);
 /**
  * migration_transferred_bytes: Return number of bytes transferred
  *
- * @f: QEMUFile used for main migration channel
- *
  * Returns how many bytes have we transferred since the beginning of
  * the migration.  It accounts for bytes sent through any migration
  * channel, multifd, qemu_file, rdma, 
  */
-uint64_t migration_transferred_bytes(QEMUFile *f);
+uint64_t migration_transferred_bytes(void);
 #endif
diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index 1d9197b4c3..4ae8c0c722 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -30,7 +30,7 @@ bool migration_rate_exceeded(QEMUFile *f)
 }
 
 uint64_t rate_limit_start = stat64_get(_stats.rate_limit_start);
-uint64_t rate_limit_current = migration_transferred_bytes(f);
+uint64_t rate_limit_current = migration_transferred_bytes();
 uint64_t rate_limit_used = rate_limit_current - rate_limit_start;
 
 if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) {
@@ -56,10 +56,10 @@ void migration_rate_set(uint64_t limit)
 
 void migration_rate_reset(QEMUFile *f)
 {
-stat64_set(_stats.rate_limit_start, migration_transferred_bytes(f));
+stat64_set(_stats.rate_limit_start, migration_transferred_bytes());
 }
 
-uint64_t migration_transferred_bytes(QEMUFile *f)
+uint64_t migration_transferred_bytes(void)
 {
 uint64_t multifd = stat64_get(_stats.multifd_bytes);
 uint64_t rdma = stat64_get(_stats.rdma_bytes);
diff --git a/migration/migration.c b/migration/migration.c
index cb2d7161b5..04d4546150 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2704,7 +2704,7 @@ static MigThrError migration_detect_error(MigrationState 
*s)
 
 static void migration_calculate_complete(MigrationState *s)
 {
-uint64_t bytes = migration_transferred_bytes(s->to_dst_file);
+uint64_t bytes = migration_transferred_bytes();
 int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 int64_t transfer_time;
 
@@ -2730,7 +2730,7 @@ static void 
update_iteration_initial_status(MigrationState *s)
  * wrong speed calculation.
  */
 s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
-s->iteration_initial_bytes = migration_transferred_bytes(s->to_dst_file);
+s->iteration_initial_bytes = migration_transferred_bytes();
 s->iteration_initial_pages = ram_get_total_transferred_pages();
 }
 
@@ -2749,7 +2749,7 @@ static void migration_update_counters(MigrationState *s,
 }
 
 switchover_bw = migrate_avail_switchover_bandwidth();
-current_bytes = migration_transferred_bytes(s->to_dst_file);
+current_bytes = migration_transferred_bytes();
 transferred = current_bytes - s->iteration_initial_bytes;
 time_spent = current_time - s->iteration_start_time;
 bandwidth = (double)transferred / time_spent;
-- 
2.41.0




[PULL 27/38] qemu-file: Don't increment qemu_file_transferred at qemu_file_fill_buffer

2023-10-31 Thread Juan Quintela
We only call qemu_file_transferred_* on the sending side. Remove the
increment at qemu_file_fill_buffer() and add asserts to
qemu_file_transferred* functions.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-2-quint...@redhat.com>
---
 migration/qemu-file.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 3fb25148d1..6814c562e6 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -337,7 +337,6 @@ static ssize_t coroutine_mixed_fn qemu_fill_buffer(QEMUFile 
*f)
 
 if (len > 0) {
 f->buf_size += len;
-f->total_transferred += len;
 } else if (len == 0) {
 qemu_file_set_error_obj(f, -EIO, local_error);
 } else {
@@ -627,6 +626,8 @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 uint64_t ret = f->total_transferred;
 int i;
 
+g_assert(qemu_file_is_writable(f));
+
 for (i = 0; i < f->iovcnt; i++) {
 ret += f->iov[i].iov_len;
 }
@@ -636,6 +637,7 @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 
 uint64_t qemu_file_transferred(QEMUFile *f)
 {
+g_assert(qemu_file_is_writable(f));
 qemu_fflush(f);
 return f->total_transferred;
 }
-- 
2.41.0




[PULL 36/38] migration: Use migration_transferred_bytes()

2023-10-31 Thread Juan Quintela
There are only two differnces with the old value:

- the amount of QEMUFile that hasn't yet been flushed.  It can be
  discussed what is more exact, the new or the old one.
- the amount of transferred bytes that we forgot to account for (the
  newer is better, i.e. exact).

Notice that this two values are used to:
a - present to the user
b - calculate the rate_limit

So a few KB here and there is not going to make a difference.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-11-quint...@redhat.com>
---
 migration/migration.c | 2 +-
 migration/ram.c   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index a25a2f3c54..aa7b791833 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -942,7 +942,7 @@ static void populate_ram_info(MigrationInfo *info, 
MigrationState *s)
 size_t page_size = qemu_target_page_size();
 
 info->ram = g_malloc0(sizeof(*info->ram));
-info->ram->transferred = stat64_get(_stats.transferred);
+info->ram->transferred = migration_transferred_bytes();
 info->ram->total = ram_bytes_total();
 info->ram->duplicate = stat64_get(_stats.zero_pages);
 /* legacy value.  It is not used anymore */
diff --git a/migration/ram.c b/migration/ram.c
index 20e6153114..8dd36e3d2b 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -557,7 +557,7 @@ void mig_throttle_counter_reset(void)
 
 rs->time_last_bitmap_sync = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 rs->num_dirty_pages_period = 0;
-rs->bytes_xfer_prev = stat64_get(_stats.transferred);
+rs->bytes_xfer_prev = migration_transferred_bytes();
 }
 
 /**
@@ -1003,7 +1003,7 @@ static void migration_trigger_throttle(RAMState *rs)
 {
 uint64_t threshold = migrate_throttle_trigger_threshold();
 uint64_t bytes_xfer_period =
-stat64_get(_stats.transferred) - rs->bytes_xfer_prev;
+migration_transferred_bytes() - rs->bytes_xfer_prev;
 uint64_t bytes_dirty_period = rs->num_dirty_pages_period * 
TARGET_PAGE_SIZE;
 uint64_t bytes_dirty_threshold = bytes_xfer_period * threshold / 100;
 
@@ -1073,7 +1073,7 @@ static void migration_bitmap_sync(RAMState *rs, bool 
last_stage)
 /* reset period counters */
 rs->time_last_bitmap_sync = end_time;
 rs->num_dirty_pages_period = 0;
-rs->bytes_xfer_prev = stat64_get(_stats.transferred);
+rs->bytes_xfer_prev = migration_transferred_bytes();
 }
 if (migrate_events()) {
 uint64_t generation = stat64_get(_stats.dirty_sync_count);
-- 
2.41.0




[PULL 32/38] qemu-file: Remove _noflush from qemu_file_transferred_noflush()

2023-10-31 Thread Juan Quintela
qemu_file_transferred() don't exist anymore, so we can reuse the name.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 

Message-ID: <20231025091117.6342-7-quint...@redhat.com>
Signed-off-by: Juan Quintela 
---
 migration/qemu-file.h | 9 -
 migration/block.c | 4 ++--
 migration/qemu-file.c | 2 +-
 migration/savevm.c| 6 +++---
 migration/vmstate.c   | 4 ++--
 5 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index 8b71152754..1b2f6b8d8f 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -34,15 +34,14 @@ QEMUFile *qemu_file_new_output(QIOChannel *ioc);
 int qemu_fclose(QEMUFile *f);
 
 /*
- * qemu_file_transferred_noflush:
+ * qemu_file_transferred:
  *
- * As qemu_file_transferred except for writable files, where no flush
- * is performed and the reported amount will include the size of any
- * queued buffers, on top of the amount actually transferred.
+ * No flush is performed and the reported amount will include the size
+ * of any queued buffers, on top of the amount actually transferred.
  *
  * Returns: the total bytes transferred and queued
  */
-uint64_t qemu_file_transferred_noflush(QEMUFile *f);
+uint64_t qemu_file_transferred(QEMUFile *f);
 
 /*
  * put_buffer without copying the buffer.
diff --git a/migration/block.c b/migration/block.c
index acffe88f84..a15f9bddcb 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -755,7 +755,7 @@ static int block_save_setup(QEMUFile *f, void *opaque)
 static int block_save_iterate(QEMUFile *f, void *opaque)
 {
 int ret;
-uint64_t last_bytes = qemu_file_transferred_noflush(f);
+uint64_t last_bytes = qemu_file_transferred(f);
 
 trace_migration_block_save("iterate", block_mig_state.submitted,
block_mig_state.transferred);
@@ -807,7 +807,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
 }
 
 qemu_put_be64(f, BLK_MIG_FLAG_EOS);
-uint64_t delta_bytes = qemu_file_transferred_noflush(f) - last_bytes;
+uint64_t delta_bytes = qemu_file_transferred(f) - last_bytes;
 return (delta_bytes > 0);
 }
 
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index efa5f11033..0158db2a54 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -618,7 +618,7 @@ int coroutine_mixed_fn qemu_get_byte(QEMUFile *f)
 return result;
 }
 
-uint64_t qemu_file_transferred_noflush(QEMUFile *f)
+uint64_t qemu_file_transferred(QEMUFile *f)
 {
 uint64_t ret = stat64_get(_stats.qemu_file_transferred);
 int i;
diff --git a/migration/savevm.c b/migration/savevm.c
index ca5c7cebe0..9ec78abd53 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -927,9 +927,9 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
 static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
JSONWriter *vmdesc)
 {
-uint64_t old_offset = qemu_file_transferred_noflush(f);
+uint64_t old_offset = qemu_file_transferred(f);
 se->ops->save_state(f, se->opaque);
-uint64_t size = qemu_file_transferred_noflush(f) - old_offset;
+uint64_t size = qemu_file_transferred(f) - old_offset;
 
 if (vmdesc) {
 json_writer_int64(vmdesc, "size", size);
@@ -3053,7 +3053,7 @@ bool save_snapshot(const char *name, bool overwrite, 
const char *vmstate,
 goto the_end;
 }
 ret = qemu_savevm_state(f, errp);
-vm_state_size = qemu_file_transferred_noflush(f);
+vm_state_size = qemu_file_transferred(f);
 ret2 = qemu_fclose(f);
 if (ret < 0) {
 goto the_end;
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 9c36803c8a..b7723a4187 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -387,7 +387,7 @@ int vmstate_save_state_v(QEMUFile *f, const 
VMStateDescription *vmsd,
 void *curr_elem = first_elem + size * i;
 
 vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
-old_offset = qemu_file_transferred_noflush(f);
+old_offset = qemu_file_transferred(f);
 if (field->flags & VMS_ARRAY_OF_POINTER) {
 assert(curr_elem);
 curr_elem = *(void **)curr_elem;
@@ -417,7 +417,7 @@ int vmstate_save_state_v(QEMUFile *f, const 
VMStateDescription *vmsd,
 return ret;
 }
 
-written_bytes = qemu_file_transferred_noflush(f) - old_offset;
+written_bytes = qemu_file_transferred(f) - old_offset;
 vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, 
i);
 
 /* Compressed arrays only care about the first element */
-- 
2.41.0




[PULL 34/38] migration: migration_rate_limit_reset() don't need the QEMUFile

2023-10-31 Thread Juan Quintela
Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-9-quint...@redhat.com>
---
 migration/migration-stats.h | 4 +---
 migration/migration-stats.c | 2 +-
 migration/migration.c   | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index e3863bf9bb..68f3939188 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -120,10 +120,8 @@ uint64_t migration_rate_get(void);
  * migration_rate_reset: Reset the rate limit counter.
  *
  * This is called when we know we start a new transfer cycle.
- *
- * @f: QEMUFile used for main migration channel
  */
-void migration_rate_reset(QEMUFile *f);
+void migration_rate_reset(void);
 
 /**
  * migration_rate_set: Set the maximum amount that can be transferred.
diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index 4ae8c0c722..f690b98a03 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -54,7 +54,7 @@ void migration_rate_set(uint64_t limit)
 stat64_set(_stats.rate_limit_max, limit / XFER_LIMIT_RATIO);
 }
 
-void migration_rate_reset(QEMUFile *f)
+void migration_rate_reset(void)
 {
 stat64_set(_stats.rate_limit_start, migration_transferred_bytes());
 }
diff --git a/migration/migration.c b/migration/migration.c
index 04d4546150..a25a2f3c54 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2785,7 +2785,7 @@ static void migration_update_counters(MigrationState *s,
 stat64_get(_stats.dirty_bytes_last_sync) / expected_bw_per_ms;
 }
 
-migration_rate_reset(s->to_dst_file);
+migration_rate_reset();
 
 update_iteration_initial_status(s);
 
-- 
2.41.0




[PULL 06/38] migration: Rename ram_handle_compressed() to ram_handle_zero()

2023-10-31 Thread Juan Quintela
Now that we know it only handles zero, we can remove the ch parameter.

Reviewed-by: Fabiano Rosas 
Reviewed-by: Peter Xu 
Signed-off-by: Juan Quintela 
Message-ID: <20231019085259.13307-3-quint...@redhat.com>
---
 migration/ram.h  |  2 +-
 migration/ram.c  | 10 +-
 migration/rdma.c |  2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/migration/ram.h b/migration/ram.h
index 145c915ca7..3f724b2f02 100644
--- a/migration/ram.h
+++ b/migration/ram.h
@@ -60,7 +60,7 @@ int ram_discard_range(const char *block_name, uint64_t start, 
size_t length);
 int ram_postcopy_incoming_init(MigrationIncomingState *mis);
 int ram_load_postcopy(QEMUFile *f, int channel);
 
-void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
+void ram_handle_zero(void *host, uint64_t size);
 
 void ram_transferred_add(uint64_t bytes);
 void ram_release_page(const char *rbname, uint64_t offset);
diff --git a/migration/ram.c b/migration/ram.c
index 4bfb20c94a..e0ad732ee8 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3446,7 +3446,7 @@ static inline void *colo_cache_from_block_offset(RAMBlock 
*block,
 }
 
 /**
- * ram_handle_compressed: handle the zero page case
+ * ram_handle_zero: handle the zero page case
  *
  * If a page (or a whole RDMA chunk) has been
  * determined to be zero, then zap it.
@@ -3455,10 +3455,10 @@ static inline void 
*colo_cache_from_block_offset(RAMBlock *block,
  * @ch: what the page is filled from.  We only support zero
  * @size: size of the zero page
  */
-void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
+void ram_handle_zero(void *host, uint64_t size)
 {
-if (ch != 0 || !buffer_is_zero(host, size)) {
-memset(host, ch, size);
+if (!buffer_is_zero(host, size)) {
+memset(host, 0, size);
 }
 }
 
@@ -4037,7 +4037,7 @@ static int ram_load_precopy(QEMUFile *f)
 ret = -EINVAL;
 break;
 }
-ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
+ram_handle_zero(host, TARGET_PAGE_SIZE);
 break;
 
 case RAM_SAVE_FLAG_PAGE:
diff --git a/migration/rdma.c b/migration/rdma.c
index 2d963fd147..e3493e3b3e 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -3597,7 +3597,7 @@ int rdma_registration_handle(QEMUFile *f)
  comp->value);
 goto err;
 }
-ram_handle_compressed(host_addr, comp->value, comp->length);
+ram_handle_zero(host_addr, comp->length);
 break;
 
 case RDMA_CONTROL_REGISTER_FINISHED:
-- 
2.41.0




[PULL 12/38] migration: Move busy++ to migrate_with_multithread

2023-10-31 Thread Juan Quintela
And now we can simplify save_compress_page().

Reviewed-by: Lukas Straub 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-7-quint...@redhat.com>
---
 migration/ram-compress.c | 1 +
 migration/ram.c  | 8 ++--
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/migration/ram-compress.c b/migration/ram-compress.c
index a991b15b7a..f56e1f8e69 100644
--- a/migration/ram-compress.c
+++ b/migration/ram-compress.c
@@ -291,6 +291,7 @@ bool compress_page_with_multi_thread(RAMBlock *block, 
ram_addr_t offset,
 }
 if (!wait) {
 qemu_mutex_unlock(_done_lock);
+compression_counters.busy++;
 return false;
 }
 /*
diff --git a/migration/ram.c b/migration/ram.c
index 63a575ae90..46209388ec 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -2067,12 +2067,8 @@ static bool save_compress_page(RAMState *rs, 
PageSearchStatus *pss,
 return false;
 }
 
-if (compress_page_with_multi_thread(pss->block, offset, send_queued_data)) 
{
-return true;
-}
-
-compression_counters.busy++;
-return false;
+return compress_page_with_multi_thread(pss->block, offset,
+   send_queued_data);
 }
 
 /**
-- 
2.41.0




[PULL 20/38] migration: set file error on subsection loading

2023-10-31 Thread Juan Quintela
From: Marc-André Lureau 

commit 13cde50889237 ("vmstate: Return error in case of error") sets
QemuFile error to stop reading from it and report to the caller (checked
by unit tests). We should do the same on subsection loading error.

Signed-off-by: Marc-André Lureau 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231024084043.2926316-8-marcandre.lur...@redhat.com>
---
 migration/vmstate.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 16e33a5d34..9c36803c8a 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -179,6 +179,7 @@ int vmstate_load_state(QEMUFile *f, const 
VMStateDescription *vmsd,
 assert(field->flags == VMS_END);
 ret = vmstate_subsection_load(f, vmsd, opaque);
 if (ret != 0) {
+qemu_file_set_error(f, ret);
 return ret;
 }
 if (vmsd->post_load) {
-- 
2.41.0




[PULL 07/38] migration: Give one error if trying to set MULTIFD and XBZRLE

2023-10-31 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-2-quint...@redhat.com>
---
 migration/options.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/migration/options.c b/migration/options.c
index 42fb818956..b8c3c3218d 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -618,6 +618,13 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, 
Error **errp)
 }
 }
 
+if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
+if (new_caps[MIGRATION_CAPABILITY_XBZRLE]) {
+error_setg(errp, "Multifd is not compatible with xbzrle");
+return false;
+}
+}
+
 return true;
 }
 
-- 
2.41.0




[PULL 08/38] migration: Give one error if trying to set COMPRESSION and XBZRLE

2023-10-31 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-3-quint...@redhat.com>
---
 migration/options.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/migration/options.c b/migration/options.c
index b8c3c3218d..37fa1cfe74 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -625,6 +625,13 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, 
Error **errp)
 }
 }
 
+if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
+if (new_caps[MIGRATION_CAPABILITY_XBZRLE]) {
+error_setg(errp, "Compression is not compatible with xbzrle");
+return false;
+}
+}
+
 return true;
 }
 
-- 
2.41.0




[PULL 17/38] migration: Rename ram_compressed_pages() to compress_ram_pages()

2023-10-31 Thread Juan Quintela
We are moving to have all functions exported from ram-compress.c to
start with compress_.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-12-quint...@redhat.com>
---
 migration/ram-compress.h | 2 +-
 migration/ram-compress.c | 2 +-
 migration/ram.c  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/migration/ram-compress.h b/migration/ram-compress.h
index e222887fb7..0d89a2f55e 100644
--- a/migration/ram-compress.h
+++ b/migration/ram-compress.h
@@ -68,7 +68,7 @@ int compress_threads_load_setup(QEMUFile *f);
 void decompress_data_with_multi_threads(QEMUFile *f, void *host, int len);
 
 void populate_compress(MigrationInfo *info);
-uint64_t ram_compressed_pages(void);
+uint64_t compress_ram_pages(void);
 void update_compress_thread_counts(const CompressParam *param, int bytes_xmit);
 void compress_update_rates(uint64_t page_count);
 int compress_send_queued_data(CompressParam *param);
diff --git a/migration/ram-compress.c b/migration/ram-compress.c
index 036e44085b..fa4388f6a6 100644
--- a/migration/ram-compress.c
+++ b/migration/ram-compress.c
@@ -516,7 +516,7 @@ void populate_compress(MigrationInfo *info)
 info->compression->compression_rate = 
compression_counters.compression_rate;
 }
 
-uint64_t ram_compressed_pages(void)
+uint64_t compress_ram_pages(void)
 {
 return compression_counters.pages;
 }
diff --git a/migration/ram.c b/migration/ram.c
index 849752ef29..6335564035 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -932,7 +932,7 @@ uint64_t ram_get_total_transferred_pages(void)
 {
 return stat64_get(_stats.normal_pages) +
 stat64_get(_stats.zero_pages) +
-ram_compressed_pages() + xbzrle_counters.pages;
+compress_ram_pages() + xbzrle_counters.pages;
 }
 
 static void migration_update_rates(RAMState *rs, int64_t end_time)
-- 
2.41.0




[PULL 04/38] migration/doc: We broke backwards compatibility

2023-10-31 Thread Juan Quintela
When we detect that we have broken backwards compatibility in a
released version, we can't do anything for that version.  But once we
fix that bug on the next released version, we can "mitigate" that
problem when migrating to new versions to give a way out of that
machine until it does a hard reboot.

Acked-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231018112827.1325-5-quint...@redhat.com>
---
 docs/devel/migration.rst | 202 +++
 1 file changed, 202 insertions(+)

diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index 974505e4a7..be913630c3 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -1235,3 +1235,205 @@ In this section we have considered that we are using 
the same QEMU
 binary in both sides of the migration.  If we use different QEMU
 versions process, then we need to have into account all other
 differences and the examples become even more complicated.
+
+How to mitigate when we have a backward compatibility error
+---
+
+We broke migration for old machine types continuously during
+development.  But as soon as we find that there is a problem, we fix
+it.  The problem is what happens when we detect after we have done a
+release that something has gone wrong.
+
+Let see how it worked with one example.
+
+After the release of qemu-8.0 we found a problem when doing migration
+of the machine type pc-7.2.
+
+- $ qemu-7.2 -M pc-7.2  ->  qemu-7.2 -M pc-7.2
+
+  This migration works
+
+- $ qemu-8.0 -M pc-7.2  ->  qemu-8.0 -M pc-7.2
+
+  This migration works
+
+- $ qemu-8.0 -M pc-7.2  ->  qemu-7.2 -M pc-7.2
+
+  This migration fails
+
+- $ qemu-7.2 -M pc-7.2  ->  qemu-8.0 -M pc-7.2
+
+  This migration fails
+
+So clearly something fails when migration between qemu-7.2 and
+qemu-8.0 with machine type pc-7.2.  The error messages, and git bisect
+pointed to this commit.
+
+In qemu-8.0 we got this commit::
+
+commit 010746ae1db7f52700cb2e2c46eb94f299cfa0d2
+Author: Jonathan Cameron 
+Date:   Thu Mar 2 13:37:02 2023 +
+
+hw/pci/aer: Implement PCI_ERR_UNCOR_MASK register
+
+
+The relevant bits of the commit for our example are this ones::
+
+--- a/hw/pci/pcie_aer.c
++++ b/hw/pci/pcie_aer.c
+@@ -112,6 +112,10 @@ int pcie_aer_init(PCIDevice *dev,
+
+ pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
+  PCI_ERR_UNC_SUPPORTED);
++pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
++ PCI_ERR_UNC_MASK_DEFAULT);
++pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
++ PCI_ERR_UNC_SUPPORTED);
+
+ pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
+ PCI_ERR_UNC_SEVERITY_DEFAULT);
+
+The patch changes how we configure PCI space for AER.  But QEMU fails
+when the PCI space configuration is different between source and
+destination.
+
+The following commit shows how this got fixed::
+
+commit 5ed3dabe57dd9f4c007404345e5f5bf0e347317f
+Author: Leonardo Bras 
+Date:   Tue May 2 21:27:02 2023 -0300
+
+hw/pci: Disable PCI_ERR_UNCOR_MASK register for machine type < 8.0
+
+[...]
+
+The relevant parts of the fix in QEMU are as follow:
+
+First, we create a new property for the device to be able to configure
+the old behaviour or the new behaviour::
+
+diff --git a/hw/pci/pci.c b/hw/pci/pci.c
+index 8a87ccc8b0..5153ad63d6 100644
+--- a/hw/pci/pci.c
++++ b/hw/pci/pci.c
+@@ -79,6 +79,8 @@ static Property pci_props[] = {
+ DEFINE_PROP_STRING("failover_pair_id", PCIDevice,
+failover_pair_id),
+ DEFINE_PROP_UINT32("acpi-index",  PCIDevice, acpi_index, 0),
++DEFINE_PROP_BIT("x-pcie-err-unc-mask", PCIDevice, cap_present,
++QEMU_PCIE_ERR_UNC_MASK_BITNR, true),
+ DEFINE_PROP_END_OF_LIST()
+ };
+
+Notice that we enable the feature for new machine types.
+
+Now we see how the fix is done.  This is going to depend on what kind
+of breakage happens, but in this case it is quite simple::
+
+diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
+index 103667c368..374d593ead 100644
+--- a/hw/pci/pcie_aer.c
++++ b/hw/pci/pcie_aer.c
+@@ -112,10 +112,13 @@ int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver,
+uint16_t offset,
+
+ pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
+  PCI_ERR_UNC_SUPPORTED);
+-pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
+- PCI_ERR_UNC_MASK_DEFAULT);
+-pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
+- PCI_ERR_UNC_SUPPORTED);
++
++if (dev->cap_present & QEMU_PCIE_ERR_UNC_MASK) {
++pci_set_long(dev-&

[PULL 29/38] qemu_file: total_transferred is not used anymore

2023-10-31 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231025091117.6342-4-quint...@redhat.com>
---
 migration/qemu-file.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 384985f534..641ab703cc 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -41,9 +41,6 @@ struct QEMUFile {
 QIOChannel *ioc;
 bool is_writable;
 
-/* The sum of bytes transferred on the wire */
-uint64_t total_transferred;
-
 int buf_index;
 int buf_size; /* 0 when writing */
 uint8_t buf[IO_BUF_SIZE];
@@ -282,7 +279,6 @@ void qemu_fflush(QEMUFile *f)
 qemu_file_set_error_obj(f, -EIO, local_error);
 } else {
 uint64_t size = iov_size(f->iov, f->iovcnt);
-f->total_transferred += size;
 stat64_add(_stats.qemu_file_transferred, size);
 }
 
-- 
2.41.0




[PULL 19/38] migration: rename vmstate_save_needed->vmstate_section_needed

2023-10-31 Thread Juan Quintela
From: Marc-André Lureau 

The function is used on save at this point. The following commits will
use it on load.

Signed-off-by: Marc-André Lureau 
Reviewed-by: Juan Quintela 
Signed-off-by: Juan Quintela 
Message-ID: <20231024084043.2926316-5-marcandre.lur...@redhat.com>
---
 include/migration/vmstate.h | 2 +-
 migration/savevm.c  | 2 +-
 migration/vmstate.c | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1a31fb7293..1af181877c 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -1202,7 +1202,7 @@ int vmstate_save_state_v(QEMUFile *f, const 
VMStateDescription *vmsd,
  void *opaque, JSONWriter *vmdesc,
  int version_id, Error **errp);
 
-bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
+bool vmstate_section_needed(const VMStateDescription *vmsd, void *opaque);
 
 #define  VMSTATE_INSTANCE_ID_ANY  -1
 
diff --git a/migration/savevm.c b/migration/savevm.c
index 8622f229e5..ca5c7cebe0 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -985,7 +985,7 @@ static int vmstate_save(QEMUFile *f, SaveStateEntry *se, 
JSONWriter *vmdesc)
 if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
 return 0;
 }
-if (se->vmsd && !vmstate_save_needed(se->vmsd, se->opaque)) {
+if (se->vmsd && !vmstate_section_needed(se->vmsd, se->opaque)) {
 trace_savevm_section_skip(se->idstr, se->section_id);
 return 0;
 }
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 1cf9e45b85..16e33a5d34 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -324,7 +324,7 @@ static void vmsd_desc_field_end(const VMStateDescription 
*vmsd,
 }
 
 
-bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque)
+bool vmstate_section_needed(const VMStateDescription *vmsd, void *opaque)
 {
 if (vmsd->needed && !vmsd->needed(opaque)) {
 /* optional section not needed */
@@ -522,7 +522,7 @@ static int vmstate_subsection_save(QEMUFile *f, const 
VMStateDescription *vmsd,
 
 trace_vmstate_subsection_save_top(vmsd->name);
 while (sub && *sub) {
-if (vmstate_save_needed(*sub, opaque)) {
+if (vmstate_section_needed(*sub, opaque)) {
 const VMStateDescription *vmsdsub = *sub;
 uint8_t len;
 
-- 
2.41.0




[PULL 23/38] migration: migrate 'blk' command option is deprecated.

2023-10-31 Thread Juan Quintela
Use blocked-mirror with NBD instead.

Acked-by: Stefan Hajnoczi 
Reviewed-by: Thomas Huth 
Reviewed-by: Markus Armbruster 
Signed-off-by: Juan Quintela 
Message-ID: <20231018115513.2163-4-quint...@redhat.com>
---
 docs/about/deprecated.rst  | 9 +
 qapi/migration.json| 7 ---
 migration/migration-hmp-cmds.c | 5 +
 migration/migration.c  | 5 +
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 1c8c8c34c4..c1613468e6 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -477,3 +477,12 @@ Use blockdev-mirror with NBD instead.
 As an intermediate step the ``inc`` functionality can be achieved by
 setting the ``block-incremental`` migration parameter to ``true``.
 But this parameter is also deprecated.
+
+``blk`` migrate command option (since 8.2)
+''
+
+Use blockdev-mirror with NBD instead.
+
+As an intermediate step the ``blk`` functionality can be achieved by
+setting the ``block`` migration capability to ``true``.  But this
+capability is also deprecated.
diff --git a/qapi/migration.json b/qapi/migration.json
index fa7f4f2575..3765c2b662 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1526,8 +1526,8 @@
 #
 # Features:
 #
-# @deprecated: Member @inc is deprecated.  Use blockdev-mirror with
-# NBD instead.
+# @deprecated: Members @inc and @blk are deprecated.  Use
+# blockdev-mirror with NBD instead.
 #
 # Returns: nothing on success
 #
@@ -1550,7 +1550,8 @@
 # <- { "return": {} }
 ##
 { 'command': 'migrate',
-  'data': {'uri': 'str', '*blk': 'bool',
+  'data': {'uri': 'str',
+   '*blk': { 'type': 'bool', 'features': [ 'deprecated' ] },
'*inc': { 'type': 'bool', 'features': [ 'deprecated' ] },
'*detach': 'bool', '*resume': 'bool' } }
 
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 83176f5bae..dfe98da355 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -750,6 +750,11 @@ void hmp_migrate(Monitor *mon, const QDict *qdict)
 " use blockdev-mirror with NBD instead");
 }
 
+if (blk) {
+warn_report("option '-b' is deprecated;"
+" use blockdev-mirror with NBD instead");
+}
+
 qmp_migrate(uri, !!blk, blk, !!inc, inc,
 false, false, true, resume, );
 if (hmp_handle_error(mon, err)) {
diff --git a/migration/migration.c b/migration/migration.c
index 06a706ad90..cb2d7161b5 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1625,6 +1625,11 @@ static bool migrate_prepare(MigrationState *s, bool blk, 
bool blk_inc,
 " use blockdev-mirror with NBD instead");
 }
 
+if (blk) {
+warn_report("parameter 'blk' is deprecated;"
+" use blockdev-mirror with NBD instead");
+}
+
 if (resume) {
 if (s->state != MIGRATION_STATUS_POSTCOPY_PAUSED) {
 error_setg(errp, "Cannot resume if there is no "
-- 
2.41.0




[PULL 11/38] migration: Simplify compress_page_with_multithread()

2023-10-31 Thread Juan Quintela
Move the goto to a while true.

Reviewed-by: Lukas Straub 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-6-quint...@redhat.com>
---
 migration/ram-compress.c | 48 
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/migration/ram-compress.c b/migration/ram-compress.c
index ef03d60a6d..a991b15b7a 100644
--- a/migration/ram-compress.c
+++ b/migration/ram-compress.c
@@ -271,35 +271,35 @@ bool compress_page_with_multi_thread(RAMBlock *block, 
ram_addr_t offset,
 
 thread_count = migrate_compress_threads();
 qemu_mutex_lock(_done_lock);
-retry:
-for (int i = 0; i < thread_count; i++) {
-if (comp_param[i].done) {
-CompressParam *param = _param[i];
-qemu_mutex_lock(>mutex);
-param->done = false;
-send_queued_data(param);
-assert(qemu_file_buffer_empty(param->file));
-compress_reset_result(param);
-set_compress_params(param, block, offset);
 
-qemu_cond_signal(>cond);
-qemu_mutex_unlock(>mutex);
+while (true) {
+for (int i = 0; i < thread_count; i++) {
+if (comp_param[i].done) {
+CompressParam *param = _param[i];
+qemu_mutex_lock(>mutex);
+param->done = false;
+send_queued_data(param);
+assert(qemu_file_buffer_empty(param->file));
+compress_reset_result(param);
+set_compress_params(param, block, offset);
+
+qemu_cond_signal(>cond);
+qemu_mutex_unlock(>mutex);
+qemu_mutex_unlock(_done_lock);
+return true;
+}
+}
+if (!wait) {
 qemu_mutex_unlock(_done_lock);
-return true;
+return false;
 }
-}
-
-/*
- * wait for the free thread if the user specifies 'compress-wait-thread',
- * otherwise we will post the page out in the main thread as normal page.
- */
-if (wait) {
+/*
+ * wait for a free thread if the user specifies
+ * 'compress-wait-thread', otherwise we will post the page out
+ * in the main thread as normal page.
+ */
 qemu_cond_wait(_done_cond, _done_lock);
-goto retry;
 }
-qemu_mutex_unlock(_done_lock);
-
-return false;
 }
 
 /* return the size after decompression, or negative value on error */
-- 
2.41.0




[PULL 21/38] qemu-iotests: Filter warnings about block migration being deprecated

2023-10-31 Thread Juan Quintela
Create a new filter that removes the two warnings for test 183.

Reviewed-by: Hanna Czenczek 
Signed-off-by: Juan Quintela 
Message-ID: <20231018115513.2163-2-quint...@redhat.com>
---
 tests/qemu-iotests/183   | 2 +-
 tests/qemu-iotests/common.filter | 7 +++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
index ee62939e72..b85770458e 100755
--- a/tests/qemu-iotests/183
+++ b/tests/qemu-iotests/183
@@ -90,7 +90,7 @@ echo
 reply="$(_send_qemu_cmd $src \
 "{ 'execute': 'migrate',
'arguments': { 'uri': 'unix:${MIG_SOCKET}', 'blk': true } }" \
-'return\|error')"
+'return\|error' | _filter_migration_block_deprecated)"
 echo "$reply"
 if echo "$reply" | grep "compiled without old-style" > /dev/null; then
 _notrun "migrate -b support not compiled in"
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index fc3c64bcb8..2846c83808 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -359,5 +359,12 @@ _filter_qcow2_compression_type_bit()
 -e 's/\(incompatible_features.*\), 3\(,.*\)/\1\2/'
 }
 
+# filter warnings caused for block migration deprecation
+_filter_migration_block_deprecated()
+{
+gsed -e '/warning: parameter .blk. is deprecated; use blockdev-mirror with 
NBD instead/d' \
+ -e '/warning: block migration is deprecated; use blockdev-mirror with 
NBD instead/d'
+}
+
 # make sure this script returns success
 true
-- 
2.41.0




[PULL 05/38] migration: Receiving a zero page non zero is an error

2023-10-31 Thread Juan Quintela
We don't allow non zero compressed pages since:

commit 3edcd7e6ebae3ef0ac178eed5f4225803159562d
Author: Peter Lieven 
Date:   Tue Mar 26 10:58:35 2013 +0100

migration: search for zero instead of dup pages

RDMA case is a bit more complicated, but they don't handle it since:

commit a1febc4950f2c6232c002f401d7cd409f6fa6a88
Author: Richard Henderson 
Date:   Mon Aug 29 11:46:14 2016 -0700

cutils: Export only buffer_is_zero

Reviewed-by: Fabiano Rosas 
Reviewed-by: Peter Xu 
Signed-off-by: Juan Quintela 
Message-ID: <20231019085259.13307-2-quint...@redhat.com>
---
 migration/ram.c  | 15 +++
 migration/rdma.c |  6 +-
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/migration/ram.c b/migration/ram.c
index 92769902bb..4bfb20c94a 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -3715,16 +3715,18 @@ int ram_load_postcopy(QEMUFile *f, int channel)
 switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
 case RAM_SAVE_FLAG_ZERO:
 ch = qemu_get_byte(f);
+if (ch != 0) {
+error_report("Found a zero page with value %d", ch);
+ret = -EINVAL;
+break;
+}
 /*
  * Can skip to set page_buffer when
  * this is a zero page and (block->page_size == TARGET_PAGE_SIZE).
  */
-if (ch || !matches_target_page_size) {
+if (!matches_target_page_size) {
 memset(page_buffer, ch, TARGET_PAGE_SIZE);
 }
-if (ch) {
-tmp_page->all_zero = false;
-}
 break;
 
 case RAM_SAVE_FLAG_PAGE:
@@ -4030,6 +4032,11 @@ static int ram_load_precopy(QEMUFile *f)
 
 case RAM_SAVE_FLAG_ZERO:
 ch = qemu_get_byte(f);
+if (ch != 0) {
+error_report("Found a zero page with value %d", ch);
+ret = -EINVAL;
+break;
+}
 ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
 break;
 
diff --git a/migration/rdma.c b/migration/rdma.c
index 2a1852ec7f..2d963fd147 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -3592,7 +3592,11 @@ int rdma_registration_handle(QEMUFile *f)
 
 host_addr = block->local_host_addr +
 (comp->offset - block->offset);
-
+if (comp->value) {
+error_report("rdma: Zero page with non-zero (%d) value",
+ comp->value);
+goto err;
+}
 ram_handle_compressed(host_addr, comp->value, comp->length);
 break;
 
-- 
2.41.0




[PULL 09/38] migration: Remove save_page_use_compression()

2023-10-31 Thread Juan Quintela
After previous patch, we disable the posiblity that we use compression
together with xbzrle.  So we can use directly migrate_compress().

Once there, now we don't need the rs parameter, so remove it.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-4-quint...@redhat.com>
---
 migration/ram.c | 34 +++---
 1 file changed, 7 insertions(+), 27 deletions(-)

diff --git a/migration/ram.c b/migration/ram.c
index e0ad732ee8..8246663f64 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1291,8 +1291,6 @@ static int ram_save_multifd_page(QEMUFile *file, RAMBlock 
*block,
 return 1;
 }
 
-static bool save_page_use_compression(RAMState *rs);
-
 static int send_queued_data(CompressParam *param)
 {
 PageSearchStatus *pss = _state->pss[RAM_CHANNEL_PRECOPY];
@@ -1329,9 +1327,9 @@ static int send_queued_data(CompressParam *param)
 return len;
 }
 
-static void ram_flush_compressed_data(RAMState *rs)
+static void ram_flush_compressed_data(void)
 {
-if (!save_page_use_compression(rs)) {
+if (!migrate_compress()) {
 return;
 }
 
@@ -1393,7 +1391,7 @@ static int find_dirty_block(RAMState *rs, 
PageSearchStatus *pss)
  * Also If xbzrle is on, stop using the data compression at this
  * point. In theory, xbzrle can do better than compression.
  */
-ram_flush_compressed_data(rs);
+ram_flush_compressed_data();
 
 /* Hit the end of the list */
 pss->block = QLIST_FIRST_RCU(_list.blocks);
@@ -2042,24 +2040,6 @@ int ram_save_queue_pages(const char *rbname, ram_addr_t 
start, ram_addr_t len)
 return 0;
 }
 
-static bool save_page_use_compression(RAMState *rs)
-{
-if (!migrate_compress()) {
-return false;
-}
-
-/*
- * If xbzrle is enabled (e.g., after first round of migration), stop
- * using the data compression. In theory, xbzrle can do better than
- * compression.
- */
-if (rs->xbzrle_started) {
-return false;
-}
-
-return true;
-}
-
 /*
  * try to compress the page before posting it out, return true if the page
  * has been properly handled by compression, otherwise needs other
@@ -2068,7 +2048,7 @@ static bool save_page_use_compression(RAMState *rs)
 static bool save_compress_page(RAMState *rs, PageSearchStatus *pss,
ram_addr_t offset)
 {
-if (!save_page_use_compression(rs)) {
+if (!migrate_compress()) {
 return false;
 }
 
@@ -2083,7 +2063,7 @@ static bool save_compress_page(RAMState *rs, 
PageSearchStatus *pss,
  * much CPU resource.
  */
 if (pss->block != pss->last_sent_block) {
-ram_flush_compressed_data(rs);
+ram_flush_compressed_data();
 return false;
 }
 
@@ -3135,7 +3115,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
  * page is sent in one chunk.
  */
 if (migrate_postcopy_ram()) {
-ram_flush_compressed_data(rs);
+ram_flush_compressed_data();
 }
 
 /*
@@ -3236,7 +3216,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
 }
 qemu_mutex_unlock(>bitmap_mutex);
 
-ram_flush_compressed_data(rs);
+ram_flush_compressed_data();
 
 int ret = rdma_registration_stop(f, RAM_CONTROL_FINISH);
 if (ret < 0) {
-- 
2.41.0




[PULL 10/38] migration: Make compress_data_with_multithreads return bool

2023-10-31 Thread Juan Quintela
Reviewed-by: Lukas Straub 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231019110724.15324-5-quint...@redhat.com>
---
 migration/ram-compress.h |  4 ++--
 migration/ram-compress.c | 17 ++---
 migration/ram.c  |  3 +--
 3 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/migration/ram-compress.h b/migration/ram-compress.h
index e55d3b50bd..b228640092 100644
--- a/migration/ram-compress.h
+++ b/migration/ram-compress.h
@@ -60,8 +60,8 @@ void compress_threads_save_cleanup(void);
 int compress_threads_save_setup(void);
 
 void flush_compressed_data(int (send_queued_data(CompressParam *)));
-int compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset,
-int (send_queued_data(CompressParam *)));
+bool compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset,
+  int (send_queued_data(CompressParam *)));
 
 int wait_for_decompress_done(void);
 void compress_threads_load_cleanup(void);
diff --git a/migration/ram-compress.c b/migration/ram-compress.c
index d037dfe6cf..ef03d60a6d 100644
--- a/migration/ram-compress.c
+++ b/migration/ram-compress.c
@@ -260,10 +260,13 @@ static inline void set_compress_params(CompressParam 
*param, RAMBlock *block,
 param->trigger = true;
 }
 
-int compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset,
-int (send_queued_data(CompressParam *)))
+/*
+ * Return true when it compress a page
+ */
+bool compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset,
+ int (send_queued_data(CompressParam *)))
 {
-int  thread_count, pages = -1;
+int thread_count;
 bool wait = migrate_compress_wait_thread();
 
 thread_count = migrate_compress_threads();
@@ -281,8 +284,8 @@ retry:
 
 qemu_cond_signal(>cond);
 qemu_mutex_unlock(>mutex);
-pages = 1;
-break;
+qemu_mutex_unlock(_done_lock);
+return true;
 }
 }
 
@@ -290,13 +293,13 @@ retry:
  * wait for the free thread if the user specifies 'compress-wait-thread',
  * otherwise we will post the page out in the main thread as normal page.
  */
-if (pages < 0 && wait) {
+if (wait) {
 qemu_cond_wait(_done_cond, _done_lock);
 goto retry;
 }
 qemu_mutex_unlock(_done_lock);
 
-return pages;
+return false;
 }
 
 /* return the size after decompression, or negative value on error */
diff --git a/migration/ram.c b/migration/ram.c
index 8246663f64..63a575ae90 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -2067,8 +2067,7 @@ static bool save_compress_page(RAMState *rs, 
PageSearchStatus *pss,
 return false;
 }
 
-if (compress_page_with_multi_thread(pss->block, offset,
-send_queued_data) > 0) {
+if (compress_page_with_multi_thread(pss->block, offset, send_queued_data)) 
{
 return true;
 }
 
-- 
2.41.0




[PULL 02/38] migration/doc: Add documentation for backwards compatiblity

2023-10-31 Thread Juan Quintela
State what are the requeriments to get migration working between qemu
versions.  And once there explain how one is supposed to implement a
new feature/default value and not break migration.

Reviewed-by: Vladimir Sementsov-Ogievskiy 
Acked-by: Peter Xu 
Signed-off-by: Juan Quintela 
Message-ID: <20231018112827.1325-3-quint...@redhat.com>
---
 docs/devel/migration.rst | 219 +++
 1 file changed, 219 insertions(+)

diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index 4d6a98ae58..6fe275b1ec 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -919,3 +919,222 @@ versioned machine types to cut down on the combinations 
that will need
 support.  This is also useful when newer versions of firmware outgrow
 the padding.
 
+
+Backwards compatibility
+===
+
+How backwards compatibility works
+-
+
+When we do migration, we have two QEMU processes: the source and the
+target.  There are two cases, they are the same version or they are
+different versions.  The easy case is when they are the same version.
+The difficult one is when they are different versions.
+
+There are two things that are different, but they have very similar
+names and sometimes get confused:
+
+- QEMU version
+- machine type version
+
+Let's start with a practical example, we start with:
+
+- qemu-system-x86_64 (v5.2), from now on qemu-5.2.
+- qemu-system-x86_64 (v5.1), from now on qemu-5.1.
+
+Related to this are the "latest" machine types defined on each of
+them:
+
+- pc-q35-5.2 (newer one in qemu-5.2) from now on pc-5.2
+- pc-q35-5.1 (newer one in qemu-5.1) from now on pc-5.1
+
+First of all, migration is only supposed to work if you use the same
+machine type in both source and destination. The QEMU hardware
+configuration needs to be the same also on source and destination.
+Most aspects of the backend configuration can be changed at will,
+except for a few cases where the backend features influence frontend
+device feature exposure.  But that is not relevant for this section.
+
+I am going to list the number of combinations that we can have.  Let's
+start with the trivial ones, QEMU is the same on source and
+destination:
+
+1 - qemu-5.2 -M pc-5.2  -> migrates to -> qemu-5.2 -M pc-5.2
+
+  This is the latest QEMU with the latest machine type.
+  This have to work, and if it doesn't work it is a bug.
+
+2 - qemu-5.1 -M pc-5.1  -> migrates to -> qemu-5.1 -M pc-5.1
+
+  Exactly the same case than the previous one, but for 5.1.
+  Nothing to see here either.
+
+This are the easiest ones, we will not talk more about them in this
+section.
+
+Now we start with the more interesting cases.  Consider the case where
+we have the same QEMU version in both sides (qemu-5.2) but we are using
+the latest machine type for that version (pc-5.2) but one of an older
+QEMU version, in this case pc-5.1.
+
+3 - qemu-5.2 -M pc-5.1  -> migrates to -> qemu-5.2 -M pc-5.1
+
+  It needs to use the definition of pc-5.1 and the devices as they
+  were configured on 5.1, but this should be easy in the sense that
+  both sides are the same QEMU and both sides have exactly the same
+  idea of what the pc-5.1 machine is.
+
+4 - qemu-5.1 -M pc-5.2  -> migrates to -> qemu-5.1 -M pc-5.2
+
+  This combination is not possible as the qemu-5.1 doen't understand
+  pc-5.2 machine type.  So nothing to worry here.
+
+Now it comes the interesting ones, when both QEMU processes are
+different.  Notice also that the machine type needs to be pc-5.1,
+because we have the limitation than qemu-5.1 doesn't know pc-5.2.  So
+the possible cases are:
+
+5 - qemu-5.2 -M pc-5.1  -> migrates to -> qemu-5.1 -M pc-5.1
+
+  This migration is known as newer to older.  We need to make sure
+  when we are developing 5.2 we need to take care about not to break
+  migration to qemu-5.1.  Notice that we can't make updates to
+  qemu-5.1 to understand whatever qemu-5.2 decides to change, so it is
+  in qemu-5.2 side to make the relevant changes.
+
+6 - qemu-5.1 -M pc-5.1  -> migrates to -> qemu-5.2 -M pc-5.1
+
+  This migration is known as older to newer.  We need to make sure
+  than we are able to receive migrations from qemu-5.1. The problem is
+  similar to the previous one.
+
+If qemu-5.1 and qemu-5.2 were the same, there will not be any
+compatibility problems.  But the reason that we create qemu-5.2 is to
+get new features, devices, defaults, etc.
+
+If we get a device that has a new feature, or change a default value,
+we have a problem when we try to migrate between different QEMU
+versions.
+
+So we need a way to tell qemu-5.2 that when we are using machine type
+pc-5.1, it needs to **not** use the feature, to be able to migrate to
+real qemu-5.1.
+
+And the equivalent part when migrating from qemu-5.1 to qemu-5.2.
+qemu-5.2 has to expect that it is not going to get data for the new
+feature, because qemu-5.1 doesn't know

[PULL 00/38] Migration 20231031 patches

2023-10-31 Thread Juan Quintela
The following changes since commit fd9a38fd437c4c31705071c240f4be11394ca1f8:

  Merge tag 'pull-hex-20231018' of https://github.com/quic/qemu into staging 
(2023-10-30 13:42:29 +0900)

are available in the Git repository at:

  https://gitlab.com/juan.quintela/qemu.git tags/migration-20231031-pull-request

for you to fetch changes up to be07a0ed22cf10ede7330efbb4818f5896cd6fe3:

  qemu-file: Make qemu_fflush() return errors (2023-10-31 08:44:33 +0100)


Migration Pull request (20231031)

Hi

This is repeat of the Migration PULL for 20231020.
- I removed vmstate_register(big problems with s390x)
- I added yet more countes (juan)

CI: https://gitlab.com/juan.quintela/qemu/-/pipelines/1055797950

Please apply.

Thanks, Juan.



Juan Quintela (34):
  migration/doc: Add contents
  migration/doc: Add documentation for backwards compatiblity
  migration/doc: How to migrate when hosts have different features
  migration/doc: We broke backwards compatibility
  migration: Receiving a zero page non zero is an error
  migration: Rename ram_handle_compressed() to ram_handle_zero()
  migration: Give one error if trying to set MULTIFD and XBZRLE
  migration: Give one error if trying to set COMPRESSION and XBZRLE
  migration: Remove save_page_use_compression()
  migration: Make compress_data_with_multithreads return bool
  migration: Simplify compress_page_with_multithread()
  migration: Move busy++ to migrate_with_multithread
  migration: Create compress_update_rates()
  migration: Export send_queued_data()
  migration: Move ram_flush_compressed_data() to ram-compress.c
  migration: Merge flush_compressed_data() and compress_flush_data()
  migration: Rename ram_compressed_pages() to compress_ram_pages()
  qemu-iotests: Filter warnings about block migration being deprecated
  migration: migrate 'inc' command option is deprecated.
  migration: migrate 'blk' command option is deprecated.
  migration: Deprecate block migration
  migration: Deprecate old compression method
  qemu-file: Don't increment qemu_file_transferred at
qemu_file_fill_buffer
  qemu_file: Use a stat64 for qemu_file_transferred
  qemu_file: total_transferred is not used anymore
  migration: Use the number of transferred bytes directly
  qemu_file: Remove unused qemu_file_transferred()
  qemu-file: Remove _noflush from qemu_file_transferred_noflush()
  migration: migration_transferred_bytes() don't need the QEMUFile
  migration: migration_rate_limit_reset() don't need the QEMUFile
  qemu-file: Simplify qemu_file_get_error()
  migration: Use migration_transferred_bytes()
  migration: Remove transferred atomic counter
  qemu-file: Make qemu_fflush() return errors

Marc-André Lureau (2):
  migration: rename vmstate_save_needed->vmstate_section_needed
  migration: set file error on subsection loading

Peter Xu (1):
  migration: Stop migration immediately in RDMA error paths

Thomas Huth (1):
  migration/ram: Fix compilation with -Wshadow=local

 docs/about/deprecated.rst|  35 +++
 docs/devel/migration.rst | 520 +++
 qapi/migration.json  |  93 --
 include/migration/vmstate.h  |   2 +-
 migration/migration-stats.h  |  16 +-
 migration/qemu-file.h|  27 +-
 migration/ram-compress.h |  10 +-
 migration/ram.h  |   3 +-
 migration/block.c|   7 +-
 migration/colo.c |  11 +-
 migration/migration-hmp-cmds.c   |  10 +
 migration/migration-stats.c  |  10 +-
 migration/migration.c|  27 +-
 migration/multifd.c  |   3 -
 migration/options.c  |  36 ++-
 migration/qemu-file.c|  43 +--
 migration/ram-compress.c | 112 +--
 migration/ram.c  | 150 +++--
 migration/rdma.c |  12 +-
 migration/savevm.c   |  11 +-
 migration/vmstate.c  |   9 +-
 tests/qemu-iotests/183   |   2 +-
 tests/qemu-iotests/common.filter |   7 +
 23 files changed, 880 insertions(+), 276 deletions(-)

-- 
2.41.0




[PULL 01/38] migration/doc: Add contents

2023-10-31 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231018112827.1325-2-quint...@redhat.com>
---
 docs/devel/migration.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index c3e1400c0c..4d6a98ae58 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -28,6 +28,8 @@ the guest to be stopped.  Typically the time that the guest is
 unresponsive during live migration is the low hundred of milliseconds
 (notice that this depends on a lot of things).
 
+.. contents::
+
 Transports
 ==
 
-- 
2.41.0




[PULL 03/38] migration/doc: How to migrate when hosts have different features

2023-10-31 Thread Juan Quintela
Sometimes devices have different features depending of things outside
of qemu.  For instance the kernel.  Document how to handle that cases.

Acked-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
Message-ID: <20231018112827.1325-4-quint...@redhat.com>
---
 docs/devel/migration.rst | 97 
 1 file changed, 97 insertions(+)

diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index 6fe275b1ec..974505e4a7 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -1138,3 +1138,100 @@ machine types to have the right value::
 +{ "virtio-blk-device", "num-queues", "1"},
  ...
  };
+
+A device with diferent features on both sides
+-
+
+Let's assume that we are using the same QEMU binary on both sides,
+just to make the things easier.  But we have a device that has
+different features on both sides of the migration.  That can be
+because the devices are different, because the kernel driver of both
+devices have different features, whatever.
+
+How can we get this to work with migration.  The way to do that is
+"theoretically" easy.  You have to get the features that the device
+has in the source of the migration.  The features that the device has
+on the target of the migration, you get the intersection of the
+features of both sides, and that is the way that you should launch
+QEMU.
+
+Notice that this is not completely related to QEMU.  The most
+important thing here is that this should be handled by the managing
+application that launches QEMU.  If QEMU is configured correctly, the
+migration will succeed.
+
+That said, actually doing it is complicated.  Almost all devices are
+bad at being able to be launched with only some features enabled.
+With one big exception: cpus.
+
+You can read the documentation for QEMU x86 cpu models here:
+
+https://qemu-project.gitlab.io/qemu/system/qemu-cpu-models.html
+
+See when they talk about migration they recommend that one chooses the
+newest cpu model that is supported for all cpus.
+
+Let's say that we have:
+
+Host A:
+
+Device X has the feature Y
+
+Host B:
+
+Device X has not the feature Y
+
+If we try to migrate without any care from host A to host B, it will
+fail because when migration tries to load the feature Y on
+destination, it will find that the hardware is not there.
+
+Doing this would be the equivalent of doing with cpus:
+
+Host A:
+
+$ qemu-system-x86_64 -cpu host
+
+Host B:
+
+$ qemu-system-x86_64 -cpu host
+
+When both hosts have different cpu features this is guaranteed to
+fail.  Especially if Host B has less features than host A.  If host A
+has less features than host B, sometimes it works.  Important word of
+last sentence is "sometimes".
+
+So, forgetting about cpu models and continuing with the -cpu host
+example, let's see that the differences of the cpus is that Host A and
+B have the following features:
+
+Features:   'pcid'  'stibp' 'taa-no'
+Host A:X   X
+Host B:X
+
+And we want to migrate between them, the way configure both QEMU cpu
+will be:
+
+Host A:
+
+$ qemu-system-x86_64 -cpu host,pcid=off,stibp=off
+
+Host B:
+
+$ qemu-system-x86_64 -cpu host,taa-no=off
+
+And you would be able to migrate between them.  It is responsability
+of the management application or of the user to make sure that the
+configuration is correct.  QEMU doesn't know how to look at this kind
+of features in general.
+
+Notice that we don't recomend to use -cpu host for migration.  It is
+used in this example because it makes the example simpler.
+
+Other devices have worse control about individual features.  If they
+want to be able to migrate between hosts that show different features,
+the device needs a way to configure which ones it is going to use.
+
+In this section we have considered that we are using the same QEMU
+binary in both sides of the migration.  If we use different QEMU
+versions process, then we need to have into account all other
+differences and the examples become even more complicated.
-- 
2.41.0




Re: [PULL 00/39] Migration 20231024 patches

2023-10-26 Thread Juan Quintela
Stefan Hajnoczi  wrote:
> On Tue, 24 Oct 2023 at 23:45, Juan Quintela  wrote:
>>
>> The following changes since commit a95260486aa7e78d7c7194eba65cf03311ad94ad:
>>
>>   Merge tag 'pull-tcg-20231023' of https://gitlab.com/rth7680/qemu into 
>> staging (2023-10-23 14:45:46 -0700)
>>
>> are available in the Git repository at:
>>
>>   https://gitlab.com/juan.quintela/qemu.git 
>> tags/migration-20231024-pull-request
>>
>> for you to fetch changes up to 088f7f03da3f5b3487091302b795c22b1bfe56fb:
>>
>>   migration: Deprecate old compression method (2023-10-24 13:48:24 +0200)
>>
>> 
>> Migration Pull request (20231024)
>>
>> Hi
>>
>> In this PULL:
>> - vmstate registration fixes (thomas, juan)
>> - start merging vmstate_section_needed changes (marc)
>> - migration depreactions (juan)
>> - migration documentation for backwards compatibility (juan)
>>
>> Please apply.
>
> Hi Juan,
> I'm seeing CI failures:
> https://gitlab.com/qemu-project/qemu/-/pipelines/1048630760

start with s390x:

Errors:

 32/840 qemu:qtest+qtest-s390x / qtest-s390x/qom-test   
  ERROR  50.27s   killed by signal 6 SIGABRT
104/840 qemu:qtest+qtest-s390x / qtest-s390x/test-hmp   
  ERROR  51.55s   killed by signal 6 SIGABRT
189/840 qemu:qtest+qtest-s390x / qtest-s390x/boot-serial-test   
  ERROR  54.07s   killed by signal 6 SIGABRT
192/840 qemu:qtest+qtest-s390x / qtest-s390x/qos-test   
  ERROR  51.29s   killed by signal 6 SIGABRT
519/840 qemu:qtest+qtest-s390x / qtest-s390x/test-filter-mirror 
  ERROR  50.36s   killed by signal 6 SIGABRT
520/840 qemu:qtest+qtest-s390x / qtest-s390x/test-netfilter 
  ERROR  51.03s   killed by signal 6 SIGABRT
522/840 qemu:qtest+qtest-s390x / qtest-s390x/device-plug-test   
  ERROR  50.99s   killed by signal 6 SIGABRT
523/840 qemu:qtest+qtest-s390x / qtest-s390x/test-filter-redirector 
  ERROR  54.14s   killed by signal 6 SIGABRT
524/840 qemu:qtest+qtest-s390x / qtest-s390x/drive_del-test 
  ERROR  53.40s   killed by signal 6 SIGABRT
525/840 qemu:qtest+qtest-s390x / qtest-s390x/virtio-ccw-test
  ERROR  54.67s   killed by signal 6 SIGABRT
526/840 qemu:qtest+qtest-s390x / qtest-s390x/device-introspect-test 
  ERROR  51.15s   killed by signal 6 SIGABRT
527/840 qemu:qtest+qtest-s390x / qtest-s390x/cpu-plug-test  
  ERROR  51.21s   killed by signal 6 SIGABRT
535/840 qemu:qtest+qtest-s390x / qtest-s390x/qmp-test   
  ERROR  51.18s   killed by signal 6 SIGABRT
534/840 qemu:qtest+qtest-s390x / qtest-s390x/machine-none-test  
  ERROR  51.21s   killed by signal 6 SIGABRT
533/840 qemu:qtest+qtest-s390x / qtest-s390x/qmp-cmd-test   
  ERROR  51.22s   killed by signal 6 SIGABRT
549/840 qemu:qtest+qtest-s390x / qtest-s390x/readconfig-test
  ERROR  51.20s   killed by signal 6 SIGABRT
644/840 qemu:block / io-qcow2-001   
  ERROR   0.32s   exit status 1
645/840 qemu:block / io-qcow2-002   
  ERROR   0.32s   exit status 1
646/840 qemu:block / io-qcow2-003   
  ERROR   0.34s   exit status 1
647/840 qemu:block / io-qcow2-004   
  ERROR   0.31s   exit status 1
648/840 qemu:block / io-qcow2-005   
  ERROR   0.43s   exit status 1
649/840 qemu:block / io-qcow2-007   
  ERROR   0.34s   exit status 1
650/840 qemu:block / io-qcow2-008   
  ERROR   0.63s   exit status 1
651/840 qemu:block / io-qcow2-009   
  ERROR   0.32s   exit status 1
652/840 qemu:block / io-qcow2-010   
  ERROR   0.30s   exit status 1
654/840 qemu:block / io-qcow2-011   
  ERROR   0.31s   exit status 1
655/840 qemu:block / io-qcow2-012   
  ERROR   0.36s   exit status 1
657/840 qemu:block / io-qcow2-013   
  ERROR   0.51s   exit status 1
658/840 qemu:block / io-qcow2-017   
  ERROR   0.37s   exit status 1
659/840 qemu:block / io-qcow2-01

[PATCH v2 07/12] migration: migration_transferred_bytes() don't need the QEMUFile

2023-10-25 Thread Juan Quintela
Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Juan Quintela 
---
 migration/migration-stats.h | 4 +---
 migration/migration-stats.c | 6 +++---
 migration/migration.c   | 6 +++---
 3 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index b7795e7914..e3863bf9bb 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -137,11 +137,9 @@ void migration_rate_set(uint64_t new_rate);
 /**
  * migration_transferred_bytes: Return number of bytes transferred
  *
- * @f: QEMUFile used for main migration channel
- *
  * Returns how many bytes have we transferred since the beginning of
  * the migration.  It accounts for bytes sent through any migration
  * channel, multifd, qemu_file, rdma, 
  */
-uint64_t migration_transferred_bytes(QEMUFile *f);
+uint64_t migration_transferred_bytes(void);
 #endif
diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index 1d9197b4c3..4ae8c0c722 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -30,7 +30,7 @@ bool migration_rate_exceeded(QEMUFile *f)
 }
 
 uint64_t rate_limit_start = stat64_get(_stats.rate_limit_start);
-uint64_t rate_limit_current = migration_transferred_bytes(f);
+uint64_t rate_limit_current = migration_transferred_bytes();
 uint64_t rate_limit_used = rate_limit_current - rate_limit_start;
 
 if (rate_limit_max > 0 && rate_limit_used > rate_limit_max) {
@@ -56,10 +56,10 @@ void migration_rate_set(uint64_t limit)
 
 void migration_rate_reset(QEMUFile *f)
 {
-stat64_set(_stats.rate_limit_start, migration_transferred_bytes(f));
+stat64_set(_stats.rate_limit_start, migration_transferred_bytes());
 }
 
-uint64_t migration_transferred_bytes(QEMUFile *f)
+uint64_t migration_transferred_bytes(void)
 {
 uint64_t multifd = stat64_get(_stats.multifd_bytes);
 uint64_t rdma = stat64_get(_stats.rdma_bytes);
diff --git a/migration/migration.c b/migration/migration.c
index 67547eb6a1..e199d2f50d 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2694,7 +2694,7 @@ static MigThrError migration_detect_error(MigrationState 
*s)
 
 static void migration_calculate_complete(MigrationState *s)
 {
-uint64_t bytes = migration_transferred_bytes(s->to_dst_file);
+uint64_t bytes = migration_transferred_bytes();
 int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 int64_t transfer_time;
 
@@ -2720,7 +2720,7 @@ static void 
update_iteration_initial_status(MigrationState *s)
  * wrong speed calculation.
  */
 s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
-s->iteration_initial_bytes = migration_transferred_bytes(s->to_dst_file);
+s->iteration_initial_bytes = migration_transferred_bytes();
 s->iteration_initial_pages = ram_get_total_transferred_pages();
 }
 
@@ -2739,7 +2739,7 @@ static void migration_update_counters(MigrationState *s,
 }
 
 switchover_bw = migrate_avail_switchover_bandwidth();
-current_bytes = migration_transferred_bytes(s->to_dst_file);
+current_bytes = migration_transferred_bytes();
 transferred = current_bytes - s->iteration_initial_bytes;
 time_spent = current_time - s->iteration_start_time;
 bandwidth = (double)transferred / time_spent;
-- 
2.41.0




[PATCH v2 05/12] qemu_file: Remove unused qemu_file_transferred()

2023-10-25 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
---
 migration/qemu-file.h | 18 --
 migration/qemu-file.c |  7 ---
 2 files changed, 25 deletions(-)

diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index a29c37b0d0..8b71152754 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -33,24 +33,6 @@ QEMUFile *qemu_file_new_input(QIOChannel *ioc);
 QEMUFile *qemu_file_new_output(QIOChannel *ioc);
 int qemu_fclose(QEMUFile *f);
 
-/*
- * qemu_file_transferred:
- *
- * Report the total number of bytes transferred with
- * this file.
- *
- * For writable files, any pending buffers will be
- * flushed, so the reported value will be equal to
- * the number of bytes transferred on the wire.
- *
- * For readable files, the reported value will be
- * equal to the number of bytes transferred on the
- * wire.
- *
- * Returns: the total bytes transferred
- */
-uint64_t qemu_file_transferred(QEMUFile *f);
-
 /*
  * qemu_file_transferred_noflush:
  *
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 641ab703cc..efa5f11033 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -632,13 +632,6 @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 return ret;
 }
 
-uint64_t qemu_file_transferred(QEMUFile *f)
-{
-g_assert(qemu_file_is_writable(f));
-qemu_fflush(f);
-return stat64_get(_stats.qemu_file_transferred);
-}
-
 void qemu_put_be16(QEMUFile *f, unsigned int v)
 {
 qemu_put_byte(f, v >> 8);
-- 
2.41.0




[PATCH v2 03/12] qemu_file: total_transferred is not used anymore

2023-10-25 Thread Juan Quintela
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
---
 migration/qemu-file.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 384985f534..641ab703cc 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -41,9 +41,6 @@ struct QEMUFile {
 QIOChannel *ioc;
 bool is_writable;
 
-/* The sum of bytes transferred on the wire */
-uint64_t total_transferred;
-
 int buf_index;
 int buf_size; /* 0 when writing */
 uint8_t buf[IO_BUF_SIZE];
@@ -282,7 +279,6 @@ void qemu_fflush(QEMUFile *f)
 qemu_file_set_error_obj(f, -EIO, local_error);
 } else {
 uint64_t size = iov_size(f->iov, f->iovcnt);
-f->total_transferred += size;
 stat64_add(_stats.qemu_file_transferred, size);
 }
 
-- 
2.41.0




[PATCH v2 01/12] qemu-file: Don't increment qemu_file_transferred at qemu_file_fill_buffer

2023-10-25 Thread Juan Quintela
We only call qemu_file_transferred_* on the sending side. Remove the
increment at qemu_file_fill_buffer() and add asserts to
qemu_file_transferred* functions.

Signed-off-by: Juan Quintela 
---
 migration/qemu-file.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 3fb25148d1..6814c562e6 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -337,7 +337,6 @@ static ssize_t coroutine_mixed_fn qemu_fill_buffer(QEMUFile 
*f)
 
 if (len > 0) {
 f->buf_size += len;
-f->total_transferred += len;
 } else if (len == 0) {
 qemu_file_set_error_obj(f, -EIO, local_error);
 } else {
@@ -627,6 +626,8 @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 uint64_t ret = f->total_transferred;
 int i;
 
+g_assert(qemu_file_is_writable(f));
+
 for (i = 0; i < f->iovcnt; i++) {
 ret += f->iov[i].iov_len;
 }
@@ -636,6 +637,7 @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 
 uint64_t qemu_file_transferred(QEMUFile *f)
 {
+g_assert(qemu_file_is_writable(f));
 qemu_fflush(f);
 return f->total_transferred;
 }
-- 
2.41.0




[PATCH v2 04/12] migration: Use the number of transferred bytes directly

2023-10-25 Thread Juan Quintela
We only use migration_transferred_bytes() to calculate the rate_limit,
for that we don't need to flush whatever is on the qemu_file buffer.
Remember that the buffer is really small (normal case is 32K if we use
iov's can be 64 * TARGET_PAGE_SIZE), so this is not relevant to
calculations.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
---
 migration/migration-stats.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index 4cc989d975..1d9197b4c3 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -63,7 +63,7 @@ uint64_t migration_transferred_bytes(QEMUFile *f)
 {
 uint64_t multifd = stat64_get(_stats.multifd_bytes);
 uint64_t rdma = stat64_get(_stats.rdma_bytes);
-uint64_t qemu_file = qemu_file_transferred(f);
+uint64_t qemu_file = stat64_get(_stats.qemu_file_transferred);
 
 trace_migration_transferred_bytes(qemu_file, multifd, rdma);
 return qemu_file + multifd + rdma;
-- 
2.41.0




[PATCH v2 06/12] qemu-file: Remove _noflush from qemu_file_transferred_noflush()

2023-10-25 Thread Juan Quintela
qemu_file_transferred() don't exist anymore, so we can reuse the name.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 

---

v2: Update the documentation (thanks fabiano)
---
 migration/qemu-file.h | 9 -
 migration/block.c | 4 ++--
 migration/qemu-file.c | 2 +-
 migration/savevm.c| 6 +++---
 migration/vmstate.c   | 4 ++--
 5 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index 8b71152754..1b2f6b8d8f 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -34,15 +34,14 @@ QEMUFile *qemu_file_new_output(QIOChannel *ioc);
 int qemu_fclose(QEMUFile *f);
 
 /*
- * qemu_file_transferred_noflush:
+ * qemu_file_transferred:
  *
- * As qemu_file_transferred except for writable files, where no flush
- * is performed and the reported amount will include the size of any
- * queued buffers, on top of the amount actually transferred.
+ * No flush is performed and the reported amount will include the size
+ * of any queued buffers, on top of the amount actually transferred.
  *
  * Returns: the total bytes transferred and queued
  */
-uint64_t qemu_file_transferred_noflush(QEMUFile *f);
+uint64_t qemu_file_transferred(QEMUFile *f);
 
 /*
  * put_buffer without copying the buffer.
diff --git a/migration/block.c b/migration/block.c
index b60698d6e2..47f11d0e4f 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -752,7 +752,7 @@ static int block_save_setup(QEMUFile *f, void *opaque)
 static int block_save_iterate(QEMUFile *f, void *opaque)
 {
 int ret;
-uint64_t last_bytes = qemu_file_transferred_noflush(f);
+uint64_t last_bytes = qemu_file_transferred(f);
 
 trace_migration_block_save("iterate", block_mig_state.submitted,
block_mig_state.transferred);
@@ -804,7 +804,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
 }
 
 qemu_put_be64(f, BLK_MIG_FLAG_EOS);
-uint64_t delta_bytes = qemu_file_transferred_noflush(f) - last_bytes;
+uint64_t delta_bytes = qemu_file_transferred(f) - last_bytes;
 return (delta_bytes > 0);
 }
 
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index efa5f11033..0158db2a54 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -618,7 +618,7 @@ int coroutine_mixed_fn qemu_get_byte(QEMUFile *f)
 return result;
 }
 
-uint64_t qemu_file_transferred_noflush(QEMUFile *f)
+uint64_t qemu_file_transferred(QEMUFile *f)
 {
 uint64_t ret = stat64_get(_stats.qemu_file_transferred);
 int i;
diff --git a/migration/savevm.c b/migration/savevm.c
index 8622f229e5..9c90499609 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -927,9 +927,9 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
 static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
JSONWriter *vmdesc)
 {
-uint64_t old_offset = qemu_file_transferred_noflush(f);
+uint64_t old_offset = qemu_file_transferred(f);
 se->ops->save_state(f, se->opaque);
-uint64_t size = qemu_file_transferred_noflush(f) - old_offset;
+uint64_t size = qemu_file_transferred(f) - old_offset;
 
 if (vmdesc) {
 json_writer_int64(vmdesc, "size", size);
@@ -3053,7 +3053,7 @@ bool save_snapshot(const char *name, bool overwrite, 
const char *vmstate,
 goto the_end;
 }
 ret = qemu_savevm_state(f, errp);
-vm_state_size = qemu_file_transferred_noflush(f);
+vm_state_size = qemu_file_transferred(f);
 ret2 = qemu_fclose(f);
 if (ret < 0) {
 goto the_end;
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 1cf9e45b85..16420fa9a3 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -386,7 +386,7 @@ int vmstate_save_state_v(QEMUFile *f, const 
VMStateDescription *vmsd,
 void *curr_elem = first_elem + size * i;
 
 vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
-old_offset = qemu_file_transferred_noflush(f);
+old_offset = qemu_file_transferred(f);
 if (field->flags & VMS_ARRAY_OF_POINTER) {
 assert(curr_elem);
 curr_elem = *(void **)curr_elem;
@@ -416,7 +416,7 @@ int vmstate_save_state_v(QEMUFile *f, const 
VMStateDescription *vmsd,
 return ret;
 }
 
-written_bytes = qemu_file_transferred_noflush(f) - old_offset;
+written_bytes = qemu_file_transferred(f) - old_offset;
 vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, 
i);
 
 /* Compressed arrays only care about the first element */
-- 
2.41.0




[PATCH v2 02/12] qemu_file: Use a stat64 for qemu_file_transferred

2023-10-25 Thread Juan Quintela
This way we can read it from any thread.
I checked that it gives the same value as the current one.  We never
use two qemu_files at the same time.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
---
 migration/migration-stats.h | 4 
 migration/qemu-file.c   | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index 2358caad63..b7795e7914 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -81,6 +81,10 @@ typedef struct {
  * Number of bytes sent during precopy stage.
  */
 Stat64 precopy_bytes;
+/*
+ * Number of bytes transferred with QEMUFile.
+ */
+Stat64 qemu_file_transferred;
 /*
  * Amount of transferred data at the start of current cycle.
  */
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 6814c562e6..384985f534 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -283,6 +283,7 @@ void qemu_fflush(QEMUFile *f)
 } else {
 uint64_t size = iov_size(f->iov, f->iovcnt);
 f->total_transferred += size;
+stat64_add(_stats.qemu_file_transferred, size);
 }
 
 qemu_iovec_release_ram(f);
@@ -623,7 +624,7 @@ int coroutine_mixed_fn qemu_get_byte(QEMUFile *f)
 
 uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 {
-uint64_t ret = f->total_transferred;
+uint64_t ret = stat64_get(_stats.qemu_file_transferred);
 int i;
 
 g_assert(qemu_file_is_writable(f));
@@ -639,7 +640,7 @@ uint64_t qemu_file_transferred(QEMUFile *f)
 {
 g_assert(qemu_file_is_writable(f));
 qemu_fflush(f);
-return f->total_transferred;
+return stat64_get(_stats.qemu_file_transferred);
 }
 
 void qemu_put_be16(QEMUFile *f, unsigned int v)
-- 
2.41.0




[PATCH v2 08/12] migration: migration_rate_limit_reset() don't need the QEMUFile

2023-10-25 Thread Juan Quintela
Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Juan Quintela 
---
 migration/migration-stats.h | 4 +---
 migration/migration-stats.c | 2 +-
 migration/migration.c   | 2 +-
 3 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index e3863bf9bb..68f3939188 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -120,10 +120,8 @@ uint64_t migration_rate_get(void);
  * migration_rate_reset: Reset the rate limit counter.
  *
  * This is called when we know we start a new transfer cycle.
- *
- * @f: QEMUFile used for main migration channel
  */
-void migration_rate_reset(QEMUFile *f);
+void migration_rate_reset(void);
 
 /**
  * migration_rate_set: Set the maximum amount that can be transferred.
diff --git a/migration/migration-stats.c b/migration/migration-stats.c
index 4ae8c0c722..f690b98a03 100644
--- a/migration/migration-stats.c
+++ b/migration/migration-stats.c
@@ -54,7 +54,7 @@ void migration_rate_set(uint64_t limit)
 stat64_set(_stats.rate_limit_max, limit / XFER_LIMIT_RATIO);
 }
 
-void migration_rate_reset(QEMUFile *f)
+void migration_rate_reset(void)
 {
 stat64_set(_stats.rate_limit_start, migration_transferred_bytes());
 }
diff --git a/migration/migration.c b/migration/migration.c
index e199d2f50d..bb62244288 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2775,7 +2775,7 @@ static void migration_update_counters(MigrationState *s,
 stat64_get(_stats.dirty_bytes_last_sync) / expected_bw_per_ms;
 }
 
-migration_rate_reset(s->to_dst_file);
+migration_rate_reset();
 
 update_iteration_initial_status(s);
 
-- 
2.41.0




[PATCH v2 09/12] qemu-file: Simplify qemu_file_get_error()

2023-10-25 Thread Juan Quintela
If we pass a NULL error is the same that returning directly the value.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
---
 migration/qemu-file.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 0158db2a54..7e738743ce 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -204,7 +204,7 @@ void qemu_file_set_error_obj(QEMUFile *f, int ret, Error 
*err)
  */
 int qemu_file_get_error(QEMUFile *f)
 {
-return qemu_file_get_error_obj(f, NULL);
+return f->last_error;
 }
 
 /*
-- 
2.41.0




[PATCH v2 11/12] migration: Remove transferred atomic counter

2023-10-25 Thread Juan Quintela
After last commit, it is a write only variable.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
---
 migration/migration-stats.h | 4 
 migration/multifd.c | 3 ---
 migration/ram.c | 1 -
 3 files changed, 8 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index 68f3939188..05290ade76 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -97,10 +97,6 @@ typedef struct {
  * Number of bytes sent through RDMA.
  */
 Stat64 rdma_bytes;
-/*
- * Total number of bytes transferred.
- */
-Stat64 transferred;
 /*
  * Number of pages transferred that were full of zeros.
  */
diff --git a/migration/multifd.c b/migration/multifd.c
index e2a45c667a..ec58c58082 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -188,7 +188,6 @@ static int multifd_send_initial_packet(MultiFDSendParams 
*p, Error **errp)
 return -1;
 }
 stat64_add(_stats.multifd_bytes, size);
-stat64_add(_stats.transferred, size);
 return 0;
 }
 
@@ -733,8 +732,6 @@ static void *multifd_send_thread(void *opaque)
 
 stat64_add(_stats.multifd_bytes,
p->next_packet_size + p->packet_len);
-stat64_add(_stats.transferred,
-   p->next_packet_size + p->packet_len);
 p->next_packet_size = 0;
 qemu_mutex_lock(>mutex);
 p->pending_job--;
diff --git a/migration/ram.c b/migration/ram.c
index 5ccf70333a..6d2bf50614 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -455,7 +455,6 @@ void ram_transferred_add(uint64_t bytes)
 } else {
 stat64_add(_stats.downtime_bytes, bytes);
 }
-stat64_add(_stats.transferred, bytes);
 }
 
 struct MigrationOps {
-- 
2.41.0




[PATCH v2 12/12] qemu-file: Make qemu_fflush() return errors

2023-10-25 Thread Juan Quintela
This let us simplify code of this shape.

   qemu_fflush(f);
   int ret = qemu_file_get_error(f);
   if (ret) {
  return ret;
   }

into:

   int ret = qemu_fflush(f);
   if (ret) {
  return ret;
   }

I updated all callers where there is any error check.
qemu_fclose() don't need to check for f->last_error because
qemu_fflush() returns it at the beggining of the function.

Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 

---

In v2: Now that we call always qemu_fflush() for all files, we can
simplify qemu_fclose()
---
 migration/qemu-file.h |  2 +-
 migration/colo.c  | 11 +++
 migration/migration.c |  7 +--
 migration/qemu-file.c | 23 +++
 migration/ram.c   | 22 +++---
 migration/rdma.c  |  4 +---
 migration/savevm.c|  3 +--
 7 files changed, 21 insertions(+), 51 deletions(-)

diff --git a/migration/qemu-file.h b/migration/qemu-file.h
index 1b2f6b8d8f..1774116f79 100644
--- a/migration/qemu-file.h
+++ b/migration/qemu-file.h
@@ -71,7 +71,7 @@ void qemu_file_set_error_obj(QEMUFile *f, int ret, Error 
*err);
 void qemu_file_set_error(QEMUFile *f, int ret);
 int qemu_file_shutdown(QEMUFile *f);
 QEMUFile *qemu_file_get_return_path(QEMUFile *f);
-void qemu_fflush(QEMUFile *f);
+int qemu_fflush(QEMUFile *f);
 void qemu_file_set_blocking(QEMUFile *f, bool block);
 int qemu_file_get_to_fd(QEMUFile *f, int fd, size_t size);
 
diff --git a/migration/colo.c b/migration/colo.c
index 72f4f7b37e..4447e34914 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -314,9 +314,7 @@ static void colo_send_message(QEMUFile *f, COLOMessage msg,
 return;
 }
 qemu_put_be32(f, msg);
-qemu_fflush(f);
-
-ret = qemu_file_get_error(f);
+ret = qemu_fflush(f);
 if (ret < 0) {
 error_setg_errno(errp, -ret, "Can't send COLO message");
 }
@@ -335,9 +333,7 @@ static void colo_send_message_value(QEMUFile *f, 
COLOMessage msg,
 return;
 }
 qemu_put_be64(f, value);
-qemu_fflush(f);
-
-ret = qemu_file_get_error(f);
+ret = qemu_fflush(f);
 if (ret < 0) {
 error_setg_errno(errp, -ret, "Failed to send value for message:%s",
  COLOMessage_str(msg));
@@ -483,8 +479,7 @@ static int colo_do_checkpoint_transaction(MigrationState *s,
 }
 
 qemu_put_buffer(s->to_dst_file, bioc->data, bioc->usage);
-qemu_fflush(s->to_dst_file);
-ret = qemu_file_get_error(s->to_dst_file);
+ret = qemu_fflush(s->to_dst_file);
 if (ret < 0) {
 goto out;
 }
diff --git a/migration/migration.c b/migration/migration.c
index a6cde985a2..ce12fca520 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -305,12 +305,7 @@ static int migrate_send_rp_message(MigrationIncomingState 
*mis,
 qemu_put_be16(mis->to_src_file, (unsigned int)message_type);
 qemu_put_be16(mis->to_src_file, len);
 qemu_put_buffer(mis->to_src_file, data, len);
-qemu_fflush(mis->to_src_file);
-
-/* It's possible that qemu file got error during sending */
-ret = qemu_file_get_error(mis->to_src_file);
-
-return ret;
+return qemu_fflush(mis->to_src_file);
 }
 
 /* Request one page from the source VM at the given start address.
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 7e738743ce..d64500310d 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -262,14 +262,14 @@ static void qemu_iovec_release_ram(QEMUFile *f)
  * This will flush all pending data. If data was only partially flushed, it
  * will set an error state.
  */
-void qemu_fflush(QEMUFile *f)
+int qemu_fflush(QEMUFile *f)
 {
 if (!qemu_file_is_writable(f)) {
-return;
+return f->last_error;
 }
 
-if (qemu_file_get_error(f)) {
-return;
+if (f->last_error) {
+return f->last_error;
 }
 if (f->iovcnt > 0) {
 Error *local_error = NULL;
@@ -287,6 +287,7 @@ void qemu_fflush(QEMUFile *f)
 
 f->buf_index = 0;
 f->iovcnt = 0;
+return f->last_error;
 }
 
 /*
@@ -353,22 +354,12 @@ static ssize_t coroutine_mixed_fn 
qemu_fill_buffer(QEMUFile *f)
  */
 int qemu_fclose(QEMUFile *f)
 {
-int ret, ret2;
-qemu_fflush(f);
-ret = qemu_file_get_error(f);
-
-ret2 = qio_channel_close(f->ioc, NULL);
+int ret = qemu_fflush(f);
+int ret2 = qio_channel_close(f->ioc, NULL);
 if (ret >= 0) {
 ret = ret2;
 }
 g_clear_pointer(>ioc, object_unref);
-
-/* If any error was spotted before closing, we should report it
- * instead of the close() return value.
- */
-if (f->last_error) {
-ret = f->last_error;
-}
 error_free(f->last_error_obj);
 g_free(f);
 trace_qemu_file_fclose();
diff --git a/migration/ram.c b/migration/ram.c
index 6d2bf50614..3a1d9882ce 100644
--- a/migration/ram.c
+++ b/migrat

[PATCH v2 10/12] migration: Use migration_transferred_bytes()

2023-10-25 Thread Juan Quintela
There are only two differnces with the old value:

- the amount of QEMUFile that hasn't yet been flushed.  It can be
  discussed what is more exact, the new or the old one.
- the amount of transferred bytes that we forgot to account for (the
  newer is better, i.e. exact).

Notice that this two values are used to:
a - present to the user
b - calculate the rate_limit

So a few KB here and there is not going to make a difference.

Reviewed-by: Fabiano Rosas 
Signed-off-by: Juan Quintela 
---
 migration/migration.c | 2 +-
 migration/ram.c   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/migration/migration.c b/migration/migration.c
index bb62244288..a6cde985a2 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -942,7 +942,7 @@ static void populate_ram_info(MigrationInfo *info, 
MigrationState *s)
 size_t page_size = qemu_target_page_size();
 
 info->ram = g_malloc0(sizeof(*info->ram));
-info->ram->transferred = stat64_get(_stats.transferred);
+info->ram->transferred = migration_transferred_bytes();
 info->ram->total = ram_bytes_total();
 info->ram->duplicate = stat64_get(_stats.zero_pages);
 /* legacy value.  It is not used anymore */
diff --git a/migration/ram.c b/migration/ram.c
index 92769902bb..5ccf70333a 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -564,7 +564,7 @@ void mig_throttle_counter_reset(void)
 
 rs->time_last_bitmap_sync = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
 rs->num_dirty_pages_period = 0;
-rs->bytes_xfer_prev = stat64_get(_stats.transferred);
+rs->bytes_xfer_prev = migration_transferred_bytes();
 }
 
 /**
@@ -1030,7 +1030,7 @@ static void migration_trigger_throttle(RAMState *rs)
 {
 uint64_t threshold = migrate_throttle_trigger_threshold();
 uint64_t bytes_xfer_period =
-stat64_get(_stats.transferred) - rs->bytes_xfer_prev;
+migration_transferred_bytes() - rs->bytes_xfer_prev;
 uint64_t bytes_dirty_period = rs->num_dirty_pages_period * 
TARGET_PAGE_SIZE;
 uint64_t bytes_dirty_threshold = bytes_xfer_period * threshold / 100;
 
@@ -1100,7 +1100,7 @@ static void migration_bitmap_sync(RAMState *rs, bool 
last_stage)
 /* reset period counters */
 rs->time_last_bitmap_sync = end_time;
 rs->num_dirty_pages_period = 0;
-rs->bytes_xfer_prev = stat64_get(_stats.transferred);
+rs->bytes_xfer_prev = migration_transferred_bytes();
 }
 if (migrate_events()) {
 uint64_t generation = stat64_get(_stats.dirty_sync_count);
-- 
2.41.0




[PATCH v2 00/12] migration: Yet another round of atomic counters

2023-10-25 Thread Juan Quintela
Hi

On this v2:
- Redid commint for patch 1
- Every other patch is reviewed now.

Please review pending patch.

Thanks, Juan.

[v1]
Goal of the whole series was to be able to move rate_limit logic to
not use qemu_file.  Goal achieved.

Removal of trasnferred atomic counter.

After this series, we have three atomic counters:
- multifd_bytes
- rdma_bytes
- qemu_file_trasferred

And we only need to setup one (and only one) of these each time that
we sent anything.

Please review.

Later, Juan.

Juan Quintela (12):
  qemu-file: Don't increment qemu_file_transferred at
qemu_file_fill_buffer
  qemu_file: Use a stat64 for qemu_file_transferred
  qemu_file: total_transferred is not used anymore
  migration: Use the number of transferred bytes directly
  qemu_file: Remove unused qemu_file_transferred()
  qemu-file: Remove _noflush from qemu_file_transferred_noflush()
  migration: migration_transferred_bytes() don't need the QEMUFile
  migration: migration_rate_limit_reset() don't need the QEMUFile
  qemu-file: Simplify qemu_file_get_error()
  migration: Use migration_transferred_bytes()
  migration: Remove transferred atomic counter
  qemu-file: Make qemu_fflush() return errors

 migration/migration-stats.h | 16 ++
 migration/qemu-file.h   | 27 ---
 migration/block.c   |  4 ++--
 migration/colo.c| 11 +++---
 migration/migration-stats.c | 10 -
 migration/migration.c   | 17 ++-
 migration/multifd.c |  3 ---
 migration/qemu-file.c   | 43 +++--
 migration/ram.c | 29 +
 migration/rdma.c|  4 +---
 migration/savevm.c  |  9 
 migration/vmstate.c |  4 ++--
 12 files changed, 56 insertions(+), 121 deletions(-)

-- 
2.41.0




Re: [PATCH 02/12] qemu_file: Use a stat64 for qemu_file_transferred

2023-10-25 Thread Juan Quintela
Eric Blake  wrote:
> On Tue, Oct 24, 2023 at 05:10:32PM +0200, Juan Quintela wrote:
>> This way we can read it from any thread.
>> I checked that it gives the same value than the current one.  We never
>
> s/than/as/

Done

>> use to qemu_files at the same time.
>
> s/to/two/

Done

Thanks.




Re: [PATCH 01/12] qemu-file: We only call qemu_file_transferred_* on the sending side

2023-10-25 Thread Juan Quintela
Fabiano Rosas  wrote:
> Juan Quintela  writes:
>
>> Remove the increase in qemu_file_fill_buffer() and add asserts to
>> qemu_file_transferred* functions.
>
> Patch looks ok, but I would rewrite the whole commit message like this:
>
> Don't increment qemu_file_transferred at qemu_file_fill_buffer
>
> We only call qemu_file_transferred_* on the sending side. Remove the
> increment at qemu_file_fill_buffer() and add asserts to
> qemu_file_transferred* functions.

Changed the commint text.

Thanks,




[PATCH 02/12] qemu_file: Use a stat64 for qemu_file_transferred

2023-10-24 Thread Juan Quintela
This way we can read it from any thread.
I checked that it gives the same value than the current one.  We never
use to qemu_files at the same time.

Signed-off-by: Juan Quintela 
---
 migration/migration-stats.h | 4 
 migration/qemu-file.c   | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/migration/migration-stats.h b/migration/migration-stats.h
index 2358caad63..b7795e7914 100644
--- a/migration/migration-stats.h
+++ b/migration/migration-stats.h
@@ -81,6 +81,10 @@ typedef struct {
  * Number of bytes sent during precopy stage.
  */
 Stat64 precopy_bytes;
+/*
+ * Number of bytes transferred with QEMUFile.
+ */
+Stat64 qemu_file_transferred;
 /*
  * Amount of transferred data at the start of current cycle.
  */
diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 6814c562e6..384985f534 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -283,6 +283,7 @@ void qemu_fflush(QEMUFile *f)
 } else {
 uint64_t size = iov_size(f->iov, f->iovcnt);
 f->total_transferred += size;
+stat64_add(_stats.qemu_file_transferred, size);
 }
 
 qemu_iovec_release_ram(f);
@@ -623,7 +624,7 @@ int coroutine_mixed_fn qemu_get_byte(QEMUFile *f)
 
 uint64_t qemu_file_transferred_noflush(QEMUFile *f)
 {
-uint64_t ret = f->total_transferred;
+uint64_t ret = stat64_get(_stats.qemu_file_transferred);
 int i;
 
 g_assert(qemu_file_is_writable(f));
@@ -639,7 +640,7 @@ uint64_t qemu_file_transferred(QEMUFile *f)
 {
 g_assert(qemu_file_is_writable(f));
 qemu_fflush(f);
-return f->total_transferred;
+return stat64_get(_stats.qemu_file_transferred);
 }
 
 void qemu_put_be16(QEMUFile *f, unsigned int v)
-- 
2.41.0




[PATCH 03/12] qemu_file: total_transferred is not used anymore

2023-10-24 Thread Juan Quintela
Signed-off-by: Juan Quintela 
---
 migration/qemu-file.c | 4 
 1 file changed, 4 deletions(-)

diff --git a/migration/qemu-file.c b/migration/qemu-file.c
index 384985f534..641ab703cc 100644
--- a/migration/qemu-file.c
+++ b/migration/qemu-file.c
@@ -41,9 +41,6 @@ struct QEMUFile {
 QIOChannel *ioc;
 bool is_writable;
 
-/* The sum of bytes transferred on the wire */
-uint64_t total_transferred;
-
 int buf_index;
 int buf_size; /* 0 when writing */
 uint8_t buf[IO_BUF_SIZE];
@@ -282,7 +279,6 @@ void qemu_fflush(QEMUFile *f)
 qemu_file_set_error_obj(f, -EIO, local_error);
 } else {
 uint64_t size = iov_size(f->iov, f->iovcnt);
-f->total_transferred += size;
 stat64_add(_stats.qemu_file_transferred, size);
 }
 
-- 
2.41.0




  1   2   3   4   5   6   7   8   9   10   >