diff mbox series

[v3,1/7] introduce 'track-writes-ram' migration capability

Message ID 20201119125940.20017-2-andrey.gruzdev@virtuozzo.com (mailing list archive)
State New, archived
Headers show
Series UFFD write-tracking migration/snapshots | expand

Commit Message

Andrey Gruzdev Nov. 19, 2020, 12:59 p.m. UTC
Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
---
 migration/migration.c | 96 +++++++++++++++++++++++++++++++++++++++++++
 migration/migration.h |  1 +
 qapi/migration.json   |  7 +++-
 3 files changed, 103 insertions(+), 1 deletion(-)

Comments

Peter Xu Nov. 19, 2020, 6:51 p.m. UTC | #1
On Thu, Nov 19, 2020 at 03:59:34PM +0300, Andrey Gruzdev via wrote:
> Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
> ---
>  migration/migration.c | 96 +++++++++++++++++++++++++++++++++++++++++++
>  migration/migration.h |  1 +
>  qapi/migration.json   |  7 +++-
>  3 files changed, 103 insertions(+), 1 deletion(-)
> 
> diff --git a/migration/migration.c b/migration/migration.c
> index 87a9b59f83..ff0364dde0 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -56,6 +56,7 @@
>  #include "net/announce.h"
>  #include "qemu/queue.h"
>  #include "multifd.h"
> +#include "sysemu/cpus.h"
>  
>  #ifdef CONFIG_VFIO
>  #include "hw/vfio/vfio-common.h"
> @@ -1165,6 +1166,91 @@ static bool migrate_caps_check(bool *cap_list,
>          }
>      }
>  
> +    if (cap_list[MIGRATION_CAPABILITY_TRACK_WRITES_RAM]) {
> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with postcopy-ram");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_DIRTY_BITMAPS]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with dirty-bitmaps");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with postcopy-blocktime");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with late-block-activate");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_RETURN_PATH]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with return-path");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
> +            error_setg(errp, "Track-writes is not compatible with multifd");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with pause-before-switchover");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with auto-converge");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_RELEASE_RAM]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with release-ram");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_RDMA_PIN_ALL]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with rdma-pin-all");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with compression");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_XBZRLE]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with XBZLRE");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_X_COLO]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with x-colo");
> +            return false;
> +        }
> +
> +        if (cap_list[MIGRATION_CAPABILITY_VALIDATE_UUID]) {
> +            error_setg(errp,
> +                    "Track-writes is not compatible with validate-uuid");
> +            return false;
> +        }
> +    }
> +
>      return true;
>  }
>  
> @@ -2490,6 +2576,15 @@ bool migrate_use_block_incremental(void)
>      return s->parameters.block_incremental;
>  }
>  
> +bool migrate_track_writes_ram(void)
> +{
> +    MigrationState *s;
> +
> +    s = migrate_get_current();
> +
> +    return s->enabled_capabilities[MIGRATION_CAPABILITY_TRACK_WRITES_RAM];
> +}
> +
>  /* migration thread support */
>  /*
>   * Something bad happened to the RP stream, mark an error
> @@ -3783,6 +3878,7 @@ static Property migration_properties[] = {
>      DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
>      DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
>      DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
> +    DEFINE_PROP_MIG_CAP("x-track-writes-ram", MIGRATION_CAPABILITY_TRACK_WRITES_RAM),
>  
>      DEFINE_PROP_END_OF_LIST(),
>  };
> diff --git a/migration/migration.h b/migration/migration.h
> index d096b77f74..339ae720e0 100644
> --- a/migration/migration.h
> +++ b/migration/migration.h
> @@ -341,6 +341,7 @@ int migrate_compress_wait_thread(void);
>  int migrate_decompress_threads(void);
>  bool migrate_use_events(void);
>  bool migrate_postcopy_blocktime(void);
> +bool migrate_track_writes_ram(void);
>  
>  /* Sending on the return path - generic and then for each message type */
>  void migrate_send_rp_shut(MigrationIncomingState *mis,
> diff --git a/qapi/migration.json b/qapi/migration.json
> index 3c75820527..a28d8b7ee8 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -442,6 +442,11 @@
>  # @validate-uuid: Send the UUID of the source to allow the destination
>  #                 to ensure it is the same. (since 4.2)
>  #
> +# @track-writes-ram: If enabled, the migration stream will be a snapshot
> +#                    of the VM exactly at the point when the migration
> +#                    procedure starts. The VM RAM is saved with running VM.
> +#                    (since 6.0)
> +#

The name is slightly confusing to me.  Could I ask why changed from previous
one?  "snapshot" sounds a very necessary keyword to me here and tells exactly
on what we do...  Because we can do quite a few things with "trace-writes-ram"
but not snapshotting, e.g., to calculate per-vm dirty rates.
Peter Xu Nov. 19, 2020, 7:07 p.m. UTC | #2
On Thu, Nov 19, 2020 at 01:51:50PM -0500, Peter Xu wrote:
> On Thu, Nov 19, 2020 at 03:59:34PM +0300, Andrey Gruzdev via wrote:
> > Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
> > ---
> >  migration/migration.c | 96 +++++++++++++++++++++++++++++++++++++++++++
> >  migration/migration.h |  1 +
> >  qapi/migration.json   |  7 +++-
> >  3 files changed, 103 insertions(+), 1 deletion(-)
> > 
> > diff --git a/migration/migration.c b/migration/migration.c
> > index 87a9b59f83..ff0364dde0 100644
> > --- a/migration/migration.c
> > +++ b/migration/migration.c
> > @@ -56,6 +56,7 @@
> >  #include "net/announce.h"
> >  #include "qemu/queue.h"
> >  #include "multifd.h"
> > +#include "sysemu/cpus.h"
> >  
> >  #ifdef CONFIG_VFIO
> >  #include "hw/vfio/vfio-common.h"
> > @@ -1165,6 +1166,91 @@ static bool migrate_caps_check(bool *cap_list,
> >          }
> >      }
> >  
> > +    if (cap_list[MIGRATION_CAPABILITY_TRACK_WRITES_RAM]) {
> > +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with postcopy-ram");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_DIRTY_BITMAPS]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with dirty-bitmaps");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with postcopy-blocktime");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with late-block-activate");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_RETURN_PATH]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with return-path");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
> > +            error_setg(errp, "Track-writes is not compatible with multifd");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with pause-before-switchover");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with auto-converge");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_RELEASE_RAM]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with release-ram");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_RDMA_PIN_ALL]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with rdma-pin-all");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with compression");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_XBZRLE]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with XBZLRE");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_X_COLO]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with x-colo");
> > +            return false;
> > +        }
> > +
> > +        if (cap_list[MIGRATION_CAPABILITY_VALIDATE_UUID]) {
> > +            error_setg(errp,
> > +                    "Track-writes is not compatible with validate-uuid");
> > +            return false;
> > +        }

