qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend
@ 2017-01-11 11:33 Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 1/9] exec: check kvm mmu notifiers earlier Marc-André Lureau
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Add a new Linux-specific memory backend, similar to hostmem-file,
except that it doesn't need file path. It also try to enforce memory
sealing if available. It is thus slightly easier and secure, and is
compatible with transparent huge-pages since Linux 4.8.

v1->v2:
- make it linux-specific
- minor changes and commit message tweaks

Marc-André Lureau (9):
  exec: check kvm mmu notifiers earlier
  exec: split file_ram_alloc()
  exec: split qemu_ram_alloc_from_file()
  Add memory_region_init_ram_from_fd()
  ivshmem: use ram_from_fd()
  memory: remove memory_region_set_fd
  memfd: split qemu_memfd_alloc()
  Add memfd based hostmem
  tests: use memfd in vhost-user-test

 include/exec/memory.h    |  31 ++++++++-----
 include/exec/ram_addr.h  |   3 ++
 include/qemu/memfd.h     |   2 +
 backends/hostmem-memfd.c |  67 +++++++++++++++++++++++++++
 exec.c                   | 116 ++++++++++++++++++++++++++++-------------------
 hw/misc/ivshmem.c        |  14 +++---
 memory.c                 |  26 +++++++----
 tests/vhost-user-test.c  |  14 +++---
 util/memfd.c             |  42 ++++++++++-------
 backends/Makefile.objs   |   2 +
 qemu-options.hx          |  11 +++++
 11 files changed, 229 insertions(+), 99 deletions(-)
 create mode 100644 backends/hostmem-memfd.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 1/9] exec: check kvm mmu notifiers earlier
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 2/9] exec: split file_ram_alloc() Marc-André Lureau
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Move kvm mmu notifiers check before calling file_ram_alloc(), with the
other xen precondition. (the function will be reused in other cases than
-mem-path).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 exec.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/exec.c b/exec.c
index 47835c1dc1..172baba30e 100644
--- a/exec.c
+++ b/exec.c
@@ -1273,12 +1273,6 @@ static void *file_ram_alloc(RAMBlock *block,
     int fd = -1;
     int64_t file_size;
 
-    if (kvm_enabled() && !kvm_has_sync_mmu()) {
-        error_setg(errp,
-                   "host lacks kvm mmu notifiers, -mem-path unsupported");
-        return NULL;
-    }
-
     for (;;) {
         fd = open(path, O_RDWR);
         if (fd >= 0) {
@@ -1703,6 +1697,12 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
         return NULL;
     }
 
+    if (kvm_enabled() && !kvm_has_sync_mmu()) {
+        error_setg(errp,
+                   "host lacks kvm mmu notifiers, -mem-path unsupported");
+        return NULL;
+    }
+
     if (phys_mem_alloc != qemu_anon_ram_alloc) {
         /*
          * file_ram_alloc() needs to allocate just like
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 2/9] exec: split file_ram_alloc()
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 1/9] exec: check kvm mmu notifiers earlier Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 3/9] exec: split qemu_ram_alloc_from_file() Marc-André Lureau
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Move file opening part in a seperate function file_ram_open(). This
allows for reuse of file_ram_alloc() with only a fd.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 exec.c | 83 +++++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 46 insertions(+), 37 deletions(-)

diff --git a/exec.c b/exec.c
index 172baba30e..b6d52e7c43 100644
--- a/exec.c
+++ b/exec.c
@@ -1260,19 +1260,17 @@ static int64_t get_file_size(int fd)
     return size;
 }
 
-static void *file_ram_alloc(RAMBlock *block,
-                            ram_addr_t memory,
-                            const char *path,
-                            Error **errp)
+static int file_ram_open(const char *path,
+                         const char *region_name,
+                         bool *created,
+                         Error **errp)
 {
-    bool unlink_on_error = false;
     char *filename;
     char *sanitized_name;
     char *c;
-    void *area = MAP_FAILED;
     int fd = -1;
-    int64_t file_size;
 
+    *created = false;
     for (;;) {
         fd = open(path, O_RDWR);
         if (fd >= 0) {
@@ -1283,13 +1281,13 @@ static void *file_ram_alloc(RAMBlock *block,
             /* @path names a file that doesn't exist, create it */
             fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
             if (fd >= 0) {
-                unlink_on_error = true;
+                *created = true;
                 break;
             }
         } else if (errno == EISDIR) {
             /* @path names a directory, create a file there */
             /* Make name safe to use with mkstemp by replacing '/' with '_'. */
-            sanitized_name = g_strdup(memory_region_name(block->mr));
+            sanitized_name = g_strdup(region_name);
             for (c = sanitized_name; *c != '\0'; c++) {
                 if (*c == '/') {
                     *c = '_';
@@ -1312,7 +1310,7 @@ static void *file_ram_alloc(RAMBlock *block,
             error_setg_errno(errp, errno,
                              "can't open backing store %s for guest RAM",
                              path);
-            goto error;
+            return -1;
         }
         /*
          * Try again on EINTR and EEXIST.  The latter happens when
@@ -1320,6 +1318,17 @@ static void *file_ram_alloc(RAMBlock *block,
          */
     }
 
+    return fd;
+}
+
+static void *file_ram_alloc(RAMBlock *block,
+                            ram_addr_t memory,
+                            int fd,
+                            bool truncate,
+                            Error **errp)
+{
+    void *area;
+
     block->page_size = qemu_fd_getpagesize(fd);
     block->mr->align = block->page_size;
 #if defined(__s390x__)
@@ -1328,20 +1337,11 @@ static void *file_ram_alloc(RAMBlock *block,
     }
 #endif
 
-    file_size = get_file_size(fd);
-
     if (memory < block->page_size) {
         error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
                    "or larger than page size 0x%zx",
                    memory, block->page_size);
-        goto error;
-    }
-
-    if (file_size > 0 && file_size < memory) {
-        error_setg(errp, "backing store %s size 0x%" PRIx64
-                   " does not match 'size' option 0x" RAM_ADDR_FMT,
-                   path, file_size, memory);
-        goto error;
+        return NULL;
     }
 
     memory = ROUND_UP(memory, block->page_size);
@@ -1360,7 +1360,7 @@ static void *file_ram_alloc(RAMBlock *block,
      * those labels. Therefore, extending the non-empty backend file
      * is disabled as well.
      */
-    if (!file_size && ftruncate(fd, memory)) {
+    if (truncate && ftruncate(fd, memory)) {
         perror("ftruncate");
     }
 
@@ -1369,30 +1369,19 @@ static void *file_ram_alloc(RAMBlock *block,
     if (area == MAP_FAILED) {
         error_setg_errno(errp, errno,
                          "unable to map backing store for guest RAM");
-        goto error;
+        return NULL;
     }
 
     if (mem_prealloc) {
         os_mem_prealloc(fd, area, memory, errp);
         if (errp && *errp) {
-            goto error;
+            qemu_ram_munmap(area, memory);
+            return NULL;
         }
     }
 
     block->fd = fd;
     return area;
-
-error:
-    if (area != MAP_FAILED) {
-        qemu_ram_munmap(area, memory);
-    }
-    if (unlink_on_error) {
-        unlink(path);
-    }
-    if (fd != -1) {
-        close(fd);
-    }
-    return NULL;
 }
 #endif
 
@@ -1691,6 +1680,9 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
 {
     RAMBlock *new_block;
     Error *local_err = NULL;
+    int fd;
+    bool created;
+    int64_t file_size;
 
     if (xen_enabled()) {
         error_setg(errp, "-mem-path not supported with Xen");
@@ -1714,15 +1706,32 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
         return NULL;
     }
 
+    fd = file_ram_open(mem_path, memory_region_name(mr), &created, errp);
+    if (fd < 0) {
+        return NULL;
+    }
+
     size = HOST_PAGE_ALIGN(size);
+    file_size = get_file_size(fd);
+    if (file_size > 0 && file_size < size) {
+        error_setg(errp, "backing store %s size 0x%" PRIx64
+                   " does not match 'size' option 0x" RAM_ADDR_FMT,
+                   mem_path, file_size, size);
+        close(fd);
+        return NULL;
+    }
+
     new_block = g_malloc0(sizeof(*new_block));
     new_block->mr = mr;
     new_block->used_length = size;
     new_block->max_length = size;
     new_block->flags = share ? RAM_SHARED : 0;
-    new_block->host = file_ram_alloc(new_block, size,
-                                     mem_path, errp);
+    new_block->host = file_ram_alloc(new_block, size, fd, !file_size, errp);
     if (!new_block->host) {
+        if (created) {
+            unlink(mem_path);
+        }
+        close(fd);
         g_free(new_block);
         return NULL;
     }
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 3/9] exec: split qemu_ram_alloc_from_file()
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 1/9] exec: check kvm mmu notifiers earlier Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 2/9] exec: split file_ram_alloc() Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 4/9] Add memory_region_init_ram_from_fd() Marc-André Lureau
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Add qemu_ram_alloc_from_fd(), which can be use to allocate ramblock from
fd only.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/exec/ram_addr.h |  3 +++
 exec.c                  | 45 ++++++++++++++++++++++++++++++---------------
 2 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 54d7108a9e..7f013fe795 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -98,6 +98,9 @@ void qemu_mutex_unlock_ramlist(void);
 RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
                                    bool share, const char *mem_path,
                                    Error **errp);
+RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
+                                 bool share, int fd,
+                                 Error **errp);
 RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
                                   MemoryRegion *mr, Error **errp);
 RAMBlock *qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp);
