diff mbox series

[2/2] migration: dirty-bitmap: Allow control of bitmap persistence on destination

Message ID 3afd4b353cf75c01c9260ca65e073d897e8c42d2.1612356810.git.pkrempa@redhat.com (mailing list archive)
State New, archived
Headers show
Series migration: dirty-bitmap: Allow control of bitmap persistence on destination | expand

Commit Message

Peter Krempa Feb. 3, 2021, 1 p.m. UTC
Bitmap's source persistence is transported over the migration stream and
the destination mirrors it. In some cases the destination might want to
persist bitmaps which are not persistent on the source (e.g. the result
of merge of bitmaps from a number of layers on the source when migrating
into a squashed image) but currently it would need to create another set
of persistent bitmaps and merge them.

This adds 'dest-persistent' optional property to
'BitmapMigrationBitmapAlias' which when present overrides the bitmap
presence state from the source.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 migration/block-dirty-bitmap.c | 30 +++++++++++++++++++++++++++++-
 qapi/migration.json            |  7 ++++++-
 2 files changed, 35 insertions(+), 2 deletions(-)

Comments

Vladimir Sementsov-Ogievskiy Feb. 3, 2021, 1:23 p.m. UTC | #1
03.02.2021 16:00, Peter Krempa wrote:
> Bitmap's source persistence is transported over the migration stream and
> the destination mirrors it. In some cases the destination might want to
> persist bitmaps which are not persistent on the source (e.g. the result
> of merge of bitmaps from a number of layers on the source when migrating
> into a squashed image)

Why not make merge target on source be persistent itself? Then it will be persistent on migration destination.

> but currently it would need to create another set
> of persistent bitmaps and merge them.
> 
> This adds 'dest-persistent' optional property to
> 'BitmapMigrationBitmapAlias' which when present overrides the bitmap
> presence state from the source.

It's seems simpler to make a separate qmp command block-dirty-bitmap-make-persistent.. Didn't you consider this way?
Peter Krempa Feb. 3, 2021, 1:27 p.m. UTC | #2
On Wed, Feb 03, 2021 at 16:23:21 +0300, Vladimir Sementsov-Ogievskiy wrote:
> 03.02.2021 16:00, Peter Krempa wrote:
> > Bitmap's source persistence is transported over the migration stream and
> > the destination mirrors it. In some cases the destination might want to
> > persist bitmaps which are not persistent on the source (e.g. the result
> > of merge of bitmaps from a number of layers on the source when migrating
> > into a squashed image)
> 
> Why not make merge target on source be persistent itself? Then it will be persistent on migration destination.

Because they are temporary on the source. I don't want to make it
persistent in case of a failure so that it doesn't get written to the
disk e.g. in case of VM shutdown.

> 
> > but currently it would need to create another set
> > of persistent bitmaps and merge them.
> > 
> > This adds 'dest-persistent' optional property to
> > 'BitmapMigrationBitmapAlias' which when present overrides the bitmap
> > presence state from the source.
> 
> It's seems simpler to make a separate qmp command block-dirty-bitmap-make-persistent.. Didn't you consider this way?

I'm not sure how the internals work entirely. In my case it's way
simpler to do this setup when generating the mapping which I need to do
anyways rather than calling separate commands.
Peter Krempa Feb. 3, 2021, 1:39 p.m. UTC | #3
On Wed, Feb 03, 2021 at 14:27:49 +0100, Peter Krempa wrote:
> On Wed, Feb 03, 2021 at 16:23:21 +0300, Vladimir Sementsov-Ogievskiy wrote:
> > 03.02.2021 16:00, Peter Krempa wrote:
> > > Bitmap's source persistence is transported over the migration stream and
> > > the destination mirrors it. In some cases the destination might want to
> > > persist bitmaps which are not persistent on the source (e.g. the result
> > > of merge of bitmaps from a number of layers on the source when migrating
> > > into a squashed image)
> > 
> > Why not make merge target on source be persistent itself? Then it will be persistent on migration destination.
> 
> Because they are temporary on the source. I don't want to make it
> persistent in case of a failure so that it doesn't get written to the
> disk e.g. in case of VM shutdown.

