Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F176851984
D61067.1793506383.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None
D61067.1793506383.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 1, 4:13 AM (19 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41273748
Default Alt Text
D61067.1793506383.diff (9 KB)
Attached To
Mode
D61067: vmm: Add a shared guest-memory discard interface
Attached
Detach File
Event Timeline