diff --git a/exec.c b/exec.c
index b6d52e7c43..fbf02d15d0 100644
--- a/exec.c
+++ b/exec.c
@@ -1674,14 +1674,12 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
 }
 
 #ifdef __linux__
-RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
-                                   bool share, const char *mem_path,
-                                   Error **errp)
+RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
+                                 bool share, int fd,
+                                 Error **errp)
 {
     RAMBlock *new_block;
     Error *local_err = NULL;
-    int fd;
-    bool created;
     int64_t file_size;
 
     if (xen_enabled()) {
@@ -1706,18 +1704,12 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
         return NULL;
     }
 
-    fd = file_ram_open(mem_path, memory_region_name(mr), &created, errp);
-    if (fd < 0) {
-        return NULL;
-    }
-
     size = HOST_PAGE_ALIGN(size);
     file_size = get_file_size(fd);
     if (file_size > 0 && file_size < size) {
         error_setg(errp, "backing store %s size 0x%" PRIx64
                    " does not match 'size' option 0x" RAM_ADDR_FMT,
                    mem_path, file_size, size);
-        close(fd);
         return NULL;
     }
 
@@ -1728,10 +1720,6 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
     new_block->flags = share ? RAM_SHARED : 0;
     new_block->host = file_ram_alloc(new_block, size, fd, !file_size, errp);
     if (!new_block->host) {
-        if (created) {
-            unlink(mem_path);
-        }
-        close(fd);
         g_free(new_block);
         return NULL;
     }
@@ -1743,6 +1731,33 @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
         return NULL;
     }
     return new_block;
