From owner-svn-src-all@freebsd.org Thu Jun 27 23:10:41 2019 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C73F515D0E4C; Thu, 27 Jun 2019 23:10:41 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 6D63D75CC6; Thu, 27 Jun 2019 23:10:41 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4A6001E376; Thu, 27 Jun 2019 23:10:41 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x5RNAf4Y027391; Thu, 27 Jun 2019 23:10:41 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x5RNAes5027389; Thu, 27 Jun 2019 23:10:40 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <201906272310.x5RNAes5027389@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Thu, 27 Jun 2019 23:10:40 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r349476 - in head/sys: kern sys X-SVN-Group: head X-SVN-Commit-Author: rmacklem X-SVN-Commit-Paths: in head/sys: kern sys X-SVN-Commit-Revision: 349476 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 6D63D75CC6 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.95 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.95)[-0.952,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 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: Thu, 27 Jun 2019 23:10:42 -0000 Author: rmacklem Date: Thu Jun 27 23:10:40 2019 New Revision: 349476 URL: https://svnweb.freebsd.org/changeset/base/349476 Log: Add non-blocking trylock variants for the rangelock functions. A future patch that will add a Linux compatible copy_file_range(2) syscall needs to be able to lock the byte ranges of two files concurrently. To do this without a risk of deadlock, a non-blocking variant of vn_rangelock_rlock() called vn_rangelock_tryrlock() was needed. This patch adds this, along with vn_rangelock_trywlock(), in order to do this. The patch also adds a couple of comments, that I hope clarify how the algorithm used in kern_rangelock.c works. Reviewed by: kib, asomers (previous version) Differential Revision: https://reviews.freebsd.org/D20645 Modified: head/sys/kern/kern_rangelock.c head/sys/sys/rangelock.h head/sys/sys/vnode.h Modified: head/sys/kern/kern_rangelock.c ============================================================================== --- head/sys/kern/kern_rangelock.c Thu Jun 27 22:50:11 2019 (r349475) +++ head/sys/kern/kern_rangelock.c Thu Jun 27 23:10:40 2019 (r349476) @@ -141,15 +141,33 @@ out: static void rangelock_unlock_locked(struct rangelock *lock, struct rl_q_entry *entry, - struct mtx *ilk) + struct mtx *ilk, bool do_calc_block) { MPASS(lock != NULL && entry != NULL && ilk != NULL); mtx_assert(ilk, MA_OWNED); - KASSERT(entry != lock->rl_currdep, ("stuck currdep")); + if (!do_calc_block) { + /* + * This is the case where rangelock_enqueue() has been called + * with trylock == true and just inserted this entry in the + * queue. + * If rl_currdep is this entry, rl_currdep needs to + * be set to the next entry in the rl_waiters list. + * However, since this entry is the last entry in the + * list, the next entry is NULL. + */ + if (lock->rl_currdep == entry) { + KASSERT(TAILQ_NEXT(lock->rl_currdep, rl_q_link) == NULL, + ("rangelock_enqueue: next entry not NULL")); + lock->rl_currdep = NULL; + } + } else + KASSERT(entry != lock->rl_currdep, ("stuck currdep")); + TAILQ_REMOVE(&lock->rl_waiters, entry, rl_q_link); - rangelock_calc_block(lock); + if (do_calc_block) + rangelock_calc_block(lock); mtx_unlock(ilk); if (curthread->td_rlqe == NULL) curthread->td_rlqe = entry; @@ -164,7 +182,7 @@ rangelock_unlock(struct rangelock *lock, void *cookie, MPASS(lock != NULL && cookie != NULL && ilk != NULL); mtx_lock(ilk); - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); } /* @@ -185,7 +203,7 @@ rangelock_unlock_range(struct rangelock *lock, void *c mtx_lock(ilk); if (entry->rl_q_end == end) { - rangelock_unlock_locked(lock, cookie, ilk); + rangelock_unlock_locked(lock, cookie, ilk, true); return (NULL); } entry->rl_q_end = end; @@ -196,11 +214,11 @@ rangelock_unlock_range(struct rangelock *lock, void *c /* * Add the lock request to the queue of the pending requests for - * rangelock. Sleep until the request can be granted. + * rangelock. Sleep until the request can be granted unless trylock == true. */ static void * rangelock_enqueue(struct rangelock *lock, off_t start, off_t end, int mode, - struct mtx *ilk) + struct mtx *ilk, bool trylock) { struct rl_q_entry *entry; struct thread *td; @@ -226,11 +244,28 @@ rangelock_enqueue(struct rangelock *lock, off_t start, */ TAILQ_INSERT_TAIL(&lock->rl_waiters, entry, rl_q_link); + /* + * If rl_currdep == NULL, there is no entry waiting for a conflicting + * range to be resolved, so set rl_currdep to this entry. If there is + * no conflicting entry for this entry, rl_currdep will be set back to + * NULL by rangelock_calc_block(). + */ if (lock->rl_currdep == NULL) lock->rl_currdep = entry; rangelock_calc_block(lock); - while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) + while (!(entry->rl_q_flags & RL_LOCK_GRANTED)) { + if (trylock) { + /* + * For this case, the range is not actually locked + * yet, but removal from the list requires the same + * steps, except for not doing a rangelock_calc_block() + * call, since rangelock_calc_block() was called above. + */ + rangelock_unlock_locked(lock, entry, ilk, false); + return (NULL); + } msleep(entry, ilk, 0, "range", 0); + } mtx_unlock(ilk); return (entry); } @@ -239,12 +274,28 @@ void * rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, false)); } void * +rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_READ, ilk, true)); +} + +void * rangelock_wlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk) { - return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk)); + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, false)); +} + +void * +rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk) +{ + + return (rangelock_enqueue(lock, start, end, RL_LOCK_WRITE, ilk, true)); } Modified: head/sys/sys/rangelock.h ============================================================================== --- head/sys/sys/rangelock.h Thu Jun 27 22:50:11 2019 (r349475) +++ head/sys/sys/rangelock.h Thu Jun 27 23:10:40 2019 (r349476) @@ -75,7 +75,11 @@ void *rangelock_unlock_range(struct rangelock *lock, v off_t start, off_t end, struct mtx *ilk); void *rangelock_rlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); +void *rangelock_tryrlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); void *rangelock_wlock(struct rangelock *lock, off_t start, off_t end, + struct mtx *ilk); +void *rangelock_trywlock(struct rangelock *lock, off_t start, off_t end, struct mtx *ilk); void rlqentry_free(struct rl_q_entry *rlqe); Modified: head/sys/sys/vnode.h ============================================================================== --- head/sys/sys/vnode.h Thu Jun 27 22:50:11 2019 (r349475) +++ head/sys/sys/vnode.h Thu Jun 27 23:10:40 2019 (r349476) @@ -720,8 +720,12 @@ int vn_io_fault_pgmove(vm_page_t ma[], vm_offset_t off VI_MTX(vp)) #define vn_rangelock_rlock(vp, start, end) \ rangelock_rlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_tryrlock(vp, start, end) \ + rangelock_tryrlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) #define vn_rangelock_wlock(vp, start, end) \ rangelock_wlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) +#define vn_rangelock_trywlock(vp, start, end) \ + rangelock_trywlock(&(vp)->v_rl, (start), (end), VI_MTX(vp)) int vfs_cache_lookup(struct vop_lookup_args *ap); void vfs_timestamp(struct timespec *);