int sys_munmap(struct lwp *l, const struct sys_munmap_args *uap, register_t *retval) { /* { syscallarg(void *) addr; syscallarg(size_t) len; } */ struct proc *p = l->l_proc; vaddr_t addr; vsize_t size, pageoff; struct vm_map *map; struct vm_map_entry *dead_entries; int error; /* * get syscall args. */ addr = (vaddr_t)SCARG(uap, addr); size = (vsize_t)SCARG(uap, len); /* * align the address to a page boundary and adjust the size accordingly. */ pageoff = (addr & PAGE_MASK); addr -= pageoff; size += pageoff; size = (vsize_t)round_page(size); if (size == 0) return (0); error = range_test(addr, size, false); if (error) return error; map = &p->p_vmspace->vm_map; /* * interesting system call semantic: make sure entire range is * allocated before allowing an unmap. */ vm_map_lock(map); #if 0 if (!uvm_map_checkprot(map, addr, addr + size, VM_PROT_NONE)) { vm_map_unlock(map); return (EINVAL); } #endif uvm_unmap_remove(map, addr, addr + size, &dead_entries, NULL, 0); vm_map_unlock(map); if (dead_entries != NULL) uvm_unmap_detach(dead_entries, 0); return (0); }
void uvm_km_free_wakeup(struct vm_map *map, vaddr_t addr, vsize_t size) { struct vm_map_entry *dead_entries; vm_map_lock(map); uvm_unmap_remove(map, trunc_page(addr), round_page(addr+size), &dead_entries, NULL); wakeup(map); vm_map_unlock(map); if (dead_entries != NULL) uvm_unmap_detach(dead_entries, 0); }
int uvm_io(vm_map_t map, struct uio *uio, int flags) { vaddr_t baseva, endva, pageoffset, kva; vsize_t chunksz, togo, sz; struct uvm_map_deadq dead_entries; int error, extractflags; /* * step 0: sanity checks and set up for copy loop. start with a * large chunk size. if we have trouble finding vm space we will * reduce it. */ if (uio->uio_resid == 0) return(0); togo = uio->uio_resid; baseva = (vaddr_t) uio->uio_offset; endva = baseva + (togo - 1); if (endva < baseva) /* wrap around? */ return(EIO); if (baseva >= VM_MAXUSER_ADDRESS) return(0); if (endva >= VM_MAXUSER_ADDRESS) /* EOF truncate */ togo = togo - (endva - VM_MAXUSER_ADDRESS + 1); pageoffset = baseva & PAGE_MASK; baseva = trunc_page(baseva); chunksz = min(round_page(togo + pageoffset), MAXBSIZE); error = 0; extractflags = 0; if (flags & UVM_IO_FIXPROT) extractflags |= UVM_EXTRACT_FIXPROT; /* step 1: main loop... while we've got data to move */ for (/*null*/; togo > 0 ; pageoffset = 0) { /* step 2: extract mappings from the map into kernel_map */ error = uvm_map_extract(map, baseva, chunksz, &kva, extractflags); if (error) { /* retry with a smaller chunk... */ if (error == ENOMEM && chunksz > PAGE_SIZE) { chunksz = trunc_page(chunksz / 2); if (chunksz < PAGE_SIZE) chunksz = PAGE_SIZE; continue; } break; } /* step 3: move a chunk of data */ sz = chunksz - pageoffset; if (sz > togo) sz = togo; error = uiomove((caddr_t) (kva + pageoffset), sz, uio); togo -= sz; baseva += chunksz; /* step 4: unmap the area of kernel memory */ vm_map_lock(kernel_map); TAILQ_INIT(&dead_entries); uvm_unmap_remove(kernel_map, kva, kva+chunksz, &dead_entries, FALSE, TRUE); vm_map_unlock(kernel_map); uvm_unmap_detach(&dead_entries, AMAP_REFALL); /* * We defer checking the error return from uiomove until * here so that we won't leak memory. */ if (error) break; } return (error); }
int sys_munmap(struct proc *p, void *v, register_t *retval) { struct sys_munmap_args /* { syscallarg(void *) addr; syscallarg(size_t) len; } */ *uap = v; vaddr_t addr; vsize_t size, pageoff; vm_map_t map; vaddr_t vm_min_address = VM_MIN_ADDRESS; struct vm_map_entry *dead_entries; /* * get syscall args... */ addr = (vaddr_t) SCARG(uap, addr); size = (vsize_t) SCARG(uap, len); /* * align the address to a page boundary, and adjust the size accordingly */ ALIGN_ADDR(addr, size, pageoff); /* * Check for illegal addresses. Watch out for address wrap... * Note that VM_*_ADDRESS are not constants due to casts (argh). */ if (addr > SIZE_MAX - size) return (EINVAL); if (VM_MAXUSER_ADDRESS > 0 && addr + size > VM_MAXUSER_ADDRESS) return (EINVAL); if (vm_min_address > 0 && addr < vm_min_address) return (EINVAL); map = &p->p_vmspace->vm_map; vm_map_lock(map); /* lock map so we can checkprot */ /* * interesting system call semantic: make sure entire range is * allocated before allowing an unmap. */ if (!uvm_map_checkprot(map, addr, addr + size, VM_PROT_NONE)) { vm_map_unlock(map); return (EINVAL); } /* * doit! */ uvm_unmap_remove(map, addr, addr + size, &dead_entries, p); vm_map_unlock(map); /* and unlock */ if (dead_entries != NULL) uvm_unmap_detach(dead_entries, 0); return (0); }