summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-11-16 23:02:32 +0000
committerkib <kib@FreeBSD.org>2014-11-16 23:02:32 +0000
commite01547e9e70b57b8238e62634e4bd6c88ed32cc0 (patch)
treedc5cde361b78c3c877b05e1653ac200915de5866
parent7fb42ed981537c54e039f09af4b1cc969a4219ba (diff)
downloadFreeBSD-src-e01547e9e70b57b8238e62634e4bd6c88ed32cc0.zip
FreeBSD-src-e01547e9e70b57b8238e62634e4bd6c88ed32cc0.tar.gz
MFC r273966:
Fix two issues with lockmgr(9) LK_CAN_SHARE() test, related to the exclusive locker starvation. MFC r273986: Fix the build with ADAPTIVE_LOCKMGRS kernel option.
-rw-r--r--share/man/man9/lock.927
-rw-r--r--sys/kern/kern_lock.c15
-rw-r--r--sys/kern/vfs_lookup.c1
-rw-r--r--sys/sys/lockmgr.h1
4 files changed, 35 insertions, 9 deletions
diff --git a/share/man/man9/lock.9 b/share/man/man9/lock.9
index cb77686..b47ce0e 100644
--- a/share/man/man9/lock.9
+++ b/share/man/man9/lock.9
@@ -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.
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c
index 8fa3fba..f221569 100644
--- a/sys/kern/kern_lock.c
+++ b/sys/kern/kern_lock.c
@@ -116,10 +116,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)
@@ -531,7 +532,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk,
* 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;
@@ -615,7 +616,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk,
__func__, lk, spintries, i);
x = lk->lk_lock;
if ((x & LK_SHARE) == 0 ||
- LK_CAN_SHARE(x) != 0)
+ LK_CAN_SHARE(x, flags) != 0)
break;
cpu_spinwait();
}
@@ -636,7 +637,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk,
* 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;
}
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index c85f9ed..f301961 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -392,6 +392,7 @@ compute_cn_lkflags(struct mount *mp, int lkflags, int cnflags)
lkflags &= ~LK_SHARED;
lkflags |= LK_EXCLUSIVE;
}
+ lkflags |= LK_NODDLKTREAT;
return (lkflags);
}
diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h
index a48523f..ff0473d 100644
--- a/sys/sys/lockmgr.h
+++ b/sys/sys/lockmgr.h
@@ -158,6 +158,7 @@ _lockmgr_args_rw(struct lock *lk, u_int flags, struct rwlock *ilk,
#define LK_RETRY 0x000400
#define LK_SLEEPFAIL 0x000800
#define LK_TIMELOCK 0x001000
+#define LK_NODDLKTREAT 0x002000
/*
* Operations for lockmgr().
OpenPOWER on IntegriCloud