Module Name: src
Committed By: christos
Date: Wed Jun 1 00:49:45 UTC 2016
Modified Files:
src/sys/uvm: uvm_map.c
Log Message:
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.
To generate a diff of this commit:
cvs rdiff -u -r1.337 -r1.338 src/sys/uvm/uvm_map.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/uvm/uvm_map.c
diff -u src/sys/uvm/uvm_map.c:1.337 src/sys/uvm/uvm_map.c:1.338
--- src/sys/uvm/uvm_map.c:1.337 Wed May 25 13:43:58 2016
+++ src/sys/uvm/uvm_map.c Tue May 31 20:49:44 2016
@@ -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,
{
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,
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;
}