Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167244836
D58851.id184202.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D58851.id184202.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58851: vm_object_take_pages_for_io(9)
Attached
Detach File
Event Timeline
Log In to Comment