aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2022-02-07 22:11:10 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2022-04-29 23:08:17 +0000
commitffd150099ca0fbbecb62814e73dff9388fbe3b87 (patch)
tree849bcd2bbc119fcb6f639ef0871d23397927601b
parent345739ccaccce822a24a5ef9121accce541ed6de (diff)
downloadsrc-ffd150099ca0fbbecb62814e73dff9388fbe3b87.tar.gz
src-ffd150099ca0fbbecb62814e73dff9388fbe3b87.zip
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 (cherry picked from commit 64269786170ffd8e3348edea0fc5f5b09b79391e)
-rw-r--r--lib/libvmmapi/vmmapi.c41
-rw-r--r--sys/amd64/include/vmm_dev.h1
-rw-r--r--sys/amd64/vmm/vmm_dev.c29
-rw-r--r--sys/amd64/vmm/vmm_stat.c23
-rw-r--r--sys/amd64/vmm/vmm_stat.h6
5 files changed, 81 insertions, 19 deletions
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index 0543c92f4300..03c2538e226d 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