svn commit: r332878 - head/sys/kern
Mateusz Guzik
mjg at FreeBSD.org
Mon Apr 23 07:51:20 UTC 2018
Author: mjg
Date: Mon Apr 23 07:51:19 2018
New Revision: 332878
URL: https://svnweb.freebsd.org/changeset/base/332878
Log:
lockf: free state only when recycling the vnode
This avoids malloc/free cycles when locking/unlocking the vnode when
nobody is contending.
Tested by: pho
Modified:
head/sys/kern/kern_lockf.c
Modified: head/sys/kern/kern_lockf.c
==============================================================================
--- head/sys/kern/kern_lockf.c Mon Apr 23 07:15:49 2018 (r332877)
+++ head/sys/kern/kern_lockf.c Mon Apr 23 07:51:19 2018 (r332878)
@@ -412,7 +412,7 @@ int
lf_advlockasync(struct vop_advlockasync_args *ap, struct lockf **statep,
u_quad_t size)
{
- struct lockf *state, *freestate = NULL;
+ struct lockf *state;
struct flock *fl = ap->a_fl;
struct lockf_entry *lock;
struct vnode *vp = ap->a_vp;
@@ -721,38 +721,17 @@ retry_setlock:
#endif
sx_xunlock(&state->ls_lock);
- /*
- * If we have removed the last active lock on the vnode and
- * this is the last thread that was in-progress, we can free
- * the state structure. We update the caller's pointer inside
- * the vnode interlock but call free outside.
- *
- * XXX alternatively, keep the state structure around until
- * the filesystem recycles - requires a callback from the
- * filesystem.
- */
VI_LOCK(vp);
state->ls_threads--;
wakeup(state);
if (LIST_EMPTY(&state->ls_active) && state->ls_threads == 0) {
KASSERT(LIST_EMPTY(&state->ls_pending),
- ("freeing state with pending locks"));
- freestate = state;
- *statep = NULL;
+ ("freeable state with pending locks"));
}
VI_UNLOCK(vp);
- if (freestate != NULL) {
- sx_xlock(&lf_lock_states_lock);
- LIST_REMOVE(freestate, ls_link);
- sx_xunlock(&lf_lock_states_lock);
- sx_destroy(&freestate->ls_lock);
- free(freestate, M_LOCKF);
- freestate = NULL;
- }
-
if (error == EDOOFUS) {
KASSERT(ap->a_op == F_SETLK, ("EDOOFUS"));
goto retry_setlock;
@@ -793,62 +772,62 @@ lf_purgelocks(struct vnode *vp, struct lockf **statep)
KASSERT(vp->v_iflag & VI_DOOMED,
("lf_purgelocks: vp %p has not vgone yet", vp));
state = *statep;
- if (state) {
- *statep = NULL;
- state->ls_threads++;
+ if (state == NULL) {
VI_UNLOCK(vp);
+ return;
+ }
+ *statep = NULL;
+ state->ls_threads++;
+ VI_UNLOCK(vp);
- sx_xlock(&state->ls_lock);
- sx_xlock(&lf_owner_graph_lock);
- LIST_FOREACH_SAFE(lock, &state->ls_pending, lf_link, nlock) {
- LIST_REMOVE(lock, lf_link);
- lf_remove_outgoing(lock);
- lf_remove_incoming(lock);
+ sx_xlock(&state->ls_lock);
+ sx_xlock(&lf_owner_graph_lock);
+ LIST_FOREACH_SAFE(lock, &state->ls_pending, lf_link, nlock) {
+ LIST_REMOVE(lock, lf_link);
+ lf_remove_outgoing(lock);
+ lf_remove_incoming(lock);
- /*
- * If its an async lock, we can just free it
- * here, otherwise we let the sleeping thread
- * free it.
- */
- if (lock->lf_async_task) {
- lf_free_lock(lock);
- } else {
- lock->lf_flags |= F_INTR;
- wakeup(lock);
- }
- }
- sx_xunlock(&lf_owner_graph_lock);
- sx_xunlock(&state->ls_lock);
-
/*
- * Wait for all other threads, sleeping and otherwise
- * to leave.
+ * If its an async lock, we can just free it
+ * here, otherwise we let the sleeping thread
+ * free it.
*/
- VI_LOCK(vp);
- while (state->ls_threads > 1)
- msleep(state, VI_MTX(vp), 0, "purgelocks", 0);
- VI_UNLOCK(vp);
-
- /*
- * We can just free all the active locks since they
- * will have no dependencies (we removed them all
- * above). We don't need to bother locking since we
- * are the last thread using this state structure.
- */
- KASSERT(LIST_EMPTY(&state->ls_pending),
- ("lock pending for %p", state));
- LIST_FOREACH_SAFE(lock, &state->ls_active, lf_link, nlock) {
- LIST_REMOVE(lock, lf_link);
+ if (lock->lf_async_task) {
lf_free_lock(lock);
+ } else {
+ lock->lf_flags |= F_INTR;
+ wakeup(lock);
}
- sx_xlock(&lf_lock_states_lock);
- LIST_REMOVE(state, ls_link);
- sx_xunlock(&lf_lock_states_lock);
- sx_destroy(&state->ls_lock);
- free(state, M_LOCKF);
- } else {
- VI_UNLOCK(vp);
}
+ sx_xunlock(&lf_owner_graph_lock);
+ sx_xunlock(&state->ls_lock);
+
+ /*
+ * Wait for all other threads, sleeping and otherwise
+ * to leave.
+ */
+ VI_LOCK(vp);
+ while (state->ls_threads > 1)
+ msleep(state, VI_MTX(vp), 0, "purgelocks", 0);
+ VI_UNLOCK(vp);
+
+ /*
+ * We can just free all the active locks since they
+ * will have no dependencies (we removed them all
+ * above). We don't need to bother locking since we
+ * are the last thread using this state structure.
+ */
+ KASSERT(LIST_EMPTY(&state->ls_pending),
+ ("lock pending for %p", state));
+ LIST_FOREACH_SAFE(lock, &state->ls_active, lf_link, nlock) {
+ LIST_REMOVE(lock, lf_link);
+ lf_free_lock(lock);
+ }
+ sx_xlock(&lf_lock_states_lock);
+ LIST_REMOVE(state, ls_link);
+ sx_xunlock(&lf_lock_states_lock);
+ sx_destroy(&state->ls_lock);
+ free(state, M_LOCKF);
}
/*
More information about the svn-src-all
mailing list