To be a bit more specific, I don't want the bitmaps to stay in the
image, that means that I'd have to also delete them on the source after
a successfull migration before qemu is terminated, which might not even
be possible since source deactivates storage after migration.

So making them persistent on source is impossible.

> 
> > 
> > > but currently it would need to create another set
> > > of persistent bitmaps and merge them.
> > > 
> > > This adds 'dest-persistent' optional property to
> > > 'BitmapMigrationBitmapAlias' which when present overrides the bitmap
> > > presence state from the source.
> > 
> > It's seems simpler to make a separate qmp command block-dirty-bitmap-make-persistent.. Didn't you consider this way?
> 
> I'm not sure how the internals work entirely. In my case it's way
> simpler to do this setup when generating the mapping which I need to do
> anyways rather than calling separate commands.

Similarly here, after a successful migration I'd have to go and make all
the bitmaps persistent, which is an extra step, and also a vector for
possible failures after migration which also doesn't seem appealing.
Vladimir Sementsov-Ogievskiy Feb. 3, 2021, 2:14 p.m. UTC | #4
03.02.2021 16:39, Peter Krempa wrote:
> On Wed, Feb 03, 2021 at 14:27:49 +0100, Peter Krempa wrote:
>> On Wed, Feb 03, 2021 at 16:23:21 +0300, Vladimir Sementsov-Ogievskiy wrote:
>>> 03.02.2021 16:00, Peter Krempa wrote:
>>>> Bitmap's source persistence is transported over the migration stream and
>>>> the destination mirrors it. In some cases the destination might want to
>>>> persist bitmaps which are not persistent on the source (e.g. the result
>>>> of merge of bitmaps from a number of layers on the source when migrating
>>>> into a squashed image)
>>>
>>> Why not make merge target on source be persistent itself? Then it will be persistent on migration destination.
>>
>> Because they are temporary on the source. I don't want to make it
>> persistent in case of a failure so that it doesn't get written to the
>> disk e.g. in case of VM shutdown.
> 
> To be a bit more specific, I don't want the bitmaps to stay in the
> image, that means that I'd have to also delete them on the source after
> a successfull migration before qemu is terminated, which might not even
> be possible since source deactivates storage after migration.
> 
> So making them persistent on source is impossible.

Actually on success path, persistent bitmaps are not stored on source.

Normally persistent bitmaps are stored on image inactivation. But bitmaps
involved into migration are an exclusion, they are not stored (otherwise,
stoing will influence downtime of migration). And of-course, we can't
store bitmaps after disks inactivation.

So, on success path, the only way to store bitmaps on source is to do
qmp 'cont' command on source after migration..

I'm not so sure about error path. Of course, if something breaks between
merge target creation and migration start, bitmaps will be stored.

So, I agree that in general it's bad idea to make temporary bitmap 'persistent'.

> 
>>
>>>
>>>> but currently it would need to create another set
>>>> of persistent bitmaps and merge them.
>>>>
>>>> This adds 'dest-persistent' optional property to
>>>> 'BitmapMigrationBitmapAlias' which when present overrides the bitmap
>>>> presence state from the source.
>>>
>>> It's seems simpler to make a separate qmp command block-dirty-bitmap-make-persistent.. Didn't you consider this way?
>>
>> I'm not sure how the internals work entirely. In my case it's way
>> simpler to do this setup when generating the mapping which I need to do
>> anyways rather than calling separate commands.
> 
> Similarly here, after a successful migration I'd have to go and make all
> the bitmaps persistent, which is an extra step, and also a vector for
> possible failures after migration which also doesn't seem appealing.
> 