Another thing forgot to mention - we can at least define an array for live
snapshot now so we just loop over that one instead of copy-paste these lines...

> > +    }
> > +
> >      return true;
> >  }
> >  
> > @@ -2490,6 +2576,15 @@ bool migrate_use_block_incremental(void)
> >      return s->parameters.block_incremental;
> >  }
> >  
> > +bool migrate_track_writes_ram(void)
> > +{
> > +    MigrationState *s;
> > +
> > +    s = migrate_get_current();
> > +
> > +    return s->enabled_capabilities[MIGRATION_CAPABILITY_TRACK_WRITES_RAM];
> > +}
> > +
> >  /* migration thread support */
> >  /*
> >   * Something bad happened to the RP stream, mark an error
> > @@ -3783,6 +3878,7 @@ static Property migration_properties[] = {
> >      DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
> >      DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
> >      DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
> > +    DEFINE_PROP_MIG_CAP("x-track-writes-ram", MIGRATION_CAPABILITY_TRACK_WRITES_RAM),
> >  
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> > diff --git a/migration/migration.h b/migration/migration.h
> > index d096b77f74..339ae720e0 100644
> > --- a/migration/migration.h
> > +++ b/migration/migration.h
> > @@ -341,6 +341,7 @@ int migrate_compress_wait_thread(void);
> >  int migrate_decompress_threads(void);
> >  bool migrate_use_events(void);
> >  bool migrate_postcopy_blocktime(void);
> > +bool migrate_track_writes_ram(void);
> >  
> >  /* Sending on the return path - generic and then for each message type */
> >  void migrate_send_rp_shut(MigrationIncomingState *mis,
> > diff --git a/qapi/migration.json b/qapi/migration.json
> > index 3c75820527..a28d8b7ee8 100644
> > --- a/qapi/migration.json
> > +++ b/qapi/migration.json
> > @@ -442,6 +442,11 @@
> >  # @validate-uuid: Send the UUID of the source to allow the destination
> >  #                 to ensure it is the same. (since 4.2)
> >  #
> > +# @track-writes-ram: If enabled, the migration stream will be a snapshot
> > +#                    of the VM exactly at the point when the migration
> > +#                    procedure starts. The VM RAM is saved with running VM.
> > +#                    (since 6.0)
> > +#
> 
> The name is slightly confusing to me.  Could I ask why changed from previous
> one?  "snapshot" sounds a very necessary keyword to me here and tells exactly
> on what we do...  Because we can do quite a few things with "trace-writes-ram"
> but not snapshotting, e.g., to calculate per-vm dirty rates.
> 
> -- 
> Peter Xu
Andrey Gruzdev Nov. 20, 2020, 11:32 a.m. UTC | #3
On 19.11.2020 21:51, Peter Xu wrote:
> On Thu, Nov 19, 2020 at 03:59:34PM +0300, Andrey Gruzdev via wrote:
>> Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
>> ---
>>   migration/migration.c | 96 +++++++++++++++++++++++++++++++++++++++++++
>>   migration/migration.h |  1 +
>>   qapi/migration.json   |  7 +++-
>>   3 files changed, 103 insertions(+), 1 deletion(-)
>>
>> diff --git a/migration/migration.c b/migration/migration.c
>> index 87a9b59f83..ff0364dde0 100644
>> --- a/migration/migration.c
>> +++ b/migration/migration.c
>> @@ -56,6 +56,7 @@
>>   #include "net/announce.h"
>>   #include "qemu/queue.h"
>>   #include "multifd.h"
>> +#include "sysemu/cpus.h"
>>   
>>   #ifdef CONFIG_VFIO
>>   #include "hw/vfio/vfio-common.h"
>> @@ -1165,6 +1166,91 @@ static bool migrate_caps_check(bool *cap_list,
>>           }
>>       }
>>   
>> +    if (cap_list[MIGRATION_CAPABILITY_TRACK_WRITES_RAM]) {
>> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with postcopy-ram");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_DIRTY_BITMAPS]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with dirty-bitmaps");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with postcopy-blocktime");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with late-block-activate");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_RETURN_PATH]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with return-path");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
>> +            error_setg(errp, "Track-writes is not compatible with multifd");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with pause-before-switchover");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with auto-converge");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_RELEASE_RAM]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with release-ram");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_RDMA_PIN_ALL]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with rdma-pin-all");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with compression");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_XBZRLE]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with XBZLRE");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_X_COLO]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with x-colo");
>> +            return false;
>> +        }
>> +
>> +        if (cap_list[MIGRATION_CAPABILITY_VALIDATE_UUID]) {
>> +            error_setg(errp,
>> +                    "Track-writes is not compatible with validate-uuid");
>> +            return false;
>> +        }
>> +    }
>> +
>>       return true;
>>   }
>>   
>> @@ -2490,6 +2576,15 @@ bool migrate_use_block_incremental(void)
>>       return s->parameters.block_incremental;
>>   }
>>   
>> +bool migrate_track_writes_ram(void)
>> +{
>> +    MigrationState *s;
>> +
>> +    s = migrate_get_current();
>> +
>> +    return s->enabled_capabilities[MIGRATION_CAPABILITY_TRACK_WRITES_RAM];
>> +}
>> +
>>   /* migration thread support */
>>   /*
>>    * Something bad happened to the RP stream, mark an error
>> @@ -3783,6 +3878,7 @@ static Property migration_properties[] = {
>>       DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
>>       DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
>>       DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
>> +    DEFINE_PROP_MIG_CAP("x-track-writes-ram", MIGRATION_CAPABILITY_TRACK_WRITES_RAM),
>>   
>>       DEFINE_PROP_END_OF_LIST(),
>>   };
>> diff --git a/migration/migration.h b/migration/migration.h
>> index d096b77f74..339ae720e0 100644
>> --- a/migration/migration.h
>> +++ b/migration/migration.h
>> @@ -341,6 +341,7 @@ int migrate_compress_wait_thread(void);
>>   int migrate_decompress_threads(void);
>>   bool migrate_use_events(void);
>>   bool migrate_postcopy_blocktime(void);
>> +bool migrate_track_writes_ram(void);
>>   
>>   /* Sending on the return path - generic and then for each message type */
>>   void migrate_send_rp_shut(MigrationIncomingState *mis,
>> diff --git a/qapi/migration.json b/qapi/migration.json
>> index 3c75820527..a28d8b7ee8 100644
>> --- a/qapi/migration.json
>> +++ b/qapi/migration.json
>> @@ -442,6 +442,11 @@
>>   # @validate-uuid: Send the UUID of the source to allow the destination
>>   #                 to ensure it is the same. (since 4.2)
>>   #
>> +# @track-writes-ram: If enabled, the migration stream will be a snapshot
>> +#                    of the VM exactly at the point when the migration
>> +#                    procedure starts. The VM RAM is saved with running VM.
>> +#                    (since 6.0)
>> +#
> 
> The name is slightly confusing to me.  Could I ask why changed from previous
> one?  "snapshot" sounds a very necessary keyword to me here and tells exactly
> on what we do...  Because we can do quite a few things with "trace-writes-ram"
> but not snapshotting, e.g., to calculate per-vm dirty rates.
> 

Mm, the idea was that we introduce alternative mechanism of migration.. 
But it's really intended for snapshots only, correct. Yes, let's change 
the name to original one.
Andrey Gruzdev Nov. 20, 2020, 11:35 a.m. UTC | #4
On 19.11.2020 22:07, Peter Xu wrote:
> On Thu, Nov 19, 2020 at 01:51:50PM -0500, Peter Xu wrote:
>> On Thu, Nov 19, 2020 at 03:59:34PM +0300, Andrey Gruzdev via wrote:
>>> Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
>>> ---
>>>   migration/migration.c | 96 +++++++++++++++++++++++++++++++++++++++++++
>>>   migration/migration.h |  1 +
>>>   qapi/migration.json   |  7 +++-
>>>   3 files changed, 103 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/migration/migration.c b/migration/migration.c
>>> index 87a9b59f83..ff0364dde0 100644
>>> --- a/migration/migration.c
>>> +++ b/migration/migration.c
>>> @@ -56,6 +56,7 @@
>>>   #include "net/announce.h"
>>>   #include "qemu/queue.h"
>>>   #include "multifd.h"
>>> +#include "sysemu/cpus.h"
>>>   
>>>   #ifdef CONFIG_VFIO
>>>   #include "hw/vfio/vfio-common.h"
>>> @@ -1165,6 +1166,91 @@ static bool migrate_caps_check(bool *cap_list,
>>>           }
>>>       }
>>>   
>>> +    if (cap_list[MIGRATION_CAPABILITY_TRACK_WRITES_RAM]) {
>>> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with postcopy-ram");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_DIRTY_BITMAPS]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with dirty-bitmaps");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with postcopy-blocktime");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with late-block-activate");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_RETURN_PATH]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with return-path");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
>>> +            error_setg(errp, "Track-writes is not compatible with multifd");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with pause-before-switchover");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with auto-converge");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_RELEASE_RAM]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with release-ram");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_RDMA_PIN_ALL]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with rdma-pin-all");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with compression");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_XBZRLE]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with XBZLRE");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_X_COLO]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with x-colo");
>>> +            return false;
>>> +        }
>>> +
>>> +        if (cap_list[MIGRATION_CAPABILITY_VALIDATE_UUID]) {
>>> +            error_setg(errp,
>>> +                    "Track-writes is not compatible with validate-uuid");
>>> +            return false;
>>> +        }
> 
> Another thing forgot to mention - we can at least define an array for live
> snapshot now so we just loop over that one instead of copy-paste these lines...
> 