+
+}
+
+
+RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
+                                   bool share, const char *mem_path,
+                                   Error **errp)
+{
+    int fd;
+    bool created;
+    RAMBlock *block;
+
+    fd = file_ram_open(mem_path, memory_region_name(mr), &created, errp);
+    if (fd < 0) {
+        return NULL;
+    }
+
+    block = qemu_ram_alloc_from_fd(size, mr, share, fd, errp);
+    if (!block) {
+        if (created) {
+            unlink(mem_path);
+        }
+        close(fd);
+        return NULL;
+    }
+
+    return block;
 }
 #endif
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 4/9] Add memory_region_init_ram_from_fd()
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
                   ` (2 preceding siblings ...)
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 3/9] exec: split qemu_ram_alloc_from_file() Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 5/9] ivshmem: use ram_from_fd() Marc-André Lureau
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Add a new function to initialize a RAM memory region with a file
descriptor to be mmap-ed.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/exec/memory.h | 20 ++++++++++++++++++++
 memory.c              | 16 ++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index bec9756667..6f98e4df6a 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -429,6 +429,26 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
                                       bool share,
                                       const char *path,
                                       Error **errp);
+
+/**
+ * memory_region_init_ram_from_fd:  Initialize RAM memory region with a
+ *                                  mmap-ed backend.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @owner: the object that tracks the region's reference count
+ * @name: the name of the region.
+ * @size: size of the region.
+ * @share: %true if memory must be mmaped with the MAP_SHARED flag
+ * @fd: the fd to mmap.
+ * @errp: pointer to Error*, to store an error if it happens.
+ */
+void memory_region_init_ram_from_fd(MemoryRegion *mr,
+                                    struct Object *owner,
+                                    const char *name,
+                                    uint64_t size,
+                                    bool share,
+                                    int fd,
+                                    Error **errp);
 #endif
 
 /**
diff --git a/memory.c b/memory.c
index 2bfc37f65c..ec894865a2 100644
--- a/memory.c
+++ b/memory.c
@@ -1401,6 +1401,22 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
     mr->ram_block = qemu_ram_alloc_from_file(size, mr, share, path, errp);
     mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
 }
+
+void memory_region_init_ram_from_fd(MemoryRegion *mr,
+                                    struct Object *owner,
+                                    const char *name,
+                                    uint64_t size,
+                                    bool share,
+                                    int fd,
+                                    Error **errp)
+{
+    memory_region_init(mr, owner, name, size);
+    mr->ram = true;
+    mr->terminates = true;
+    mr->destructor = memory_region_destructor_ram;
+    mr->ram_block = qemu_ram_alloc_from_fd(size, mr, share, fd, errp);
+    mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
+}
 #endif
 
 void memory_region_init_ram_ptr(MemoryRegion *mr,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 5/9] ivshmem: use ram_from_fd()
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
                   ` (3 preceding siblings ...)
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 4/9] Add memory_region_init_ram_from_fd() Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 6/9] memory: remove memory_region_set_fd Marc-André Lureau
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Instead of having its own mmap handling code, reuse the code from
exec.c.

