diff options
author | jhb <jhb@FreeBSD.org> | 2006-02-21 22:09:54 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2006-02-21 22:09:54 +0000 |
commit | 55b3bd61d28f09f0843c4772be973289d0a7a1ff (patch) | |
tree | 54705807bf28d82b1b964eea340ef0ee2ec35ef7 /sys | |
parent | abc45ce01034a350e17a8e6e9be4260b6c2b2b67 (diff) | |
download | FreeBSD-src-55b3bd61d28f09f0843c4772be973289d0a7a1ff.zip FreeBSD-src-55b3bd61d28f09f0843c4772be973289d0a7a1ff.tar.gz |
Lock the vm_object while checking its type to see if it is a vnode-backed
object that requires Giant in vm_object_deallocate(). This is somewhat
hairy in that if we can't obtain Giant directly, we have to drop the
object lock, then lock Giant, then relock the object lock and verify that
we still need Giant. If we don't (because the object changed to OBJT_DEAD
for example), then we drop Giant before continuing.
Reviewed by: alc
Tested by: kris
Diffstat (limited to 'sys')
-rw-r--r-- | sys/vm/vm_object.c | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 5000db4..5321b53 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -438,23 +438,37 @@ vm_object_deallocate(vm_object_t object) while (object != NULL) { int vfslocked; - /* - * In general, the object should be locked when working with - * its type. In this case, in order to maintain proper lock - * ordering, an exception is possible because a vnode-backed - * object never changes its type. - */ + vfslocked = 0; - if (object->type == OBJT_VNODE) { - struct vnode *vp = (struct vnode *) object->handle; - vfslocked = VFS_LOCK_GIANT(vp->v_mount); - } + restart: VM_OBJECT_LOCK(object); if (object->type == OBJT_VNODE) { + struct vnode *vp = (struct vnode *) object->handle; + + /* + * Conditionally acquire Giant for a vnode-backed + * object. We have to be careful since the type of + * a vnode object can change while the object is + * unlocked. + */ + if (VFS_NEEDSGIANT(vp->v_mount) && !vfslocked) { + vfslocked = 1; + if (!mtx_trylock(&Giant)) { + VM_OBJECT_UNLOCK(object); + mtx_lock(&Giant); + goto restart; + } + } vm_object_vndeallocate(object); VFS_UNLOCK_GIANT(vfslocked); return; - } + } else + /* + * This is to handle the case that the object + * changed type while we dropped its lock to + * obtain Giant. + */ + VFS_UNLOCK_GIANT(vfslocked); KASSERT(object->ref_count != 0, ("vm_object_deallocate: object deallocated too many times: %d", object->type)); |