/* * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Hyra nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #define VN_TIMEOUT_USEC 200000 #define pr_trace(fmt, ...) kprintf("vm_vnode: " fmt, ##__VA_ARGS__) #define pr_error(...) pr_trace(__VA_ARGS__) /* Debug print helper */ #if defined(PR_DEBUG) #define pr_debug(...) pr_trace(__VA_ARGS__) #else #define pr_debug(...) __nothing #endif /* PR_DEBUG */ const struct vm_pagerops vm_vnops; /* * Perform read/write operation on vnode to/from pages. * * Returns number of bytes read. */ static int vn_io(struct vnode *vp, struct vm_page **pgs, unsigned int npages, int rw) { struct vop_getattr_args args; struct sio_txn sio; struct vattr vattr; size_t c, read = 0; int err; /* TODO: Add support for writes */ if (rw != 0) { return -ENOTSUP; } args.vp = vp; args.res = &vattr; c = MAX(vattr.size / DEFAULT_PAGESIZE, 1); if ((err = vfs_vop_getattr(vp, &args)) != 0) { return err; } if (npages > c) { npages = c; } /* Prepare SIO constants */ sio.len = DEFAULT_PAGESIZE; sio.offset = 0; /* Copy in each page */ for (size_t i = 0; i < npages; ++i) { sio.buf = PHYS_TO_VIRT(pgs[i]->phys_addr); read = vfs_vop_read(vp, &sio); if (read < 0) pr_debug("vn_io: page-in @ %p failed (err=%d)\n", err); } return read; } /* * Get pages from backing store. * * @obp: Object representing the backing store. * @pgs: Page descriptors to be filled. * @off: Offset to read from in backing store. * @len: Length to read in bytes. */ static int vn_get(struct vm_object *obp, struct vm_page **pgs, off_t off, size_t len) { struct vm_page *pgtmp; size_t j, pgcnt; spinlock_acquire(&obp->lock); for (int i = off; i < len; i += DEFAULT_PAGESIZE) { j = i / DEFAULT_PAGESIZE; pgtmp = vm_pagelookup(obp, i); /* * If we have no corresponding page in the object * at this offset, we will need to make our own. */ if (pgtmp == NULL) { pgtmp = vm_pagealloc(obp, PALLOC_ZERO); if (pgtmp == NULL) { pgs[j]->flags &= ~PG_VALID; continue; } pgtmp->offset = i; pgs[j] = pgtmp; } if (spinlock_usleep(&pgtmp->lock, VN_TIMEOUT_USEC) != 0) { pgs[j]->flags &= ~PG_VALID; continue; } /* Set the page count and ensure it is valid */ pgcnt = ALIGN_DOWN(len, DEFAULT_PAGESIZE); pgcnt = MAX(pgcnt, 1); /* Page in and save this pgtmp */ vn_io(obp->data, &pgtmp, pgcnt, 0); pgs[j] = pgtmp; spinlock_release(&pgtmp->lock); } spinlock_release(&obp->lock); return 0; } /* * Attach a virtual memory object to a vnode. * * @vp: Vnode to attach to. */ struct vm_object * vn_attach(struct vnode *vp, vm_prot_t prot) { struct vm_object *vmobj; int error; if (vp->type != VREG) { pr_error("vn_attach: vp=%p, prot=%x\n", vp, prot); pr_error("vn_attach: Special files not supported yet!\n"); return NULL; } error = vm_obj_init(&vp->vobj, &vm_vnops, 1); if (error != 0) { return NULL; } vmobj = &vp->vobj; vmobj->prot = prot; vmobj->data = vp; vmobj->pgops = &vm_vnops; return vmobj; } const struct vm_pagerops vm_vnops = { .get = vn_get };