19454b2d8SWarner Losh /*- 292dc7331SDavid Greenman * Copyright (c) 1982, 1986, 1989, 1993 392dc7331SDavid Greenman * The Regents of the University of California. All rights reserved. 492dc7331SDavid Greenman * 592dc7331SDavid Greenman * This code is derived from software contributed to Berkeley by 692dc7331SDavid Greenman * Scooter Morris at Genentech Inc. 792dc7331SDavid Greenman * 892dc7331SDavid Greenman * Redistribution and use in source and binary forms, with or without 992dc7331SDavid Greenman * modification, are permitted provided that the following conditions 1092dc7331SDavid Greenman * are met: 1192dc7331SDavid Greenman * 1. Redistributions of source code must retain the above copyright 1292dc7331SDavid Greenman * notice, this list of conditions and the following disclaimer. 1392dc7331SDavid Greenman * 2. Redistributions in binary form must reproduce the above copyright 1492dc7331SDavid Greenman * notice, this list of conditions and the following disclaimer in the 1592dc7331SDavid Greenman * documentation and/or other materials provided with the distribution. 1692dc7331SDavid Greenman * 4. Neither the name of the University nor the names of its contributors 1792dc7331SDavid Greenman * may be used to endorse or promote products derived from this software 1892dc7331SDavid Greenman * without specific prior written permission. 1992dc7331SDavid Greenman * 2092dc7331SDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2192dc7331SDavid Greenman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2292dc7331SDavid Greenman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2392dc7331SDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2492dc7331SDavid Greenman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2592dc7331SDavid Greenman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2692dc7331SDavid Greenman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2792dc7331SDavid Greenman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2892dc7331SDavid Greenman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2992dc7331SDavid Greenman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3092dc7331SDavid Greenman * SUCH DAMAGE. 3192dc7331SDavid Greenman * 3292dc7331SDavid Greenman * @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94 3392dc7331SDavid Greenman */ 3492dc7331SDavid Greenman 35677b542eSDavid E. O'Brien #include <sys/cdefs.h> 36677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 37677b542eSDavid E. O'Brien 383f2076daSEivind Eklund #include "opt_debug_lockf.h" 393f2076daSEivind Eklund 4092dc7331SDavid Greenman #include <sys/param.h> 4192dc7331SDavid Greenman #include <sys/systm.h> 421c5bb3eaSPeter Wemm #include <sys/kernel.h> 43104a9b7eSAlexander Kabaev #include <sys/limits.h> 441cd52ec3SBruce Evans #include <sys/lock.h> 457f52a691SPoul-Henning Kamp #include <sys/mount.h> 46fb919e4dSMark Murray #include <sys/mutex.h> 4792dc7331SDavid Greenman #include <sys/proc.h> 48b71fec07SBruce Evans #include <sys/unistd.h> 4992dc7331SDavid Greenman #include <sys/vnode.h> 5092dc7331SDavid Greenman #include <sys/malloc.h> 5192dc7331SDavid Greenman #include <sys/fcntl.h> 5292dc7331SDavid Greenman #include <sys/lockf.h> 5392dc7331SDavid Greenman 5492dc7331SDavid Greenman /* 5592dc7331SDavid Greenman * This variable controls the maximum number of processes that will 5692dc7331SDavid Greenman * be checked in doing deadlock detection. 5792dc7331SDavid Greenman */ 58996c772fSJohn Dyson static int maxlockdepth = MAXDEPTH; 5992dc7331SDavid Greenman 6092dc7331SDavid Greenman #ifdef LOCKF_DEBUG 61996c772fSJohn Dyson #include <sys/sysctl.h> 62a8687b6dSBruce Evans 63a8687b6dSBruce Evans #include <ufs/ufs/quota.h> 64a8687b6dSBruce Evans #include <ufs/ufs/inode.h> 65a8687b6dSBruce Evans 6655166637SPoul-Henning Kamp 677f725eacSBruce Evans static int lockf_debug = 0; 687f725eacSBruce Evans SYSCTL_INT(_debug, OID_AUTO, lockf_debug, CTLFLAG_RW, &lockf_debug, 0, ""); 6992dc7331SDavid Greenman #endif 7092dc7331SDavid Greenman 71603c8667SAlfred Perlstein MALLOC_DEFINE(M_LOCKF, "lockf", "Byte-range locking structures"); 7255166637SPoul-Henning Kamp 7392dc7331SDavid Greenman #define NOLOCKF (struct lockf *)0 7492dc7331SDavid Greenman #define SELF 0x1 7592dc7331SDavid Greenman #define OTHERS 0x2 76bc02f1d9SJeff Roberson static int lf_clearlock(struct lockf *, struct lockf **); 774d77a549SAlfred Perlstein static int lf_findoverlap(struct lockf *, 784d77a549SAlfred Perlstein struct lockf *, int, struct lockf ***, struct lockf **); 7987b6de2bSPoul-Henning Kamp static struct lockf * 804d77a549SAlfred Perlstein lf_getblock(struct lockf *); 814d77a549SAlfred Perlstein static int lf_getlock(struct lockf *, struct flock *); 82bc02f1d9SJeff Roberson static int lf_setlock(struct lockf *, struct vnode *, struct lockf **); 83bc02f1d9SJeff Roberson static void lf_split(struct lockf *, struct lockf *, struct lockf **); 844d77a549SAlfred Perlstein static void lf_wakelock(struct lockf *); 85013e6650SJeff Roberson #ifdef LOCKF_DEBUG 86013e6650SJeff Roberson static void lf_print(char *, struct lockf *); 87013e6650SJeff Roberson static void lf_printlist(char *, struct lockf *); 88013e6650SJeff Roberson #endif 8992dc7331SDavid Greenman 9092dc7331SDavid Greenman /* 9192dc7331SDavid Greenman * Advisory record locking support 9292dc7331SDavid Greenman */ 9392dc7331SDavid Greenman int 9492dc7331SDavid Greenman lf_advlock(ap, head, size) 9592dc7331SDavid Greenman struct vop_advlock_args /* { 9692dc7331SDavid Greenman struct vnode *a_vp; 9792dc7331SDavid Greenman caddr_t a_id; 9892dc7331SDavid Greenman int a_op; 9992dc7331SDavid Greenman struct flock *a_fl; 10092dc7331SDavid Greenman int a_flags; 10192dc7331SDavid Greenman } */ *ap; 10292dc7331SDavid Greenman struct lockf **head; 10392dc7331SDavid Greenman u_quad_t size; 10492dc7331SDavid Greenman { 105bc02f1d9SJeff Roberson struct flock *fl = ap->a_fl; 106bc02f1d9SJeff Roberson struct lockf *lock; 107bc02f1d9SJeff Roberson struct vnode *vp = ap->a_vp; 108c4778eedSAndrey A. Chernov off_t start, end, oadd; 109004e08beSKonstantin Belousov struct lockf *clean, *n; 11092dc7331SDavid Greenman int error; 11192dc7331SDavid Greenman 11292dc7331SDavid Greenman /* 11392dc7331SDavid Greenman * Convert the flock structure into a start and end. 11492dc7331SDavid Greenman */ 11592dc7331SDavid Greenman switch (fl->l_whence) { 11692dc7331SDavid Greenman 11792dc7331SDavid Greenman case SEEK_SET: 11892dc7331SDavid Greenman case SEEK_CUR: 11992dc7331SDavid Greenman /* 12092dc7331SDavid Greenman * Caller is responsible for adding any necessary offset 12192dc7331SDavid Greenman * when SEEK_CUR is used. 12292dc7331SDavid Greenman */ 12392dc7331SDavid Greenman start = fl->l_start; 12492dc7331SDavid Greenman break; 12592dc7331SDavid Greenman 12692dc7331SDavid Greenman case SEEK_END: 127c8e76343SAndrey A. Chernov if (size > OFF_MAX || 128bc02f1d9SJeff Roberson (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 129bc02f1d9SJeff Roberson return (EOVERFLOW); 13092dc7331SDavid Greenman start = size + fl->l_start; 13192dc7331SDavid Greenman break; 13292dc7331SDavid Greenman 13392dc7331SDavid Greenman default: 134bc02f1d9SJeff Roberson return (EINVAL); 13592dc7331SDavid Greenman } 136bc02f1d9SJeff Roberson if (start < 0) 137bc02f1d9SJeff Roberson return (EINVAL); 138f510e1c2SAndrey A. Chernov if (fl->l_len < 0) { 139bc02f1d9SJeff Roberson if (start == 0) 140bc02f1d9SJeff Roberson return (EINVAL); 141f510e1c2SAndrey A. Chernov end = start - 1; 14262be011eSAndrey A. Chernov start += fl->l_len; 143bc02f1d9SJeff Roberson if (start < 0) 144bc02f1d9SJeff Roberson return (EINVAL); 145f510e1c2SAndrey A. Chernov } else if (fl->l_len == 0) 14692dc7331SDavid Greenman end = -1; 147a88bd8aaSBruce Evans else { 148c4778eedSAndrey A. Chernov oadd = fl->l_len - 1; 149bc02f1d9SJeff Roberson if (oadd > OFF_MAX - start) 150bc02f1d9SJeff Roberson return (EOVERFLOW); 15169cc1d0dSAndrey A. Chernov end = start + oadd; 152a88bd8aaSBruce Evans } 153a88bd8aaSBruce Evans /* 154a88bd8aaSBruce Evans * Avoid the common case of unlocking when inode has no locks. 155a88bd8aaSBruce Evans */ 156a88bd8aaSBruce Evans if (*head == (struct lockf *)0) { 157a88bd8aaSBruce Evans if (ap->a_op != F_SETLK) { 158a88bd8aaSBruce Evans fl->l_type = F_UNLCK; 159bc02f1d9SJeff Roberson return (0); 160a88bd8aaSBruce Evans } 161a88bd8aaSBruce Evans } 16292dc7331SDavid Greenman /* 163bc02f1d9SJeff Roberson * Allocate a spare structure in case we have to split. 164bc02f1d9SJeff Roberson */ 165004e08beSKonstantin Belousov clean = NULL; 166004e08beSKonstantin Belousov if (ap->a_op == F_SETLK || ap->a_op == F_UNLCK) { 167004e08beSKonstantin Belousov MALLOC(clean, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 168004e08beSKonstantin Belousov clean->lf_next = NULL; 169004e08beSKonstantin Belousov } 170bc02f1d9SJeff Roberson /* 17192dc7331SDavid Greenman * Create the lockf structure 17292dc7331SDavid Greenman */ 173a163d034SWarner Losh MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); 17492dc7331SDavid Greenman lock->lf_start = start; 17592dc7331SDavid Greenman lock->lf_end = end; 17692dc7331SDavid Greenman lock->lf_id = ap->a_id; 17759aff5fcSAlfred Perlstein /* 17859aff5fcSAlfred Perlstein * XXX The problem is that VTOI is ufs specific, so it will 17959aff5fcSAlfred Perlstein * break LOCKF_DEBUG for all other FS's other than UFS because 18059aff5fcSAlfred Perlstein * it casts the vnode->data ptr to struct inode *. 18159aff5fcSAlfred Perlstein */ 18259aff5fcSAlfred Perlstein /* lock->lf_inode = VTOI(ap->a_vp); */ 18359aff5fcSAlfred Perlstein lock->lf_inode = (struct inode *)0; 18492dc7331SDavid Greenman lock->lf_type = fl->l_type; 185996c772fSJohn Dyson lock->lf_head = head; 18692dc7331SDavid Greenman lock->lf_next = (struct lockf *)0; 187996c772fSJohn Dyson TAILQ_INIT(&lock->lf_blkhd); 18892dc7331SDavid Greenman lock->lf_flags = ap->a_flags; 18992dc7331SDavid Greenman /* 19092dc7331SDavid Greenman * Do the requested operation. 19192dc7331SDavid Greenman */ 192bc02f1d9SJeff Roberson VI_LOCK(vp); 19392dc7331SDavid Greenman switch(ap->a_op) { 19492dc7331SDavid Greenman case F_SETLK: 195004e08beSKonstantin Belousov error = lf_setlock(lock, vp, &clean); 196bc02f1d9SJeff Roberson break; 19792dc7331SDavid Greenman 19892dc7331SDavid Greenman case F_UNLCK: 199004e08beSKonstantin Belousov error = lf_clearlock(lock, &clean); 200004e08beSKonstantin Belousov lock->lf_next = clean; 201004e08beSKonstantin Belousov clean = lock; 202bc02f1d9SJeff Roberson break; 20392dc7331SDavid Greenman 20492dc7331SDavid Greenman case F_GETLK: 20592dc7331SDavid Greenman error = lf_getlock(lock, fl); 206004e08beSKonstantin Belousov lock->lf_next = clean; 207004e08beSKonstantin Belousov clean = lock; 208bc02f1d9SJeff Roberson break; 20992dc7331SDavid Greenman 21092dc7331SDavid Greenman default: 211004e08beSKonstantin Belousov lock->lf_next = clean; 212004e08beSKonstantin Belousov clean = lock; 213013e6650SJeff Roberson error = EINVAL; 214bc02f1d9SJeff Roberson break; 21592dc7331SDavid Greenman } 216bc02f1d9SJeff Roberson VI_UNLOCK(vp); 217004e08beSKonstantin Belousov for (lock = clean; lock != NULL; ) { 218004e08beSKonstantin Belousov n = lock->lf_next; 219004e08beSKonstantin Belousov free(lock, M_LOCKF); 220004e08beSKonstantin Belousov lock = n; 221004e08beSKonstantin Belousov } 222013e6650SJeff Roberson return (error); 22392dc7331SDavid Greenman } 22492dc7331SDavid Greenman 22592dc7331SDavid Greenman /* 22692dc7331SDavid Greenman * Set a byte-range lock. 22792dc7331SDavid Greenman */ 22887b6de2bSPoul-Henning Kamp static int 229004e08beSKonstantin Belousov lf_setlock(lock, vp, clean) 230bc02f1d9SJeff Roberson struct lockf *lock; 231bc02f1d9SJeff Roberson struct vnode *vp; 232004e08beSKonstantin Belousov struct lockf **clean; 23392dc7331SDavid Greenman { 234bc02f1d9SJeff Roberson struct lockf *block; 23592dc7331SDavid Greenman struct lockf **head = lock->lf_head; 23692dc7331SDavid Greenman struct lockf **prev, *overlap, *ltmp; 23792dc7331SDavid Greenman static char lockstr[] = "lockf"; 23892dc7331SDavid Greenman int ovcase, priority, needtolink, error; 23992dc7331SDavid Greenman 24092dc7331SDavid Greenman #ifdef LOCKF_DEBUG 24192dc7331SDavid Greenman if (lockf_debug & 1) 24292dc7331SDavid Greenman lf_print("lf_setlock", lock); 24392dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 24492dc7331SDavid Greenman 24592dc7331SDavid Greenman /* 24692dc7331SDavid Greenman * Set the priority 24792dc7331SDavid Greenman */ 24892dc7331SDavid Greenman priority = PLOCK; 24992dc7331SDavid Greenman if (lock->lf_type == F_WRLCK) 25092dc7331SDavid Greenman priority += 4; 25192dc7331SDavid Greenman priority |= PCATCH; 25292dc7331SDavid Greenman /* 25392dc7331SDavid Greenman * Scan lock list for this file looking for locks that would block us. 25492dc7331SDavid Greenman */ 255bb56ec4aSPoul-Henning Kamp while ((block = lf_getblock(lock))) { 25692dc7331SDavid Greenman /* 25792dc7331SDavid Greenman * Free the structure and return if nonblocking. 25892dc7331SDavid Greenman */ 25992dc7331SDavid Greenman if ((lock->lf_flags & F_WAIT) == 0) { 260004e08beSKonstantin Belousov lock->lf_next = *clean; 261004e08beSKonstantin Belousov *clean = lock; 26292dc7331SDavid Greenman return (EAGAIN); 26392dc7331SDavid Greenman } 26492dc7331SDavid Greenman /* 26592dc7331SDavid Greenman * We are blocked. Since flock style locks cover 26692dc7331SDavid Greenman * the whole file, there is no chance for deadlock. 26792dc7331SDavid Greenman * For byte-range locks we must check for deadlock. 26892dc7331SDavid Greenman * 26992dc7331SDavid Greenman * Deadlock detection is done by looking through the 27092dc7331SDavid Greenman * wait channels to see if there are any cycles that 27192dc7331SDavid Greenman * involve us. MAXDEPTH is set just to make sure we 27292dc7331SDavid Greenman * do not go off into neverland. 27392dc7331SDavid Greenman */ 27492dc7331SDavid Greenman if ((lock->lf_flags & F_POSIX) && 27592dc7331SDavid Greenman (block->lf_flags & F_POSIX)) { 276982d11f8SJeff Roberson struct proc *wproc; 277982d11f8SJeff Roberson struct proc *nproc; 278b40ce416SJulian Elischer struct thread *td; 279982d11f8SJeff Roberson struct lockf *waitblock; 28092dc7331SDavid Greenman int i = 0; 28192dc7331SDavid Greenman 28292dc7331SDavid Greenman /* The block is waiting on something */ 28392dc7331SDavid Greenman wproc = (struct proc *)block->lf_id; 284982d11f8SJeff Roberson restart: 285982d11f8SJeff Roberson nproc = NULL; 286982d11f8SJeff Roberson PROC_SLOCK(wproc); 287b40ce416SJulian Elischer FOREACH_THREAD_IN_PROC(wproc, td) { 288982d11f8SJeff Roberson thread_lock(td); 289b40ce416SJulian Elischer while (td->td_wchan && 290b40ce416SJulian Elischer (td->td_wmesg == lockstr) && 29192dc7331SDavid Greenman (i++ < maxlockdepth)) { 292b40ce416SJulian Elischer waitblock = (struct lockf *)td->td_wchan; 29392dc7331SDavid Greenman /* Get the owner of the blocking lock */ 29492dc7331SDavid Greenman waitblock = waitblock->lf_next; 29592dc7331SDavid Greenman if ((waitblock->lf_flags & F_POSIX) == 0) 29692dc7331SDavid Greenman break; 297982d11f8SJeff Roberson nproc = (struct proc *)waitblock->lf_id; 298982d11f8SJeff Roberson if (nproc == (struct proc *)lock->lf_id) { 299982d11f8SJeff Roberson PROC_SUNLOCK(wproc); 300982d11f8SJeff Roberson thread_unlock(td); 301004e08beSKonstantin Belousov lock->lf_next = *clean; 302004e08beSKonstantin Belousov *clean = lock; 30392dc7331SDavid Greenman return (EDEADLK); 30492dc7331SDavid Greenman } 30592dc7331SDavid Greenman } 306982d11f8SJeff Roberson thread_unlock(td); 307b40ce416SJulian Elischer } 308982d11f8SJeff Roberson PROC_SUNLOCK(wproc); 309982d11f8SJeff Roberson wproc = nproc; 310982d11f8SJeff Roberson if (wproc) 311982d11f8SJeff Roberson goto restart; 31292dc7331SDavid Greenman } 31392dc7331SDavid Greenman /* 31492dc7331SDavid Greenman * For flock type locks, we must first remove 31592dc7331SDavid Greenman * any shared locks that we hold before we sleep 31692dc7331SDavid Greenman * waiting for an exclusive lock. 31792dc7331SDavid Greenman */ 31892dc7331SDavid Greenman if ((lock->lf_flags & F_FLOCK) && 31992dc7331SDavid Greenman lock->lf_type == F_WRLCK) { 32092dc7331SDavid Greenman lock->lf_type = F_UNLCK; 321004e08beSKonstantin Belousov (void) lf_clearlock(lock, clean); 32292dc7331SDavid Greenman lock->lf_type = F_WRLCK; 32392dc7331SDavid Greenman } 32492dc7331SDavid Greenman /* 32592dc7331SDavid Greenman * Add our lock to the blocked list and sleep until we're free. 32692dc7331SDavid Greenman * Remember who blocked us (for deadlock detection). 32792dc7331SDavid Greenman */ 32892dc7331SDavid Greenman lock->lf_next = block; 329996c772fSJohn Dyson TAILQ_INSERT_TAIL(&block->lf_blkhd, lock, lf_block); 33092dc7331SDavid Greenman #ifdef LOCKF_DEBUG 33192dc7331SDavid Greenman if (lockf_debug & 1) { 33292dc7331SDavid Greenman lf_print("lf_setlock: blocking on", block); 33392dc7331SDavid Greenman lf_printlist("lf_setlock", block); 33492dc7331SDavid Greenman } 33592dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 336bc02f1d9SJeff Roberson error = msleep(lock, VI_MTX(vp), priority, lockstr, 0); 33792dc7331SDavid Greenman /* 3381168ab08SBruce Evans * We may have been awakened by a signal and/or by a 3391168ab08SBruce Evans * debugger continuing us (in which cases we must remove 3401168ab08SBruce Evans * ourselves from the blocked list) and/or by another 3411168ab08SBruce Evans * process releasing a lock (in which case we have 3421168ab08SBruce Evans * already been removed from the blocked list and our 343996c772fSJohn Dyson * lf_next field set to NOLOCKF). 34492dc7331SDavid Greenman */ 3451168ab08SBruce Evans if (lock->lf_next) { 3461168ab08SBruce Evans TAILQ_REMOVE(&lock->lf_next->lf_blkhd, lock, lf_block); 3471168ab08SBruce Evans lock->lf_next = NOLOCKF; 3481168ab08SBruce Evans } 3491168ab08SBruce Evans if (error) { 350004e08beSKonstantin Belousov lock->lf_next = *clean; 351004e08beSKonstantin Belousov *clean = lock; 35292dc7331SDavid Greenman return (error); 35392dc7331SDavid Greenman } 35492dc7331SDavid Greenman } 35592dc7331SDavid Greenman /* 35692dc7331SDavid Greenman * No blocks!! Add the lock. Note that we will 35792dc7331SDavid Greenman * downgrade or upgrade any overlapping locks this 35892dc7331SDavid Greenman * process already owns. 35992dc7331SDavid Greenman * 36092dc7331SDavid Greenman * Skip over locks owned by other processes. 36192dc7331SDavid Greenman * Handle any locks that overlap and are owned by ourselves. 36292dc7331SDavid Greenman */ 36392dc7331SDavid Greenman prev = head; 36492dc7331SDavid Greenman block = *head; 36592dc7331SDavid Greenman needtolink = 1; 36692dc7331SDavid Greenman for (;;) { 367bb56ec4aSPoul-Henning Kamp ovcase = lf_findoverlap(block, lock, SELF, &prev, &overlap); 368bb56ec4aSPoul-Henning Kamp if (ovcase) 36992dc7331SDavid Greenman block = overlap->lf_next; 37092dc7331SDavid Greenman /* 37192dc7331SDavid Greenman * Six cases: 37292dc7331SDavid Greenman * 0) no overlap 37392dc7331SDavid Greenman * 1) overlap == lock 37492dc7331SDavid Greenman * 2) overlap contains lock 37592dc7331SDavid Greenman * 3) lock contains overlap 37692dc7331SDavid Greenman * 4) overlap starts before lock 37792dc7331SDavid Greenman * 5) overlap ends after lock 37892dc7331SDavid Greenman */ 37992dc7331SDavid Greenman switch (ovcase) { 38092dc7331SDavid Greenman case 0: /* no overlap */ 38192dc7331SDavid Greenman if (needtolink) { 38292dc7331SDavid Greenman *prev = lock; 38392dc7331SDavid Greenman lock->lf_next = overlap; 38492dc7331SDavid Greenman } 38592dc7331SDavid Greenman break; 38692dc7331SDavid Greenman 38792dc7331SDavid Greenman case 1: /* overlap == lock */ 38892dc7331SDavid Greenman /* 38992dc7331SDavid Greenman * If downgrading lock, others may be 39092dc7331SDavid Greenman * able to acquire it. 39192dc7331SDavid Greenman */ 39292dc7331SDavid Greenman if (lock->lf_type == F_RDLCK && 39392dc7331SDavid Greenman overlap->lf_type == F_WRLCK) 39492dc7331SDavid Greenman lf_wakelock(overlap); 39592dc7331SDavid Greenman overlap->lf_type = lock->lf_type; 396004e08beSKonstantin Belousov lock->lf_next = *clean; 397004e08beSKonstantin Belousov *clean = lock; 39892dc7331SDavid Greenman lock = overlap; /* for debug output below */ 39992dc7331SDavid Greenman break; 40092dc7331SDavid Greenman 40192dc7331SDavid Greenman case 2: /* overlap contains lock */ 40292dc7331SDavid Greenman /* 40392dc7331SDavid Greenman * Check for common starting point and different types. 40492dc7331SDavid Greenman */ 40592dc7331SDavid Greenman if (overlap->lf_type == lock->lf_type) { 406004e08beSKonstantin Belousov lock->lf_next = *clean; 407004e08beSKonstantin Belousov *clean = lock; 40892dc7331SDavid Greenman lock = overlap; /* for debug output below */ 40992dc7331SDavid Greenman break; 41092dc7331SDavid Greenman } 41192dc7331SDavid Greenman if (overlap->lf_start == lock->lf_start) { 41292dc7331SDavid Greenman *prev = lock; 41392dc7331SDavid Greenman lock->lf_next = overlap; 41492dc7331SDavid Greenman overlap->lf_start = lock->lf_end + 1; 41592dc7331SDavid Greenman } else 416004e08beSKonstantin Belousov lf_split(overlap, lock, clean); 41792dc7331SDavid Greenman lf_wakelock(overlap); 41892dc7331SDavid Greenman break; 41992dc7331SDavid Greenman 42092dc7331SDavid Greenman case 3: /* lock contains overlap */ 42192dc7331SDavid Greenman /* 42292dc7331SDavid Greenman * If downgrading lock, others may be able to 42392dc7331SDavid Greenman * acquire it, otherwise take the list. 42492dc7331SDavid Greenman */ 42592dc7331SDavid Greenman if (lock->lf_type == F_RDLCK && 42692dc7331SDavid Greenman overlap->lf_type == F_WRLCK) { 42792dc7331SDavid Greenman lf_wakelock(overlap); 42892dc7331SDavid Greenman } else { 4291b727751SPoul-Henning Kamp while (!TAILQ_EMPTY(&overlap->lf_blkhd)) { 4301b727751SPoul-Henning Kamp ltmp = TAILQ_FIRST(&overlap->lf_blkhd); 431996c772fSJohn Dyson TAILQ_REMOVE(&overlap->lf_blkhd, ltmp, 432996c772fSJohn Dyson lf_block); 433996c772fSJohn Dyson TAILQ_INSERT_TAIL(&lock->lf_blkhd, 434996c772fSJohn Dyson ltmp, lf_block); 435db72e058SDmitrij Tejblum ltmp->lf_next = lock; 436996c772fSJohn Dyson } 43792dc7331SDavid Greenman } 43892dc7331SDavid Greenman /* 43992dc7331SDavid Greenman * Add the new lock if necessary and delete the overlap. 44092dc7331SDavid Greenman */ 44192dc7331SDavid Greenman if (needtolink) { 44292dc7331SDavid Greenman *prev = lock; 44392dc7331SDavid Greenman lock->lf_next = overlap->lf_next; 44492dc7331SDavid Greenman prev = &lock->lf_next; 44592dc7331SDavid Greenman needtolink = 0; 44692dc7331SDavid Greenman } else 44792dc7331SDavid Greenman *prev = overlap->lf_next; 448004e08beSKonstantin Belousov overlap->lf_next = *clean; 449004e08beSKonstantin Belousov *clean = overlap; 45092dc7331SDavid Greenman continue; 45192dc7331SDavid Greenman 45292dc7331SDavid Greenman case 4: /* overlap starts before lock */ 45392dc7331SDavid Greenman /* 45492dc7331SDavid Greenman * Add lock after overlap on the list. 45592dc7331SDavid Greenman */ 45692dc7331SDavid Greenman lock->lf_next = overlap->lf_next; 45792dc7331SDavid Greenman overlap->lf_next = lock; 45892dc7331SDavid Greenman overlap->lf_end = lock->lf_start - 1; 45992dc7331SDavid Greenman prev = &lock->lf_next; 46092dc7331SDavid Greenman lf_wakelock(overlap); 46192dc7331SDavid Greenman needtolink = 0; 46292dc7331SDavid Greenman continue; 46392dc7331SDavid Greenman 46492dc7331SDavid Greenman case 5: /* overlap ends after lock */ 46592dc7331SDavid Greenman /* 46692dc7331SDavid Greenman * Add the new lock before overlap. 46792dc7331SDavid Greenman */ 46892dc7331SDavid Greenman if (needtolink) { 46992dc7331SDavid Greenman *prev = lock; 47092dc7331SDavid Greenman lock->lf_next = overlap; 47192dc7331SDavid Greenman } 47292dc7331SDavid Greenman overlap->lf_start = lock->lf_end + 1; 47392dc7331SDavid Greenman lf_wakelock(overlap); 47492dc7331SDavid Greenman break; 47592dc7331SDavid Greenman } 47692dc7331SDavid Greenman break; 47792dc7331SDavid Greenman } 47892dc7331SDavid Greenman #ifdef LOCKF_DEBUG 47992dc7331SDavid Greenman if (lockf_debug & 1) { 48092dc7331SDavid Greenman lf_print("lf_setlock: got the lock", lock); 48192dc7331SDavid Greenman lf_printlist("lf_setlock", lock); 48292dc7331SDavid Greenman } 48392dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 48492dc7331SDavid Greenman return (0); 48592dc7331SDavid Greenman } 48692dc7331SDavid Greenman 48792dc7331SDavid Greenman /* 48892dc7331SDavid Greenman * Remove a byte-range lock on an inode. 48992dc7331SDavid Greenman * 49092dc7331SDavid Greenman * Generally, find the lock (or an overlap to that lock) 49192dc7331SDavid Greenman * and remove it (or shrink it), then wakeup anyone we can. 49292dc7331SDavid Greenman */ 49387b6de2bSPoul-Henning Kamp static int 494004e08beSKonstantin Belousov lf_clearlock(unlock, clean) 495bc02f1d9SJeff Roberson struct lockf *unlock; 496004e08beSKonstantin Belousov struct lockf **clean; 49792dc7331SDavid Greenman { 49892dc7331SDavid Greenman struct lockf **head = unlock->lf_head; 49992dc7331SDavid Greenman register struct lockf *lf = *head; 50092dc7331SDavid Greenman struct lockf *overlap, **prev; 50192dc7331SDavid Greenman int ovcase; 50292dc7331SDavid Greenman 50392dc7331SDavid Greenman if (lf == NOLOCKF) 50492dc7331SDavid Greenman return (0); 50592dc7331SDavid Greenman #ifdef LOCKF_DEBUG 50692dc7331SDavid Greenman if (unlock->lf_type != F_UNLCK) 50792dc7331SDavid Greenman panic("lf_clearlock: bad type"); 50892dc7331SDavid Greenman if (lockf_debug & 1) 50992dc7331SDavid Greenman lf_print("lf_clearlock", unlock); 51092dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 51192dc7331SDavid Greenman prev = head; 512bb56ec4aSPoul-Henning Kamp while ((ovcase = lf_findoverlap(lf, unlock, SELF, &prev, &overlap))) { 51392dc7331SDavid Greenman /* 51492dc7331SDavid Greenman * Wakeup the list of locks to be retried. 51592dc7331SDavid Greenman */ 51692dc7331SDavid Greenman lf_wakelock(overlap); 51792dc7331SDavid Greenman 51892dc7331SDavid Greenman switch (ovcase) { 51992dc7331SDavid Greenman 52092dc7331SDavid Greenman case 1: /* overlap == lock */ 52192dc7331SDavid Greenman *prev = overlap->lf_next; 522004e08beSKonstantin Belousov overlap->lf_next = *clean; 523004e08beSKonstantin Belousov *clean = overlap; 52492dc7331SDavid Greenman break; 52592dc7331SDavid Greenman 52692dc7331SDavid Greenman case 2: /* overlap contains lock: split it */ 52792dc7331SDavid Greenman if (overlap->lf_start == unlock->lf_start) { 52892dc7331SDavid Greenman overlap->lf_start = unlock->lf_end + 1; 52992dc7331SDavid Greenman break; 53092dc7331SDavid Greenman } 531004e08beSKonstantin Belousov lf_split(overlap, unlock, clean); 53292dc7331SDavid Greenman overlap->lf_next = unlock->lf_next; 53392dc7331SDavid Greenman break; 53492dc7331SDavid Greenman 53592dc7331SDavid Greenman case 3: /* lock contains overlap */ 53692dc7331SDavid Greenman *prev = overlap->lf_next; 53792dc7331SDavid Greenman lf = overlap->lf_next; 538004e08beSKonstantin Belousov overlap->lf_next = *clean; 539004e08beSKonstantin Belousov *clean = overlap; 54092dc7331SDavid Greenman continue; 54192dc7331SDavid Greenman 54292dc7331SDavid Greenman case 4: /* overlap starts before lock */ 54392dc7331SDavid Greenman overlap->lf_end = unlock->lf_start - 1; 54492dc7331SDavid Greenman prev = &overlap->lf_next; 54592dc7331SDavid Greenman lf = overlap->lf_next; 54692dc7331SDavid Greenman continue; 54792dc7331SDavid Greenman 54892dc7331SDavid Greenman case 5: /* overlap ends after lock */ 54992dc7331SDavid Greenman overlap->lf_start = unlock->lf_end + 1; 55092dc7331SDavid Greenman break; 55192dc7331SDavid Greenman } 55292dc7331SDavid Greenman break; 55392dc7331SDavid Greenman } 55492dc7331SDavid Greenman #ifdef LOCKF_DEBUG 55592dc7331SDavid Greenman if (lockf_debug & 1) 55692dc7331SDavid Greenman lf_printlist("lf_clearlock", unlock); 55792dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 55892dc7331SDavid Greenman return (0); 55992dc7331SDavid Greenman } 56092dc7331SDavid Greenman 56192dc7331SDavid Greenman /* 56292dc7331SDavid Greenman * Check whether there is a blocking lock, 56392dc7331SDavid Greenman * and if so return its process identifier. 56492dc7331SDavid Greenman */ 56587b6de2bSPoul-Henning Kamp static int 56692dc7331SDavid Greenman lf_getlock(lock, fl) 56792dc7331SDavid Greenman register struct lockf *lock; 56892dc7331SDavid Greenman register struct flock *fl; 56992dc7331SDavid Greenman { 57092dc7331SDavid Greenman register struct lockf *block; 57192dc7331SDavid Greenman 57292dc7331SDavid Greenman #ifdef LOCKF_DEBUG 57392dc7331SDavid Greenman if (lockf_debug & 1) 57492dc7331SDavid Greenman lf_print("lf_getlock", lock); 57592dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 57692dc7331SDavid Greenman 577bb56ec4aSPoul-Henning Kamp if ((block = lf_getblock(lock))) { 57892dc7331SDavid Greenman fl->l_type = block->lf_type; 57992dc7331SDavid Greenman fl->l_whence = SEEK_SET; 58092dc7331SDavid Greenman fl->l_start = block->lf_start; 58192dc7331SDavid Greenman if (block->lf_end == -1) 58292dc7331SDavid Greenman fl->l_len = 0; 58392dc7331SDavid Greenman else 58492dc7331SDavid Greenman fl->l_len = block->lf_end - block->lf_start + 1; 58592dc7331SDavid Greenman if (block->lf_flags & F_POSIX) 58692dc7331SDavid Greenman fl->l_pid = ((struct proc *)(block->lf_id))->p_pid; 58792dc7331SDavid Greenman else 58892dc7331SDavid Greenman fl->l_pid = -1; 58992dc7331SDavid Greenman } else { 59092dc7331SDavid Greenman fl->l_type = F_UNLCK; 59192dc7331SDavid Greenman } 59292dc7331SDavid Greenman return (0); 59392dc7331SDavid Greenman } 59492dc7331SDavid Greenman 59592dc7331SDavid Greenman /* 59692dc7331SDavid Greenman * Walk the list of locks for an inode and 59792dc7331SDavid Greenman * return the first blocking lock. 59892dc7331SDavid Greenman */ 59987b6de2bSPoul-Henning Kamp static struct lockf * 60092dc7331SDavid Greenman lf_getblock(lock) 60192dc7331SDavid Greenman register struct lockf *lock; 60292dc7331SDavid Greenman { 60392dc7331SDavid Greenman struct lockf **prev, *overlap, *lf = *(lock->lf_head); 60492dc7331SDavid Greenman int ovcase; 60592dc7331SDavid Greenman 60692dc7331SDavid Greenman prev = lock->lf_head; 607bb56ec4aSPoul-Henning Kamp while ((ovcase = lf_findoverlap(lf, lock, OTHERS, &prev, &overlap))) { 60892dc7331SDavid Greenman /* 60992dc7331SDavid Greenman * We've found an overlap, see if it blocks us 61092dc7331SDavid Greenman */ 61192dc7331SDavid Greenman if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK)) 61292dc7331SDavid Greenman return (overlap); 61392dc7331SDavid Greenman /* 61492dc7331SDavid Greenman * Nope, point to the next one on the list and 61592dc7331SDavid Greenman * see if it blocks us 61692dc7331SDavid Greenman */ 61792dc7331SDavid Greenman lf = overlap->lf_next; 61892dc7331SDavid Greenman } 61992dc7331SDavid Greenman return (NOLOCKF); 62092dc7331SDavid Greenman } 62192dc7331SDavid Greenman 62292dc7331SDavid Greenman /* 62392dc7331SDavid Greenman * Walk the list of locks for an inode to 62492dc7331SDavid Greenman * find an overlapping lock (if any). 62592dc7331SDavid Greenman * 62692dc7331SDavid Greenman * NOTE: this returns only the FIRST overlapping lock. There 62792dc7331SDavid Greenman * may be more than one. 62892dc7331SDavid Greenman */ 62987b6de2bSPoul-Henning Kamp static int 63092dc7331SDavid Greenman lf_findoverlap(lf, lock, type, prev, overlap) 63192dc7331SDavid Greenman register struct lockf *lf; 63292dc7331SDavid Greenman struct lockf *lock; 63392dc7331SDavid Greenman int type; 63492dc7331SDavid Greenman struct lockf ***prev; 63592dc7331SDavid Greenman struct lockf **overlap; 63692dc7331SDavid Greenman { 63792dc7331SDavid Greenman off_t start, end; 63892dc7331SDavid Greenman 63992dc7331SDavid Greenman *overlap = lf; 64092dc7331SDavid Greenman if (lf == NOLOCKF) 64192dc7331SDavid Greenman return (0); 64292dc7331SDavid Greenman #ifdef LOCKF_DEBUG 64392dc7331SDavid Greenman if (lockf_debug & 2) 64492dc7331SDavid Greenman lf_print("lf_findoverlap: looking for overlap in", lock); 64592dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 64692dc7331SDavid Greenman start = lock->lf_start; 64792dc7331SDavid Greenman end = lock->lf_end; 64892dc7331SDavid Greenman while (lf != NOLOCKF) { 64992dc7331SDavid Greenman if (((type & SELF) && lf->lf_id != lock->lf_id) || 65092dc7331SDavid Greenman ((type & OTHERS) && lf->lf_id == lock->lf_id)) { 65192dc7331SDavid Greenman *prev = &lf->lf_next; 65292dc7331SDavid Greenman *overlap = lf = lf->lf_next; 65392dc7331SDavid Greenman continue; 65492dc7331SDavid Greenman } 65592dc7331SDavid Greenman #ifdef LOCKF_DEBUG 65692dc7331SDavid Greenman if (lockf_debug & 2) 65792dc7331SDavid Greenman lf_print("\tchecking", lf); 65892dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 65992dc7331SDavid Greenman /* 66092dc7331SDavid Greenman * OK, check for overlap 66192dc7331SDavid Greenman * 66292dc7331SDavid Greenman * Six cases: 66392dc7331SDavid Greenman * 0) no overlap 66492dc7331SDavid Greenman * 1) overlap == lock 66592dc7331SDavid Greenman * 2) overlap contains lock 66692dc7331SDavid Greenman * 3) lock contains overlap 66792dc7331SDavid Greenman * 4) overlap starts before lock 66892dc7331SDavid Greenman * 5) overlap ends after lock 66992dc7331SDavid Greenman */ 67092dc7331SDavid Greenman if ((lf->lf_end != -1 && start > lf->lf_end) || 67192dc7331SDavid Greenman (end != -1 && lf->lf_start > end)) { 67292dc7331SDavid Greenman /* Case 0 */ 67392dc7331SDavid Greenman #ifdef LOCKF_DEBUG 67492dc7331SDavid Greenman if (lockf_debug & 2) 67592dc7331SDavid Greenman printf("no overlap\n"); 67692dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 67792dc7331SDavid Greenman if ((type & SELF) && end != -1 && lf->lf_start > end) 67892dc7331SDavid Greenman return (0); 67992dc7331SDavid Greenman *prev = &lf->lf_next; 68092dc7331SDavid Greenman *overlap = lf = lf->lf_next; 68192dc7331SDavid Greenman continue; 68292dc7331SDavid Greenman } 68392dc7331SDavid Greenman if ((lf->lf_start == start) && (lf->lf_end == end)) { 68492dc7331SDavid Greenman /* Case 1 */ 68592dc7331SDavid Greenman #ifdef LOCKF_DEBUG 68692dc7331SDavid Greenman if (lockf_debug & 2) 68792dc7331SDavid Greenman printf("overlap == lock\n"); 68892dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 68992dc7331SDavid Greenman return (1); 69092dc7331SDavid Greenman } 69192dc7331SDavid Greenman if ((lf->lf_start <= start) && 69292dc7331SDavid Greenman (end != -1) && 69392dc7331SDavid Greenman ((lf->lf_end >= end) || (lf->lf_end == -1))) { 69492dc7331SDavid Greenman /* Case 2 */ 69592dc7331SDavid Greenman #ifdef LOCKF_DEBUG 69692dc7331SDavid Greenman if (lockf_debug & 2) 69792dc7331SDavid Greenman printf("overlap contains lock\n"); 69892dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 69992dc7331SDavid Greenman return (2); 70092dc7331SDavid Greenman } 70192dc7331SDavid Greenman if (start <= lf->lf_start && 70292dc7331SDavid Greenman (end == -1 || 70392dc7331SDavid Greenman (lf->lf_end != -1 && end >= lf->lf_end))) { 70492dc7331SDavid Greenman /* Case 3 */ 70592dc7331SDavid Greenman #ifdef LOCKF_DEBUG 70692dc7331SDavid Greenman if (lockf_debug & 2) 70792dc7331SDavid Greenman printf("lock contains overlap\n"); 70892dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 70992dc7331SDavid Greenman return (3); 71092dc7331SDavid Greenman } 71192dc7331SDavid Greenman if ((lf->lf_start < start) && 71292dc7331SDavid Greenman ((lf->lf_end >= start) || (lf->lf_end == -1))) { 71392dc7331SDavid Greenman /* Case 4 */ 71492dc7331SDavid Greenman #ifdef LOCKF_DEBUG 71592dc7331SDavid Greenman if (lockf_debug & 2) 71692dc7331SDavid Greenman printf("overlap starts before lock\n"); 71792dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 71892dc7331SDavid Greenman return (4); 71992dc7331SDavid Greenman } 72092dc7331SDavid Greenman if ((lf->lf_start > start) && 72192dc7331SDavid Greenman (end != -1) && 72292dc7331SDavid Greenman ((lf->lf_end > end) || (lf->lf_end == -1))) { 72392dc7331SDavid Greenman /* Case 5 */ 72492dc7331SDavid Greenman #ifdef LOCKF_DEBUG 72592dc7331SDavid Greenman if (lockf_debug & 2) 72692dc7331SDavid Greenman printf("overlap ends after lock\n"); 72792dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 72892dc7331SDavid Greenman return (5); 72992dc7331SDavid Greenman } 73092dc7331SDavid Greenman panic("lf_findoverlap: default"); 73192dc7331SDavid Greenman } 73292dc7331SDavid Greenman return (0); 73392dc7331SDavid Greenman } 73492dc7331SDavid Greenman 73592dc7331SDavid Greenman /* 73692dc7331SDavid Greenman * Split a lock and a contained region into 73792dc7331SDavid Greenman * two or three locks as necessary. 73892dc7331SDavid Greenman */ 73987b6de2bSPoul-Henning Kamp static void 740bc02f1d9SJeff Roberson lf_split(lock1, lock2, split) 741bc02f1d9SJeff Roberson struct lockf *lock1; 742bc02f1d9SJeff Roberson struct lockf *lock2; 743bc02f1d9SJeff Roberson struct lockf **split; 74492dc7331SDavid Greenman { 745bc02f1d9SJeff Roberson struct lockf *splitlock; 74692dc7331SDavid Greenman 74792dc7331SDavid Greenman #ifdef LOCKF_DEBUG 74892dc7331SDavid Greenman if (lockf_debug & 2) { 74992dc7331SDavid Greenman lf_print("lf_split", lock1); 75092dc7331SDavid Greenman lf_print("splitting from", lock2); 75192dc7331SDavid Greenman } 75292dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 75392dc7331SDavid Greenman /* 75492dc7331SDavid Greenman * Check to see if spliting into only two pieces. 75592dc7331SDavid Greenman */ 75692dc7331SDavid Greenman if (lock1->lf_start == lock2->lf_start) { 75792dc7331SDavid Greenman lock1->lf_start = lock2->lf_end + 1; 75892dc7331SDavid Greenman lock2->lf_next = lock1; 75992dc7331SDavid Greenman return; 76092dc7331SDavid Greenman } 76192dc7331SDavid Greenman if (lock1->lf_end == lock2->lf_end) { 76292dc7331SDavid Greenman lock1->lf_end = lock2->lf_start - 1; 76392dc7331SDavid Greenman lock2->lf_next = lock1->lf_next; 76492dc7331SDavid Greenman lock1->lf_next = lock2; 76592dc7331SDavid Greenman return; 76692dc7331SDavid Greenman } 76792dc7331SDavid Greenman /* 76892dc7331SDavid Greenman * Make a new lock consisting of the last part of 769bc02f1d9SJeff Roberson * the encompassing lock. We use the preallocated 770bc02f1d9SJeff Roberson * splitlock so we don't have to block. 77192dc7331SDavid Greenman */ 772bc02f1d9SJeff Roberson splitlock = *split; 773004e08beSKonstantin Belousov KASSERT(splitlock != NULL, ("no split")); 774004e08beSKonstantin Belousov *split = splitlock->lf_next; 77580208239SAlfred Perlstein bcopy(lock1, splitlock, sizeof *splitlock); 77692dc7331SDavid Greenman splitlock->lf_start = lock2->lf_end + 1; 777996c772fSJohn Dyson TAILQ_INIT(&splitlock->lf_blkhd); 77892dc7331SDavid Greenman lock1->lf_end = lock2->lf_start - 1; 77992dc7331SDavid Greenman /* 78092dc7331SDavid Greenman * OK, now link it in 78192dc7331SDavid Greenman */ 78292dc7331SDavid Greenman splitlock->lf_next = lock1->lf_next; 78392dc7331SDavid Greenman lock2->lf_next = splitlock; 78492dc7331SDavid Greenman lock1->lf_next = lock2; 78592dc7331SDavid Greenman } 78692dc7331SDavid Greenman 78792dc7331SDavid Greenman /* 78892dc7331SDavid Greenman * Wakeup a blocklist 78992dc7331SDavid Greenman */ 79087b6de2bSPoul-Henning Kamp static void 79192dc7331SDavid Greenman lf_wakelock(listhead) 79292dc7331SDavid Greenman struct lockf *listhead; 79392dc7331SDavid Greenman { 794996c772fSJohn Dyson register struct lockf *wakelock; 79592dc7331SDavid Greenman 7961b727751SPoul-Henning Kamp while (!TAILQ_EMPTY(&listhead->lf_blkhd)) { 7971b727751SPoul-Henning Kamp wakelock = TAILQ_FIRST(&listhead->lf_blkhd); 798996c772fSJohn Dyson TAILQ_REMOVE(&listhead->lf_blkhd, wakelock, lf_block); 79992dc7331SDavid Greenman wakelock->lf_next = NOLOCKF; 80092dc7331SDavid Greenman #ifdef LOCKF_DEBUG 80192dc7331SDavid Greenman if (lockf_debug & 2) 80292dc7331SDavid Greenman lf_print("lf_wakelock: awakening", wakelock); 80392dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 80480208239SAlfred Perlstein wakeup(wakelock); 80592dc7331SDavid Greenman } 80692dc7331SDavid Greenman } 80792dc7331SDavid Greenman 80892dc7331SDavid Greenman #ifdef LOCKF_DEBUG 80992dc7331SDavid Greenman /* 81092dc7331SDavid Greenman * Print out a lock. 81192dc7331SDavid Greenman */ 812013e6650SJeff Roberson static void 81392dc7331SDavid Greenman lf_print(tag, lock) 81492dc7331SDavid Greenman char *tag; 81592dc7331SDavid Greenman register struct lockf *lock; 81692dc7331SDavid Greenman { 81792dc7331SDavid Greenman 818d974cf4dSBruce Evans printf("%s: lock %p for ", tag, (void *)lock); 81992dc7331SDavid Greenman if (lock->lf_flags & F_POSIX) 820d974cf4dSBruce Evans printf("proc %ld", (long)((struct proc *)lock->lf_id)->p_pid); 82192dc7331SDavid Greenman else 822d974cf4dSBruce Evans printf("id %p", (void *)lock->lf_id); 82359aff5fcSAlfred Perlstein if (lock->lf_inode != (struct inode *)0) 8247933351aSPoul-Henning Kamp printf(" in ino %ju on dev <%s>, %s, start %jd, end %jd", 825a7a00d05SMaxime Henrion (uintmax_t)lock->lf_inode->i_number, 8267933351aSPoul-Henning Kamp devtoname(lock->lf_inode->i_dev), 82792dc7331SDavid Greenman lock->lf_type == F_RDLCK ? "shared" : 82892dc7331SDavid Greenman lock->lf_type == F_WRLCK ? "exclusive" : 829a7a00d05SMaxime Henrion lock->lf_type == F_UNLCK ? "unlock" : "unknown", 830a7a00d05SMaxime Henrion (intmax_t)lock->lf_start, (intmax_t)lock->lf_end); 83159aff5fcSAlfred Perlstein else 832a7a00d05SMaxime Henrion printf(" %s, start %jd, end %jd", 83359aff5fcSAlfred Perlstein lock->lf_type == F_RDLCK ? "shared" : 83459aff5fcSAlfred Perlstein lock->lf_type == F_WRLCK ? "exclusive" : 835a7a00d05SMaxime Henrion lock->lf_type == F_UNLCK ? "unlock" : "unknown", 836a7a00d05SMaxime Henrion (intmax_t)lock->lf_start, (intmax_t)lock->lf_end); 8371b727751SPoul-Henning Kamp if (!TAILQ_EMPTY(&lock->lf_blkhd)) 8381b727751SPoul-Henning Kamp printf(" block %p\n", (void *)TAILQ_FIRST(&lock->lf_blkhd)); 83992dc7331SDavid Greenman else 84092dc7331SDavid Greenman printf("\n"); 84192dc7331SDavid Greenman } 84292dc7331SDavid Greenman 843013e6650SJeff Roberson static void 84492dc7331SDavid Greenman lf_printlist(tag, lock) 84592dc7331SDavid Greenman char *tag; 84692dc7331SDavid Greenman struct lockf *lock; 84792dc7331SDavid Greenman { 848996c772fSJohn Dyson register struct lockf *lf, *blk; 84992dc7331SDavid Greenman 85059aff5fcSAlfred Perlstein if (lock->lf_inode == (struct inode *)0) 85159aff5fcSAlfred Perlstein return; 85259aff5fcSAlfred Perlstein 85397eb8cfaSPoul-Henning Kamp printf("%s: Lock list for ino %ju on dev <%s>:\n", 854a7a00d05SMaxime Henrion tag, (uintmax_t)lock->lf_inode->i_number, 85597eb8cfaSPoul-Henning Kamp devtoname(lock->lf_inode->i_dev)); 85692dc7331SDavid Greenman for (lf = lock->lf_inode->i_lockf; lf; lf = lf->lf_next) { 857d974cf4dSBruce Evans printf("\tlock %p for ",(void *)lf); 85892dc7331SDavid Greenman if (lf->lf_flags & F_POSIX) 859d974cf4dSBruce Evans printf("proc %ld", 860d974cf4dSBruce Evans (long)((struct proc *)lf->lf_id)->p_pid); 86192dc7331SDavid Greenman else 862d974cf4dSBruce Evans printf("id %p", (void *)lf->lf_id); 863a7a00d05SMaxime Henrion printf(", %s, start %jd, end %jd", 86492dc7331SDavid Greenman lf->lf_type == F_RDLCK ? "shared" : 86592dc7331SDavid Greenman lf->lf_type == F_WRLCK ? "exclusive" : 86692dc7331SDavid Greenman lf->lf_type == F_UNLCK ? "unlock" : 867a7a00d05SMaxime Henrion "unknown", (intmax_t)lf->lf_start, (intmax_t)lf->lf_end); 8681b727751SPoul-Henning Kamp TAILQ_FOREACH(blk, &lf->lf_blkhd, lf_block) { 869d974cf4dSBruce Evans printf("\n\t\tlock request %p for ", (void *)blk); 870996c772fSJohn Dyson if (blk->lf_flags & F_POSIX) 871d974cf4dSBruce Evans printf("proc %ld", 872d974cf4dSBruce Evans (long)((struct proc *)blk->lf_id)->p_pid); 87392dc7331SDavid Greenman else 874d974cf4dSBruce Evans printf("id %p", (void *)blk->lf_id); 875a7a00d05SMaxime Henrion printf(", %s, start %jd, end %jd", 876996c772fSJohn Dyson blk->lf_type == F_RDLCK ? "shared" : 877996c772fSJohn Dyson blk->lf_type == F_WRLCK ? "exclusive" : 878996c772fSJohn Dyson blk->lf_type == F_UNLCK ? "unlock" : 879a7a00d05SMaxime Henrion "unknown", (intmax_t)blk->lf_start, 880a7a00d05SMaxime Henrion (intmax_t)blk->lf_end); 8811b727751SPoul-Henning Kamp if (!TAILQ_EMPTY(&blk->lf_blkhd)) 882996c772fSJohn Dyson panic("lf_printlist: bad list"); 883996c772fSJohn Dyson } 88492dc7331SDavid Greenman printf("\n"); 88592dc7331SDavid Greenman } 88692dc7331SDavid Greenman } 88792dc7331SDavid Greenman #endif /* LOCKF_DEBUG */ 888