svn commit: r273966 - in head: share/man/man9 sys/kern sys/sys

Konstantin Belousov kib at FreeBSD.org
Sun Nov 2 13:10:33 UTC 2014


Author: kib
Date: Sun Nov  2 13:10:31 2014
New Revision: 273966
URL: https://svnweb.freebsd.org/changeset/base/273966

Log:
  Fix two issues with lockmgr(9) LK_CAN_SHARE() test, which determines
  whether the shared request for already shared-locked lock could be
  granted.  Both problems result in the exclusive locker starvation.
  
  The concurrent exclusive request is indicated by either
  LK_EXCLUSIVE_WAITERS or LK_EXCLUSIVE_SPINNERS flags.  The reverse
  condition, i.e. no exclusive waiters, must check that both flags are
  cleared.
  
  Add a flag LK_NODDLKTREAT for shared lock request to indicate that
  current thread guarantees that it does not own the lock in shared
  mode.  This turns back the exclusive lock starvation avoidance code;
  see man page update for detailed description.
  
  Use LK_NODDLKTREAT when doing lookup(9).
  
  Reported and tested by:	pho
  No objections from:	attilio
  Sponsored by:	The FreeBSD Foundation
  MFC after:	2 weeks

Modified:
  head/share/man/man9/lock.9
  head/sys/kern/kern_lock.c
  head/sys/kern/vfs_lookup.c
  head/sys/sys/lockmgr.h

Modified: head/share/man/man9/lock.9
==============================================================================
--- head/share/man/man9/lock.9	Sun Nov  2 11:47:40 2014	(r273965)
+++ head/share/man/man9/lock.9	Sun Nov  2 13:10:31 2014	(r273966)
@@ -26,7 +26,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 6, 2013
+.Dd November 2, 2014
 .Dt LOCK 9
 .Os
 .Sh NAME
@@ -145,7 +145,7 @@ Their arguments are:
 A pointer to the lock to manipulate.
 .It Fa flags
 Flags indicating what action is to be taken.
-.Bl -tag -width ".Dv LK_CANRECURSE"
+.Bl -tag -width ".Dv LK_NODDLKTREAT"
 .It Dv LK_SHARED
 Acquire a shared lock.
 If an exclusive lock is currently held,
@@ -199,6 +199,29 @@ Allow recursion on an exclusive lock.
 For every lock there must be a release.
 .It Dv LK_INTERLOCK
 Unlock the interlock (which should be locked already).
+.It Dv LK_NODDLKTREAT
+Normally,
+.Fn lockmgr
+postpones serving further shared requests for shared-locked lock if there is
+exclusive waiter, to avoid exclusive lock starvation.
+But, if the thread requesting the shared lock already owns a shared lockmgr
+lock, the request is granted even in presence of the parallel exclusive lock
+request, which is done to avoid deadlocks with recursive shared acquisition.
+.Pp
+The
+.Dv LK_NODDLKTREAT
+flag can only be used by code which requests shared non-recursive lock.
+The flag allows exclusive requests to preempt the current shared request
+even if the current thread owns shared locks.
+This is safe since shared lock is guaranteed to not recurse, and is used
+when thread is known to held unrelated shared locks, to not cause
+unneccessary starvation.  An example is
+.Dv vp
+locking in VFS
+.Xr lookup 9 ,
+when
+.Dv dvp
+is already locked.
 .El
 .It Fa ilk
 An interlock mutex for controlling group access to the lock.

Modified: head/sys/kern/kern_lock.c
==============================================================================
--- head/sys/kern/kern_lock.c	Sun Nov  2 11:47:40 2014	(r273965)
+++ head/sys/kern/kern_lock.c	Sun Nov  2 13:10:31 2014	(r273966)
@@ -115,10 +115,11 @@ CTASSERT(LK_UNLOCKED == (LK_UNLOCKED &
 	}								\
 } while (0)
 
-#define	LK_CAN_SHARE(x)							\
-	(((x) & LK_SHARE) && (((x) & LK_EXCLUSIVE_WAITERS) == 0 ||	\
-	((x) & LK_EXCLUSIVE_SPINNERS) == 0 ||				\
-	curthread->td_lk_slocks || (curthread->td_pflags & TDP_DEADLKTREAT)))
+#define	LK_CAN_SHARE(x, flags)						\
+	(((x) & LK_SHARE) &&						\
+	(((x) & (LK_EXCLUSIVE_WAITERS | LK_EXCLUSIVE_SPINNERS)) == 0 ||	\
+	(curthread->td_lk_slocks != 0 && !(flags & LK_NODDLKTREAT)) ||	\
+	(curthread->td_pflags & TDP_DEADLKTREAT)))
 #define	LK_TRYOP(x)							\
 	((x) & LK_NOWAIT)
 
@@ -530,7 +531,7 @@ __lockmgr_args(struct lock *lk, u_int fl
 			 * waiters, if we fail to acquire the shared lock
 			 * loop back and retry.
 			 */
-			if (LK_CAN_SHARE(x)) {
+			if (LK_CAN_SHARE(x, flags)) {
 				if (atomic_cmpset_acq_ptr(&lk->lk_lock, x,
 				    x + LK_ONE_SHARER))
 					break;
@@ -635,7 +636,7 @@ __lockmgr_args(struct lock *lk, u_int fl
 			 * if the lock can be acquired in shared mode, try
 			 * again.
 			 */
-			if (LK_CAN_SHARE(x)) {
+			if (LK_CAN_SHARE(x, flags)) {
 				sleepq_release(&lk->lock_object);
 				continue;
 			}

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c	Sun Nov  2 11:47:40 2014	(r273965)
+++ head/sys/kern/vfs_lookup.c	Sun Nov  2 13:10:31 2014	(r273966)
@@ -390,6 +390,7 @@ compute_cn_lkflags(struct mount *mp, int
 		lkflags &= ~LK_SHARED;
 		lkflags |= LK_EXCLUSIVE;
 	}
+	lkflags |= LK_NODDLKTREAT;
 	return (lkflags);
 }
 

Modified: head/sys/sys/lockmgr.h
==============================================================================
--- head/sys/sys/lockmgr.h	Sun Nov  2 11:47:40 2014	(r273965)
+++ head/sys/sys/lockmgr.h	Sun Nov  2 13:10:31 2014	(r273966)
@@ -158,6 +158,7 @@ _lockmgr_args_rw(struct lock *lk, u_int 
 #define	LK_RETRY	0x000400
 #define	LK_SLEEPFAIL	0x000800
 #define	LK_TIMELOCK	0x001000
+#define	LK_NODDLKTREAT	0x002000
 
 /*
  * Operations for lockmgr().


More information about the svn-src-head mailing list