Note: memory_region_init_ram_from_fd() adds some restrictions
(check for xen, kvm sync-mmu, etc) and changes (such as size
alignment). This may actually be more correct.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/misc/ivshmem.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index abeaf3da08..49db6a27aa 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -491,9 +491,9 @@ static void setup_interrupt(IVShmemState *s, int vector, Error **errp)
 
 static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
 {
+    Error *local_err = NULL;
     struct stat buf;
     size_t size;
-    void *ptr;
 
     if (s->ivshmem_bar2) {
         error_setg(errp, "server sent unexpected shared memory message");
@@ -522,15 +522,13 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
     }
 
     /* mmap the region and map into the BAR2 */
-    ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    if (ptr == MAP_FAILED) {
-        error_setg_errno(errp, errno, "Failed to mmap shared memory");
-        close(fd);
+    memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
+                                   "ivshmem.bar2", size, true, fd, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
         return;
     }
-    memory_region_init_ram_ptr(&s->server_bar2, OBJECT(s),
-                               "ivshmem.bar2", size, ptr);
-    memory_region_set_fd(&s->server_bar2, fd);
+
     s->ivshmem_bar2 = &s->server_bar2;
 }
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 6/9] memory: remove memory_region_set_fd
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
                   ` (4 preceding siblings ...)
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 5/9] ivshmem: use ram_from_fd() Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 7/9] memfd: split qemu_memfd_alloc() Marc-André Lureau
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Now unnecessary since ivshmem uses memory_region_init_ram_from_fd.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/exec/memory.h | 11 -----------
 memory.c              | 10 ----------
 2 files changed, 21 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 6f98e4df6a..5dbc3d1a6c 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -774,17 +774,6 @@ static inline bool memory_region_is_rom(MemoryRegion *mr)
  */
 int memory_region_get_fd(MemoryRegion *mr);
 
-/**
- * memory_region_set_fd: Mark a RAM memory region as backed by a
- * file descriptor.
- *
- * This function is typically used after memory_region_init_ram_ptr().
- *
- * @mr: the memory region being queried.
- * @fd: the file descriptor that backs @mr.
- */
-void memory_region_set_fd(MemoryRegion *mr, int fd);
-
 /**
  * memory_region_from_host: Convert a pointer into a RAM memory region
  * and an offset within it.
diff --git a/memory.c b/memory.c
index ec894865a2..3833a556d9 100644
--- a/memory.c
+++ b/memory.c
@@ -1807,16 +1807,6 @@ int memory_region_get_fd(MemoryRegion *mr)
     return fd;
 }
 
-void memory_region_set_fd(MemoryRegion *mr, int fd)
-{
-    rcu_read_lock();
-    while (mr->alias) {
-        mr = mr->alias;
-    }
-    mr->ram_block->fd = fd;
-    rcu_read_unlock();
-}
-
 void *memory_region_get_ram_ptr(MemoryRegion *mr)
 {
     void *ptr;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 7/9] memfd: split qemu_memfd_alloc()
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
                   ` (5 preceding siblings ...)
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 6/9] memory: remove memory_region_set_fd Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 8/9] Add memfd based hostmem Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 9/9] tests: use memfd in vhost-user-test Marc-André Lureau
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Add a function to only create a memfd, without mmap. The function is
used in the following memory backend.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/qemu/memfd.h |  2 ++
 util/memfd.c         | 42 +++++++++++++++++++++++++-----------------
 2 files changed, 27 insertions(+), 17 deletions(-)