Yes, too many lines here, better to use 'compatibility array' here.

>>> +    }
>>> +
>>>       return true;
>>>   }
>>>   
>>> @@ -2490,6 +2576,15 @@ bool migrate_use_block_incremental(void)
>>>       return s->parameters.block_incremental;
>>>   }
>>>   
>>> +bool migrate_track_writes_ram(void)
>>> +{
>>> +    MigrationState *s;
>>> +
>>> +    s = migrate_get_current();
>>> +
>>> +    return s->enabled_capabilities[MIGRATION_CAPABILITY_TRACK_WRITES_RAM];
>>> +}
>>> +
>>>   /* migration thread support */
>>>   /*
>>>    * Something bad happened to the RP stream, mark an error
>>> @@ -3783,6 +3878,7 @@ static Property migration_properties[] = {
>>>       DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
>>>       DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
>>>       DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
>>> +    DEFINE_PROP_MIG_CAP("x-track-writes-ram", MIGRATION_CAPABILITY_TRACK_WRITES_RAM),
>>>   
>>>       DEFINE_PROP_END_OF_LIST(),
>>>   };
>>> diff --git a/migration/migration.h b/migration/migration.h
>>> index d096b77f74..339ae720e0 100644
>>> --- a/migration/migration.h
>>> +++ b/migration/migration.h
>>> @@ -341,6 +341,7 @@ int migrate_compress_wait_thread(void);
>>>   int migrate_decompress_threads(void);
>>>   bool migrate_use_events(void);
>>>   bool migrate_postcopy_blocktime(void);
>>> +bool migrate_track_writes_ram(void);
>>>   
>>>   /* Sending on the return path - generic and then for each message type */
>>>   void migrate_send_rp_shut(MigrationIncomingState *mis,
>>> diff --git a/qapi/migration.json b/qapi/migration.json
>>> index 3c75820527..a28d8b7ee8 100644
>>> --- a/qapi/migration.json
>>> +++ b/qapi/migration.json
>>> @@ -442,6 +442,11 @@
>>>   # @validate-uuid: Send the UUID of the source to allow the destination
>>>   #                 to ensure it is the same. (since 4.2)
>>>   #
>>> +# @track-writes-ram: If enabled, the migration stream will be a snapshot
>>> +#                    of the VM exactly at the point when the migration
>>> +#                    procedure starts. The VM RAM is saved with running VM.
>>> +#                    (since 6.0)
>>> +#
>>
>> The name is slightly confusing to me.  Could I ask why changed from previous
>> one?  "snapshot" sounds a very necessary keyword to me here and tells exactly
>> on what we do...  Because we can do quite a few things with "trace-writes-ram"
>> but not snapshotting, e.g., to calculate per-vm dirty rates.
>>
>> -- 
>> Peter Xu
>
Dr. David Alan Gilbert Nov. 24, 2020, 4:55 p.m. UTC | #5
* Peter Xu (peterx@redhat.com) wrote:
> On Thu, Nov 19, 2020 at 01:51:50PM -0500, Peter Xu wrote:
> > On Thu, Nov 19, 2020 at 03:59:34PM +0300, Andrey Gruzdev via wrote:
> > > Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
> > > ---
> > >  migration/migration.c | 96 +++++++++++++++++++++++++++++++++++++++++++
> > >  migration/migration.h |  1 +
> > >  qapi/migration.json   |  7 +++-
> > >  3 files changed, 103 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/migration/migration.c b/migration/migration.c
> > > index 87a9b59f83..ff0364dde0 100644
> > > --- a/migration/migration.c
> > > +++ b/migration/migration.c
> > > @@ -56,6 +56,7 @@
> > >  #include "net/announce.h"
> > >  #include "qemu/queue.h"
> > >  #include "multifd.h"
> > > +#include "sysemu/cpus.h"
> > >  
> > >  #ifdef CONFIG_VFIO
> > >  #include "hw/vfio/vfio-common.h"
> > > @@ -1165,6 +1166,91 @@ static bool migrate_caps_check(bool *cap_list,
> > >          }
> > >      }
> > >  
> > > +    if (cap_list[MIGRATION_CAPABILITY_TRACK_WRITES_RAM]) {
> > > +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with postcopy-ram");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_DIRTY_BITMAPS]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with dirty-bitmaps");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with postcopy-blocktime");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with late-block-activate");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_RETURN_PATH]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with return-path");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
> > > +            error_setg(errp, "Track-writes is not compatible with multifd");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with pause-before-switchover");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with auto-converge");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_RELEASE_RAM]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with release-ram");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_RDMA_PIN_ALL]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with rdma-pin-all");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with compression");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_XBZRLE]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with XBZLRE");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_X_COLO]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with x-colo");
> > > +            return false;
> > > +        }
> > > +
> > > +        if (cap_list[MIGRATION_CAPABILITY_VALIDATE_UUID]) {
> > > +            error_setg(errp,
> > > +                    "Track-writes is not compatible with validate-uuid");
> > > +            return false;
> > > +        }
> 
> Another thing forgot to mention - we can at least define an array for live
> snapshot now so we just loop over that one instead of copy-paste these lines...

