Message ID | 20240404122330.92710-10-sgarzare@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | vhost-user: support any POSIX system (tested on macOS, FreeBSD, OpenBSD) | expand |
On 04.04.24 14:23, Stefano Garzarella wrote: > shm_open() creates and opens a new POSIX shared memory object. > A POSIX shared memory object allows creating memory backend with an > associated file descriptor that can be shared with external processes > (e.g. vhost-user). > > The new `memory-backend-shm` can be used as an alternative when > `memory-backend-memfd` is not available (Linux only), since shm_open() > should be provided by any POSIX-compliant operating system. > > This backend mimics memfd, allocating memory that is practically > anonymous. In theory shm_open() requires a name, but this is allocated > for a short time interval and shm_unlink() is called right after > shm_open(). After that, only fd is shared with external processes > (e.g., vhost-user) as if it were associated with anonymous memory. > > In the future we may also allow the user to specify the name to be > passed to shm_open(), but for now we keep the backend simple, mimicking > anonymous memory such as memfd. > > Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> > --- > v3 > - enriched commit message and documentation to highlight that we > want to mimic memfd (David) > --- > docs/system/devices/vhost-user.rst | 5 +- > qapi/qom.json | 17 +++++ > backends/hostmem-shm.c | 118 +++++++++++++++++++++++++++++ > backends/meson.build | 1 + > qemu-options.hx | 11 +++ > 5 files changed, 150 insertions(+), 2 deletions(-) > create mode 100644 backends/hostmem-shm.c > > diff --git a/docs/system/devices/vhost-user.rst b/docs/system/devices/vhost-user.rst > index 9b2da106ce..35259d8ec7 100644 > --- a/docs/system/devices/vhost-user.rst > +++ b/docs/system/devices/vhost-user.rst > @@ -98,8 +98,9 @@ Shared memory object > > In order for the daemon to access the VirtIO queues to process the > requests it needs access to the guest's address space. This is > -achieved via the ``memory-backend-file`` or ``memory-backend-memfd`` > -objects. A reference to a file-descriptor which can access this object > +achieved via the ``memory-backend-file``, ``memory-backend-memfd``, or > +``memory-backend-shm`` objects. > +A reference to a file-descriptor which can access this object > will be passed via the socket as part of the protocol negotiation. > > Currently the shared memory object needs to match the size of the main > diff --git a/qapi/qom.json b/qapi/qom.json > index 85e6b4f84a..5252ec69e3 100644 > --- a/qapi/qom.json > +++ b/qapi/qom.json > @@ -721,6 +721,19 @@ > '*hugetlbsize': 'size', > '*seal': 'bool' } } > > +## > +# @MemoryBackendShmProperties: > +# > +# Properties for memory-backend-shm objects. > +# > +# The @share boolean option is true by default with shm. > +# > +# Since: 9.1 > +## > +{ 'struct': 'MemoryBackendShmProperties', > + 'base': 'MemoryBackendProperties', > + 'data': { } } > + Acked-by: David Hildenbrand <david@redhat.com> One comment: we should maybe just forbid setting share=off. it doesn't make any sense and it can even result in an unexpected double memory consumption. We missed doing that for memfd, unfortunately.
On Thu, Apr 04, 2024 at 04:09:34PM +0200, David Hildenbrand wrote: >On 04.04.24 14:23, Stefano Garzarella wrote: >>shm_open() creates and opens a new POSIX shared memory object. >>A POSIX shared memory object allows creating memory backend with an >>associated file descriptor that can be shared with external processes >>(e.g. vhost-user). >> >>The new `memory-backend-shm` can be used as an alternative when >>`memory-backend-memfd` is not available (Linux only), since shm_open() >>should be provided by any POSIX-compliant operating system. >> >>This backend mimics memfd, allocating memory that is practically >>anonymous. In theory shm_open() requires a name, but this is allocated >>for a short time interval and shm_unlink() is called right after >>shm_open(). After that, only fd is shared with external processes >>(e.g., vhost-user) as if it were associated with anonymous memory. >> >>In the future we may also allow the user to specify the name to be >>passed to shm_open(), but for now we keep the backend simple, mimicking >>anonymous memory such as memfd. >> >>Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> >>--- >>v3 >>- enriched commit message and documentation to highlight that we >> want to mimic memfd (David) >>--- >> docs/system/devices/vhost-user.rst | 5 +- >> qapi/qom.json | 17 +++++ >> backends/hostmem-shm.c | 118 +++++++++++++++++++++++++++++ >> backends/meson.build | 1 + >> qemu-options.hx | 11 +++ >> 5 files changed, 150 insertions(+), 2 deletions(-) >> create mode 100644 backends/hostmem-shm.c >> >>diff --git a/docs/system/devices/vhost-user.rst b/docs/system/devices/vhost-user.rst >>index 9b2da106ce..35259d8ec7 100644 >>--- a/docs/system/devices/vhost-user.rst >>+++ b/docs/system/devices/vhost-user.rst >>@@ -98,8 +98,9 @@ Shared memory object >> In order for the daemon to access the VirtIO queues to process the >> requests it needs access to the guest's address space. This is >>-achieved via the ``memory-backend-file`` or ``memory-backend-memfd`` >>-objects. A reference to a file-descriptor which can access this object >>+achieved via the ``memory-backend-file``, ``memory-backend-memfd``, or >>+``memory-backend-shm`` objects. >>+A reference to a file-descriptor which can access this object >> will be passed via the socket as part of the protocol negotiation. >> Currently the shared memory object needs to match the size of the main >>diff --git a/qapi/qom.json b/qapi/qom.json >>index 85e6b4f84a..5252ec69e3 100644 >>--- a/qapi/qom.json >>+++ b/qapi/qom.json >>@@ -721,6 +721,19 @@ >> '*hugetlbsize': 'size', >> '*seal': 'bool' } } >>+## >>+# @MemoryBackendShmProperties: >>+# >>+# Properties for memory-backend-shm objects. >>+# >>+# The @share boolean option is true by default with shm. >>+# >>+# Since: 9.1 >>+## >>+{ 'struct': 'MemoryBackendShmProperties', >>+ 'base': 'MemoryBackendProperties', >>+ 'data': { } } >>+ > >Acked-by: David Hildenbrand <david@redhat.com> > >One comment: we should maybe just forbid setting share=off. it doesn't >make any sense and it can even result in an unexpected double memory >consumption. We missed doing that for memfd, unfortunately. Good point! IIUC the `share` property is defined by the parent `hostmem`, so I should find a way to override the property here and disable the setter, or add an option to `hostmem` to make the property non-writable. Thanks, Stefano
On 08.04.24 09:58, Stefano Garzarella wrote: > On Thu, Apr 04, 2024 at 04:09:34PM +0200, David Hildenbrand wrote: >> On 04.04.24 14:23, Stefano Garzarella wrote: >>> shm_open() creates and opens a new POSIX shared memory object. >>> A POSIX shared memory object allows creating memory backend with an >>> associated file descriptor that can be shared with external processes >>> (e.g. vhost-user). >>> >>> The new `memory-backend-shm` can be used as an alternative when >>> `memory-backend-memfd` is not available (Linux only), since shm_open() >>> should be provided by any POSIX-compliant operating system. >>> >>> This backend mimics memfd, allocating memory that is practically >>> anonymous. In theory shm_open() requires a name, but this is allocated >>> for a short time interval and shm_unlink() is called right after >>> shm_open(). After that, only fd is shared with external processes >>> (e.g., vhost-user) as if it were associated with anonymous memory. >>> >>> In the future we may also allow the user to specify the name to be >>> passed to shm_open(), but for now we keep the backend simple, mimicking >>> anonymous memory such as memfd. >>> >>> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> >>> --- >>> v3 >>> - enriched commit message and documentation to highlight that we >>> want to mimic memfd (David) >>> --- >>> docs/system/devices/vhost-user.rst | 5 +- >>> qapi/qom.json | 17 +++++ >>> backends/hostmem-shm.c | 118 +++++++++++++++++++++++++++++ >>> backends/meson.build | 1 + >>> qemu-options.hx | 11 +++ >>> 5 files changed, 150 insertions(+), 2 deletions(-) >>> create mode 100644 backends/hostmem-shm.c >>> >>> diff --git a/docs/system/devices/vhost-user.rst b/docs/system/devices/vhost-user.rst >>> index 9b2da106ce..35259d8ec7 100644 >>> --- a/docs/system/devices/vhost-user.rst >>> +++ b/docs/system/devices/vhost-user.rst >>> @@ -98,8 +98,9 @@ Shared memory object >>> In order for the daemon to access the VirtIO queues to process the >>> requests it needs access to the guest's address space. This is >>> -achieved via the ``memory-backend-file`` or ``memory-backend-memfd`` >>> -objects. A reference to a file-descriptor which can access this object >>> +achieved via the ``memory-backend-file``, ``memory-backend-memfd``, or >>> +``memory-backend-shm`` objects. >>> +A reference to a file-descriptor which can access this object >>> will be passed via the socket as part of the protocol negotiation. >>> Currently the shared memory object needs to match the size of the main >>> diff --git a/qapi/qom.json b/qapi/qom.json >>> index 85e6b4f84a..5252ec69e3 100644 >>> --- a/qapi/qom.json >>> +++ b/qapi/qom.json >>> @@ -721,6 +721,19 @@ >>> '*hugetlbsize': 'size', >>> '*seal': 'bool' } } >>> +## >>> +# @MemoryBackendShmProperties: >>> +# >>> +# Properties for memory-backend-shm objects. >>> +# >>> +# The @share boolean option is true by default with shm. >>> +# >>> +# Since: 9.1 >>> +## >>> +{ 'struct': 'MemoryBackendShmProperties', >>> + 'base': 'MemoryBackendProperties', >>> + 'data': { } } >>> + >> >> Acked-by: David Hildenbrand <david@redhat.com> >> >> One comment: we should maybe just forbid setting share=off. it doesn't >> make any sense and it can even result in an unexpected double memory >> consumption. We missed doing that for memfd, unfortunately. > > Good point! > > IIUC the `share` property is defined by the parent `hostmem`, so I > should find a way to override the property here and disable the setter, > or add an option to `hostmem` to make the property non-writable. Right, or simply fail later when you would find "share=off" in shm_backend_memory_alloc(). When ever supporting named shmem_open(), it could make sense for VM snapshotting. Right now it doesn't really make any sense.
On Mon, Apr 08, 2024 at 10:03:15AM +0200, David Hildenbrand wrote: >On 08.04.24 09:58, Stefano Garzarella wrote: >>On Thu, Apr 04, 2024 at 04:09:34PM +0200, David Hildenbrand wrote: >>>On 04.04.24 14:23, Stefano Garzarella wrote: >>>>shm_open() creates and opens a new POSIX shared memory object. >>>>A POSIX shared memory object allows creating memory backend with an >>>>associated file descriptor that can be shared with external processes >>>>(e.g. vhost-user). >>>> >>>>The new `memory-backend-shm` can be used as an alternative when >>>>`memory-backend-memfd` is not available (Linux only), since shm_open() >>>>should be provided by any POSIX-compliant operating system. >>>> >>>>This backend mimics memfd, allocating memory that is practically >>>>anonymous. In theory shm_open() requires a name, but this is allocated >>>>for a short time interval and shm_unlink() is called right after >>>>shm_open(). After that, only fd is shared with external processes >>>>(e.g., vhost-user) as if it were associated with anonymous memory. >>>> >>>>In the future we may also allow the user to specify the name to be >>>>passed to shm_open(), but for now we keep the backend simple, mimicking >>>>anonymous memory such as memfd. >>>> >>>>Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> >>>>--- >>>>v3 >>>>- enriched commit message and documentation to highlight that we >>>> want to mimic memfd (David) >>>>--- >>>> docs/system/devices/vhost-user.rst | 5 +- >>>> qapi/qom.json | 17 +++++ >>>> backends/hostmem-shm.c | 118 +++++++++++++++++++++++++++++ >>>> backends/meson.build | 1 + >>>> qemu-options.hx | 11 +++ >>>> 5 files changed, 150 insertions(+), 2 deletions(-) >>>> create mode 100644 backends/hostmem-shm.c >>>> >>>>diff --git a/docs/system/devices/vhost-user.rst b/docs/system/devices/vhost-user.rst >>>>index 9b2da106ce..35259d8ec7 100644 >>>>--- a/docs/system/devices/vhost-user.rst >>>>+++ b/docs/system/devices/vhost-user.rst >>>>@@ -98,8 +98,9 @@ Shared memory object >>>> In order for the daemon to access the VirtIO queues to process the >>>> requests it needs access to the guest's address space. This is >>>>-achieved via the ``memory-backend-file`` or ``memory-backend-memfd`` >>>>-objects. A reference to a file-descriptor which can access this object >>>>+achieved via the ``memory-backend-file``, ``memory-backend-memfd``, or >>>>+``memory-backend-shm`` objects. >>>>+A reference to a file-descriptor which can access this object >>>> will be passed via the socket as part of the protocol negotiation. >>>> Currently the shared memory object needs to match the size of the main >>>>diff --git a/qapi/qom.json b/qapi/qom.json >>>>index 85e6b4f84a..5252ec69e3 100644 >>>>--- a/qapi/qom.json >>>>+++ b/qapi/qom.json >>>>@@ -721,6 +721,19 @@ >>>> '*hugetlbsize': 'size', >>>> '*seal': 'bool' } } >>>>+## >>>>+# @MemoryBackendShmProperties: >>>>+# >>>>+# Properties for memory-backend-shm objects. >>>>+# >>>>+# The @share boolean option is true by default with shm. >>>>+# >>>>+# Since: 9.1 >>>>+## >>>>+{ 'struct': 'MemoryBackendShmProperties', >>>>+ 'base': 'MemoryBackendProperties', >>>>+ 'data': { } } >>>>+ >>> >>>Acked-by: David Hildenbrand <david@redhat.com> >>> >>>One comment: we should maybe just forbid setting share=off. it doesn't >>>make any sense and it can even result in an unexpected double memory >>>consumption. We missed doing that for memfd, unfortunately. >> >>Good point! >> >>IIUC the `share` property is defined by the parent `hostmem`, so I >>should find a way to override the property here and disable the setter, >>or add an option to `hostmem` to make the property non-writable. > >Right, or simply fail later when you would find "share=off" in >shm_backend_memory_alloc(). This seems like the simplest and cleanest approach, I'll go in this direction! > >When ever supporting named shmem_open(), it could make sense for VM >snapshotting. Right now it doesn't really make any sense. Yeah, I see. Thanks, Stefano
diff --git a/docs/system/devices/vhost-user.rst b/docs/system/devices/vhost-user.rst index 9b2da106ce..35259d8ec7 100644 --- a/docs/system/devices/vhost-user.rst +++ b/docs/system/devices/vhost-user.rst @@ -98,8 +98,9 @@ Shared memory object In order for the daemon to access the VirtIO queues to process the requests it needs access to the guest's address space. This is -achieved via the ``memory-backend-file`` or ``memory-backend-memfd`` -objects. A reference to a file-descriptor which can access this object +achieved via the ``memory-backend-file``, ``memory-backend-memfd``, or +``memory-backend-shm`` objects. +A reference to a file-descriptor which can access this object will be passed via the socket as part of the protocol negotiation. Currently the shared memory object needs to match the size of the main diff --git a/qapi/qom.json b/qapi/qom.json index 85e6b4f84a..5252ec69e3 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -721,6 +721,19 @@ '*hugetlbsize': 'size', '*seal': 'bool' } } +## +# @MemoryBackendShmProperties: +# +# Properties for memory-backend-shm objects. +# +# The @share boolean option is true by default with shm. +# +# Since: 9.1 +## +{ 'struct': 'MemoryBackendShmProperties', + 'base': 'MemoryBackendProperties', + 'data': { } } + ## # @MemoryBackendEpcProperties: # @@ -976,6 +989,8 @@ { 'name': 'memory-backend-memfd', 'if': 'CONFIG_LINUX' }, 'memory-backend-ram', + { 'name': 'memory-backend-shm', + 'if': 'CONFIG_POSIX' }, 'pef-guest', { 'name': 'pr-manager-helper', 'if': 'CONFIG_LINUX' }, @@ -1047,6 +1062,8 @@ 'memory-backend-memfd': { 'type': 'MemoryBackendMemfdProperties', 'if': 'CONFIG_LINUX' }, 'memory-backend-ram': 'MemoryBackendProperties', + 'memory-backend-shm': { 'type': 'MemoryBackendShmProperties', + 'if': 'CONFIG_POSIX' }, 'pr-manager-helper': { 'type': 'PrManagerHelperProperties', 'if': 'CONFIG_LINUX' }, 'qtest': 'QtestProperties', diff --git a/backends/hostmem-shm.c b/backends/hostmem-shm.c new file mode 100644 index 0000000000..7595204d29 --- /dev/null +++ b/backends/hostmem-shm.c @@ -0,0 +1,118 @@ +/* + * QEMU host POSIX shared memory object backend + * + * Copyright (C) 2024 Red Hat Inc + * + * Authors: + * Stefano Garzarella <sgarzare@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "sysemu/hostmem.h" +#include "qapi/error.h" + +#define TYPE_MEMORY_BACKEND_SHM "memory-backend-shm" + +OBJECT_DECLARE_SIMPLE_TYPE(HostMemoryBackendShm, MEMORY_BACKEND_SHM) + +struct HostMemoryBackendShm { + HostMemoryBackend parent_obj; +}; + +static bool +shm_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) +{ + g_autoptr(GString) shm_name = g_string_new(NULL); + g_autofree char *backend_name = NULL; + uint32_t ram_flags; + int fd, oflag; + mode_t mode; + + if (!backend->size) { + error_setg(errp, "can't create backend with size 0"); + return false; + } + + /* + * Let's use `mode = 0` because we don't want other processes to open our + * memory unless we share the file descriptor with them. + */ + mode = 0; + oflag = O_RDWR | O_CREAT | O_EXCL; + backend_name = host_memory_backend_get_name(backend); + + /* + * Some operating systems allow creating anonymous POSIX shared memory + * objects (e.g. FreeBSD provides the SHM_ANON constant), but this is not + * defined by POSIX, so let's create a unique name. + * + * From Linux's shm_open(3) man-page: + * For portable use, a shared memory object should be identified + * by a name of the form /somename;" + */ + g_string_printf(shm_name, "/qemu-" FMT_pid "-shm-%s", getpid(), + backend_name); + + fd = shm_open(shm_name->str, oflag, mode); + if (fd < 0) { + error_setg_errno(errp, errno, + "failed to create POSIX shared memory"); + return false; + } + + /* + * We have the file descriptor, so we no longer need to expose the + * POSIX shared memory object. However it will remain allocated as long as + * there are file descriptors pointing to it. + */ + shm_unlink(shm_name->str); + + if (ftruncate(fd, backend->size) == -1) { + error_setg_errno(errp, errno, + "failed to resize POSIX shared memory to %" PRIu64, + backend->size); + close(fd); + return false; + } + + ram_flags = backend->share ? RAM_SHARED : 0; + ram_flags |= backend->reserve ? 0 : RAM_NORESERVE; + + return memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), + backend_name, backend->size, + ram_flags, fd, 0, errp); +} + +static void +shm_backend_instance_init(Object *obj) +{ + HostMemoryBackendShm *m = MEMORY_BACKEND_SHM(obj); + + MEMORY_BACKEND(m)->share = true; +} + +static void +shm_backend_class_init(ObjectClass *oc, void *data) +{ + HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); + + bc->alloc = shm_backend_memory_alloc; +} + +static const TypeInfo shm_backend_info = { + .name = TYPE_MEMORY_BACKEND_SHM, + .parent = TYPE_MEMORY_BACKEND, + .instance_init = shm_backend_instance_init, + .class_init = shm_backend_class_init, + .instance_size = sizeof(HostMemoryBackendShm), +}; + +static void register_types(void) +{ + type_register_static(&shm_backend_info); +} + +type_init(register_types); diff --git a/backends/meson.build b/backends/meson.build index 8b2b111497..3867b0d363 100644 --- a/backends/meson.build +++ b/backends/meson.build @@ -13,6 +13,7 @@ system_ss.add([files( if host_os != 'windows' system_ss.add(files('rng-random.c')) system_ss.add(files('hostmem-file.c')) + system_ss.add([files('hostmem-shm.c'), rt]) endif if host_os == 'linux' system_ss.add(files('hostmem-memfd.c')) diff --git a/qemu-options.hx b/qemu-options.hx index 7fd1713fa8..02783803aa 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -5230,6 +5230,17 @@ SRST The ``share`` boolean option is on by default with memfd. + ``-object memory-backend-shm,id=id,merge=on|off,dump=on|off,share=on|off,prealloc=on|off,size=size,host-nodes=host-nodes,policy=default|preferred|bind|interleave`` + Creates a POSIX shared memory backend object, which allows + QEMU to share the memory with an external process (e.g. when + using vhost-user). This backend mimics memfd, allocating memory that is + practically anonymous. This is useful when memfd is not available. + + Please refer to ``memory-backend-file`` for a description of the + options. + + The ``share`` boolean option is on by default with shm. + ``-object iommufd,id=id[,fd=fd]`` Creates an iommufd backend which allows control of DMA mapping through the ``/dev/iommu`` device.
shm_open() creates and opens a new POSIX shared memory object. A POSIX shared memory object allows creating memory backend with an associated file descriptor that can be shared with external processes (e.g. vhost-user). The new `memory-backend-shm` can be used as an alternative when `memory-backend-memfd` is not available (Linux only), since shm_open() should be provided by any POSIX-compliant operating system. This backend mimics memfd, allocating memory that is practically anonymous. In theory shm_open() requires a name, but this is allocated for a short time interval and shm_unlink() is called right after shm_open(). After that, only fd is shared with external processes (e.g., vhost-user) as if it were associated with anonymous memory. In the future we may also allow the user to specify the name to be passed to shm_open(), but for now we keep the backend simple, mimicking anonymous memory such as memfd. Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> --- v3 - enriched commit message and documentation to highlight that we want to mimic memfd (David) --- docs/system/devices/vhost-user.rst | 5 +- qapi/qom.json | 17 +++++ backends/hostmem-shm.c | 118 +++++++++++++++++++++++++++++ backends/meson.build | 1 + qemu-options.hx | 11 +++ 5 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 backends/hostmem-shm.c