procfs_map():

- Drop the target's vm_map lock before calling uiomove(). We could
  deadlock if inspecting /proc/curproc/map.
- If the vm_map might have changed, restart the operation, but give
  up after 250 retries if the map keeps changing.  XXX This is not
  ideal.
This commit is contained in:
ad 2007-02-18 20:03:44 +00:00
parent 04a29fca2b
commit 42a7dff463
1 changed files with 31 additions and 3 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: procfs_map.c,v 1.29 2007/02/17 22:31:44 pavel Exp $ */ /* $NetBSD: procfs_map.c,v 1.30 2007/02/18 20:03:44 ad Exp $ */
/* /*
* Copyright (c) 1993 * Copyright (c) 1993
@ -76,7 +76,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: procfs_map.c,v 1.29 2007/02/17 22:31:44 pavel Exp $"); __KERNEL_RCSID(0, "$NetBSD: procfs_map.c,v 1.30 2007/02/18 20:03:44 ad Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
@ -113,7 +113,7 @@ procfs_domap(struct lwp *curl, struct proc *p, struct pfsnode *pfs,
struct uio *uio, int linuxmode) struct uio *uio, int linuxmode)
{ {
size_t len; size_t len;
int error; int error, retries;
struct vmspace *vm; struct vmspace *vm;
struct vm_map *map; struct vm_map *map;
struct vm_map_entry *entry; struct vm_map_entry *entry;
@ -123,6 +123,8 @@ procfs_domap(struct lwp *curl, struct proc *p, struct pfsnode *pfs,
struct vattr va; struct vattr va;
dev_t dev; dev_t dev;
long fileid; long fileid;
unsigned timestamp;
struct uio savuio;
if (uio->uio_rw != UIO_READ) if (uio->uio_rw != UIO_READ)
return (EOPNOTSUPP); return (EOPNOTSUPP);
@ -146,12 +148,20 @@ procfs_domap(struct lwp *curl, struct proc *p, struct pfsnode *pfs,
} }
map = &vm->vm_map; map = &vm->vm_map;
memcpy(&savuio, uio, sizeof(savuio));
retries = 0;
vm_map_lock_read(map); vm_map_lock_read(map);
restart:
for (entry = map->header.next; for (entry = map->header.next;
((uio->uio_resid > 0) && (entry != &map->header)); ((uio->uio_resid > 0) && (entry != &map->header));
entry = entry->next) { entry = entry->next) {
if (retries > 250) {
error = EWOULDBLOCK;
break;
}
if (UVM_ET_ISSUBMAP(entry)) if (UVM_ET_ISSUBMAP(entry))
continue; continue;
@ -205,9 +215,27 @@ procfs_domap(struct lwp *curl, struct proc *p, struct pfsnode *pfs,
error = EFBIG; error = EFBIG;
break; break;
} }
timestamp = map->timestamp;
vm_map_unlock_read(map);
error = uiomove(mebuffer, len, uio); error = uiomove(mebuffer, len, uio);
vm_map_lock_read(map);
if (error) if (error)
break; break;
if (timestamp != map->timestamp) {
/*
* The map may have changed, so restart. We
* make an ugly assumption about uiomove()
* and the vm_map timestamp: it will never
* fall back to copyout_vmspace() because
* we are copying out to curproc.
*/
KASSERT(uio->uio_vmspace == curproc->p_vmspace);
retries++;
memcpy(uio, &savuio, sizeof(*uio));
goto restart;
}
} }
vm_map_unlock_read(map); vm_map_unlock_read(map);