Yes, I think we've already got a name lookup
(MigrationCapability_lookup - that's generated during build), so if you
just have an array of MigrationCapability's you should be able to loop
over them.

Dave

> > > +    }
> > > +
> > >      return true;
> > >  }
> > >  
> > > @@ -2490,6 +2576,15 @@ bool migrate_use_block_incremental(void)
> > >      return s->parameters.block_incremental;
> > >  }
> > >  
> > > +bool migrate_track_writes_ram(void)
> > > +{
> > > +    MigrationState *s;
> > > +
> > > +    s = migrate_get_current();
> > > +
> > > +    return s->enabled_capabilities[MIGRATION_CAPABILITY_TRACK_WRITES_RAM];
> > > +}
> > > +
> > >  /* migration thread support */
> > >  /*
> > >   * Something bad happened to the RP stream, mark an error
> > > @@ -3783,6 +3878,7 @@ static Property migration_properties[] = {
> > >      DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
> > >      DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
> > >      DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
> > > +    DEFINE_PROP_MIG_CAP("x-track-writes-ram", MIGRATION_CAPABILITY_TRACK_WRITES_RAM),
> > >  
> > >      DEFINE_PROP_END_OF_LIST(),
> > >  };
> > > diff --git a/migration/migration.h b/migration/migration.h
> > > index d096b77f74..339ae720e0 100644
> > > --- a/migration/migration.h
> > > +++ b/migration/migration.h
> > > @@ -341,6 +341,7 @@ int migrate_compress_wait_thread(void);
> > >  int migrate_decompress_threads(void);
> > >  bool migrate_use_events(void);
> > >  bool migrate_postcopy_blocktime(void);
> > > +bool migrate_track_writes_ram(void);
> > >  
> > >  /* Sending on the return path - generic and then for each message type */
> > >  void migrate_send_rp_shut(MigrationIncomingState *mis,
> > > diff --git a/qapi/migration.json b/qapi/migration.json
> > > index 3c75820527..a28d8b7ee8 100644
> > > --- a/qapi/migration.json
> > > +++ b/qapi/migration.json
> > > @@ -442,6 +442,11 @@
> > >  # @validate-uuid: Send the UUID of the source to allow the destination
> > >  #                 to ensure it is the same. (since 4.2)
> > >  #
> > > +# @track-writes-ram: If enabled, the migration stream will be a snapshot
> > > +#                    of the VM exactly at the point when the migration
> > > +#                    procedure starts. The VM RAM is saved with running VM.
> > > +#                    (since 6.0)
> > > +#
> > 
> > The name is slightly confusing to me.  Could I ask why changed from previous
> > one?  "snapshot" sounds a very necessary keyword to me here and tells exactly
> > on what we do...  Because we can do quite a few things with "trace-writes-ram"
> > but not snapshotting, e.g., to calculate per-vm dirty rates.
> > 
> > -- 
> > Peter Xu
> 
> -- 
> Peter Xu
>
Andrey Gruzdev Nov. 24, 2020, 5:25 p.m. UTC | #6
On 24.11.2020 19:55, Dr. David Alan Gilbert wrote:
> * Peter Xu (peterx@redhat.com) wrote:
>> On Thu, Nov 19, 2020 at 01:51:50PM -0500, Peter Xu wrote:
>>> On Thu, Nov 19, 2020 at 03:59:34PM +0300, Andrey Gruzdev via wrote:
>>>> Signed-off-by: Andrey Gruzdev <andrey.gruzdev@virtuozzo.com>
>>>> ---
>>>>   migration/migration.c | 96 +++++++++++++++++++++++++++++++++++++++++++
>>>>   migration/migration.h |  1 +
>>>>   qapi/migration.json   |  7 +++-
>>>>   3 files changed, 103 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/migration/migration.c b/migration/migration.c
>>>> index 87a9b59f83..ff0364dde0 100644
>>>> --- a/migration/migration.c
>>>> +++ b/migration/migration.c
>>>> @@ -56,6 +56,7 @@
>>>>   #include "net/announce.h"
>>>>   #include "qemu/queue.h"
>>>>   #include "multifd.h"
>>>> +#include "sysemu/cpus.h"
>>>>   
>>>>   #ifdef CONFIG_VFIO
>>>>   #include "hw/vfio/vfio-common.h"
>>>> @@ -1165,6 +1166,91 @@ static bool migrate_caps_check(bool *cap_list,
>>>>           }
>>>>       }
>>>>   
>>>> +    if (cap_list[MIGRATION_CAPABILITY_TRACK_WRITES_RAM]) {
>>>> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with postcopy-ram");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_DIRTY_BITMAPS]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with dirty-bitmaps");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with postcopy-blocktime");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with late-block-activate");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_RETURN_PATH]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with return-path");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
>>>> +            error_setg(errp, "Track-writes is not compatible with multifd");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with pause-before-switchover");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with auto-converge");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_RELEASE_RAM]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with release-ram");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_RDMA_PIN_ALL]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with rdma-pin-all");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with compression");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_XBZRLE]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with XBZLRE");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_X_COLO]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with x-colo");
>>>> +            return false;
>>>> +        }
>>>> +
>>>> +        if (cap_list[MIGRATION_CAPABILITY_VALIDATE_UUID]) {
>>>> +            error_setg(errp,
>>>> +                    "Track-writes is not compatible with validate-uuid");
>>>> +            return false;
>>>> +        }
>>
>> Another thing forgot to mention - we can at least define an array for live
>> snapshot now so we just loop over that one instead of copy-paste these lines...
> 
> Yes, I think we've already got a name lookup
> (MigrationCapability_lookup - that's generated during build), so if you
> just have an array of MigrationCapability's you should be able to loop
> over them.
> 
> Dave
> 

Yes, totally agree, already changed to loop-through incompatible caps 
array. Names are easy to lookup, found it.

Andrey

>>>> +    }
>>>> +
>>>>       return true;
>>>>   }
>>>>   
>>>> @@ -2490,6 +2576,15 @@ bool migrate_use_block_incremental(void)
>>>>       return s->parameters.block_incremental;
>>>>   }
>>>>   
>>>> +bool migrate_track_writes_ram(void)
>>>> +{
>>>> +    MigrationState *s;
>>>> +
>>>> +    s = migrate_get_current();
>>>> +
>>>> +    return s->enabled_capabilities[MIGRATION_CAPABILITY_TRACK_WRITES_RAM];
>>>> +}
>>>> +
>>>>   /* migration thread support */
>>>>   /*
>>>>    * Something bad happened to the RP stream, mark an error
>>>> @@ -3783,6 +3878,7 @@ static Property migration_properties[] = {
>>>>       DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
>>>>       DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
>>>>       DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
>>>> +    DEFINE_PROP_MIG_CAP("x-track-writes-ram", MIGRATION_CAPABILITY_TRACK_WRITES_RAM),
>>>>   
>>>>       DEFINE_PROP_END_OF_LIST(),
>>>>   };
>>>> diff --git a/migration/migration.h b/migration/migration.h
>>>> index d096b77f74..339ae720e0 100644
>>>> --- a/migration/migration.h
>>>> +++ b/migration/migration.h
>>>> @@ -341,6 +341,7 @@ int migrate_compress_wait_thread(void);
>>>>   int migrate_decompress_threads(void);
>>>>   bool migrate_use_events(void);
>>>>   bool migrate_postcopy_blocktime(void);
>>>> +bool migrate_track_writes_ram(void);
>>>>   
>>>>   /* Sending on the return path - generic and then for each message type */
>>>>   void migrate_send_rp_shut(MigrationIncomingState *mis,
>>>> diff --git a/qapi/migration.json b/qapi/migration.json
>>>> index 3c75820527..a28d8b7ee8 100644
>>>> --- a/qapi/migration.json
>>>> +++ b/qapi/migration.json
>>>> @@ -442,6 +442,11 @@
>>>>   # @validate-uuid: Send the UUID of the source to allow the destination
>>>>   #                 to ensure it is the same. (since 4.2)
>>>>   #
>>>> +# @track-writes-ram: If enabled, the migration stream will be a snapshot
>>>> +#                    of the VM exactly at the point when the migration
>>>> +#                    procedure starts. The VM RAM is saved with running VM.
>>>> +#                    (since 6.0)
>>>> +#
>>>
>>> The name is slightly confusing to me.  Could I ask why changed from previous
>>> one?  "snapshot" sounds a very necessary keyword to me here and tells exactly
>>> on what we do...  Because we can do quite a few things with "trace-writes-ram"
>>> but not snapshotting, e.g., to calculate per-vm dirty rates.
>>>
>>> -- 
>>> Peter Xu
>>
>> -- 
>> Peter Xu
>>
diff mbox series

Patch

diff --git a/migration/migration.c b/migration/migration.c
index 87a9b59f83..ff0364dde0 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -56,6 +56,7 @@ 
 #include "net/announce.h"
 #include "qemu/queue.h"
 #include "multifd.h"
+#include "sysemu/cpus.h"
 
 #ifdef CONFIG_VFIO
 #include "hw/vfio/vfio-common.h"
@@ -1165,6 +1166,91 @@  static bool migrate_caps_check(bool *cap_list,
         }
     }
 
