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-all
mailing list