Page MenuHomeFreeBSD

D58851.id184202.diff
No OneTemporary

D58851.id184202.diff

diff --git a/sys/dev/vmgp_test/vmgp_test.h b/sys/dev/vmgp_test/vmgp_test.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/vmgp_test/vmgp_test.h
@@ -0,0 +1,23 @@
+/*
+ *
+ */
+
+#ifndef __SYS_DEV_VMGP_TEST_H__
+#define __SYS_DEV_VMGP_TEST_H__
+
+#include <sys/types.h>
+#include <sys/ioccom.h>
+
+struct vmgp_test_param {
+ int fd;
+ int prot;
+ off_t offset;
+ off_t length;
+ int error;
+ int mach_error;
+ int pages;
+};
+
+#define VMGPIOCTEST _IOWR('v', 1, struct vmgp_test_param)
+
+#endif
diff --git a/sys/dev/vmgp_test/vmgp_test.c b/sys/dev/vmgp_test/vmgp_test.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/vmgp_test/vmgp_test.c
@@ -0,0 +1,129 @@
+/*
+ *
+ */
+
+#include <sys/systm.h>
+#include <sys/capsicum.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rwlock.h>
+#include <sys/stat.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+
+#include <dev/vmgp_test/vmgp_test.h>
+
+static struct cdev *vmgp_test_cdev;
+MALLOC_DEFINE(M_VMGP_TEST, "vmgp_test", "vmgp_test");
+
+static void
+vmgp_do_test(struct thread *td, struct vmgp_test_param *p)
+{
+ struct vnode *vp;
+ vm_object_t obj;
+ vm_page_t *ma;
+ unsigned npages;
+
+ if (p->prot != VM_PROT_READ && p->prot != VM_PROT_WRITE) {
+ p->error = EINVAL;
+ return;
+ }
+ npages = atop(round_page(p->offset + p->length) - trunc_page(p->offset));
+ ma = mallocarray(npages, sizeof(vm_page_t), M_VMGP_TEST, M_WAITOK);
+ p->error = fgetvp(td, p->fd, &cap_read_rights, &vp);
+ if (p->error != 0)
+ goto out1;
+
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ obj = vp->v_object;
+ if (obj == NULL) {
+ p->error = EINVAL;
+ goto out2;
+ }
+ VM_OBJECT_WLOCK(obj);
+ p->mach_error = vm_object_take_pages_for_io(obj, p->prot, ma, npages,
+ p->offset, p->offset + p->length, &p->pages);
+ if (p->mach_error != KERN_SUCCESS)
+ goto out3;
+ if (p->pages > 0) {
+ vm_object_put_pages_after_io(obj, p->prot, ma, p->pages,
+ p->offset, p->offset + p->length);
+ }
+out3:
+ VM_OBJECT_WUNLOCK(obj);
+out2:
+ vput(vp);
+out1:
+ free(ma, M_VMGP_TEST);
+}
+
+static int
+vmgp_test_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+ struct thread *td)
+{
+ switch (cmd) {
+ case VMGPIOCTEST:
+ vmgp_do_test(td, (struct vmgp_test_param *)data);
+ return (0);
+
+ default:
+ return (ENOTTY);
+ }
+}
+
+static struct cdevsw vmgp_test_cdevsw = {
+ .d_version = D_VERSION,
+ .d_flags = 0,
+ .d_ioctl = vmgp_test_ioctl,
+ .d_name = "vmgp_test",
+};
+
+static int
+vmgp_test_modevent(module_t mod __unused, int type, void *data __unused)
+{
+ struct make_dev_args mda;
+ int error;
+
+ error = 0;
+ switch (type) {
+ case MOD_LOAD:
+ make_dev_args_init(&mda);
+ mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
+ mda.mda_devsw = &vmgp_test_cdevsw;
+ mda.mda_uid = UID_ROOT;
+ mda.mda_gid = GID_GAMES;
+ mda.mda_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
+ S_IROTH | S_IWOTH;
+
+ error = make_dev_s(&mda, &vmgp_test_cdev, "vmgp_test");
+ if (error != 0) {
+ printf("cannot create vmgp_test dev err %d\n", error);
+ break;
+ }
+ if (bootverbose)
+ printf("vmgp_test\n");
+ break;
+
+ case MOD_UNLOAD:
+ destroy_dev(vmgp_test_cdev);
+ break;
+
+ case MOD_SHUTDOWN:
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ }
+
+ return (error);
+}
+
+DEV_MODULE(vmgp_test, vmgp_test_modevent, NULL);
+MODULE_VERSION(vmgp_test, 1);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -427,6 +427,7 @@
videomode \
vkbd \
${_vmd} \
+ vmgp_test \
${_vmm} \
${_vmware} \
vr \
diff --git a/sys/modules/vmgp_test/Makefile b/sys/modules/vmgp_test/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/vmgp_test/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/dev/vmgp_test
+
+KMOD= vmgp_test
+SRCS= vmgp_test.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h
--- a/sys/vm/vm_object.h
+++ b/sys/vm/vm_object.h
@@ -391,6 +391,11 @@
vm_size_t length, uint8_t queue);
struct vnode *vm_object_vnode(vm_object_t object);
bool vm_object_is_active(vm_object_t obj);
+int vm_object_take_pages_for_io(vm_object_t obj, vm_prot_t prot,
+ vm_page_t ma[], int total_ma_len, vm_ooffset_t start, vm_ooffset_t end,
+ int *ma_len);
+void vm_object_put_pages_after_io(vm_object_t obj, vm_prot_t prot,
+ vm_page_t ma[], int ma_len, vm_ooffset_t start, vm_ooffset_t wend);
#endif /* _KERNEL */
#endif /* _VM_OBJECT_ */
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -2512,6 +2512,145 @@
return (obj->ref_count > atomic_load_int(&obj->shadow_count));
}
+static void
+vm_object_unbusy_pages_after_io(vm_object_t obj, vm_prot_t prot, vm_page_t ma[],
+ int ma_len)
+{
+ int j;
+
+ VM_OBJECT_ASSERT_WLOCKED(obj);
+ MPASS((obj->flags & OBJ_UNMANAGED) == 0);
+ MPASS(prot == VM_PROT_READ || prot == VM_PROT_WRITE);
+#ifdef INVARIANTS
+ for (j = 1; j < ma_len; j++) {
+ MPASS(ma[j]->object == obj);
+ MPASS(ma[j]->pindex == ma[0]->pindex + j);
+ }
+#endif
+
+ if (prot == VM_PROT_READ) {
+ for (j = 0; j < ma_len; j++)
+ vm_page_sunbusy(ma[j]);
+ } else {
+ for (j = 0; j < ma_len; j++)
+ vm_page_xunbusy(ma[j]);
+ }
+}
+
+static void
+vm_object_reference_pages(vm_page_t ma[], int ma_len)
+{
+ int j;
+
+ for (j = 0; j < ma_len; j++)
+ vm_page_reference(ma[j]);
+}
+
+void
+vm_object_put_pages_after_io(vm_object_t obj, vm_prot_t prot, vm_page_t ma[],
+ int ma_len, vm_ooffset_t start, vm_ooffset_t wend)
+{
+ int d_len, i;
+
+ VM_OBJECT_ASSERT_WLOCKED(obj);
+ MPASS(ma_len > 0);
+ MPASS(ma[0]->object == obj);
+ MPASS(ma[0]->pindex == OFF_TO_IDX(trunc_page(start)));
+ MPASS(ma[0]->pindex + ma_len >= OFF_TO_IDX(round_page(wend)));
+
+ if (prot == VM_PROT_WRITE) {
+ d_len = atop(MIN(round_page(wend), ptoa(obj->size)) -
+ trunc_page(start));
+ MPASS(d_len <= ma_len);
+ for (i = 0; i < d_len; i++)
+ vm_page_dirty(ma[i]);
+ }
+ vm_object_unbusy_pages_after_io(obj, prot, ma, ma_len);
+}
+
+/*
+ * vm_object_take_pages_for_io(): prepare the range of the object
+ * pages from start to end inclusive for io. Object must be
+ * write-locked. If the object is backed by a vnode, the vnode must
+ * be locked.
+ *
+ * The run of the prepared pages is pointed to by the ma[] array,
+ * which length is passed as total_ma_len. The length of the filled
+ * part of the array is returned in *ma_lenp.
+ *
+ * If prot == VM_PROT_READ, the pages are sbusy and write mappings of
+ * them are invalidated, which ensures that pages do not change
+ * identity and cannot be modified by a parallel write.
+ *
+ * If prot == VM_PROT_WRITE, the pages are xbusy and all mappings of
+ * them are invalidated, which allows to write to the pages as needed.
+ *
+ * After the io operation is done, call vm_object_put_pages() to
+ * unbusy the pages. If the prot == VM_PROT_WRITE, then pages from
+ * the beginning of the run to wend are dirtied. The wend offset
+ * might be less than the end offset passed to take_pages(), which is
+ * useful if the write was short.
+ */
+int
+vm_object_take_pages_for_io(vm_object_t obj, vm_prot_t prot, vm_page_t ma[],
+ int total_ma_len, vm_ooffset_t start, vm_ooffset_t end, int *ma_lenp)
+{
+ vm_page_t m;
+ struct pctrie_iter pages;
+ vm_pindex_t pi, ma_len;
+ int error, i;
+
+ VM_OBJECT_ASSERT_WLOCKED(obj);
+ MPASS((obj->flags & OBJ_UNMANAGED) == 0);
+ MPASS(prot == VM_PROT_READ || prot == VM_PROT_WRITE);
+ if (obj->type == OBJT_VNODE)
+ ASSERT_VOP_LOCKED(obj->handle, "vm_object_busy_pages");
+
+ end = MIN(round_page(end), ptoa(obj->size));
+ start = trunc_page(start);
+ ma_len = atop(end - start);
+ MPASS(total_ma_len >= ma_len);
+
+ vm_object_pip_add(obj, 1);
+
+again:
+ vm_page_iter_init(&pages, obj);
+ for (i = 0, pi = atop(start), m = vm_radix_iter_lookup(&pages, pi);
+ i < ma_len; i++, pi++, m = vm_radix_iter_next(&pages)) {
+ if (m == NULL || !vm_page_all_valid(m)) {
+ vm_object_reference_pages(ma, i);
+ vm_object_unbusy_pages_after_io(obj, prot, ma, i);
+ error = vm_page_grab_valid_iter(&m, obj, pi,
+ VM_ALLOC_NOBUSY, &pages);
+ if (error != KERN_SUCCESS) {
+ vm_object_pip_wakeup(obj);
+ return (error);
+ }
+ vm_page_reference(m);
+ goto again;
+ }
+ if (vm_page_busy_acquire(m, VM_ALLOC_WAITFAIL |
+ (prot == VM_PROT_READ ? VM_ALLOC_SBUSY : 0))) {
+ ma[i] = m;
+ continue;
+ }
+ vm_object_reference_pages(ma, i);
+ vm_object_unbusy_pages_after_io(obj, prot, ma, i);
+ goto again;
+ }
+
+ vm_object_pip_wakeup(obj);
+
+ for (i = 0; i < ma_len; i++) {
+ if (prot == VM_PROT_READ)
+ pmap_remove_write(ma[i]);
+ else
+ pmap_remove_all(ma[i]);
+ }
+ *ma_lenp = ma_len;
+ return (KERN_SUCCESS);
+}
+
static int
vm_object_list_handler(struct sysctl_req *req, bool swap_only)
{

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 21, 7:48 AM (1 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36921747
Default Alt Text
D58851.id184202.diff (8 KB)

Event Timeline