Changeset View
Changeset View
Standalone View
Standalone View
sys/vm/vm_mmap.c
Show First 20 Lines • Show All 212 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
kern_mmap_req(struct thread *td, const struct mmap_req *mrp) | kern_mmap_req(struct thread *td, const struct mmap_req *mrp) | ||||
{ | { | ||||
struct vmspace *vms; | struct vmspace *vms; | ||||
struct file *fp; | struct file *fp; | ||||
struct proc *p; | struct proc *p; | ||||
off_t pos; | off_t pos; | ||||
vm_offset_t addr; | vm_offset_t addr, orig_addr; | ||||
vm_size_t len, pageoff, size; | vm_size_t len, pageoff, size; | ||||
vm_prot_t cap_maxprot; | vm_prot_t cap_maxprot; | ||||
int align, error, fd, flags, max_prot, prot; | int align, error, fd, flags, max_prot, prot; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
mmap_check_fp_fn check_fp_fn; | mmap_check_fp_fn check_fp_fn; | ||||
addr = mrp->mr_hint; | orig_addr = addr = mrp->mr_hint; | ||||
len = mrp->mr_len; | len = mrp->mr_len; | ||||
prot = mrp->mr_prot; | prot = mrp->mr_prot; | ||||
flags = mrp->mr_flags; | flags = mrp->mr_flags; | ||||
fd = mrp->mr_fd; | fd = mrp->mr_fd; | ||||
pos = mrp->mr_pos; | pos = mrp->mr_pos; | ||||
check_fp_fn = mrp->mr_check_fp_fn; | check_fp_fn = mrp->mr_check_fp_fn; | ||||
if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) | if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) | ||||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Lines | if ((flags & (MAP_SHARED | MAP_PRIVATE)) == 0 && | ||||
goto done; | goto done; | ||||
} | } | ||||
if (check_fp_fn != NULL) { | if (check_fp_fn != NULL) { | ||||
error = check_fp_fn(fp, prot, max_prot & cap_maxprot, | error = check_fp_fn(fp, prot, max_prot & cap_maxprot, | ||||
flags); | flags); | ||||
if (error != 0) | if (error != 0) | ||||
goto done; | goto done; | ||||
} | } | ||||
if (fp->f_ops == &shm_ops_large) | |||||
kevans: No specific suggestion, but it'd be nice if we had a cleaner way to do this, though I suppose… | |||||
Done Inline ActionsI am not sure if the way I redid it is cleaner, but now I do not see a specific need for shm_ops_large. kib: I am not sure if the way I redid it is cleaner, but now I do not see a specific need for… | |||||
addr = orig_addr; | |||||
/* This relies on VM_PROT_* matching PROT_*. */ | /* This relies on VM_PROT_* matching PROT_*. */ | ||||
Done Inline ActionsThe check does not work properly in some cases because shm_flags gets clobbered on every open() as I pointed out before. So either SHM_LARGEPAGE needs to be preserved in kern_shm_open2() or some other method of identifying largepage objects is needed. markj: The check does not work properly in some cases because shm_flags gets clobbered on every open()… | |||||
error = fo_mmap(fp, &vms->vm_map, &addr, size, prot, | error = fo_mmap(fp, &vms->vm_map, &addr, size, prot, | ||||
max_prot & cap_maxprot, flags, pos, td); | max_prot & cap_maxprot, flags, pos, td); | ||||
} | } | ||||
if (error == 0) | if (error == 0) | ||||
td->td_retval[0] = (register_t) (addr + pageoff); | td->td_retval[0] = (register_t) (addr + pageoff); | ||||
done: | done: | ||||
if (fp) | if (fp) | ||||
▲ Show 20 Lines • Show All 180 Lines • ▼ Show 20 Lines | if (vm_map_lookup_entry(map, addr, &entry)) { | ||||
pkm.pm_address = (uintptr_t) addr; | pkm.pm_address = (uintptr_t) addr; | ||||
pkm.pm_size = (size_t) size; | pkm.pm_size = (size_t) size; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#endif | #endif | ||||
vm_map_delete(map, addr, addr + size); | vm_map_delete(map, addr, addr + size); | ||||
Done Inline Actionsvm_map_delete() can fail now, but the error is not propagating to userland. markj: vm_map_delete() can fail now, but the error is not propagating to userland. | |||||
#ifdef HWPMC_HOOKS | #ifdef HWPMC_HOOKS | ||||
if (__predict_false(pmc_handled)) { | if (__predict_false(pmc_handled)) { | ||||
/* downgrade the lock to prevent a LOR with the pmc-sx lock */ | /* downgrade the lock to prevent a LOR with the pmc-sx lock */ | ||||
vm_map_lock_downgrade(map); | vm_map_lock_downgrade(map); | ||||
if (pkm.pm_address != (uintptr_t) NULL) | if (pkm.pm_address != (uintptr_t) NULL) | ||||
PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); | PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); | ||||
vm_map_unlock_read(map); | vm_map_unlock_read(map); | ||||
▲ Show 20 Lines • Show All 468 Lines • ▼ Show 20 Lines | |||||
#ifdef RACCT | #ifdef RACCT | ||||
if (racct_enable && error != KERN_SUCCESS) { | if (racct_enable && error != KERN_SUCCESS) { | ||||
PROC_LOCK(proc); | PROC_LOCK(proc); | ||||
racct_set(proc, RACCT_MEMLOCK, | racct_set(proc, RACCT_MEMLOCK, | ||||
ptoa(pmap_wired_count(map->pmap))); | ptoa(pmap_wired_count(map->pmap))); | ||||
PROC_UNLOCK(proc); | PROC_UNLOCK(proc); | ||||
} | } | ||||
#endif | #endif | ||||
return (error == KERN_SUCCESS ? 0 : ENOMEM); | return (error == KERN_SUCCESS ? 0 : ENOMEM); | ||||
Done Inline ActionsThis should become vm_mmap_to_errno() I think. Otherwise a clip error results in ENOMEM. markj: This should become vm_mmap_to_errno() I think. Otherwise a clip error results in ENOMEM. | |||||
Done Inline ActionsThen it would be EACCESS as well. I changed this to local switch. kib: Then it would be EACCESS as well. I changed this to local switch. | |||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct mlockall_args { | struct mlockall_args { | ||||
int how; | int how; | ||||
}; | }; | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 388 Lines • ▼ Show 20 Lines | if (error != 0 && object != NULL) { | ||||
*/ | */ | ||||
if (writecounted) | if (writecounted) | ||||
vm_pager_release_writecount(object, 0, size); | vm_pager_release_writecount(object, 0, size); | ||||
vm_object_deallocate(object); | vm_object_deallocate(object); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* Internal version of mmap that maps a specific VM object into an | |||||
* map. Called by mmap for MAP_ANON, vm_mmap, shm_mmap, and vn_mmap. | |||||
*/ | |||||
int | int | ||||
vm_mmap_object(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, | kern_mmap_racct_check(struct thread *td, vm_map_t map, vm_size_t size) | ||||
vm_prot_t maxprot, int flags, vm_object_t object, vm_ooffset_t foff, | |||||
boolean_t writecounted, struct thread *td) | |||||
{ | { | ||||
boolean_t curmap, fitit; | int error; | ||||
vm_offset_t max_addr; | |||||
int docow, error, findspace, rv; | |||||
curmap = map == &td->td_proc->p_vmspace->vm_map; | |||||
if (curmap) { | |||||
RACCT_PROC_LOCK(td->td_proc); | RACCT_PROC_LOCK(td->td_proc); | ||||
if (map->size + size > lim_cur(td, RLIMIT_VMEM)) { | if (map->size + size > lim_cur(td, RLIMIT_VMEM)) { | ||||
RACCT_PROC_UNLOCK(td->td_proc); | RACCT_PROC_UNLOCK(td->td_proc); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
if (racct_set(td->td_proc, RACCT_VMEM, map->size + size)) { | if (racct_set(td->td_proc, RACCT_VMEM, map->size + size)) { | ||||
RACCT_PROC_UNLOCK(td->td_proc); | RACCT_PROC_UNLOCK(td->td_proc); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
if (!old_mlock && map->flags & MAP_WIREFUTURE) { | if (!old_mlock && map->flags & MAP_WIREFUTURE) { | ||||
if (ptoa(pmap_wired_count(map->pmap)) + size > | if (ptoa(pmap_wired_count(map->pmap)) + size > | ||||
lim_cur(td, RLIMIT_MEMLOCK)) { | lim_cur(td, RLIMIT_MEMLOCK)) { | ||||
racct_set_force(td->td_proc, RACCT_VMEM, | racct_set_force(td->td_proc, RACCT_VMEM, map->size); | ||||
map->size); | |||||
RACCT_PROC_UNLOCK(td->td_proc); | RACCT_PROC_UNLOCK(td->td_proc); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
error = racct_set(td->td_proc, RACCT_MEMLOCK, | error = racct_set(td->td_proc, RACCT_MEMLOCK, | ||||
ptoa(pmap_wired_count(map->pmap)) + size); | ptoa(pmap_wired_count(map->pmap)) + size); | ||||
if (error != 0) { | if (error != 0) { | ||||
racct_set_force(td->td_proc, RACCT_VMEM, | racct_set_force(td->td_proc, RACCT_VMEM, map->size); | ||||
map->size); | |||||
RACCT_PROC_UNLOCK(td->td_proc); | RACCT_PROC_UNLOCK(td->td_proc); | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
RACCT_PROC_UNLOCK(td->td_proc); | RACCT_PROC_UNLOCK(td->td_proc); | ||||
return (0); | |||||
} | |||||
/* | |||||
* Internal version of mmap that maps a specific VM object into an | |||||
* map. Called by mmap for MAP_ANON, vm_mmap, shm_mmap, and vn_mmap. | |||||
*/ | |||||
int | |||||
vm_mmap_object(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, | |||||
vm_prot_t maxprot, int flags, vm_object_t object, vm_ooffset_t foff, | |||||
boolean_t writecounted, struct thread *td) | |||||
{ | |||||
vm_offset_t max_addr; | |||||
int docow, error, findspace, rv; | |||||
bool curmap, fitit; | |||||
curmap = map == &td->td_proc->p_vmspace->vm_map; | |||||
if (curmap) { | |||||
error = kern_mmap_racct_check(td, map, size); | |||||
if (error != 0) | |||||
return (error); | |||||
} | } | ||||
/* | /* | ||||
* We currently can only deal with page aligned file offsets. | * We currently can only deal with page aligned file offsets. | ||||
* The mmap() system call already enforces this by subtracting | * The mmap() system call already enforces this by subtracting | ||||
* the page offset from the file offset, but checking here | * the page offset from the file offset, but checking here | ||||
* catches errors in device drivers (e.g. d_single_mmap() | * catches errors in device drivers (e.g. d_single_mmap() | ||||
* callbacks) and other internal mapping requests (such as in | * callbacks) and other internal mapping requests (such as in | ||||
▲ Show 20 Lines • Show All 109 Lines • Show Last 20 Lines |
No specific suggestion, but it'd be nice if we had a cleaner way to do this, though I suppose this won't really expand to too many other file types. shmfd can now tell easily enough from some fo_* operation, for example, if it's configured for this since we've recently started recording the opening shm_flags.