+    if (cap_list[MIGRATION_CAPABILITY_TRACK_WRITES_RAM]) {
+        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with postcopy-ram");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_DIRTY_BITMAPS]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with dirty-bitmaps");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with postcopy-blocktime");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with late-block-activate");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_RETURN_PATH]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with return-path");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_MULTIFD]) {
+            error_setg(errp, "Track-writes is not compatible with multifd");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with pause-before-switchover");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_AUTO_CONVERGE]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with auto-converge");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_RELEASE_RAM]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with release-ram");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_RDMA_PIN_ALL]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with rdma-pin-all");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with compression");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_XBZRLE]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with XBZLRE");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_X_COLO]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with x-colo");
+            return false;
+        }
+
+        if (cap_list[MIGRATION_CAPABILITY_VALIDATE_UUID]) {
+            error_setg(errp,
+                    "Track-writes is not compatible with validate-uuid");
+            return false;
+        }
+    }
+
     return true;
 }
 
@@ -2490,6 +2576,15 @@  bool migrate_use_block_incremental(void)
     return s->parameters.block_incremental;
 }
 
+bool migrate_track_writes_ram(void)
+{
+    MigrationState *s;
+
+    s = migrate_get_current();
+
+    return s->enabled_capabilities[MIGRATION_CAPABILITY_TRACK_WRITES_RAM];
+}
+
 /* migration thread support */
 /*
  * Something bad happened to the RP stream, mark an error
@@ -3783,6 +3878,7 @@  static Property migration_properties[] = {
     DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
     DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
     DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
+    DEFINE_PROP_MIG_CAP("x-track-writes-ram", MIGRATION_CAPABILITY_TRACK_WRITES_RAM),
 
     DEFINE_PROP_END_OF_LIST(),
 };
diff --git a/migration/migration.h b/migration/migration.h
index d096b77f74..339ae720e0 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -341,6 +341,7 @@  int migrate_compress_wait_thread(void);
 int migrate_decompress_threads(void);
 bool migrate_use_events(void);
 bool migrate_postcopy_blocktime(void);
+bool migrate_track_writes_ram(void);
 
 /* Sending on the return path - generic and then for each message type */
 void migrate_send_rp_shut(MigrationIncomingState *mis,
diff --git a/qapi/migration.json b/qapi/migration.json
index 3c75820527..a28d8b7ee8 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -442,6 +442,11 @@ 
 # @validate-uuid: Send the UUID of the source to allow the destination
 #                 to ensure it is the same. (since 4.2)
 #
+# @track-writes-ram: If enabled, the migration stream will be a snapshot
+#                    of the VM exactly at the point when the migration
+#                    procedure starts. The VM RAM is saved with running VM.
+#                    (since 6.0)
+#
 # Since: 1.2
 ##
 { 'enum': 'MigrationCapability',
@@ -449,7 +454,7 @@ 
            'compress', 'events', 'postcopy-ram', 'x-colo', 'release-ram',
            'block', 'return-path', 'pause-before-switchover', 'multifd',
            'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate',
-           'x-ignore-shared', 'validate-uuid' ] }
+           'x-ignore-shared', 'validate-uuid', 'track-writes-ram'] }
 
 ##
 # @MigrationCapabilityStatus: