[PATCH V8 04/39] memory: RAM_ANON flag

Steve Sistare posted 39 patches 3 years, 7 months ago
Maintainers: Stefano Stabellini <sstabellini@kernel.org>, Anthony Perard <anthony.perard@citrix.com>, Paul Durrant <paul@xen.org>, David Hildenbrand <david@redhat.com>, Igor Mammedov <imammedo@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, "Alex Bennée" <alex.bennee@linaro.org>, "Philippe Mathieu-Daudé" <f4bug@amsat.org>, "Dr. David Alan Gilbert" <dgilbert@redhat.com>, "Michael S. Tsirkin" <mst@redhat.com>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, Alex Williamson <alex.williamson@redhat.com>, Steve Sistare <steven.sistare@oracle.com>, Mark Kanda <mark.kanda@oracle.com>, Peter Xu <peterx@redhat.com>, Juan Quintela <quintela@redhat.com>, Markus Armbruster <armbru@redhat.com>, Michael Roth <michael.roth@amd.com>, John Snow <jsnow@redhat.com>, Cleber Rosa <crosa@redhat.com>, Beraldo Leal <bleal@redhat.com>, Eric Blake <eblake@redhat.com>, Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>, Wainer dos Santos Moschetta <wainersm@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>, Stefan Weil <sw@weilnetz.de>
There is a newer version of this series
[PATCH V8 04/39] memory: RAM_ANON flag
Posted by Steve Sistare 3 years, 7 months ago
A memory-backend-ram or a memory-backend-memfd block with the RAM_SHARED
flag set is not migrated when migrate_ignore_shared() is true, but this
is wrong, because it has no named backing store, and its contents will be
lost.  Define a new flag RAM_ANON to distinguish this case.  Cpr will also
test this flag, for similar reasons.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
---
 backends/hostmem-epc.c   |  2 +-
 backends/hostmem-memfd.c |  1 +
 backends/hostmem-ram.c   |  1 +
 include/exec/memory.h    |  3 +++
 include/exec/ram_addr.h  |  1 +
 migration/ram.c          |  3 ++-
 softmmu/physmem.c        | 12 +++++++++---
 7 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c
index 037292d..cb06255 100644
--- a/backends/hostmem-epc.c
+++ b/backends/hostmem-epc.c
@@ -37,7 +37,7 @@ sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
     }
 
     name = object_get_canonical_path(OBJECT(backend));
-    ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED;
+    ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED | MAP_ANON;
     memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
                                    name, backend->size, ram_flags,
                                    fd, 0, errp);
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 3fc85c3..c9d8001 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -55,6 +55,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
     name = host_memory_backend_get_name(backend);
     ram_flags = backend->share ? RAM_SHARED : 0;
     ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+    ram_flags |= RAM_ANON;
     memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
                                    backend->size, ram_flags, fd, 0, errp);
     g_free(name);
diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
index b8e55cd..5e80149 100644
--- a/backends/hostmem-ram.c
+++ b/backends/hostmem-ram.c
@@ -30,6 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
     name = host_memory_backend_get_name(backend);
     ram_flags = backend->share ? RAM_SHARED : 0;
     ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
+    ram_flags |= RAM_ANON;
     memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend), name,
                                            backend->size, ram_flags, errp);
     g_free(name);
diff --git a/include/exec/memory.h b/include/exec/memory.h
index f1c1945..0daddd7 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -203,6 +203,9 @@ typedef struct IOMMUTLBEvent {
 /* RAM that isn't accessible through normal means. */
 #define RAM_PROTECTED (1 << 8)
 
+/* RAM has no name outside the qemu process. */
+#define RAM_ANON (1 << 9)
+
 static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn,
                                        IOMMUNotifierFlag flags,
                                        hwaddr start, hwaddr end,
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index f3e0c78..56188b8 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -94,6 +94,7 @@ static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr,
 }
 
 bool ramblock_is_pmem(RAMBlock *rb);
+bool ramblock_is_anon(RAMBlock *rb);
 
 long qemu_minrampagesize(void);
 long qemu_maxrampagesize(void);
diff --git a/migration/ram.c b/migration/ram.c
index 5f5e37f..5cdb93d 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -164,7 +164,8 @@ out:
 bool ramblock_is_ignored(RAMBlock *block)
 {
     return !qemu_ram_is_migratable(block) ||
-           (migrate_ignore_shared() && qemu_ram_is_shared(block));
+           (migrate_ignore_shared() && qemu_ram_is_shared(block) &&
+            !ramblock_is_anon(block));
 }
 
 #undef RAMBLOCK_FOREACH
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
index 657841e..0f1ce28 100644
--- a/softmmu/physmem.c
+++ b/softmmu/physmem.c
@@ -1975,6 +1975,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
     new_block->offset = find_ram_offset(new_block->max_length);
 
     if (!new_block->host) {
+        new_block->flags |= RAM_ANON;
         if (xen_enabled()) {
             xen_ram_alloc(new_block->offset, new_block->max_length,
                           new_block->mr, &err);
@@ -2059,7 +2060,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
 
     /* Just support these ram flags by now. */
     assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
-                          RAM_PROTECTED)) == 0);
+                          RAM_PROTECTED | RAM_ANON)) == 0);
 
     if (xen_enabled()) {
         error_setg(errp, "-mem-path not supported with Xen");
@@ -2151,7 +2152,7 @@ RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
     Error *local_err = NULL;
 
     assert((ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC |
-                          RAM_NORESERVE)) == 0);
+                          RAM_NORESERVE | RAM_ANON)) == 0);
     assert(!host ^ (ram_flags & RAM_PREALLOC));
 
     size = HOST_PAGE_ALIGN(size);
@@ -2185,7 +2186,7 @@ RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
 RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags,
                          MemoryRegion *mr, Error **errp)
 {
-    assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE)) == 0);
+    assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE | RAM_ANON)) == 0);
     return qemu_ram_alloc_internal(size, size, NULL, NULL, ram_flags, mr, errp);
 }
 
@@ -3664,6 +3665,11 @@ bool ramblock_is_pmem(RAMBlock *rb)
     return rb->flags & RAM_PMEM;
 }
 
+bool ramblock_is_anon(RAMBlock *rb)
+{
+    return rb->flags & RAM_ANON;
+}
+
 static void mtree_print_phys_entries(int start, int end, int skip, int ptr)
 {
     if (start == end - 1) {
-- 
1.8.3.1
Re: [PATCH V8 04/39] memory: RAM_ANON flag
Posted by David Hildenbrand 3 years, 7 months ago
On 15.06.22 16:51, Steve Sistare wrote:
> A memory-backend-ram or a memory-backend-memfd block with the RAM_SHARED
> flag set is not migrated when migrate_ignore_shared() is true, but this
> is wrong, because it has no named backing store, and its contents will be
> lost.  Define a new flag RAM_ANON to distinguish this case.  Cpr will also
> test this flag, for similar reasons.
> 
> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
> ---
>  backends/hostmem-epc.c   |  2 +-
>  backends/hostmem-memfd.c |  1 +
>  backends/hostmem-ram.c   |  1 +
>  include/exec/memory.h    |  3 +++
>  include/exec/ram_addr.h  |  1 +
>  migration/ram.c          |  3 ++-
>  softmmu/physmem.c        | 12 +++++++++---
>  7 files changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c
> index 037292d..cb06255 100644
> --- a/backends/hostmem-epc.c
> +++ b/backends/hostmem-epc.c
> @@ -37,7 +37,7 @@ sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
>      }
>  
>      name = object_get_canonical_path(OBJECT(backend));
> -    ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED;
> +    ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED | MAP_ANON;

I'm pretty sure that doesn't compile. -> RAM_ANON

>      memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
>                                     name, backend->size, ram_flags,
>                                     fd, 0, errp);
> diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
> index 3fc85c3..c9d8001 100644
> --- a/backends/hostmem-memfd.c
> +++ b/backends/hostmem-memfd.c
> @@ -55,6 +55,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
>      name = host_memory_backend_get_name(backend);
>      ram_flags = backend->share ? RAM_SHARED : 0;
>      ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
> +    ram_flags |= RAM_ANON;
>      memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
>                                     backend->size, ram_flags, fd, 0, errp);
>      g_free(name);
> diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
> index b8e55cd..5e80149 100644
> --- a/backends/hostmem-ram.c
> +++ b/backends/hostmem-ram.c
> @@ -30,6 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
>      name = host_memory_backend_get_name(backend);
>      ram_flags = backend->share ? RAM_SHARED : 0;
>      ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
> +    ram_flags |= RAM_ANON;
>      memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend), name,
>                                             backend->size, ram_flags, errp);
>      g_free(name);
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index f1c1945..0daddd7 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -203,6 +203,9 @@ typedef struct IOMMUTLBEvent {
>  /* RAM that isn't accessible through normal means. */
>  #define RAM_PROTECTED (1 << 8)
>  
> +/* RAM has no name outside the qemu process. */
> +#define RAM_ANON (1 << 9)

That name is a bit misleading because it mangles anonymous memory with
an anonymous file, which doesn't provide anonymous memory in "kernel
speak". Please find a better name, some idea below ...

I think what you actual want to know is: is this from a real file,
instead of from an anonymous file or anonymous memory. A real file can
be re-opened and remapped after closing QEMU. Further, you need
MAP_SHARED semantics.


/* RAM maps a real file instead of an anonymous file or no file/fd. */
#define RAM_REAL_FILE (1 << 9)

bool ramblock_maps_real_file(RAMBlock *rb)
{
    return rb->flags & RAM_REAL_FILE;
}


Maybe we can come up with a better name for "real file".


Set the flag from applicable callsites. When setting the flag
internally, assert that we don't have a fd -- that cannot possibly make
sense.

At applicable callsites check for ramblock_maps_real_file() and that
it's actually a shared mapping. If not, it cannot be preserved by
restarting QEMU (easily, there might be ways for memfd involving other
processes).


Make sense?

-- 
Thanks,

David / dhildenb
Re: [PATCH V8 04/39] memory: RAM_ANON flag
Posted by Steven Sistare 3 years, 7 months ago
On 6/15/2022 4:25 PM, David Hildenbrand wrote:
> On 15.06.22 16:51, Steve Sistare wrote:
>> A memory-backend-ram or a memory-backend-memfd block with the RAM_SHARED
>> flag set is not migrated when migrate_ignore_shared() is true, but this
>> is wrong, because it has no named backing store, and its contents will be
>> lost.  Define a new flag RAM_ANON to distinguish this case.  Cpr will also
>> test this flag, for similar reasons.
>>
>> Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
>> ---
>>  backends/hostmem-epc.c   |  2 +-
>>  backends/hostmem-memfd.c |  1 +
>>  backends/hostmem-ram.c   |  1 +
>>  include/exec/memory.h    |  3 +++
>>  include/exec/ram_addr.h  |  1 +
>>  migration/ram.c          |  3 ++-
>>  softmmu/physmem.c        | 12 +++++++++---
>>  7 files changed, 18 insertions(+), 5 deletions(-)
>>
>> diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c
>> index 037292d..cb06255 100644
>> --- a/backends/hostmem-epc.c
>> +++ b/backends/hostmem-epc.c
>> @@ -37,7 +37,7 @@ sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
>>      }
>>  
>>      name = object_get_canonical_path(OBJECT(backend));
>> -    ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED;
>> +    ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED | MAP_ANON;
> 
> I'm pretty sure that doesn't compile. -> RAM_ANON

