diff options
author | alc <alc@FreeBSD.org> | 2007-05-01 03:09:57 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2007-05-01 03:09:57 +0000 |
commit | 9c008bb303f5e83730828adf7adc7316a6bd7715 (patch) | |
tree | fd79bd067d397b81f9681c6a99340ac1f58cfccc /sys/compat | |
parent | c27ef034149379823d3f1a1ed091d766fe5abb17 (diff) | |
download | FreeBSD-src-9c008bb303f5e83730828adf7adc7316a6bd7715.zip FreeBSD-src-9c008bb303f5e83730828adf7adc7316a6bd7715.tar.gz |
Synchronize vm map and object accesses.
Approved by: des@
Diffstat (limited to 'sys/compat')
-rw-r--r-- | sys/compat/linprocfs/linprocfs.c | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index c4fde2f..787ea1e 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -860,12 +860,14 @@ linprocfs_doprocmaps(PFS_FILL_ARGS) { char mebuffer[512]; vm_map_t map = &p->p_vmspace->vm_map; - vm_map_entry_t entry; + vm_map_entry_t entry, tmp_entry; vm_object_t obj, tobj, lobj; + vm_offset_t saved_end; vm_ooffset_t off = 0; char *name = "", *freename = NULL; size_t len; ino_t ino; + unsigned int last_timestamp; int ref_count, shadow_count, flags; int error; struct vnode *vp; @@ -885,8 +887,7 @@ linprocfs_doprocmaps(PFS_FILL_ARGS) return (0); error = 0; - if (map != &curthread->td_proc->p_vmspace->vm_map) - vm_map_lock_read(map); + vm_map_lock_read(map); for (entry = map->header.next; ((uio->uio_resid > 0) && (entry != &map->header)); entry = entry->next) { @@ -894,12 +895,16 @@ linprocfs_doprocmaps(PFS_FILL_ARGS) freename = NULL; if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) continue; + saved_end = entry->end; obj = entry->object.vm_object; - for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) + for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { + VM_OBJECT_LOCK(tobj); + if (lobj != obj) + VM_OBJECT_UNLOCK(lobj); lobj = tobj; + } ino = 0; if (lobj) { - VM_OBJECT_LOCK(lobj); off = IDX_TO_OFF(lobj->size); if (lobj->type == OBJT_VNODE) { vp = lobj->handle; @@ -908,10 +913,12 @@ linprocfs_doprocmaps(PFS_FILL_ARGS) } else vp = NULL; + if (lobj != obj) + VM_OBJECT_UNLOCK(lobj); flags = obj->flags; ref_count = obj->ref_count; shadow_count = obj->shadow_count; - VM_OBJECT_UNLOCK(lobj); + VM_OBJECT_UNLOCK(obj); if (vp) { vn_fullpath(td, vp, &name, &freename); locked = VFS_LOCK_GIANT(vp->v_mount); @@ -953,12 +960,23 @@ linprocfs_doprocmaps(PFS_FILL_ARGS) * XXX We should probably return * EFBIG here, as in procfs. */ + last_timestamp = map->timestamp; + vm_map_unlock_read(map); error = uiomove(mebuffer, len, uio); + vm_map_lock_read(map); if (error) break; + if (last_timestamp + 1 != map->timestamp) { + /* + * Look again for the entry because the map was + * modified while it was unlocked. Specifically, + * the entry may have been clipped, merged, or deleted. + */ + vm_map_lookup_entry(map, saved_end - 1, &tmp_entry); + entry = tmp_entry; + } } - if (map != &curthread->td_proc->p_vmspace->vm_map) - vm_map_unlock_read(map); + vm_map_unlock_read(map); return (error); } |