Avoid locking issues when copying out requires taking a fault and we are

finding out our own maps, by allocating a buffer and copying out after
we collected the information.
This commit is contained in:
christos 2016-06-01 00:49:44 +00:00
parent 71229fdd60
commit bafdaf94ba

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_map.c,v 1.337 2016/05/25 17:43:58 christos Exp $ */
/* $NetBSD: uvm_map.c,v 1.338 2016/06/01 00:49:44 christos Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.337 2016/05/25 17:43:58 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.338 2016/06/01 00:49:44 christos Exp $");
#include "opt_ddb.h"
#include "opt_uvmhist.h"
@ -4877,14 +4877,18 @@ fill_vmentries(struct lwp *l, pid_t pid, u_int elem_size, void *oldp,
{
int error;
struct proc *p;
struct kinfo_vmentry vme;
struct kinfo_vmentry *vme;
struct vmspace *vm;
struct vm_map *map;
struct vm_map_entry *entry;
char *dp;
size_t count;
size_t count, vmesize;
vme = NULL;
vmesize = *oldlenp;
count = 0;
if (oldp && *oldlenp > 1024 * 1024)
return E2BIG;
if ((error = proc_find_locked(l, &p, pid)) != 0)
return error;
@ -4896,31 +4900,44 @@ fill_vmentries(struct lwp *l, pid_t pid, u_int elem_size, void *oldp,
vm_map_lock_read(map);
dp = oldp;
if (oldp)
vme = kmem_alloc(vmesize, KM_SLEEP);
for (entry = map->header.next; entry != &map->header;
entry = entry->next) {
if (oldp && (dp - (char *)oldp) < *oldlenp + elem_size) {
error = fill_vmentry(l, p, &vme, map, entry);
error = fill_vmentry(l, p, &vme[count], map, entry);
if (error)
break;
error = sysctl_copyout(l, &vme, dp,
min(elem_size, sizeof(vme)));
if (error)
break;
goto out;
dp += elem_size;
}
count++;
}
vm_map_unlock_read(map);
uvmspace_free(vm);
out:
if (pid != -1)
mutex_exit(p->p_lock);
if (error == 0) {
const u_int esize = min(sizeof(*vme), elem_size);
dp = oldp;
for (size_t i = 0; i < count; i++) {
if (oldp && (dp - (char *)oldp) < *oldlenp + elem_size)
{
error = sysctl_copyout(l, &vme[i], dp, esize);
if (error)
break;
dp += elem_size;
} else
break;
}
count *= elem_size;
if (oldp != NULL && *oldlenp < count)
error = ENOSPC;
*oldlenp = count;
}
if (vme)
kmem_free(vme, vmesize);
return error;
}