tech@,

tl;dr: standardize vmd/vmm/vmctl on counting memory in bytes at all
times instead of a mix of MiB and bytes.

There's some design friction between vmd(8)/vmctl(8) and vmm(4).

For instance, the user-facing code deals in MiB, but internally a vm's
memory ranges are defined in terms of bytes...but only after being
converted at vm launch.

Consequently, at different points in vmd's lifecycle, the same struct
member for storing a vm's requested memory size contains a value in
bytes OR in MiB meaning any code accessing the value needs to be
contextually aware of if/when the value must be scaled.

Given we dropped vmm(4) on i386 awhile ago, let's make use of 64-bit
values! Plus this helps my other queued up changes simpler as they can
avoid confusing scaling at points.

There *is* some existing code duplication between vmd/vmctl related to
parsing user provided memory values via scan_scaled(3), but I'm not
looking to consolidate that now.

If you're going to test, you'll need to build the kernel and either copy
or link the patched vmmvar.h into /usr/include/machine/ before building
vmd(8)/vmctl(8). (Don't forget to actually boot the kernel.)

Otherwise, looking for ok's so I can continue squashing a few bugs in
vmd that will be easier/cleaner to fix once this goes in.

While the diff looks long-ish, it shouldn't require deep vmm/vmd
knowledge to help review ;)

-dv


