summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2006-02-21 22:09:54 +0000
committerjhb <jhb@FreeBSD.org>2006-02-21 22:09:54 +0000
commit55b3bd61d28f09f0843c4772be973289d0a7a1ff (patch)
tree54705807bf28d82b1b964eea340ef0ee2ec35ef7 /sys
parentabc45ce01034a350e17a8e6e9be4260b6c2b2b67 (diff)
downloadFreeBSD-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.c36
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));
OpenPOWER on IntegriCloud