diff mbox series

RFC: mark non-volatile memory region

Message ID 20180920151730.30381-1-marcandre.lureau@redhat.com
State New
Headers show
Series RFC: mark non-volatile memory region | expand

Commit Message

Marc-André Lureau Sept. 20, 2018, 3:17 p.m. UTC
This is RFC patch to show how NVDIMM could set a flag on the
MemoryRegion that would be propagated down to the flat view.

This way, guest_phys_blocks_region_add() can skip the NV memory
regions for dumps and TCG memory clear.

qemu-system-x86_64 -machine pc,nvdimm -m 2G,slots=4,maxmem=16G -enable-kvm -monitor stdio -object memory-backend-file,id=mem1,share=on,mem-path=/tmp/foo,size=1G -device nvdimm,id=nvdimm1,memdev=mem1

HMP info mtree command reflects the flag with "nv-" prefix on memory type:

(qemu) info mtree
0000000100000000-000000013fffffff (prio 0, nv-i/o): alias nvdimm-memory @/objects/mem1 0000000000000000-000000003fffffff

(qemu) info mtree -f
0000000100000000-000000013fffffff (prio 0, nv-ram): /objects/mem1

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/exec/memory.h    | 25 +++++++++++++++++++++++
 hw/mem/nvdimm.c          |  1 +
 memory.c                 | 43 ++++++++++++++++++++++++++++++----------
 memory_mapping.c         |  3 ++-
 docs/devel/migration.rst |  1 +
 5 files changed, 62 insertions(+), 11 deletions(-)

Comments

Michael S. Tsirkin Sept. 20, 2018, 4:26 p.m. UTC | #1
On Thu, Sep 20, 2018 at 07:17:30PM +0400, Marc-André Lureau wrote:
> This is RFC patch to show how NVDIMM could set a flag on the
> MemoryRegion that would be propagated down to the flat view.
> 
> This way, guest_phys_blocks_region_add() can skip the NV memory
> regions for dumps and TCG memory clear.
> 
> qemu-system-x86_64 -machine pc,nvdimm -m 2G,slots=4,maxmem=16G -enable-kvm -monitor stdio -object memory-backend-file,id=mem1,share=on,mem-path=/tmp/foo,size=1G -device nvdimm,id=nvdimm1,memdev=mem1
> 
> HMP info mtree command reflects the flag with "nv-" prefix on memory type:
> 
> (qemu) info mtree
> 0000000100000000-000000013fffffff (prio 0, nv-i/o): alias nvdimm-memory @/objects/mem1 0000000000000000-000000003fffffff
> 
> (qemu) info mtree -f
> 0000000100000000-000000013fffffff (prio 0, nv-ram): /objects/mem1
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

I would do s/nv/nonvolatile/ besides that looks good to me.

