svn commit: r355122 - in head/sys: sys vm
Jeff Roberson
jeff at FreeBSD.org
Wed Nov 27 00:39:24 UTC 2019
Author: jeff
Date: Wed Nov 27 00:39:23 2019
New Revision: 355122
URL: https://svnweb.freebsd.org/changeset/base/355122
Log:
Use atomics in more cases for object references. We now can completely
omit the object lock if we are above a certain threshold. Hold only a
single vnode reference when the vnode object has any ref > 0. This
allows us to only lock the object and vnode on 0-1 and 1-0 transitions.
Differential Revision: https://reviews.freebsd.org/D22452
Modified:
head/sys/sys/refcount.h
head/sys/vm/vm_object.c
head/sys/vm/vnode_pager.c
Modified: head/sys/sys/refcount.h
==============================================================================
--- head/sys/sys/refcount.h Tue Nov 26 22:17:02 2019 (r355121)
+++ head/sys/sys/refcount.h Wed Nov 27 00:39:23 2019 (r355122)
@@ -72,7 +72,7 @@ refcount_init(volatile u_int *count, u_int value)
*count = value;
}
-static __inline void
+static __inline u_int
refcount_acquire(volatile u_int *count)
{
u_int old;
@@ -80,9 +80,11 @@ refcount_acquire(volatile u_int *count)
old = atomic_fetchadd_int(count, 1);
if (__predict_false(REFCOUNT_SATURATED(old)))
_refcount_update_saturated(count);
+
+ return (old);
}
-static __inline void
+static __inline u_int
refcount_acquiren(volatile u_int *count, u_int n)
{
u_int old;
@@ -92,6 +94,8 @@ refcount_acquiren(volatile u_int *count, u_int n)
old = atomic_fetchadd_int(count, n);
if (__predict_false(REFCOUNT_SATURATED(old)))
_refcount_update_saturated(count);
+
+ return (old);
}
static __inline __result_use_check bool
@@ -144,13 +148,13 @@ refcount_wait(volatile u_int *count, const char *wmesg
* incremented. Else zero is returned.
*/
static __inline __result_use_check bool
-refcount_acquire_if_not_zero(volatile u_int *count)
+refcount_acquire_if_gt(volatile u_int *count, u_int n)
{
u_int old;
old = *count;
for (;;) {
- if (REFCOUNT_COUNT(old) == 0)
+ if (REFCOUNT_COUNT(old) <= n)
return (false);
if (__predict_false(REFCOUNT_SATURATED(old)))
return (true);
@@ -160,19 +164,10 @@ refcount_acquire_if_not_zero(volatile u_int *count)
}
static __inline __result_use_check bool
-refcount_release_if_not_last(volatile u_int *count)
+refcount_acquire_if_not_zero(volatile u_int *count)
{
- u_int old;
- old = *count;
- for (;;) {
- if (REFCOUNT_COUNT(old) == 1)
- return (false);
- if (__predict_false(REFCOUNT_SATURATED(old)))
- return (true);
- if (atomic_fcmpset_int(count, &old, old - 1))
- return (true);
- }
+ return refcount_acquire_if_gt(count, 0);
}
static __inline __result_use_check bool
@@ -193,4 +188,10 @@ refcount_release_if_gt(volatile u_int *count, u_int n)
}
}
+static __inline __result_use_check bool
+refcount_release_if_not_last(volatile u_int *count)
+{
+
+ return refcount_release_if_gt(count, 1);
+}
#endif /* ! __SYS_REFCOUNT_H__ */
Modified: head/sys/vm/vm_object.c
==============================================================================
--- head/sys/vm/vm_object.c Tue Nov 26 22:17:02 2019 (r355121)
+++ head/sys/vm/vm_object.c Wed Nov 27 00:39:23 2019 (r355122)
@@ -468,11 +468,28 @@ vm_object_allocate_anon(vm_pindex_t size)
void
vm_object_reference(vm_object_t object)
{
+ struct vnode *vp;
+ u_int old;
+
if (object == NULL)
return;
- VM_OBJECT_RLOCK(object);
- vm_object_reference_locked(object);
- VM_OBJECT_RUNLOCK(object);
+
+ /*
+ * Many places assume exclusive access to objects with a single
+ * ref. vm_object_collapse() in particular will directly mainpulate
+ * references for objects in this state. vnode objects only need
+ * the lock for the first ref to reference the vnode.
+ */
+ if (!refcount_acquire_if_gt(&object->ref_count,
+ object->type == OBJT_VNODE ? 0 : 1)) {
+ VM_OBJECT_RLOCK(object);
+ old = refcount_acquire(&object->ref_count);
+ if (object->type == OBJT_VNODE && old == 0) {
+ vp = object->handle;
+ vref(vp);
+ }
+ VM_OBJECT_RUNLOCK(object);
+ }
}
/*
@@ -486,10 +503,11 @@ void
vm_object_reference_locked(vm_object_t object)
{
struct vnode *vp;
+ u_int old;
VM_OBJECT_ASSERT_LOCKED(object);
- refcount_acquire(&object->ref_count);
- if (object->type == OBJT_VNODE) {
+ old = refcount_acquire(&object->ref_count);
+ if (object->type == OBJT_VNODE && old == 0) {
vp = object->handle;
vref(vp);
}
@@ -507,11 +525,10 @@ vm_object_vndeallocate(vm_object_t object)
("vm_object_vndeallocate: not a vnode object"));
KASSERT(vp != NULL, ("vm_object_vndeallocate: missing vp"));
- if (refcount_release(&object->ref_count) &&
- !umtx_shm_vnobj_persistent)
+ if (!umtx_shm_vnobj_persistent)
umtx_shm_object_terminated(object);
- VM_OBJECT_RUNLOCK(object);
+ VM_OBJECT_WUNLOCK(object);
/* vrele may need the vnode lock. */
vrele(vp);
}
@@ -531,15 +548,9 @@ void
vm_object_deallocate(vm_object_t object)
{
vm_object_t robject, temp;
- bool released;
+ bool last, released;
while (object != NULL) {
- VM_OBJECT_RLOCK(object);
- if (object->type == OBJT_VNODE) {
- vm_object_vndeallocate(object);
- return;
- }
-
/*
* If the reference count goes to 0 we start calling
* vm_object_terminate() on the object chain. A ref count
@@ -551,7 +562,6 @@ vm_object_deallocate(vm_object_t object)
released = refcount_release_if_gt(&object->ref_count, 1);
else
released = refcount_release_if_gt(&object->ref_count, 2);
- VM_OBJECT_RUNLOCK(object);
if (released)
return;
@@ -559,7 +569,14 @@ vm_object_deallocate(vm_object_t object)
KASSERT(object->ref_count != 0,
("vm_object_deallocate: object deallocated too many times: %d", object->type));
- refcount_release(&object->ref_count);
+ last = refcount_release(&object->ref_count);
+ if (object->type == OBJT_VNODE) {
+ if (last)
+ vm_object_vndeallocate(object);
+ else
+ VM_OBJECT_WUNLOCK(object);
+ return;
+ }
if (object->ref_count > 1) {
VM_OBJECT_WUNLOCK(object);
return;
@@ -629,7 +646,7 @@ retry:
VM_OBJECT_WUNLOCK(object);
if (robject->ref_count == 1) {
- robject->ref_count--;
+ refcount_release(&robject->ref_count);
object = robject;
goto doterm;
}
@@ -1838,7 +1855,7 @@ vm_object_collapse(vm_object_t object)
backing_object));
vm_object_pip_wakeup(backing_object);
backing_object->type = OBJT_DEAD;
- backing_object->ref_count = 0;
+ refcount_release(&backing_object->ref_count);
VM_OBJECT_WUNLOCK(backing_object);
vm_object_destroy(backing_object);
Modified: head/sys/vm/vnode_pager.c
==============================================================================
--- head/sys/vm/vnode_pager.c Tue Nov 26 22:17:02 2019 (r355121)
+++ head/sys/vm/vnode_pager.c Wed Nov 27 00:39:23 2019 (r355122)
@@ -150,6 +150,7 @@ vnode_create_vobject(struct vnode *vp, off_t isize, st
vm_object_t object;
vm_ooffset_t size = isize;
struct vattr va;
+ bool last;
if (!vn_isdisk(vp, NULL) && vn_canvmio(vp) == FALSE)
return (0);
@@ -171,12 +172,15 @@ vnode_create_vobject(struct vnode *vp, off_t isize, st
object = vnode_pager_alloc(vp, size, 0, 0, td->td_ucred);
/*
* Dereference the reference we just created. This assumes
- * that the object is associated with the vp.
+ * that the object is associated with the vp. We still have
+ * to serialize with vnode_pager_dealloc() for the last
+ * potential reference.
*/
VM_OBJECT_RLOCK(object);
- refcount_release(&object->ref_count);
+ last = refcount_release(&object->ref_count);
VM_OBJECT_RUNLOCK(object);
- vrele(vp);
+ if (last)
+ vrele(vp);
KASSERT(vp->v_object != NULL, ("vnode_create_vobject: NULL object"));
@@ -293,15 +297,17 @@ retry:
}
vp->v_object = object;
VI_UNLOCK(vp);
+ vrefact(vp);
} else {
- VM_OBJECT_WLOCK(object);
- refcount_acquire(&object->ref_count);
+ vm_object_reference(object);
#if VM_NRESERVLEVEL > 0
- vm_object_color(object, 0);
+ if ((object->flags & OBJ_COLORED) == 0) {
+ VM_OBJECT_WLOCK(object);
+ vm_object_color(object, 0);
+ VM_OBJECT_WUNLOCK(object);
+ }
#endif
- VM_OBJECT_WUNLOCK(object);
}
- vrefact(vp);
return (object);
}
@@ -345,7 +351,7 @@ vnode_pager_dealloc(vm_object_t object)
vp->v_writecount = 0;
VI_UNLOCK(vp);
VM_OBJECT_WUNLOCK(object);
- while (refs-- > 0)
+ if (refs > 0)
vunref(vp);
VM_OBJECT_WLOCK(object);
}
More information about the svn-src-all
mailing list