static int anon_contig_new(struct vir_region *region) { u32_t allocflags; phys_bytes new_pages, new_page_cl, cur_ph; phys_bytes p, pages; allocflags = vrallocflags(region->flags); pages = region->length/VM_PAGE_SIZE; assert(physregions(region) == 0); for(p = 0; p < pages; p++) { struct phys_block *pb = pb_new(MAP_NONE); struct phys_region *pr = NULL; if(pb) pr = pb_reference(pb, p * VM_PAGE_SIZE, region, &mem_type_anon_contig); if(!pr) { if(pb) pb_free(pb); map_free(region); return ENOMEM; } } assert(physregions(region) == pages); if((new_page_cl = alloc_mem(pages, allocflags)) == NO_MEM) { map_free(region); return ENOMEM; } cur_ph = new_pages = CLICK2ABS(new_page_cl); for(p = 0; p < pages; p++) { struct phys_region *pr = physblock_get(region, p * VM_PAGE_SIZE); assert(pr); assert(pr->ph); assert(pr->ph->phys == MAP_NONE); assert(pr->offset == p * VM_PAGE_SIZE); pr->ph->phys = cur_ph + pr->offset; } return OK; }
static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region, struct phys_region *ph, int write, vfs_callback_t cb, void *state, int statelen, int *io) { u32_t allocflags; int procfd = region->param.file.fdref->fd; allocflags = vrallocflags(region->flags); assert(ph->ph->refcount > 0); assert(region->param.file.inited); assert(region->param.file.fdref); assert(region->param.file.fdref->dev != NO_DEV); /* Totally new block? Create it. */ if(ph->ph->phys == MAP_NONE) { struct cached_page *cp; u64_t referenced_offset = region->param.file.offset + ph->offset; if(region->param.file.fdref->ino == VMC_NO_INODE) { cp = find_cached_page_bydev(region->param.file.fdref->dev, referenced_offset, VMC_NO_INODE, 0, 1); } else { cp = find_cached_page_byino(region->param.file.fdref->dev, region->param.file.fdref->ino, referenced_offset, 1); } if(cp) { int result = OK; pb_unreferenced(region, ph, 0); pb_link(ph, cp->page, ph->offset, region); if(roundup(ph->offset+region->param.file.clearend, VM_PAGE_SIZE) >= region->length) { result = cow_block(vmp, region, ph, region->param.file.clearend); } else if(result == OK && write) { result = cow_block(vmp, region, ph, 0); } return result; } if(!cb) { #if 0 printf("VM: mem_file: no callback, returning EFAULT\n"); #endif sys_diagctl_stacktrace(vmp->vm_endpoint); return EFAULT; } if(vfs_request(VMVFSREQ_FDIO, procfd, vmp, referenced_offset, VM_PAGE_SIZE, cb, NULL, state, statelen) != OK) { printf("VM: mappedfile_pagefault: vfs_request failed\n"); return ENOMEM; } *io = 1; return SUSPEND; } if(!write) { #if 0 printf("mappedfile_pagefault: nonwrite fault?\n"); #endif return OK; } return cow_block(vmp, region, ph, 0); }
static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region, struct phys_region *ph, int write, vfs_callback_t cb, void *state, int statelen, int *io) { u32_t allocflags; int procfd = region->param.file.fdref->fd; allocflags = vrallocflags(region->flags); assert(ph->ph->refcount > 0); assert(region->param.file.inited); assert(region->param.file.fdref); assert(region->param.file.fdref->dev != NO_DEV); /* Totally new block? Create it. */ if(ph->ph->phys == MAP_NONE) { struct cached_page *cp; u64_t referenced_offset = region->param.file.offset + ph->offset; if(region->param.file.fdref->ino == VMC_NO_INODE) { cp = find_cached_page_bydev(region->param.file.fdref->dev, referenced_offset, VMC_NO_INODE, 0, 1); } else { cp = find_cached_page_byino(region->param.file.fdref->dev, region->param.file.fdref->ino, referenced_offset, 1); } /* * Normally, a cache hit saves a round-trip to the file system * to load the page. However, if the page in the VM cache is * marked for one-time use, then force a round-trip through the * file system anyway, so that the FS can update the page by * by readding it to the cache. Thus, for one-time use pages, * no caching is performed. This approach is correct even in * the light of concurrent requests and disappearing processes * but relies on VM requests to VFS being fully serialized. */ if(cp && (!cb || !(cp->flags & VMSF_ONCE))) { int result = OK; pb_unreferenced(region, ph, 0); pb_link(ph, cp->page, ph->offset, region); if(roundup(ph->offset+region->param.file.clearend, VM_PAGE_SIZE) >= region->length) { result = cow_block(vmp, region, ph, region->param.file.clearend); } else if(result == OK && write) { result = cow_block(vmp, region, ph, 0); } /* Discard one-use pages after mapping them in. */ if (result == OK && (cp->flags & VMSF_ONCE)) rmcache(cp); return result; } if(!cb) { #if 0 printf("VM: mem_file: no callback, returning EFAULT\n"); sys_diagctl_stacktrace(vmp->vm_endpoint); #endif return EFAULT; } if(vfs_request(VMVFSREQ_FDIO, procfd, vmp, referenced_offset, VM_PAGE_SIZE, cb, NULL, state, statelen) != OK) { printf("VM: mappedfile_pagefault: vfs_request failed\n"); return ENOMEM; } *io = 1; return SUSPEND; } if(!write) { #if 0 printf("mappedfile_pagefault: nonwrite fault?\n"); #endif return OK; } return cow_block(vmp, region, ph, 0); }