diff --git a/include/qemu/memfd.h b/include/qemu/memfd.h
index 745a8c501e..30c1ab1d91 100644
--- a/include/qemu/memfd.h
+++ b/include/qemu/memfd.h
@@ -16,6 +16,8 @@
 #define F_SEAL_WRITE    0x0008  /* prevent writes */
 #endif
 
+int qemu_memfd_create(const char *name, size_t size, unsigned int seals,
+                      bool must_seal);
 void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals,
                        int *fd);
 void qemu_memfd_free(void *ptr, size_t size, int fd);
diff --git a/util/memfd.c b/util/memfd.c
index 4571d1aba8..e6476df083 100644
--- a/util/memfd.c
+++ b/util/memfd.c
@@ -55,45 +55,53 @@ static int memfd_create(const char *name, unsigned int flags)
 #define MFD_ALLOW_SEALING 0x0002U
 #endif
 
-/*
- * This is a best-effort helper for shared memory allocation, with
- * optional sealing. The helper will do his best to allocate using
- * memfd with sealing, but may fallback on other methods without
- * sealing.
- */
-void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals,
-                       int *fd)
+int qemu_memfd_create(const char *name, size_t size, unsigned int seals,
+    bool must_seal)
 {
-    void *ptr;
     int mfd = -1;
 
-    *fd = -1;
-
 #ifdef CONFIG_LINUX
     if (seals) {
         mfd = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
     }
 
-    if (mfd == -1) {
+    if (mfd == -1 && !must_seal) {
         /* some systems have memfd without sealing */
         mfd = memfd_create(name, MFD_CLOEXEC);
         seals = 0;
     }
-#endif
 
-    if (mfd != -1) {
+    if (mfd >= 0) {
         if (ftruncate(mfd, size) == -1) {
             perror("ftruncate");
             close(mfd);
-            return NULL;
+            return -1;
         }
 
         if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) {
             perror("fcntl");
             close(mfd);
-            return NULL;
+            return -1;
         }
-    } else {
+    }
+#endif
+
+    return mfd;
+}
+
+/*
+ * This is a best-effort helper for shared memory allocation, with
+ * optional sealing. The helper will do his best to allocate using
+ * memfd with sealing, but may fallback on other methods without
+ * sealing.
+ */
+void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals,
+                       int *fd)
+{
+    void *ptr;
+    int mfd = qemu_memfd_create(name, size, seals, false);
+
+    if (mfd == -1) {
         const char *tmpdir = g_get_tmp_dir();
         gchar *fname;
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 8/9] Add memfd based hostmem
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
                   ` (6 preceding siblings ...)
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 7/9] memfd: split qemu_memfd_alloc() Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 9/9] tests: use memfd in vhost-user-test Marc-André Lureau
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

Add a new memory backend, similar to hostmem-file, except that it
doesn't need to create files. It also enforces memory sealing.

This backend is mainly useful for sharing the memory with other
processes.

Note that Linux supports transparent huge-pages of shmem/memfd memory
since 4.8. It is relatively easier to set up THP than a dedicate
hugepage mount point by using "madvise" in
/sys/kernel/mm/transparent_hugepage/shmem_enabled.

Usage:
-object memory-backend-memfd,id=mem1,size=1G

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 backends/hostmem-memfd.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
 backends/Makefile.objs   |  2 ++
 qemu-options.hx          | 11 ++++++++
 3 files changed, 80 insertions(+)
 create mode 100644 backends/hostmem-memfd.c

diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
new file mode 100644
index 0000000000..13d300d9ad
--- /dev/null
+++ b/backends/hostmem-memfd.c
@@ -0,0 +1,67 @@
+/*
+ * QEMU host memfd memory backend
+ *
+ * Copyright (C) 2016 Red Hat Inc
+ *
+ * Authors:
+ *   Marc-André Lureau <marcandre.lureau@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 "qemu-common.h"
+#include "sysemu/hostmem.h"
+#include "sysemu/sysemu.h"
+#include "qom/object_interfaces.h"
+#include "qemu/memfd.h"
+#include "qapi/error.h"
+
+#define TYPE_MEMORY_BACKEND_MEMFD "memory-backend-memfd"
+
+static void
+memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
+{
+    int fd;
+
+    if (!backend->size) {
+        error_setg(errp, "can't create backend with size 0");
+        return;
+    }
+
+    if (!memory_region_size(&backend->mr)) {
+        backend->force_prealloc = mem_prealloc;
+        fd = qemu_memfd_create(TYPE_MEMORY_BACKEND_MEMFD,
+                               backend->size,
+                               F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL,
+                               true);
+        if (fd == -1) {
+            error_setg(errp, "can't allocate memfd backend");
+            return;
+        }
+        memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
+            object_get_canonical_path(OBJECT(backend)),
+            backend->size, true, fd, errp);
+    }
+}
+
+static void
+memfd_backend_class_init(ObjectClass *oc, void *data)
+{
+    HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
+
+    bc->alloc = memfd_backend_memory_alloc;
+}
+
+static const TypeInfo memfd_backend_info = {
+    .name = TYPE_MEMORY_BACKEND_MEMFD,
+    .parent = TYPE_MEMORY_BACKEND,
+    .class_init = memfd_backend_class_init,
+};
+
+static void register_types(void)
+{
+    type_register_static(&memfd_backend_info);
+}
+
+type_init(register_types);
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 18469980e6..1ed7e5b286 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -12,3 +12,5 @@ common-obj-$(CONFIG_LINUX) += hostmem-file.o
 
 common-obj-y += cryptodev.o
 common-obj-y += cryptodev-builtin.o
+
+common-obj-$(CONFIG_LINUX) += hostmem-memfd.o
diff --git a/qemu-options.hx b/qemu-options.hx
index c534a2f7f9..d48463dd81 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3807,6 +3807,17 @@ The @option{share} boolean option determines whether the memory
 region is marked as private to QEMU, or shared. The latter allows
 a co-operating external process to access the QEMU memory region.
 
+@item -object memory-backend-memfd,id=@var{id},size=@var{size}
+
+Creates an anonymous memory file backend object, which can be used to
+share the memory with a co-operating external process. The memory is
+allocated with memfd and sealing. (Linux only)
+
+The @option{id} parameter is a unique ID that will be used to
+reference this memory region when configuring the @option{-numa}
+argument. The @option{size} option provides the size of the memory
+region, and accepts common suffixes, eg @option{500M}.
+
 @item -object rng-random,id=@var{id},filename=@var{/dev/random}
 
 Creates a random number generator backend which obtains entropy from
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v2 9/9] tests: use memfd in vhost-user-test
  2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
                   ` (7 preceding siblings ...)
  2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 8/9] Add memfd based hostmem Marc-André Lureau