OK, that's reasonable, thanks for explanation
Eric Blake Feb. 4, 2021, 7:15 p.m. UTC | #5
On 2/3/21 7:00 AM, Peter Krempa wrote:
> Bitmap's source persistence is transported over the migration stream and
> the destination mirrors it. In some cases the destination might want to
> persist bitmaps which are not persistent on the source (e.g. the result
> of merge of bitmaps from a number of layers on the source when migrating
> into a squashed image) but currently it would need to create another set
> of persistent bitmaps and merge them.
> 
> This adds 'dest-persistent' optional property to
> 'BitmapMigrationBitmapAlias' which when present overrides the bitmap
> presence state from the source.

persistance

> 
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---
>  migration/block-dirty-bitmap.c | 30 +++++++++++++++++++++++++++++-
>  qapi/migration.json            |  7 ++++++-
>  2 files changed, 35 insertions(+), 2 deletions(-)
> 

> +++ b/qapi/migration.json
> @@ -533,12 +533,17 @@
>  # @alias: An alias name for migration (for example the bitmap name on
>  #         the opposite site).
>  #
> +# @dest-persistent: If populated set the bitmap will be turned persistent
> +#                   or transient depending on this parameter.

s/populated set/present,/

> +#                   (since 6.0)
> +#
>  # Since: 5.2
>  ##
>  { 'struct': 'BitmapMigrationBitmapAlias',
>    'data': {
>        'name': 'str',
> -      'alias': 'str'
> +      'alias': 'str',
> +      '*dest-persistent': 'bool'
>    } }
> 
>  ##
> 

The grammar fix is trivial, so
Reviewed-by: Eric Blake <eblake@redhat.com>

