The branch main has been updated by jhb:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=64269786170ffd8e3348edea0fc5f5b09b79391e

commit 64269786170ffd8e3348edea0fc5f5b09b79391e
Author:     John Baldwin <[email protected]>
AuthorDate: 2022-02-07 22:11:10 +0000
Commit:     John Baldwin <[email protected]>
CommitDate: 2022-02-07 22:11:10 +0000

    Extend the VMM stats interface to support a dynamic count of statistics.
    
    - Add a starting index to 'struct vmstats' and change the
      VM_STATS ioctl to fetch the 64 stats starting at that index.
      A compat shim for <= 13 continues to fetch only the first 64
      stats.
    
    - Extend vm_get_stats() in libvmmapi to use a loop and a static
      thread local buffer which grows to hold the stats needed.
    
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D27463
---
 lib/libvmmapi/vmmapi.c      | 41 +++++++++++++++++++++++++++++++++--------
 sys/amd64/include/vmm_dev.h |  1 +
 sys/amd64/vmm/vmm_dev.c     | 29 +++++++++++++++++++++++++++--
 sys/amd64/vmm/vmm_stat.c    | 23 ++++++++++++++++++-----
 sys/amd64/vmm/vmm_stat.h    |  6 ++----
 5 files changed, 81 insertions(+), 19 deletions(-)

diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index a2d26b1b33b9..0291e4a10c33 100644
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -1066,19 +1066,44 @@ uint64_t *
 vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv,
             int *ret_entries)
 {
-       int error;
-
-       static struct vm_stats vmstats;
-
+       static _Thread_local uint64_t *stats_buf;
+       static _Thread_local u_int stats_count;
+       uint64_t *new_stats;
+       struct vm_stats vmstats;
+       u_int count, index;
+       bool have_stats;
+
+       have_stats = false;
        vmstats.cpuid = vcpu;
+       count = 0;
+       for (index = 0;; index += nitems(vmstats.statbuf)) {
+               vmstats.index = index;
+               if (ioctl(ctx->fd, VM_STATS, &vmstats) != 0)
+                       break;
+               if (stats_count < index + vmstats.num_entries) {
+                       new_stats = realloc(stats_buf,
+                           (index + vmstats.num_entries) * sizeof(uint64_t));
+                       if (new_stats == NULL) {
+                               errno = ENOMEM;
+                               return (NULL);
+                       }
+                       stats_count = index + vmstats.num_entries;
+                       stats_buf = new_stats;
+               }
+               memcpy(stats_buf + index, vmstats.statbuf,
+                   vmstats.num_entries * sizeof(uint64_t));
+               count += vmstats.num_entries;
+               have_stats = true;
 
-       error = ioctl(ctx->fd, VM_STATS, &vmstats);
-       if (error == 0) {
+               if (vmstats.num_entries != nitems(vmstats.statbuf))
+                       break;
+       }
+       if (have_stats) {
                if (ret_entries)
-                       *ret_entries = vmstats.num_entries;
+                       *ret_entries = count;
                if (ret_tv)
                        *ret_tv = vmstats.tv;
-               return (vmstats.statbuf);
+               return (stats_buf);
        } else
                return (NULL);
 }
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
index a048e05d4b7c..9ed8f32302ae 100644
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -174,6 +174,7 @@ struct vm_nmi {
 #define        MAX_VM_STATS    64
 struct vm_stats {
        int             cpuid;                          /* in */
+       int             index;                          /* in */
        int             num_entries;                    /* out */
        struct timeval  tv;
        uint64_t        statbuf[MAX_VM_STATS];
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index 2ce9470cf6dd..a83c74219fee 100644
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -69,6 +69,18 @@ __FBSDID("$FreeBSD$");
 #include "io/vhpet.h"
 #include "io/vrtc.h"
 
+#ifdef COMPAT_FREEBSD13
+struct vm_stats_old {
+       int             cpuid;                          /* in */
+       int             num_entries;                    /* out */
+       struct timeval  tv;
+       uint64_t        statbuf[MAX_VM_STATS];
+};
+
+#define        VM_STATS_OLD \
+       _IOWR('v', IOCNUM_VM_STATS, struct vm_stats_old)
+#endif
+
 struct devmem_softc {
        int     segid;
        char    *name;
@@ -376,6 +388,9 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, 
int fflag,
        struct vm_pptdev_msi *pptmsi;
        struct vm_pptdev_msix *pptmsix;
        struct vm_nmi *vmnmi;
+#ifdef COMPAT_FREEBSD13
+       struct vm_stats_old *vmstats_old;
+#endif
        struct vm_stats *vmstats;
        struct vm_stat_desc *statdesc;
        struct vm_x2apic *x2apic;
@@ -501,11 +516,21 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, 
int fflag,
                                        statdesc->desc, sizeof(statdesc->desc));
                break;
        }
+#ifdef COMPAT_FREEBSD13
+       case VM_STATS_OLD:
+               vmstats_old = (struct vm_stats_old *)data;
+               getmicrotime(&vmstats_old->tv);
+               error = vmm_stat_copy(sc->vm, vmstats_old->cpuid, 0,
+                                     nitems(vmstats_old->statbuf),
+                                     &vmstats_old->num_entries,
+                                     vmstats_old->statbuf);
+               break;
+#endif
        case VM_STATS: {
-               CTASSERT(MAX_VM_STATS >= MAX_VMM_STAT_ELEMS);
                vmstats = (struct vm_stats *)data;
                getmicrotime(&vmstats->tv);
-               error = vmm_stat_copy(sc->vm, vmstats->cpuid,
+               error = vmm_stat_copy(sc->vm, vmstats->cpuid, vmstats->index,
+                                     nitems(vmstats->statbuf),
                                      &vmstats->num_entries, vmstats->statbuf);
                break;
        }
diff --git a/sys/amd64/vmm/vmm_stat.c b/sys/amd64/vmm/vmm_stat.c
index 89133d4b3868..497db4452f3b 100644
--- a/sys/amd64/vmm/vmm_stat.c
+++ b/sys/amd64/vmm/vmm_stat.c
@@ -82,15 +82,29 @@ vmm_stat_register(void *arg)
 }
 
 int
-vmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf)
+vmm_stat_copy(struct vm *vm, int vcpu, int index, int count, int *num_stats,
+    uint64_t *buf)
 {
        struct vmm_stat_type *vst;
        uint64_t *stats;
-       int i;
+       int i, tocopy;
 
        if (vcpu < 0 || vcpu >= vm_get_maxcpus(vm))
                return (EINVAL);
 
+       if (index < 0 || count < 0)
+               return (EINVAL);
+
+       if (index > vst_num_elems)
+               return (ENOENT);
+
+       if (index == vst_num_elems) {
+               *num_stats = 0;
+               return (0);
+       }
+
+       tocopy = min(vst_num_elems - index, count);
+
        /* Let stats functions update their counters */
        for (i = 0; i < vst_num_types; i++) {
                vst = vsttab[i];
@@ -100,9 +114,8 @@ vmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, 
uint64_t *buf)
 
        /* Copy over the stats */
        stats = vcpu_stats(vm, vcpu);
-       for (i = 0; i < vst_num_elems; i++)
-               buf[i] = stats[i];
-       *num_stats = vst_num_elems;
+       memcpy(buf, stats + index, tocopy * sizeof(stats[0]));
+       *num_stats = tocopy;
        return (0);
 }
 
diff --git a/sys/amd64/vmm/vmm_stat.h b/sys/amd64/vmm/vmm_stat.h
index f97743e77fe7..0e9c8db8429d 100644
--- a/sys/amd64/vmm/vmm_stat.h
+++ b/sys/amd64/vmm/vmm_stat.h
@@ -87,10 +87,8 @@ void *vmm_stat_alloc(void);
 void   vmm_stat_init(void *vp);
 void   vmm_stat_free(void *vp);
 
-/*
- * 'buf' should be at least fit 'MAX_VMM_STAT_TYPES' entries
- */
-int    vmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf);
+int    vmm_stat_copy(struct vm *vm, int vcpu, int index, int count,
+           int *num_stats, uint64_t *buf);
 int    vmm_stat_desc_copy(int index, char *buf, int buflen);
 
 static void __inline

Reply via email to