@ 2017-01-11 11:33 ` Marc-André Lureau
  8 siblings, 0 replies; 10+ messages in thread
From: Marc-André Lureau @ 2017-01-11 11:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, Marc-André Lureau

This will exercise the memfd memory backend and should generally be
better for testing than memory-backend-file (thanks to anonymous files
and sealing).

The test is already Linux-specific, but will now require Linux with
memfd (since 3.17).

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 tests/vhost-user-test.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 96bf00eefa..bf0630e38b 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -39,8 +39,8 @@
 #define HAVE_MONOTONIC_TIME
 #endif
 
-#define QEMU_CMD_MEM    " -m %d -object memory-backend-file,id=mem,size=%dM,"\
-                        "mem-path=%s,share=on -numa node,memdev=mem"
+#define QEMU_CMD_MEM    " -m %d -object memory-backend-memfd,id=mem,size=%dM,"\
+                        " -numa node,memdev=mem"
 #define QEMU_CMD_CHR    " -chardev socket,id=%s,path=%s%s"
 #define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce"
 #define QEMU_CMD_NET    " -device virtio-net-pci,netdev=net0"
@@ -475,12 +475,12 @@ static inline void test_server_connect(TestServer *server)
     test_server_create_chr(server, ",reconnect=1");
 }
 
-#define GET_QEMU_CMD(s)                                         \
-    g_strdup_printf(QEMU_CMD, 512, 512, (root), (s)->chr_name,  \
+#define GET_QEMU_CMD(s)                                 \
+    g_strdup_printf(QEMU_CMD, 512, 512, (s)->chr_name,  \
                     (s)->socket_path, "", (s)->chr_name)
 
-#define GET_QEMU_CMDE(s, mem, chr_opts, extra, ...)                     \
-    g_strdup_printf(QEMU_CMD extra, (mem), (mem), (root), (s)->chr_name, \
+#define GET_QEMU_CMDE(s, mem, chr_opts, extra, ...)                      \
+    g_strdup_printf(QEMU_CMD extra, (mem), (mem), (s)->chr_name,        \
                     (s)->socket_path, (chr_opts), (s)->chr_name, ##__VA_ARGS__)
 
 static gboolean _test_server_free(TestServer *server)
@@ -883,7 +883,7 @@ static void test_multiqueue(void)
 
     cmd = g_strdup_printf(QEMU_CMD_MEM QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
                           "-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
-                          512, 512, root, s->chr_name,
+                          512, 512, s->chr_name,
                           s->socket_path, "", s->chr_name,
                           queues, queues * 2 + 2);
     qtest_start(cmd);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-01-11 11:34 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-01-11 11:33 [Qemu-devel] [PATCH v2 0/9] Add memfd memory backend Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 1/9] exec: check kvm mmu notifiers earlier Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 2/9] exec: split file_ram_alloc() Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 3/9] exec: split qemu_ram_alloc_from_file() Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 4/9] Add memory_region_init_ram_from_fd() Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 5/9] ivshmem: use ram_from_fd() Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 6/9] memory: remove memory_region_set_fd Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 7/9] memfd: split qemu_memfd_alloc() Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 8/9] Add memfd based hostmem Marc-André Lureau
2017-01-11 11:33 ` [Qemu-devel] [PATCH v2 9/9] tests: use memfd in vhost-user-test Marc-André Lureau

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).