Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libnvmm Rewrite the gpa map/unmap functions. Dig holes i...



details:   https://anonhg.NetBSD.org/src/rev/c2a54348262d
branches:  trunk
changeset: 446294:c2a54348262d
user:      maxv <maxv%NetBSD.org@localhost>
date:      Thu Nov 29 19:55:20 2018 +0000

description:
Rewrite the gpa map/unmap functions. Dig holes in the mapped areas when
there is an overlap. Close to what Qemu expects.

diffstat:

 lib/libnvmm/libnvmm.c |  218 +++++++++++++++++++++++++++++++------------------
 lib/libnvmm/nvmm.h    |   11 +--
 2 files changed, 141 insertions(+), 88 deletions(-)

diffs (truncated from 352 to 300 lines):

diff -r ce3630d67e4a -r c2a54348262d lib/libnvmm/libnvmm.c
--- a/lib/libnvmm/libnvmm.c     Thu Nov 29 18:53:42 2018 +0000
+++ b/lib/libnvmm/libnvmm.c     Thu Nov 29 19:55:20 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: libnvmm.c,v 1.2 2018/11/19 21:45:37 maxv Exp $ */
+/*     $NetBSD: libnvmm.c,v 1.3 2018/11/29 19:55:20 maxv Exp $ */
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -39,78 +39,145 @@
 #include <errno.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/queue.h>
 
 #include "nvmm.h"
 
+typedef struct __area {
+       LIST_ENTRY(__area) list;
+       gpaddr_t gpa;
+       uintptr_t hva;
+       size_t size;
+} area_t;
+
+typedef LIST_HEAD(, __area) area_list_t;
+
 static int nvmm_fd = -1;
 static size_t nvmm_page_size = 0;
 
 /* -------------------------------------------------------------------------- */
 
 static int