> ---
>  include/exec/memory.h    | 25 +++++++++++++++++++++++
>  hw/mem/nvdimm.c          |  1 +
>  memory.c                 | 43 ++++++++++++++++++++++++++++++----------
>  memory_mapping.c         |  3 ++-
>  docs/devel/migration.rst |  1 +
>  5 files changed, 62 insertions(+), 11 deletions(-)
> 
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index eb4f2fb249..b334331d3e 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -360,6 +360,7 @@ struct MemoryRegion {
>      bool ram;
>      bool subpage;
>      bool readonly; /* For RAM regions */
> +    bool nv; /* For non-volatile regions */
>      bool rom_device;
>      bool flush_coalesced_mmio;
>      bool global_locking;
> @@ -485,6 +486,7 @@ static inline FlatView *address_space_to_flatview(AddressSpace *as)
>   * @offset_within_address_space: the address of the first byte of the section
>   *     relative to the region's address space
>   * @readonly: writes to this section are ignored
> + * @nv: this section is non-volatile
>   */
>  struct MemoryRegionSection {
>      MemoryRegion *mr;
> @@ -493,6 +495,7 @@ struct MemoryRegionSection {
>      Int128 size;
>      hwaddr offset_within_address_space;
>      bool readonly;
> +    bool nv;
>  };
>  
>  /**
> @@ -1175,6 +1178,17 @@ static inline bool memory_region_is_rom(MemoryRegion *mr)
>      return mr->ram && mr->readonly;
>  }
>  
> +/**
> + * memory_region_is_nv: check whether a memory region is non-volatile
> + *
> + * Returns %true is a memory region is non-volatile memory.
> + *
> + * @mr: the memory region being queried
> + */
> +static inline bool memory_region_is_nv(MemoryRegion *mr)
> +{
> +    return mr->nv;
> +}
>  
>  /**
>   * memory_region_get_fd: Get a file descriptor backing a RAM memory region.
> @@ -1346,6 +1360,17 @@ void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr,
>   */
>  void memory_region_set_readonly(MemoryRegion *mr, bool readonly);
>  
> +/**
> + * memory_region_set_nv: Turn a memory region non-volatile
> + *
> + * Allows a memory region to be marked as non-volatile.
> + * only useful on RAM regions.
> + *
> + * @mr: the region being updated.
> + * @nv: whether rhe region is to be NV.
> + */
> +void memory_region_set_nv(MemoryRegion *mr, bool nv);
> +
>  /**
>   * memory_region_rom_device_set_romd: enable/disable ROMD mode
>   *
> diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
> index 1c6674c4ed..016a9fbbb4 100644
> --- a/hw/mem/nvdimm.c
> +++ b/hw/mem/nvdimm.c
> @@ -115,6 +115,7 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp)
>      nvdimm->nvdimm_mr = g_new(MemoryRegion, 1);
>      memory_region_init_alias(nvdimm->nvdimm_mr, OBJECT(dimm),
>                               "nvdimm-memory", mr, 0, pmem_size);
> +    memory_region_set_nv(nvdimm->nvdimm_mr, true);
>      nvdimm->nvdimm_mr->align = align;
>  }
>  
> diff --git a/memory.c b/memory.c
> index 9b73892768..8b34a1a077 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -216,6 +216,7 @@ struct FlatRange {
>      uint8_t dirty_log_mask;
>      bool romd_mode;
>      bool readonly;
> +    bool nv;
>  };
>  
>  #define FOR_EACH_FLAT_RANGE(var, view)          \
> @@ -231,6 +232,7 @@ section_from_flat_range(FlatRange *fr, FlatView *fv)
>          .size = fr->addr.size,
>          .offset_within_address_space = int128_get64(fr->addr.start),
>          .readonly = fr->readonly,
> +        .nv = fr->nv,
>      };
>  }
>  
> @@ -240,7 +242,8 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b)
>          && addrrange_equal(a->addr, b->addr)
>          && a->offset_in_region == b->offset_in_region
>          && a->romd_mode == b->romd_mode
> -        && a->readonly == b->readonly;
> +        && a->readonly == b->readonly
> +        && a->nv == b->nv;
>  }
>  
>  static FlatView *flatview_new(MemoryRegion *mr_root)
> @@ -312,7 +315,8 @@ static bool can_merge(FlatRange *r1, FlatRange *r2)
>                       int128_make64(r2->offset_in_region))
>          && r1->dirty_log_mask == r2->dirty_log_mask
>          && r1->romd_mode == r2->romd_mode
> -        && r1->readonly == r2->readonly;
> +        && r1->readonly == r2->readonly
> +        && r1->nv == r2->nv;
>  }
>  
>  /* Attempt to simplify a view by merging adjacent ranges */
> @@ -619,7 +623,8 @@ static void render_memory_region(FlatView *view,
>                                   MemoryRegion *mr,
>                                   Int128 base,
>                                   AddrRange clip,
> -                                 bool readonly)
> +                                 bool readonly,
> +                                 bool nv)
>  {
>      MemoryRegion *subregion;
>      unsigned i;
> @@ -635,6 +640,7 @@ static void render_memory_region(FlatView *view,
>  
>      int128_addto(&base, int128_make64(mr->addr));
>      readonly |= mr->readonly;
> +    nv |= mr->nv;
>  
>      tmp = addrrange_make(base, mr->size);
>  
> @@ -647,13 +653,13 @@ static void render_memory_region(FlatView *view,
>      if (mr->alias) {
>          int128_subfrom(&base, int128_make64(mr->alias->addr));
>          int128_subfrom(&base, int128_make64(mr->alias_offset));
> -        render_memory_region(view, mr->alias, base, clip, readonly);
> +        render_memory_region(view, mr->alias, base, clip, readonly, nv);
>          return;
>      }
>  
>      /* Render subregions in priority order. */
>      QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
> -        render_memory_region(view, subregion, base, clip, readonly);
> +        render_memory_region(view, subregion, base, clip, readonly, nv);
>      }
>  
>      if (!mr->terminates) {
> @@ -668,6 +674,7 @@ static void render_memory_region(FlatView *view,
>      fr.dirty_log_mask = memory_region_get_dirty_log_mask(mr);
>      fr.romd_mode = mr->romd_mode;
>      fr.readonly = readonly;
> +    fr.nv = nv;
>  
>      /* Render the region itself into any gaps left by the current view. */
>      for (i = 0; i < view->nr && int128_nz(remain); ++i) {
> @@ -753,7 +760,8 @@ static FlatView *generate_memory_topology(MemoryRegion *mr)
>  
>      if (mr) {
>          render_memory_region(view, mr, int128_zero(),
> -                             addrrange_make(int128_zero(), int128_2_64()), false);
> +                             addrrange_make(int128_zero(), int128_2_64()),
> +                             false, false);
>      }
>      flatview_simplify(view);
>  
> @@ -2038,6 +2046,16 @@ void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
>      }
>  }
>  
> +void memory_region_set_nv(MemoryRegion *mr, bool nv)
> +{
> +    if (mr->nv != nv) {
> +        memory_region_transaction_begin();
> +        mr->nv = nv;
> +        memory_region_update_pending |= mr->enabled;
> +        memory_region_transaction_commit();
> +    }
> +}
> +
>  void memory_region_rom_device_set_romd(MemoryRegion *mr, bool romd_mode)
>  {
>      if (mr->romd_mode != romd_mode) {
> @@ -2488,6 +2506,7 @@ static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr,
>      ret.size = range.size;
>      ret.offset_within_address_space = int128_get64(range.start);
>      ret.readonly = fr->readonly;
> +    ret.nv = fr->nv;
>      return ret;
>  }
>  
> @@ -2838,10 +2857,11 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
>              QTAILQ_INSERT_TAIL(alias_print_queue, ml, mrqueue);
>          }
>          mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx
> -                   " (prio %d, %s): alias %s @%s " TARGET_FMT_plx
> +                   " (prio %d, %s%s): alias %s @%s " TARGET_FMT_plx
>                     "-" TARGET_FMT_plx "%s",
>                     cur_start, cur_end,
>                     mr->priority,
> +                   mr->nv ? "nv-" : "",
>                     memory_region_type((MemoryRegion *)mr),
>                     memory_region_name(mr),
>                     memory_region_name(mr->alias),
> @@ -2853,9 +2873,10 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
>          }
>      } else {
>          mon_printf(f,
> -                   TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): %s%s",
> +                   TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s%s): %s%s",
>                     cur_start, cur_end,
>                     mr->priority,
> +                   mr->nv ? "nv-" : "",
>                     memory_region_type((MemoryRegion *)mr),
>                     memory_region_name(mr),
>                     mr->enabled ? "" : " [disabled]");
> @@ -2940,19 +2961,21 @@ static void mtree_print_flatview(gpointer key, gpointer value,
>          mr = range->mr;
>          if (range->offset_in_region) {
>              p(f, MTREE_INDENT TARGET_FMT_plx "-"
> -              TARGET_FMT_plx " (prio %d, %s): %s @" TARGET_FMT_plx,
> +              TARGET_FMT_plx " (prio %d, %s%s): %s @" TARGET_FMT_plx,
>                int128_get64(range->addr.start),
>                int128_get64(range->addr.start) + MR_SIZE(range->addr.size),
>                mr->priority,
> +              range->nv ? "nv-" : "",
>                range->readonly ? "rom" : memory_region_type(mr),
>                memory_region_name(mr),
>                range->offset_in_region);
>          } else {
>              p(f, MTREE_INDENT TARGET_FMT_plx "-"
> -              TARGET_FMT_plx " (prio %d, %s): %s",
> +              TARGET_FMT_plx " (prio %d, %s%s): %s",
>                int128_get64(range->addr.start),
>                int128_get64(range->addr.start) + MR_SIZE(range->addr.size),
>                mr->priority,
> +              range->nv ? "nv-" : "",
>                range->readonly ? "rom" : memory_region_type(mr),
>                memory_region_name(mr));
>          }
> diff --git a/memory_mapping.c b/memory_mapping.c
> index 775466f3a8..d59806f53b 100644
> --- a/memory_mapping.c
> +++ b/memory_mapping.c
> @@ -206,7 +206,8 @@ static void guest_phys_blocks_region_add(MemoryListener *listener,
>  
>      /* we only care about RAM */
>      if (!memory_region_is_ram(section->mr) ||
> -        memory_region_is_ram_device(section->mr)) {
> +        memory_region_is_ram_device(section->mr) ||
> +        memory_region_is_nv(section->mr)) {
>          return;
>      }
>  
> diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
> index 687570754d..1a0a39d500 100644
> --- a/docs/devel/migration.rst
> +++ b/docs/devel/migration.rst
> @@ -435,6 +435,7 @@ Examples of such memory API functions are:
>    - memory_region_add_subregion()
>    - memory_region_del_subregion()
>    - memory_region_set_readonly()
> +  - memory_region_set_nv()
>    - memory_region_set_enabled()
>    - memory_region_set_address()
>    - memory_region_set_alias_offset()
> -- 
> 2.19.0
diff mbox series

Patch

diff --git a/include/exec/memory.h b/include/exec/memory.h
index eb4f2fb249..b334331d3e 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -360,6 +360,7 @@  struct MemoryRegion {
     bool ram;
     bool subpage;
     bool readonly; /* For RAM regions */
+    bool nv; /* For non-volatile regions */
     bool rom_device;
     bool flush_coalesced_mmio;
     bool global_locking;
@@ -485,6 +486,7 @@  static inline FlatView *address_space_to_flatview(AddressSpace *as)
  * @offset_within_address_space: the address of the first byte of the section
  *     relative to the region's address space
  * @readonly: writes to this section are ignored
+ * @nv: this section is non-volatile
  */
 struct MemoryRegionSection {
     MemoryRegion *mr;
@@ -493,6 +495,7 @@  struct MemoryRegionSection {
     Int128 size;
     hwaddr offset_within_address_space;
     bool readonly;
+    bool nv;
 };
 
 /**
@@ -1175,6 +1178,17 @@  static inline bool memory_region_is_rom(MemoryRegion *mr)
     return mr->ram && mr->readonly;
 }
 
+/**
+ * memory_region_is_nv: check whether a memory region is non-volatile
+ *
+ * Returns %true is a memory region is non-volatile memory.
+ *
+ * @mr: the memory region being queried
+ */
+static inline bool memory_region_is_nv(MemoryRegion *mr)
+{
+    return mr->nv;
+}
 
 /**
  * memory_region_get_fd: Get a file descriptor backing a RAM memory region.
@@ -1346,6 +1360,17 @@  void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr,
  */
 void memory_region_set_readonly(MemoryRegion *mr, bool readonly);
 
+/**
+ * memory_region_set_nv: Turn a memory region non-volatile
+ *
+ * Allows a memory region to be marked as non-volatile.
+ * only useful on RAM regions.
+ *
+ * @mr: the region being updated.
+ * @nv: whether rhe region is to be NV.
+ */
+void memory_region_set_nv(MemoryRegion *mr, bool nv);
+
 /**
  * memory_region_rom_device_set_romd: enable/disable ROMD mode
  *
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 1c6674c4ed..016a9fbbb4 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -115,6 +115,7 @@  static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp)
     nvdimm->nvdimm_mr = g_new(MemoryRegion, 1);
     memory_region_init_alias(nvdimm->nvdimm_mr, OBJECT(dimm),
                              "nvdimm-memory", mr, 0, pmem_size);
+    memory_region_set_nv(nvdimm->nvdimm_mr, true);
     nvdimm->nvdimm_mr->align = align;
 }
 
diff --git a/memory.c b/memory.c
index 9b73892768..8b34a1a077 100644
--- a/memory.c
+++ b/memory.c
@@ -216,6 +216,7 @@  struct FlatRange {
     uint8_t dirty_log_mask;
     bool romd_mode;
     bool readonly;
+    bool nv;
 };
 
 #define FOR_EACH_FLAT_RANGE(var, view)          \
@@ -231,6 +232,7 @@  section_from_flat_range(FlatRange *fr, FlatView *fv)
         .size = fr->addr.size,
         .offset_within_address_space = int128_get64(fr->addr.start),
         .readonly = fr->readonly,
+        .nv = fr->nv,
     };
 }
 
@@ -240,7 +242,8 @@  static bool flatrange_equal(FlatRange *a, FlatRange *b)
         && addrrange_equal(a->addr, b->addr)
         && a->offset_in_region == b->offset_in_region
         && a->romd_mode == b->romd_mode
-        && a->readonly == b->readonly;
+        && a->readonly == b->readonly
+        && a->nv == b->nv;
 }
 
 static FlatView *flatview_new(MemoryRegion *mr_root)
@@ -312,7 +315,8 @@  static bool can_merge(FlatRange *r1, FlatRange *r2)
                      int128_make64(r2->offset_in_region))
         && r1->dirty_log_mask == r2->dirty_log_mask
         && r1->romd_mode == r2->romd_mode
-        && r1->readonly == r2->readonly;
+        && r1->readonly == r2->readonly
+        && r1->nv == r2->nv;
 }
 
 /* Attempt to simplify a view by merging adjacent ranges */
@@ -619,7 +623,8 @@  static void render_memory_region(FlatView *view,
                                  MemoryRegion *mr,
                                  Int128 base,
                                  AddrRange clip,
-                                 bool readonly)
+                                 bool readonly,
+                                 bool nv)
 {
     MemoryRegion *subregion;
     unsigned i;
@@ -635,6 +640,7 @@  static void render_memory_region(FlatView *view,
 
     int128_addto(&base, int128_make64(mr->addr));
     readonly |= mr->readonly;
+    nv |= mr->nv;
 
     tmp = addrrange_make(base, mr->size);
 
@@ -647,13 +653,13 @@  static void render_memory_region(FlatView *view,
     if (mr->alias) {
         int128_subfrom(&base, int128_make64(mr->alias->addr));
         int128_subfrom(&base, int128_make64(mr->alias_offset));
-        render_memory_region(view, mr->alias, base, clip, readonly);
+        render_memory_region(view, mr->alias, base, clip, readonly, nv);
         return;
     }
 
     /* Render subregions in priority order. */
     QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
-        render_memory_region(view, subregion, base, clip, readonly);
+        render_memory_region(view, subregion, base, clip, readonly, nv);
     }
 
     if (!mr->terminates) {
@@ -668,6 +674,7 @@  static void render_memory_region(FlatView *view,
     fr.dirty_log_mask = memory_region_get_dirty_log_mask(mr);
     fr.romd_mode = mr->romd_mode;
     fr.readonly = readonly;
+    fr.nv = nv;
 
     /* Render the region itself into any gaps left by the current view. */
     for (i = 0; i < view->nr && int128_nz(remain); ++i) {
@@ -753,7 +760,8 @@  static FlatView *generate_memory_topology(MemoryRegion *mr)
 
     if (mr) {
         render_memory_region(view, mr, int128_zero(),
-                             addrrange_make(int128_zero(), int128_2_64()), false);
+                             addrrange_make(int128_zero(), int128_2_64()),
+                             false, false);
     }
     flatview_simplify(view);
 
@@ -2038,6 +2046,16 @@  void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
     }
 }
 
+void memory_region_set_nv(MemoryRegion *mr, bool nv)
+{
+    if (mr->nv != nv) {
+        memory_region_transaction_begin();
+        mr->nv = nv;
+        memory_region_update_pending |= mr->enabled;
+        memory_region_transaction_commit();
+    }
+}
+
 void memory_region_rom_device_set_romd(MemoryRegion *mr, bool romd_mode)
 {
     if (mr->romd_mode != romd_mode) {
@@ -2488,6 +2506,7 @@  static MemoryRegionSection memory_region_find_rcu(MemoryRegion *mr,
     ret.size = range.size;
     ret.offset_within_address_space = int128_get64(range.start);
     ret.readonly = fr->readonly;
+    ret.nv = fr->nv;
     return ret;
 }
 
@@ -2838,10 +2857,11 @@  static void mtree_print_mr(fprintf_function mon_printf, void *f,
             QTAILQ_INSERT_TAIL(alias_print_queue, ml, mrqueue);
         }
         mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx
-                   " (prio %d, %s): alias %s @%s " TARGET_FMT_plx
+                   " (prio %d, %s%s): alias %s @%s " TARGET_FMT_plx
                    "-" TARGET_FMT_plx "%s",
                    cur_start, cur_end,
                    mr->priority,
+                   mr->nv ? "nv-" : "",
                    memory_region_type((MemoryRegion *)mr),
                    memory_region_name(mr),
                    memory_region_name(mr->alias),
@@ -2853,9 +2873,10 @@  static void mtree_print_mr(fprintf_function mon_printf, void *f,
         }
     } else {
         mon_printf(f,
-                   TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): %s%s",
+                   TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s%s): %s%s",
                    cur_start, cur_end,
                    mr->priority,
+                   mr->nv ? "nv-" : "",
                    memory_region_type((MemoryRegion *)mr),
                    memory_region_name(mr),
                    mr->enabled ? "" : " [disabled]");
@@ -2940,19 +2961,21 @@  static void mtree_print_flatview(gpointer key, gpointer value,
         mr = range->mr;
         if (range->offset_in_region) {
             p(f, MTREE_INDENT TARGET_FMT_plx "-"
-              TARGET_FMT_plx " (prio %d, %s): %s @" TARGET_FMT_plx,
+              TARGET_FMT_plx " (prio %d, %s%s): %s @" TARGET_FMT_plx,
               int128_get64(range->addr.start),
               int128_get64(range->addr.start) + MR_SIZE(range->addr.size),
               mr->priority,
+              range->nv ? "nv-" : "",
               range->readonly ? "rom" : memory_region_type(mr),
               memory_region_name(mr),
               range->offset_in_region);
         } else {
             p(f, MTREE_INDENT TARGET_FMT_plx "-"
-              TARGET_FMT_plx " (prio %d, %s): %s",
+              TARGET_FMT_plx " (prio %d, %s%s): %s",
               int128_get64(range->addr.start),
               int128_get64(range->addr.start) + MR_SIZE(range->addr.size),
               mr->priority,
+              range->nv ? "nv-" : "",
               range->readonly ? "rom" : memory_region_type(mr),
               memory_region_name(mr));
         }
diff --git a/memory_mapping.c b/memory_mapping.c
index 775466f3a8..d59806f53b 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -206,7 +206,8 @@  static void guest_phys_blocks_region_add(MemoryListener *listener,
 
     /* we only care about RAM */
     if (!memory_region_is_ram(section->mr) ||
-        memory_region_is_ram_device(section->mr)) {
+        memory_region_is_ram_device(section->mr) ||
+        memory_region_is_nv(section->mr)) {
         return;
     }
 
diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index 687570754d..1a0a39d500 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -435,6 +435,7 @@  Examples of such memory API functions are:
   - memory_region_add_subregion()
   - memory_region_del_subregion()
   - memory_region_set_readonly()
+  - memory_region_set_nv()
   - memory_region_set_enabled()
   - memory_region_set_address()
   - memory_region_set_alias_offset()