I see there is discussion over whether this is the best approach, but it
makes sense to me.  Unless there's a good reason why something else
would be better, I'm probably going to queue this through my dirty
bitmaps tree for a pull request sometime next week.
Vladimir Sementsov-Ogievskiy Feb. 5, 2021, 8:01 a.m. UTC | #6
03.02.2021 16:00, Peter Krempa wrote:
> Bitmap's source persistence is transported over the migration stream and
> the destination mirrors it. In some cases the destination might want to
> persist bitmaps which are not persistent on the source (e.g. the result
> of merge of bitmaps from a number of layers on the source when migrating
> into a squashed image) but currently it would need to create another set
> of persistent bitmaps and merge them.
> 
> This adds 'dest-persistent' optional property to
> 'BitmapMigrationBitmapAlias' which when present overrides the bitmap
> presence state from the source.
> 
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---
>   migration/block-dirty-bitmap.c | 30 +++++++++++++++++++++++++++++-
>   qapi/migration.json            |  7 ++++++-
>   2 files changed, 35 insertions(+), 2 deletions(-)
> 
> diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
> index b0403dd00c..1876c94c45 100644
> --- a/migration/block-dirty-bitmap.c
> +++ b/migration/block-dirty-bitmap.c
> @@ -149,6 +149,9 @@ typedef struct DBMLoadState {
> 
>       bool before_vm_start_handled; /* set in dirty_bitmap_mig_before_vm_start */
> 
> +    bool has_dest_persistent;
> +    bool dest_persistent;
> +
>       /*
>        * cancelled
>        * Incoming migration is cancelled for some reason. That means that we
> @@ -171,6 +174,10 @@ static DBMState dbm_state;
> 
>   typedef struct AliasMapInnerBitmap {
>       char *string;
> +
> +    /* for destination's properties setting bitmap state */
> +    bool has_dest_persistent;
> +    bool dest_persistent;
>   } AliasMapInnerBitmap;
> 
>   static void free_alias_map_inner_bitmap(void *amin_ptr)
> @@ -289,6 +296,8 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm,
>           for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) {
>               const BitmapMigrationBitmapAlias *bmba = bmbal->value;
>               const char *bmap_map_from, *bmap_map_to;
> +            bool bmap_has_dest_persistent = false;
> +            bool bmap_dest_persistent = false;
>               AliasMapInnerBitmap *bmap_inner;
> 
>               if (strlen(bmba->alias) > UINT8_MAX) {
> @@ -317,6 +326,9 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm,
>                   bmap_map_from = bmba->alias;
>                   bmap_map_to = bmba->name;
> 
> +                bmap_has_dest_persistent = bmba->has_dest_persistent;
> +                bmap_dest_persistent = bmba->dest_persistent;
> +
>                   if (g_hash_table_contains(bitmaps_map, bmba->alias)) {
>                       error_setg(errp, "The bitmap alias '%s'/'%s' is used twice",
>                                  bmna->alias, bmba->alias);
> @@ -326,6 +338,8 @@ static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm,
> 
>               bmap_inner = g_new0(AliasMapInnerBitmap, 1);
>               bmap_inner->string = g_strdup(bmap_map_to);
> +            bmap_inner->has_dest_persistent = bmap_has_dest_persistent;
> +            bmap_inner->dest_persistent = bmap_dest_persistent;
> 
>               g_hash_table_insert(bitmaps_map,
>                                   g_strdup(bmap_map_from), bmap_inner);
> @@ -798,6 +812,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s)
>       uint32_t granularity = qemu_get_be32(f);
>       uint8_t flags = qemu_get_byte(f);
>       LoadBitmapState *b;
> +    bool persistent;
> 
>       if (s->cancelled) {
>           return 0;
> @@ -822,7 +837,13 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s)
>           return -EINVAL;
>       }
> 
> -    if (flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT) {
> +    if (s->has_dest_persistent) {
> +        persistent = s->dest_persistent;
> +    } else {
> +        persistent = flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT;
> +    }
> +
> +    if (persistent) {
>           bdrv_dirty_bitmap_set_persistence(s->bitmap, true);
>       }
> 
> @@ -1087,6 +1108,8 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s,
> 
>       if (s->flags & DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME) {
>           const char *bitmap_name;
> +        bool bitmap_has_dest_persistent = false;
> +        bool bitmap_dest_persistent = false;
> 
>           if (!qemu_get_counted_string(f, s->bitmap_alias)) {
>               error_report("Unable to read bitmap alias string");
> @@ -1107,12 +1130,17 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s,
>               }
> 
>               bitmap_name = bmap_inner->string;
> +            bitmap_has_dest_persistent = bmap_inner->has_dest_persistent;
> +            bitmap_dest_persistent = bmap_inner->dest_persistent;
>           }
> 
>           if (!s->cancelled) {
>               g_strlcpy(s->bitmap_name, bitmap_name, sizeof(s->bitmap_name));
>               s->bitmap = bdrv_find_dirty_bitmap(s->bs, s->bitmap_name);
> 
> +            s->has_dest_persistent = bitmap_has_dest_persistent;
> +            s->dest_persistent = bitmap_dest_persistent;
> +
>               /*
>                * bitmap may be NULL here, it wouldn't be an error if it is the
>                * first occurrence of the bitmap
> diff --git a/qapi/migration.json b/qapi/migration.json
> index d1d9632c2a..32e64dbce6 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -533,12 +533,17 @@
>   # @alias: An alias name for migration (for example the bitmap name on
>   #         the opposite site).
>   #
> +# @dest-persistent: If populated set the bitmap will be turned persistent
> +#                   or transient depending on this parameter.
> +#                   (since 6.0)
> +#

Thinking of future: will we want modify other bitmap properties "in-flight"? enabled? maybe granularity? Then we'll add additional dest-* properties. Not bad, but probably better to make it nested, like

transform: { persistent: bool }

So, than we'll can add other properties:

transform: { *persistent: bool, *enable: bool, *granularity: bool }

Also, in code I see you just ignore dest-persistent if it is set on source. I think we should either error-out, or support it. Why not to allow setup property change on source alias-mapping? (and that's why I suggest "transform" which a bit more generic for using both on source and target)


Also, I don't like duplication of AliasMapInnerBitmap in DBMLoadState. Could we instead just add a pointer to bmap_inner, like this:

diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index 1876c94c45..93ae76734e 100644
--- a/migration/block-dirty-bitmap.c
+++ b/migration/block-dirty-bitmap.c
@@ -138,6 +138,14 @@ typedef struct LoadBitmapState {
      bool enabled;
  } LoadBitmapState;
  
+typedef struct AliasMapInnerBitmap {
+    char *string;
+
+    /* for destination's properties setting bitmap state */
+    bool has_dest_persistent;
+    bool dest_persistent;
+} AliasMapInnerBitmap;
+
  /* State of the dirty bitmap migration (DBM) during load process */
  typedef struct DBMLoadState {
      uint32_t flags;
@@ -149,8 +157,7 @@ typedef struct DBMLoadState {
  
      bool before_vm_start_handled; /* set in dirty_bitmap_mig_before_vm_start */
  
-    bool has_dest_persistent;
-    bool dest_persistent;
+    AliasMapInnerBitmap *bmap_inner;
  
      /*
       * cancelled
@@ -172,14 +179,6 @@ typedef struct DBMState {
  
  static DBMState dbm_state;
  
-typedef struct AliasMapInnerBitmap {
-    char *string;
-
-    /* for destination's properties setting bitmap state */
-    bool has_dest_persistent;
-    bool dest_persistent;
-} AliasMapInnerBitmap;
-
  static void free_alias_map_inner_bitmap(void *amin_ptr)
  {
      AliasMapInnerBitmap *amin = amin_ptr;
@@ -837,8 +836,8 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s)
          return -EINVAL;
      }
  
-    if (s->has_dest_persistent) {
-        persistent = s->dest_persistent;
+    if (s->bmap_inner && s->bmap_inner->has_dest_persistent) {
+        persistent = s->bmap_inner->dest_persistent;
      } else {
          persistent = flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT;
      }
@@ -1108,8 +1107,6 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s,
  
      if (s->flags & DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME) {
          const char *bitmap_name;
-        bool bitmap_has_dest_persistent = false;
-        bool bitmap_dest_persistent = false;
  
          if (!qemu_get_counted_string(f, s->bitmap_alias)) {
              error_report("Unable to read bitmap alias string");
@@ -1130,17 +1127,13 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s,
              }
  
              bitmap_name = bmap_inner->string;
-            bitmap_has_dest_persistent = bmap_inner->has_dest_persistent;
-            bitmap_dest_persistent = bmap_inner->dest_persistent;
+            s->bmap_inner = bmap_inner;
          }
  
          if (!s->cancelled) {
              g_strlcpy(s->bitmap_name, bitmap_name, sizeof(s->bitmap_name));
              s->bitmap = bdrv_find_dirty_bitmap(s->bs, s->bitmap_name);
  
-            s->has_dest_persistent = bitmap_has_dest_persistent;
-            s->dest_persistent = bitmap_dest_persistent;
-
              /*
               * bitmap may be NULL here, it wouldn't be an error if it is the
               * first occurrence of the bitmap
diff mbox series

Patch

diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index b0403dd00c..1876c94c45 100644
--- a/migration/block-dirty-bitmap.c
+++ b/migration/block-dirty-bitmap.c
@@ -149,6 +149,9 @@  typedef struct DBMLoadState {

     bool before_vm_start_handled; /* set in dirty_bitmap_mig_before_vm_start */

+    bool has_dest_persistent;
+    bool dest_persistent;
+
     /*
      * cancelled
      * Incoming migration is cancelled for some reason. That means that we
@@ -171,6 +174,10 @@  static DBMState dbm_state;

 typedef struct AliasMapInnerBitmap {
     char *string;
+
+    /* for destination's properties setting bitmap state */
+    bool has_dest_persistent;
+    bool dest_persistent;
 } AliasMapInnerBitmap;

 static void free_alias_map_inner_bitmap(void *amin_ptr)
@@ -289,6 +296,8 @@  static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm,
         for (bmbal = bmna->bitmaps; bmbal; bmbal = bmbal->next) {
             const BitmapMigrationBitmapAlias *bmba = bmbal->value;
             const char *bmap_map_from, *bmap_map_to;
+            bool bmap_has_dest_persistent = false;
+            bool bmap_dest_persistent = false;
             AliasMapInnerBitmap *bmap_inner;

             if (strlen(bmba->alias) > UINT8_MAX) {
@@ -317,6 +326,9 @@  static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm,
                 bmap_map_from = bmba->alias;
                 bmap_map_to = bmba->name;

+                bmap_has_dest_persistent = bmba->has_dest_persistent;
+                bmap_dest_persistent = bmba->dest_persistent;
+
                 if (g_hash_table_contains(bitmaps_map, bmba->alias)) {
                     error_setg(errp, "The bitmap alias '%s'/'%s' is used twice",
                                bmna->alias, bmba->alias);
@@ -326,6 +338,8 @@  static GHashTable *construct_alias_map(const BitmapMigrationNodeAliasList *bbm,

             bmap_inner = g_new0(AliasMapInnerBitmap, 1);
             bmap_inner->string = g_strdup(bmap_map_to);
+            bmap_inner->has_dest_persistent = bmap_has_dest_persistent;
+            bmap_inner->dest_persistent = bmap_dest_persistent;

             g_hash_table_insert(bitmaps_map,
                                 g_strdup(bmap_map_from), bmap_inner);
@@ -798,6 +812,7 @@  static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s)
     uint32_t granularity = qemu_get_be32(f);
     uint8_t flags = qemu_get_byte(f);
     LoadBitmapState *b;
+    bool persistent;

     if (s->cancelled) {
         return 0;
@@ -822,7 +837,13 @@  static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s)
         return -EINVAL;
     }

-    if (flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT) {
+    if (s->has_dest_persistent) {
+        persistent = s->dest_persistent;
+    } else {
+        persistent = flags & DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT;
+    }
+
+    if (persistent) {
         bdrv_dirty_bitmap_set_persistence(s->bitmap, true);
     }

@@ -1087,6 +1108,8 @@  static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s,

     if (s->flags & DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME) {
         const char *bitmap_name;
+        bool bitmap_has_dest_persistent = false;
+        bool bitmap_dest_persistent = false;

         if (!qemu_get_counted_string(f, s->bitmap_alias)) {
             error_report("Unable to read bitmap alias string");
@@ -1107,12 +1130,17 @@  static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s,
             }

             bitmap_name = bmap_inner->string;
+            bitmap_has_dest_persistent = bmap_inner->has_dest_persistent;
+            bitmap_dest_persistent = bmap_inner->dest_persistent;
         }

         if (!s->cancelled) {
             g_strlcpy(s->bitmap_name, bitmap_name, sizeof(s->bitmap_name));
             s->bitmap = bdrv_find_dirty_bitmap(s->bs, s->bitmap_name);

+            s->has_dest_persistent = bitmap_has_dest_persistent;
+            s->dest_persistent = bitmap_dest_persistent;
+
             /*
              * bitmap may be NULL here, it wouldn't be an error if it is the
              * first occurrence of the bitmap
diff --git a/qapi/migration.json b/qapi/migration.json
index d1d9632c2a..32e64dbce6 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -533,12 +533,17 @@ 
 # @alias: An alias name for migration (for example the bitmap name on
 #         the opposite site).
 #
+# @dest-persistent: If populated set the bitmap will be turned persistent
+#                   or transient depending on this parameter.
+#                   (since 6.0)
+#
 # Since: 5.2
 ##
 { 'struct': 'BitmapMigrationBitmapAlias',
   'data': {
       'name': 'str',
-      'alias': 'str'
+      'alias': 'str',
+      '*dest-persistent': 'bool'
   } }

 ##