-_nvmm_area_add(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva,
+__area_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
+ size_t size)
+{
+       struct nvmm_ioc_gpa_unmap args;
+       int ret;
+
+       args.machid = mach->machid;
+       args.gpa = gpa;
+       args.size = size;
+
+       ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args);
+       if (ret == -1)
+               return -1;
+
+       ret = munmap((void *)hva, size);
+
+       return ret;
+}
+
+static int
+__area_dig_hole(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
     size_t size)
 {
-       struct nvmm_area *area;
-       void *ptr;
-       size_t i;
+       area_list_t *areas = mach->areas;
+       area_t *ent, *tmp, *nxt;
+       size_t diff;
+
+       LIST_FOREACH_SAFE(ent, areas, list, nxt) {
+               /* Case 1. */
+               if ((gpa < ent->gpa) && (gpa + size > ent->gpa)) {
+                       diff = (gpa + size) - ent->gpa;
+                       if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) {
+                               return -1;
+                       }
+                       ent->gpa  += diff;
+                       ent->hva  += diff;
+                       ent->size -= diff;
+               }
 
-       for (i = 0; i < mach->nareas; i++) {
-               if (gpa >= mach->areas[i].gpa &&
-                   gpa < mach->areas[i].gpa + mach->areas[i].size) {
-                       goto error;
+               /* Case 2. */
+               if ((gpa >= ent->gpa) && (gpa + size <= ent->gpa + ent->size)) {
+                       /* First half. */
+                       tmp = malloc(sizeof(*tmp));
+                       tmp->gpa = ent->gpa;
+                       tmp->hva = ent->hva;
+                       tmp->size = (gpa - ent->gpa);
+                       LIST_INSERT_BEFORE(ent, tmp, list);
+                       /* Second half. */
+                       ent->gpa  += tmp->size;
+                       ent->hva  += tmp->size;
+                       ent->size -= tmp->size;
+                       diff = size;
+                       if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) {
+                               return -1;
+                       }
+                       ent->gpa  += diff;
+                       ent->hva  += diff;
+                       ent->size -= diff;
                }
-               if (gpa + size > mach->areas[i].gpa &&
-                   gpa + size <= mach->areas[i].gpa + mach->areas[i].size) {
-                       goto error;
+
+               /* Case 3. */
+               if ((gpa < ent->gpa + ent->size) &&
+                   (gpa + size > ent->gpa + ent->size)) {
+                       diff = (ent->gpa + ent->size) - gpa;
+                       if (__area_unmap(mach, hva, gpa, diff) == -1) {
+                               return -1;
+                       }
+                       ent->size -= diff;
                }
-               if (gpa < mach->areas[i].gpa &&
-                   gpa + size >= mach->areas[i].gpa + mach->areas[i].size) {
-                       goto error;
+
+               /* Case 4. */
+               if ((gpa < ent->gpa + ent->size) &&
+                   (gpa + size > ent->gpa + ent->size)) {
+                       if (__area_unmap(mach, ent->hva, ent->gpa, ent->size) == -1) {
+                               return -1;
+                       }
+                       LIST_REMOVE(ent, list);
+                       free(ent);
                }
        }
 
-       ptr = realloc(mach->areas, (mach->nareas + 1) *
-           sizeof(struct nvmm_area));
-       if (ptr == NULL)
+       return 0;
+}
+
+static int
+__area_add(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size)
+{
+       area_list_t *areas = mach->areas;
+       area_t *area;
+       int ret;
+
+       area = malloc(sizeof(*area));
+       if (area == NULL)
                return -1;
-       mach->areas = ptr;
-
-       area = &mach->areas[mach->nareas++];
        area->gpa = gpa;
        area->hva = hva;
        area->size = size;
 
-       return 0;
-
-error:
-       errno = EEXIST;
-       return -1;
-}
-
-static int
-_nvmm_area_delete(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva,
-    size_t size)
-{
-       size_t i;
-
-       for (i = 0; i < mach->nareas; i++) {
-               if (gpa == mach->areas[i].gpa &&
-                   hva == mach->areas[i].hva &&
-                   size == mach->areas[i].size) {
-                       break;
-               }
-       }
-       if (i == mach->nareas) {
-               errno = ENOENT;
+       ret = __area_dig_hole(mach, hva, gpa, size);
+       if (ret == -1) {
+               free(area);
                return -1;
        }
 
-       memmove(&mach->areas[i], &mach->areas[i+1],
-           (mach->nareas - i - 1) * sizeof(struct nvmm_area));
-       mach->nareas--;
+       LIST_INSERT_HEAD(areas, area, list);
+       return 0;
+}
 
-       return 0;
+static void
+__area_remove_all(struct nvmm_machine *mach)
+{
+       area_list_t *areas = mach->areas;
+       area_t *ent;
+
+       while ((ent = LIST_FIRST(areas)) != NULL) {
+               LIST_REMOVE(ent, list);
+               free(ent);
+       }
+
+       free(areas);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -150,17 +217,26 @@
 nvmm_machine_create(struct nvmm_machine *mach)
 {
        struct nvmm_ioc_machine_create args;
+       area_list_t *areas;
        int ret;
 
        if (nvmm_init() == -1) {
                return -1;
        }
 
-       ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CREATE, &args);
-       if (ret == -1)
+       areas = calloc(1, sizeof(*areas));
+       if (areas == NULL)
                return -1;
 
+       ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_CREATE, &args);
+       if (ret == -1) {
+               free(areas);
+               return -1;
+       }
+
        memset(mach, 0, sizeof(*mach));
+       LIST_INIT(areas);
+       mach->areas = areas;
        mach->machid = args.machid;
 
        return 0;
@@ -182,7 +258,7 @@
        if (ret == -1)
                return -1;
 
-       free(mach->areas);
+       __area_remove_all(mach);
 
        return 0;
 }
@@ -351,6 +427,10 @@
                return -1;
        }
 
+       ret = __area_add(mach, hva, gpa, size);
+       if (ret == -1)
+               return -1;
+
        args.machid = mach->machid;
        args.hva = hva;
        args.gpa = gpa;
@@ -358,13 +438,9 @@
        args.flags = flags;
 
        ret = ioctl(nvmm_fd, NVMM_IOC_GPA_MAP, &args);
-       if (ret == -1)
-               return -1;
-
-       ret = _nvmm_area_add(mach, gpa, hva, size);
        if (ret == -1) {
-               nvmm_gpa_unmap(mach, hva, gpa, size);
-               return -1;
+               /* Can't recover. */
+               abort();
        }
 
        return 0;
@@ -374,28 +450,11 @@
 nvmm_gpa_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa,
     size_t size)
 {
-       struct nvmm_ioc_gpa_unmap args;
-       int ret;
-
        if (nvmm_init() == -1) {
                return -1;
        }
 
-       ret = _nvmm_area_delete(mach, gpa, hva, size);
-       if (ret == -1)
-               return -1;
-
-       args.machid = mach->machid;
-       args.gpa = gpa;
-       args.size = size;
-
-       ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, &args);
-       if (ret == -1)
-               return -1;
-
-       ret = munmap((void *)hva, size);
-
-       return ret;
+       return __area_dig_hole(mach, hva, gpa, size);
 }
 
 /*
@@ -405,22 +464,23 @@
 int
 nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva)
 {



Home | Main Index | Thread Index | Old Index