diff refs/heads/master refs/heads/vmd-bytes
blob - 765fc19bca559dbfd83cd14c48dee94f86c4b3cc
blob + 699798c1bbffafe7074fea43755ef7e20f073a90
--- sys/arch/amd64/amd64/vmm.c
+++ sys/arch/amd64/amd64/vmm.c
@@ -1575,7 +1575,7 @@ vm_create_check_mem_ranges(struct vm_create_params *vc
 {
        size_t i, memsize = 0;
        struct vm_mem_range *vmr, *pvmr;
-       const paddr_t maxgpa = (uint64_t)VMM_MAX_VM_MEM_SIZE * 1024 * 1024;
+       const paddr_t maxgpa = VMM_MAX_VM_MEM_SIZE;

        if (vcp->vcp_nmemranges == 0 ||
            vcp->vcp_nmemranges > VMM_MAX_MEM_RANGES)
blob - 94bb172832d4c2847b1e83ebb9cc05538db6ac80
blob + 012a023943b9fbc70339166889070ff0b4619046
--- sys/arch/amd64/include/vmmvar.h
+++ sys/arch/amd64/include/vmmvar.h
@@ -31,7 +31,7 @@
 #define VMM_MAX_KERNEL_PATH    128
 #define VMM_MAX_VCPUS          512
 #define VMM_MAX_VCPUS_PER_VM   64
-#define VMM_MAX_VM_MEM_SIZE    32768
+#define VMM_MAX_VM_MEM_SIZE    32L * 1024 * 1024 * 1024        /* 32 GiB */
 #define VMM_MAX_NICS_PER_VM    4

 #define VMM_PCI_MMIO_BAR_BASE  0xF0000000ULL
blob - 0f7e4329a00d54a64fe41e1fb2bd2afcbaa9d68a
blob + 01d466f613621410803646cf3db49780f6ab9166
--- usr.sbin/vmctl/main.c
+++ usr.sbin/vmctl/main.c
@@ -404,24 +404,39 @@ parse_network(struct parse_result *res, char *word)
 int
 parse_size(struct parse_result *res, char *word)
 {
-       long long val = 0;
+       char             result[FMT_SCALED_STRSIZE];
+       long long        val = 0;

        if (word != NULL) {
                if (scan_scaled(word, &val) != 0) {
-                       warn("invalid size: %s", word);
+                       warn("invalid memory size: %s", word);
                        return (-1);
                }
        }

        if (val < (1024 * 1024)) {
-               warnx("size must be at least one megabyte");
+               warnx("memory size must be at least 1M");
                return (-1);
-       } else
-               res->size = val / 1024 / 1024;
+       }

-       if ((res->size * 1024 * 1024) != val)
-               warnx("size rounded to %lld megabytes", res->size);
+       if (val > VMM_MAX_VM_MEM_SIZE) {
+               if (fmt_scaled(val, result) == 0)
+                       warnx("memory size too large (limit is %s)", result);
+               else
+                       warnx("memory size too large");
+               return (-1);
+       }

+       /* Round down to the megabyte. */
+       res->size = (val / (1024 * 1024)) * (1024 * 1024);
+
+       if (res->size != (size_t) val) {
+               if (fmt_scaled(res->size, result) == 0)
+                       warnx("memory size rounded to %s", result);
+               else
+                       warnx("memory size rounded to %zu bytes", res->size);
+       }
+
        return (0);
 }

blob - 4c0b62fc6e16adbeb5cf951dcafbaebdbc356da8
blob + 15e6dd89ec15fa2501dcf6539c9ae9d90879ba56
--- usr.sbin/vmctl/vmctl.c
+++ usr.sbin/vmctl/vmctl.c
@@ -73,7 +73,7 @@ struct imsgbuf *ibuf;
  *  ENOMEM if a memory allocation failure occurred.
  */
 int
-vm_start(uint32_t start_id, const char *name, int memsize, int nnics,
+vm_start(uint32_t start_id, const char *name, size_t memsize, int nnics,
     char **nics, int ndisks, char **disks, int *disktypes, char *kernel,
     char *iso, char *instance, unsigned int bootdevice)
 {
@@ -122,7 +122,7 @@ vm_start(uint32_t start_id, const char *name, int mems

        /*
         * XXX: vmd(8) fills in the actual memory ranges. vmctl(8)
-        * just passes in the actual memory size in MB here.
+        * just passes in the actual memory size here.
         */
        vcp->vcp_nmemranges = 1;
        vcp->vcp_memranges[0].vmr_size = memsize;
blob - 4fd2b787debb3a0e6bea0eced9508fcce3a09991
blob + 7d44c88f8fac106508807edcad393334d806edf2
--- usr.sbin/vmctl/vmctl.h
+++ usr.sbin/vmctl/vmctl.h
@@ -48,7 +48,7 @@ struct parse_result {
        char                    *name;
        char                    *path;
        char                    *isopath;
-       long long                size;
+       size_t                   size;
        int                      nifs;
        char                    **nets;
        int                      nnets;
@@ -93,7 +93,7 @@ int    open_imagefile(int, const char *, int,
 int     create_imagefile(int, const char *, const char *, long, const char **);
 int     create_raw_imagefile(const char *, long);
 int     create_qc2_imagefile(const char *, const char *, long);
-int     vm_start(uint32_t, const char *, int, int, char **, int,
+int     vm_start(uint32_t, const char *, size_t, int, char **, int,
            char **, int *, char *, char *, char *, unsigned int);
 int     vm_start_complete(struct imsg *, int *, int);
 void    terminate_vm(uint32_t, const char *, unsigned int);
blob - ebebbf24750b075414dc872d1290a0bf9c20d52b
blob + ba86d1c7fe05f77247ee34c5323e8600e1fb0a6b
--- usr.sbin/vmd/parse.y
+++ usr.sbin/vmd/parse.y
@@ -1248,26 +1248,42 @@ symget(const char *nam)
 ssize_t
 parse_size(char *word, int64_t val)
 {
+       char             result[FMT_SCALED_STRSIZE];
        ssize_t          size;
        long long        res;

        if (word != NULL) {
                if (scan_scaled(word, &res) != 0) {
-                       log_warn("invalid size: %s", word);
+                       log_warn("invalid memory size: %s", word);
                        return (-1);
                }
                val = (int64_t)res;
        }

        if (val < (1024 * 1024)) {
-               log_warnx("size must be at least one megabyte");
+               log_warnx("memory size must be at least 1M");
                return (-1);
-       } else
-               size = val / 1024 / 1024;
+       }

-       if ((size * 1024 * 1024) != val)
-               log_warnx("size rounded to %zd megabytes", size);
+       if (val > VMM_MAX_VM_MEM_SIZE) {
+               if (fmt_scaled(val, result) == 0)
+                       log_warnx("memory size too large (limit is %s)",
+                           result);
+               else
+                       log_warnx("memory size too large");
+               return (-1);
+       }

+       /* Round down to the megabyte. */
+       size = (val / (1024 * 1024)) * (1024 * 1024);
+
+       if (size != val) {
+               if (fmt_scaled(size, result) == 0)
+                       log_warnx("memory size rounded to %s", result);
+               else
+                       log_warnx("memory size rounded to %zd bytes", size);
+       }
+
        return ((ssize_t)size);
 }

blob - 55d938ed1d118f204dc19492148fc171080c6961
blob + f59c2a834078c2e47a5b4d71de23f2b22ff2c15c
--- usr.sbin/vmd/vm.c
+++ usr.sbin/vmd/vm.c
@@ -871,15 +871,13 @@ vcpu_reset(uint32_t vmid, uint32_t vcpu_id, struct vcp
 void
 create_memory_map(struct vm_create_params *vcp)
 {
-       size_t len, mem_bytes, mem_mb;
+       size_t len, mem_bytes;

-       mem_mb = vcp->vcp_memranges[0].vmr_size;
+       mem_bytes = vcp->vcp_memranges[0].vmr_size;
        vcp->vcp_nmemranges = 0;
-       if (mem_mb < 1 || mem_mb > VMM_MAX_VM_MEM_SIZE)
+       if (mem_bytes < 1 || mem_bytes > VMM_MAX_VM_MEM_SIZE)
                return;

-       mem_bytes = mem_mb * 1024 * 1024;
-
        /* First memory region: 0 - LOWMEM_KB (DOS low mem) */
        len = LOWMEM_KB * 1024;
        vcp->vcp_memranges[0].vmr_gpa = 0x0;
blob - 5f33b64831792420fd9231f0b76b11f31ad6b31c
blob + 4d2a5a4aecf78957b3b035c1a5b5e9449f6fe769
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -56,7 +56,7 @@
 #define MAX_TAP                        256
 #define NR_BACKLOG             5
 #define VMD_SWITCH_TYPE                "bridge"
-#define VM_DEFAULT_MEMORY      512
+#define VM_DEFAULT_MEMORY      512 * 1024 * 1024       /* 512 MiB */

 #define VMD_DEFAULT_STAGGERED_START_DELAY 30

Reply via email to