From owner-svn-src-all@FreeBSD.ORG Sun Nov 2 13:10:33 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 52DD7A91; Sun, 2 Nov 2014 13:10:33 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 34390283; Sun, 2 Nov 2014 13:10:33 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sA2DAXaa003304; Sun, 2 Nov 2014 13:10:33 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sA2DAWmD003298; Sun, 2 Nov 2014 13:10:32 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201411021310.sA2DAWmD003298@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Sun, 2 Nov 2014 13:10:32 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r273966 - in head: share/man/man9 sys/kern sys/sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Nov 2014 13:10:33 -0000 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().