Page MenuHomeFreeBSD

D61067.1793503443.diff
No OneTemporary

Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None

D61067.1793503443.diff

diff --git a/lib/libvmmapi/aarch64/vmmapi_machdep.c b/lib/libvmmapi/aarch64/vmmapi_machdep.c
--- a/lib/libvmmapi/aarch64/vmmapi_machdep.c
+++ b/lib/libvmmapi/aarch64/vmmapi_machdep.c
@@ -44,6 +44,7 @@
};
#define VM_MD_IOCTLS \
+ VM_DISCARD_PAGES, \
VM_GET_VGIC_VERSION, \
VM_ATTACH_VGIC, \
VM_ASSERT_IRQ, \
diff --git a/lib/libvmmapi/amd64/vmmapi_machdep.c b/lib/libvmmapi/amd64/vmmapi_machdep.c
--- a/lib/libvmmapi/amd64/vmmapi_machdep.c
+++ b/lib/libvmmapi/amd64/vmmapi_machdep.c
@@ -55,6 +55,7 @@
};
#define VM_MD_IOCTLS \
+ VM_DISCARD_PAGES, \
VM_SET_SEGMENT_DESCRIPTOR, \
VM_GET_SEGMENT_DESCRIPTOR, \
VM_SET_KERNEMU_DEV, \
diff --git a/lib/libvmmapi/internal.h b/lib/libvmmapi/internal.h
--- a/lib/libvmmapi/internal.h
+++ b/lib/libvmmapi/internal.h
@@ -8,6 +8,7 @@
#define __VMMAPI_INTERNAL_H__
#include <sys/types.h>
+#include <dev/vmm/vmm_dev.h>
#include <dev/vmm/vmm_mem.h>
struct vmctx {
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -110,6 +110,9 @@
vm_ooffset_t segoff, size_t len, int prot);
int vm_munmap_memseg(struct vmctx *ctx, vm_paddr_t gpa, size_t len);
+#ifdef VM_DISCARD_PAGES
+int vm_discard_pages(struct vmctx *ctx, vm_paddr_t gpa, size_t len);
+#endif
int vm_create(const char *name);
struct vmctx *vm_open(const char *name);
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -347,6 +347,18 @@
return (error);
}
+#ifdef VM_DISCARD_PAGES
+int
+vm_discard_pages(struct vmctx *ctx, vm_paddr_t gpa, size_t len)
+{
+ struct vm_discard_pages req;
+
+ req.gpa = gpa;
+ req.len = len;
+ return (ioctl(ctx->fd, VM_DISCARD_PAGES, &req));
+}
+#endif
+
int
vm_mmap_getnext(struct vmctx *ctx, vm_paddr_t *gpa, int *segid,
vm_ooffset_t *segoff, size_t *len, int *prot, int *flags)
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -342,7 +342,10 @@
/* checkpoint */
IOCNUM_SNAPSHOT_REQ = 113,
- IOCNUM_RESTORE_TIME = 115
+ IOCNUM_RESTORE_TIME = 115,
+
+ /* memory reclamation */
+ IOCNUM_DISCARD_PAGES = 116,
};
#define VM_RUN \
@@ -361,6 +364,8 @@
_IOWR('v', IOCNUM_MMAP_GETNEXT, struct vm_memmap)
#define VM_MUNMAP_MEMSEG \
_IOW('v', IOCNUM_MUNMAP_MEMSEG, struct vm_munmap)
+#define VM_DISCARD_PAGES \
+ _IOW('v', IOCNUM_DISCARD_PAGES, struct vm_discard_pages)
#define VM_SET_REGISTER \
_IOW('v', IOCNUM_SET_REGISTER, struct vm_register)
#define VM_GET_REGISTER \
diff --git a/sys/arm64/include/vmm_dev.h b/sys/arm64/include/vmm_dev.h
--- a/sys/arm64/include/vmm_dev.h
+++ b/sys/arm64/include/vmm_dev.h
@@ -183,6 +183,7 @@
IOCNUM_MMAP_MEMSEG = 16,
IOCNUM_MMAP_GETNEXT = 17,
IOCNUM_MUNMAP_MEMSEG = 18,
+ IOCNUM_DISCARD_PAGES = 19,
/* register/state accessors */
IOCNUM_SET_REGISTER = 20,
@@ -231,6 +232,8 @@
_IOWR('v', IOCNUM_MMAP_GETNEXT, struct vm_memmap)
#define VM_MUNMAP_MEMSEG \
_IOW('v', IOCNUM_MUNMAP_MEMSEG, struct vm_munmap)
+#define VM_DISCARD_PAGES \
+ _IOW('v', IOCNUM_DISCARD_PAGES, struct vm_discard_pages)
#define VM_SET_REGISTER \
_IOW('v', IOCNUM_SET_REGISTER, struct vm_register)
#define VM_GET_REGISTER \
diff --git a/sys/dev/vmm/vmm_dev.h b/sys/dev/vmm/vmm_dev.h
--- a/sys/dev/vmm/vmm_dev.h
+++ b/sys/dev/vmm/vmm_dev.h
@@ -4,6 +4,11 @@
* Copyright (c) 2011 NetApp, Inc.
* Copyright (C) 2015 Mihai Carabas <mihai.carabas@gmail.com>
* All rights reserved.
+ * Copyright (c) 2026 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by
+ * Alchemilla Ventures Private Limited <hayzam@alchemilla.io> under
+ * sponsorship from the FreeBSD Foundation.
*/
#ifndef _DEV_VMM_DEV_H_
@@ -16,6 +21,31 @@
#include <dev/vmm/vmm_param.h>
+/*
+ * Discard backing for a range of guest RAM without removing its
+ * memory-segment mapping. The range must be aligned to the host page
+ * size, contain at most VM_DISCARD_PAGES_MAX_PAGES pages, and lie within
+ * one system-memory mapping, with no other guest mapping of the same
+ * object offsets. The VM_DISCARD_PAGES ioctl is defined by
+ * <machine/vmm_dev.h> on platforms that support it (amd64 and arm64).
+ *
+ * Reclamation is best-effort. A successful return does not guarantee
+ * that every page was freed or that the range remains nonresident.
+ * Host-held pages may be invalidated without being freed, and concurrent
+ * accesses may repopulate the range.
+ *
+ * The caller must ensure that the range is disposable and no device is
+ * using it. Discarded backing faults back in as zeroes in the absence
+ * of intervening accesses.
+ */
+struct vm_discard_pages {
+ uint64_t gpa;
+ uint64_t len;
+};
+_Static_assert(sizeof(struct vm_discard_pages) == 16, "ABI");
+
+#define VM_DISCARD_PAGES_MAX_PAGES 256
+
#ifdef _KERNEL
struct thread;
struct vm;
diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c
--- a/sys/dev/vmm/vmm_dev.c
+++ b/sys/dev/vmm/vmm_dev.c
@@ -419,6 +419,9 @@
#endif /* __amd64__ */
VMMDEV_IOCTL(VM_GET_MEMSEG, VMMDEV_IOCTL_SLOCK_MEMSEGS),
VMMDEV_IOCTL(VM_MMAP_GETNEXT, VMMDEV_IOCTL_SLOCK_MEMSEGS),
+#ifdef VM_DISCARD_PAGES
+ VMMDEV_IOCTL(VM_DISCARD_PAGES, VMMDEV_IOCTL_SLOCK_MEMSEGS),
+#endif
VMMDEV_IOCTL(VM_SUSPEND_CPU, VMMDEV_IOCTL_MAYBE_ALLOC_VCPU),
VMMDEV_IOCTL(VM_RESUME_CPU, VMMDEV_IOCTL_MAYBE_ALLOC_VCPU),
@@ -557,6 +560,16 @@
error = vm_munmap_memseg(sc->vm, mu->gpa, mu->len);
break;
}
+#ifdef VM_DISCARD_PAGES
+ case VM_DISCARD_PAGES: {
+ struct vm_discard_pages *discard;
+
+ discard = (struct vm_discard_pages *)data;
+ error = vm_mem_discard_pages(sc->vm, discard->gpa,
+ discard->len);
+ break;
+ }
+#endif
#ifdef __amd64__
#ifdef COMPAT_FREEBSD12
case VM_ALLOC_MEMSEG_12:
diff --git a/sys/dev/vmm/vmm_mem.h b/sys/dev/vmm/vmm_mem.h
--- a/sys/dev/vmm/vmm_mem.h
+++ b/sys/dev/vmm/vmm_mem.h
@@ -102,6 +102,8 @@
void vm_gpa_release(void *cookie);
bool vm_mem_allocated(struct vcpu *vcpu, vm_paddr_t gpa);
+int vm_mem_discard_pages(struct vm *vm, vm_paddr_t gpa, size_t len);
+
int vm_gla2gpa_nofault(struct vcpu *vcpu, struct vm_guest_paging *paging,
uint64_t gla, int prot, uint64_t *gpa, int *is_fault);
diff --git a/sys/dev/vmm/vmm_mem.c b/sys/dev/vmm/vmm_mem.c
--- a/sys/dev/vmm/vmm_mem.c
+++ b/sys/dev/vmm/vmm_mem.c
@@ -3,11 +3,17 @@
*
* Copyright (c) 2011 NetApp, Inc.
* All rights reserved.
+ * Copyright (c) 2026 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by
+ * Alchemilla Ventures Private Limited <hayzam@alchemilla.io> under
+ * sponsorship from the FreeBSD Foundation.
*/
#include <sys/types.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/rwlock.h>
#include <sys/sx.h>
#include <sys/systm.h>
@@ -424,6 +430,96 @@
return (maxaddr);
}
+#ifdef VM_DISCARD_PAGES
+/*
+ * Find the system-memory mapping that contains all of [gpa, gpa + len) and
+ * the object offset of gpa. The range must be page-aligned and contain at
+ * most maxpages pages.
+ */
+static int
+vm_mem_find_sysmem(struct vm *vm, vm_paddr_t gpa, size_t len,
+ size_t maxpages, struct vm_mem_map **mapp, vm_ooffset_t *offp)
+{
+ struct vm_mem *mem;
+ struct vm_mem_map *mm;
+ struct vm_mem_seg *seg;
+ vm_ooffset_t off;
+ int i;
+
+ vm_assert_memseg_locked(vm);
+
+ if (len == 0 || ((gpa | len) & PAGE_MASK) != 0 ||
+ len / PAGE_SIZE > maxpages)
+ return (EINVAL);
+
+ mem = vm_mem(vm);
+ for (i = 0; i < VM_MAX_MEMMAPS; i++) {
+ mm = &mem->mem_maps[i];
+ if (mm->len != 0 && gpa >= mm->gpa &&
+ gpa - mm->gpa < mm->len &&
+ len <= mm->len - (gpa - mm->gpa))
+ break;
+ }
+ if (i == VM_MAX_MEMMAPS)
+ return (EFAULT);
+
+ seg = &mem->mem_segs[mm->segid];
+ if (!seg->sysmem)
+ return (EOPNOTSUPP);
+ KASSERT(seg->object != NULL && seg->object->type == OBJT_SWAP &&
+ (seg->object->flags & OBJ_UNMANAGED) == 0,
+ ("%s: invalid system memory object", __func__));
+
+ off = mm->segoff + (gpa - mm->gpa);
+ KASSERT(off >= 0 && (uint64_t)off <= seg->len &&
+ len <= seg->len - (uint64_t)off,
+ ("%s: invalid system memory range", __func__));
+ *mapp = mm;
+ *offp = off;
+ return (0);
+}
+
+int
+vm_mem_discard_pages(struct vm *vm, vm_paddr_t gpa, size_t len)
+{
+ struct vm_mem *mem;
+ struct vm_mem_map *map, *mm;
+ vm_object_t obj;
+ vm_ooffset_t off, end;
+ int error, i;
+
+ error = vm_mem_find_sysmem(vm, gpa, len, VM_DISCARD_PAGES_MAX_PAGES,
+ &map, &off);
+ if (error != 0)
+ return (error);
+ if ((map->flags & VM_MEMMAP_F_WIRED) != 0)
+ return (EOPNOTSUPP);
+#ifdef VM_MEMMAP_F_IOMMU
+ if ((map->flags & VM_MEMMAP_F_IOMMU) != 0)
+ return (EOPNOTSUPP);
+#endif
+
+ /* Removal affects every mapping of these object offsets. */
+ mem = vm_mem(vm);
+ obj = mem->mem_segs[map->segid].object;
+ end = off + len;
+ for (i = 0; i < VM_MAX_MEMMAPS; i++) {
+ mm = &mem->mem_maps[i];
+ if (mm == map || mm->len == 0 ||
+ mem->mem_segs[mm->segid].object != obj)
+ continue;
+ if (mm->segoff < end && off < mm->segoff + mm->len)
+ return (EOPNOTSUPP);
+ }
+
+ VM_OBJECT_WLOCK(obj);
+ vm_object_page_remove(obj, OFF_TO_IDX(off), OFF_TO_IDX(end), 0);
+ VM_OBJECT_WUNLOCK(obj);
+
+ return (0);
+}
+#endif
+
static void *
_vm_gpa_hold(struct vm *vm, vm_paddr_t gpa, size_t len, int reqprot,
void **cookie)

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 1, 3:24 AM (18 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41273748
Default Alt Text
D61067.1793503443.diff (9 KB)

Event Timeline