Oh it does, but not what we want!  Thanks for the catch.

>>      memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
>>                                     name, backend->size, ram_flags,
>>                                     fd, 0, errp);
>> diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
>> index 3fc85c3..c9d8001 100644
>> --- a/backends/hostmem-memfd.c
>> +++ b/backends/hostmem-memfd.c
>> @@ -55,6 +55,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
>>      name = host_memory_backend_get_name(backend);
>>      ram_flags = backend->share ? RAM_SHARED : 0;
>>      ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
>> +    ram_flags |= RAM_ANON;
>>      memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name,
>>                                     backend->size, ram_flags, fd, 0, errp);
>>      g_free(name);
>> diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
>> index b8e55cd..5e80149 100644
>> --- a/backends/hostmem-ram.c
>> +++ b/backends/hostmem-ram.c
>> @@ -30,6 +30,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
>>      name = host_memory_backend_get_name(backend);
>>      ram_flags = backend->share ? RAM_SHARED : 0;
>>      ram_flags |= backend->reserve ? 0 : RAM_NORESERVE;
>> +    ram_flags |= RAM_ANON;
>>      memory_region_init_ram_flags_nomigrate(&backend->mr, OBJECT(backend), name,
>>                                             backend->size, ram_flags, errp);
>>      g_free(name);
>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>> index f1c1945..0daddd7 100644
>> --- a/include/exec/memory.h
>> +++ b/include/exec/memory.h
>> @@ -203,6 +203,9 @@ typedef struct IOMMUTLBEvent {
>>  /* RAM that isn't accessible through normal means. */
>>  #define RAM_PROTECTED (1 << 8)
>>  
>> +/* RAM has no name outside the qemu process. */
>> +#define RAM_ANON (1 << 9)
> 
> That name is a bit misleading because it mangles anonymous memory with
> an anonymous file, which doesn't provide anonymous memory in "kernel
> speak". Please find a better name, some idea below ...
> 
> I think what you actual want to know is: is this from a real file,
> instead of from an anonymous file or anonymous memory. A real file can
> be re-opened and remapped after closing QEMU. Further, you need
> MAP_SHARED semantics.
> 
> 
> /* RAM maps a real file instead of an anonymous file or no file/fd. */
> #define RAM_REAL_FILE (1 << 9)
> 
> bool ramblock_maps_real_file(RAMBlock *rb)
> {
>     return rb->flags & RAM_REAL_FILE;
> }
> 
> 
> Maybe we can come up with a better name for "real file".

Sure.  Ideas:
  RAM_FILE
  RAM_NAMED
  RAM_NAMED_FILE

> Set the flag from applicable callsites. When setting the flag
> internally, assert that we don't have a fd -- that cannot possibly make
> sense.

It will only be set in hostmem-file.c

> At applicable callsites check for ramblock_maps_real_file() and that
> it's actually a shared mapping. If not, it cannot be preserved by
> restarting QEMU (easily, there might be ways for memfd involving other
> processes).

Memfd is allowed for cpr restart by virtue of being shared and having an
fd which can be mapped, which I test for.  See ram_is_volatile in patch 22.
ramblock_is_anon() becomes !ramblock_is_file().

- Steve