int cache_freepages(int pages) { struct cached_page *cp, *newercp; int freed = 0; int oldsteps = 0; int skips = 0; for(cp = lru_oldest; cp && freed < pages; cp = newercp) { newercp = cp->newer; assert(cp->page->refcount >= 1); if(cp->page->refcount == 1) { rmcache(cp); freed++; skips = 0; } else skips++; oldsteps++; } return freed; }
int do_setcache(message *msg) { int r; dev_t dev = msg->m_u.m_vmmcp.dev; u64_t dev_off = (u64_t) msg->m_u.m_vmmcp.dev_offset_pages * VM_PAGE_SIZE; u64_t ino_off = (u64_t) msg->m_u.m_vmmcp.ino_offset_pages * VM_PAGE_SIZE; int n; struct vmproc *caller; vir_bytes offset; int bytes = msg->m_u.m_vmmcp.pages * VM_PAGE_SIZE; if(bytes < VM_PAGE_SIZE) return EINVAL; if(vm_isokendpt(msg->m_source, &n) != OK) panic("bogus source"); caller = &vmproc[n]; for(offset = 0; offset < bytes; offset += VM_PAGE_SIZE) { struct vir_region *region; struct phys_region *phys_region = NULL; vir_bytes v = (vir_bytes) msg->m_u.m_vmmcp.block + offset; struct cached_page *hb; if(!(region = map_lookup(caller, v, &phys_region))) { printf("VM: error: no reasonable memory region given (offset 0x%lx, 0x%lx)\n", offset, v); return EFAULT; } if(!phys_region) { printf("VM: error: no available memory region given\n"); return EFAULT; } if((hb=find_cached_page_bydev(dev, dev_off + offset, msg->m_u.m_vmmcp.ino, ino_off + offset, 1))) { /* block inode info updated */ if(hb->page != phys_region->ph) { /* previous cache entry has become * obsolete; make a new one. rmcache * removes it from the cache and frees * the page if it isn't mapped in anywhere * else. */ rmcache(hb); } else { /* block was already there, inode info might've changed which is fine */ continue; } } if(phys_region->memtype != &mem_type_anon && phys_region->memtype != &mem_type_anon_contig) { printf("VM: error: no reasonable memory type\n"); return EFAULT; } if(phys_region->ph->refcount != 1) { printf("VM: error: no reasonable refcount\n"); return EFAULT; } phys_region->memtype = &mem_type_cache; if((r=addcache(dev, dev_off + offset, msg->m_u.m_vmmcp.ino, ino_off + offset, phys_region->ph)) != OK) { printf("VM: addcache failed\n"); return r; } } #if CACHE_SANITY cache_sanitycheck_internal(); #endif 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); } /* * 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); }