1*0f4c859eSApple OSS Distributions /*
2*0f4c859eSApple OSS Distributions * Copyright (c) 2019-2022 Apple Inc. All rights reserved.
3*0f4c859eSApple OSS Distributions *
4*0f4c859eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*0f4c859eSApple OSS Distributions *
6*0f4c859eSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*0f4c859eSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*0f4c859eSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*0f4c859eSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*0f4c859eSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*0f4c859eSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*0f4c859eSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*0f4c859eSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*0f4c859eSApple OSS Distributions *
15*0f4c859eSApple OSS Distributions * Please obtain a copy of the License at
16*0f4c859eSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*0f4c859eSApple OSS Distributions *
18*0f4c859eSApple OSS Distributions * The Original Code and all software distributed under the License are
19*0f4c859eSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*0f4c859eSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*0f4c859eSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*0f4c859eSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*0f4c859eSApple OSS Distributions * Please see the License for the specific language governing rights and
24*0f4c859eSApple OSS Distributions * limitations under the License.
25*0f4c859eSApple OSS Distributions *
26*0f4c859eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*0f4c859eSApple OSS Distributions */
28*0f4c859eSApple OSS Distributions /*
29*0f4c859eSApple OSS Distributions * Copyright (c) 1982, 1986, 1989, 1993
30*0f4c859eSApple OSS Distributions * The Regents of the University of California. All rights reserved.
31*0f4c859eSApple OSS Distributions *
32*0f4c859eSApple OSS Distributions * This code is derived from software contributed to Berkeley by
33*0f4c859eSApple OSS Distributions * Scooter Morris at Genentech Inc.
34*0f4c859eSApple OSS Distributions *
35*0f4c859eSApple OSS Distributions * Redistribution and use in source and binary forms, with or without
36*0f4c859eSApple OSS Distributions * modification, are permitted provided that the following conditions
37*0f4c859eSApple OSS Distributions * are met:
38*0f4c859eSApple OSS Distributions * 1. Redistributions of source code must retain the above copyright
39*0f4c859eSApple OSS Distributions * notice, this list of conditions and the following disclaimer.
40*0f4c859eSApple OSS Distributions * 2. Redistributions in binary form must reproduce the above copyright
41*0f4c859eSApple OSS Distributions * notice, this list of conditions and the following disclaimer in the
42*0f4c859eSApple OSS Distributions * documentation and/or other materials provided with the distribution.
43*0f4c859eSApple OSS Distributions * 4. Neither the name of the University nor the names of its contributors
44*0f4c859eSApple OSS Distributions * may be used to endorse or promote products derived from this software
45*0f4c859eSApple OSS Distributions * without specific prior written permission.
46*0f4c859eSApple OSS Distributions *
47*0f4c859eSApple OSS Distributions * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48*0f4c859eSApple OSS Distributions * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49*0f4c859eSApple OSS Distributions * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50*0f4c859eSApple OSS Distributions * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51*0f4c859eSApple OSS Distributions * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52*0f4c859eSApple OSS Distributions * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53*0f4c859eSApple OSS Distributions * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54*0f4c859eSApple OSS Distributions * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55*0f4c859eSApple OSS Distributions * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56*0f4c859eSApple OSS Distributions * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57*0f4c859eSApple OSS Distributions * SUCH DAMAGE.
58*0f4c859eSApple OSS Distributions *
59*0f4c859eSApple OSS Distributions * @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94
60*0f4c859eSApple OSS Distributions */
61*0f4c859eSApple OSS Distributions
62*0f4c859eSApple OSS Distributions #include <sys/cdefs.h>
63*0f4c859eSApple OSS Distributions #include <sys/param.h>
64*0f4c859eSApple OSS Distributions #include <sys/systm.h>
65*0f4c859eSApple OSS Distributions #include <sys/kernel.h>
66*0f4c859eSApple OSS Distributions #include <sys/lock.h>
67*0f4c859eSApple OSS Distributions #include <sys/mount.h>
68*0f4c859eSApple OSS Distributions #include <sys/proc.h>
69*0f4c859eSApple OSS Distributions #include <sys/signalvar.h>
70*0f4c859eSApple OSS Distributions #include <sys/unistd.h>
71*0f4c859eSApple OSS Distributions #include <sys/user.h>
72*0f4c859eSApple OSS Distributions #include <sys/vnode.h>
73*0f4c859eSApple OSS Distributions #include <sys/vnode_internal.h>
74*0f4c859eSApple OSS Distributions #include <sys/vnode_if.h>
75*0f4c859eSApple OSS Distributions #include <sys/malloc.h>
76*0f4c859eSApple OSS Distributions #include <sys/fcntl.h>
77*0f4c859eSApple OSS Distributions #include <sys/lockf.h>
78*0f4c859eSApple OSS Distributions #include <sys/sdt.h>
79*0f4c859eSApple OSS Distributions #include <kern/policy_internal.h>
80*0f4c859eSApple OSS Distributions
81*0f4c859eSApple OSS Distributions #include <sys/file_internal.h>
82*0f4c859eSApple OSS Distributions
83*0f4c859eSApple OSS Distributions #if (DEVELOPMENT || DEBUG)
84*0f4c859eSApple OSS Distributions #define LOCKF_DEBUGGING 1
85*0f4c859eSApple OSS Distributions #endif
86*0f4c859eSApple OSS Distributions
87*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
88*0f4c859eSApple OSS Distributions #include <sys/sysctl.h>
89*0f4c859eSApple OSS Distributions void lf_print(const char *tag, struct lockf *lock);
90*0f4c859eSApple OSS Distributions void lf_printlist(const char *tag, struct lockf *lock);
91*0f4c859eSApple OSS Distributions
92*0f4c859eSApple OSS Distributions #define LF_DBG_LOCKOP (1 << 0) /* setlk, getlk, clearlk */
93*0f4c859eSApple OSS Distributions #define LF_DBG_LIST (1 << 1) /* split, coalesce */
94*0f4c859eSApple OSS Distributions #define LF_DBG_IMPINH (1 << 2) /* importance inheritance */
95*0f4c859eSApple OSS Distributions #define LF_DBG_TRACE (1 << 3) /* errors, exit */
96*0f4c859eSApple OSS Distributions #define LF_DBG_DEADLOCK (1 << 4) /* deadlock detection */
97*0f4c859eSApple OSS Distributions
98*0f4c859eSApple OSS Distributions static int lockf_debug = 0; /* was 2, could be 3 ;-) */
99*0f4c859eSApple OSS Distributions SYSCTL_INT(_debug, OID_AUTO, lockf_debug, CTLFLAG_RW | CTLFLAG_LOCKED, &lockf_debug, 0, "");
100*0f4c859eSApple OSS Distributions
101*0f4c859eSApple OSS Distributions /*
102*0f4c859eSApple OSS Distributions * If the selector is set, then output the debugging diagnostic.
103*0f4c859eSApple OSS Distributions */
104*0f4c859eSApple OSS Distributions #define LOCKF_DEBUG(mask, ...) \
105*0f4c859eSApple OSS Distributions do { \
106*0f4c859eSApple OSS Distributions if ((mask) & lockf_debug) { \
107*0f4c859eSApple OSS Distributions printf("%s>", __FUNCTION__); \
108*0f4c859eSApple OSS Distributions printf(__VA_ARGS__); \
109*0f4c859eSApple OSS Distributions } \
110*0f4c859eSApple OSS Distributions } while(0)
111*0f4c859eSApple OSS Distributions
112*0f4c859eSApple OSS Distributions #define LOCKF_DEBUGP(mask) \
113*0f4c859eSApple OSS Distributions ({ \
114*0f4c859eSApple OSS Distributions ((mask) & lockf_debug); \
115*0f4c859eSApple OSS Distributions })
116*0f4c859eSApple OSS Distributions #else /* !LOCKF_DEBUGGING */
117*0f4c859eSApple OSS Distributions #define LOCKF_DEBUG(mask, ...) /* mask */
118*0f4c859eSApple OSS Distributions #endif /* !LOCKF_DEBUGGING */
119*0f4c859eSApple OSS Distributions
120*0f4c859eSApple OSS Distributions KALLOC_TYPE_DEFINE(KT_LOCKF, struct lockf, KT_PRIV_ACCT);
121*0f4c859eSApple OSS Distributions
122*0f4c859eSApple OSS Distributions #define NOLOCKF (struct lockf *)0
123*0f4c859eSApple OSS Distributions #define SELF 0x1
124*0f4c859eSApple OSS Distributions #define OTHERS 0x2
125*0f4c859eSApple OSS Distributions #define OFF_MAX 0x7fffffffffffffffULL /* max off_t */
126*0f4c859eSApple OSS Distributions
127*0f4c859eSApple OSS Distributions /* return the effective end of a 'struct lockf': lf_end == -1 is OFF_MAX */
128*0f4c859eSApple OSS Distributions #define LF_END(l) ((l)->lf_end == -1 ? OFF_MAX : (l)->lf_end)
129*0f4c859eSApple OSS Distributions
130*0f4c859eSApple OSS Distributions /*
131*0f4c859eSApple OSS Distributions * Overlapping lock states
132*0f4c859eSApple OSS Distributions *
133*0f4c859eSApple OSS Distributions * For lk_find_overlap(..., SELF, ...), the possible sequences are a single:
134*0f4c859eSApple OSS Distributions * - OVERLAP_NONE,
135*0f4c859eSApple OSS Distributions * - OVERLAP_EQUALS_LOCK, or
136*0f4c859eSApple OSS Distributions * - OVERLAP_CONTAINS_LOCK
137*0f4c859eSApple OSS Distributions *
138*0f4c859eSApple OSS Distributions * or the following sequence:
139*0f4c859eSApple OSS Distributions * - optional OVERLAP_STARTS_BEFORE_LOCK
140*0f4c859eSApple OSS Distributions * - zero or more OVERLAP_CONTAINED_BY_LOCK
141*0f4c859eSApple OSS Distributions * - optional OVERLAP_ENDS_AFTER_LOCK
142*0f4c859eSApple OSS Distributions * - OVERLAP_NONE
143*0f4c859eSApple OSS Distributions *
144*0f4c859eSApple OSS Distributions * In the annotations:
145*0f4c859eSApple OSS Distributions * - the search lock is [SS, SE] and
146*0f4c859eSApple OSS Distributions * - the returned overlap lock is [OS,OE].
147*0f4c859eSApple OSS Distributions */
148*0f4c859eSApple OSS Distributions typedef enum {
149*0f4c859eSApple OSS Distributions OVERLAP_NONE = 0,
150*0f4c859eSApple OSS Distributions OVERLAP_EQUALS_LOCK, /* OS == SS && OE == SE */
151*0f4c859eSApple OSS Distributions OVERLAP_CONTAINS_LOCK, /* OS <= SS && OE >= SE */
152*0f4c859eSApple OSS Distributions OVERLAP_CONTAINED_BY_LOCK, /* OS >= SS && OE <= SE */
153*0f4c859eSApple OSS Distributions OVERLAP_STARTS_BEFORE_LOCK, /* OS < SS && OE >= SS */
154*0f4c859eSApple OSS Distributions OVERLAP_ENDS_AFTER_LOCK /* OS > SS && OE > SE */
155*0f4c859eSApple OSS Distributions } overlap_t;
156*0f4c859eSApple OSS Distributions
157*0f4c859eSApple OSS Distributions static int lf_clearlock(struct lockf *);
158*0f4c859eSApple OSS Distributions static int lf_transferlock(struct lockf *);
159*0f4c859eSApple OSS Distributions static overlap_t lf_findoverlap(struct lockf *,
160*0f4c859eSApple OSS Distributions struct lockf *, int, struct lockf ***, struct lockf **);
161*0f4c859eSApple OSS Distributions static struct lockf *lf_getblock(struct lockf *, pid_t);
162*0f4c859eSApple OSS Distributions static int lf_getlock(struct lockf *, struct flock *, pid_t);
163*0f4c859eSApple OSS Distributions static int lf_setlock(struct lockf *, struct timespec *);
164*0f4c859eSApple OSS Distributions static int lf_split(struct lockf *, struct lockf *);
165*0f4c859eSApple OSS Distributions static void lf_wakelock(struct lockf *, boolean_t);
166*0f4c859eSApple OSS Distributions #if IMPORTANCE_INHERITANCE
167*0f4c859eSApple OSS Distributions static void lf_hold_assertion(task_t, struct lockf *);
168*0f4c859eSApple OSS Distributions static void lf_jump_to_queue_head(struct lockf *, struct lockf *);
169*0f4c859eSApple OSS Distributions static void lf_drop_assertion(struct lockf *);
170*0f4c859eSApple OSS Distributions static void lf_boost_blocking_proc(struct lockf *, struct lockf *);
171*0f4c859eSApple OSS Distributions static void lf_adjust_assertion(struct lockf *block);
172*0f4c859eSApple OSS Distributions #endif /* IMPORTANCE_INHERITANCE */
173*0f4c859eSApple OSS Distributions
174*0f4c859eSApple OSS Distributions static LCK_GRP_DECLARE(lf_dead_lock_grp, "lf_dead_lock");
175*0f4c859eSApple OSS Distributions static LCK_MTX_DECLARE(lf_dead_lock, &lf_dead_lock_grp);
176*0f4c859eSApple OSS Distributions
177*0f4c859eSApple OSS Distributions /*
178*0f4c859eSApple OSS Distributions * lf_advlock
179*0f4c859eSApple OSS Distributions *
180*0f4c859eSApple OSS Distributions * Description: Advisory record locking support
181*0f4c859eSApple OSS Distributions *
182*0f4c859eSApple OSS Distributions * Parameters: ap Argument pointer to a vnop_advlock_args
183*0f4c859eSApple OSS Distributions * argument descriptor structure for the
184*0f4c859eSApple OSS Distributions * lock operation to be attempted.
185*0f4c859eSApple OSS Distributions *
186*0f4c859eSApple OSS Distributions * Returns: 0 Success
187*0f4c859eSApple OSS Distributions * EOVERFLOW
188*0f4c859eSApple OSS Distributions * EINVAL
189*0f4c859eSApple OSS Distributions * ENOLCK Number of locked regions exceeds limit
190*0f4c859eSApple OSS Distributions * lf_setlock:EAGAIN
191*0f4c859eSApple OSS Distributions * lf_setlock:EDEADLK
192*0f4c859eSApple OSS Distributions * lf_setlock:EINTR
193*0f4c859eSApple OSS Distributions * lf_setlock:ENOLCK
194*0f4c859eSApple OSS Distributions * lf_setlock:ETIMEDOUT
195*0f4c859eSApple OSS Distributions * lf_clearlock:ENOLCK
196*0f4c859eSApple OSS Distributions * vnode_size:???
197*0f4c859eSApple OSS Distributions *
198*0f4c859eSApple OSS Distributions * Notes: We return ENOLCK when we run out of memory to support locks; as
199*0f4c859eSApple OSS Distributions * such, there is no specific expectation limit other than the
200*0f4c859eSApple OSS Distributions * amount of available resources.
201*0f4c859eSApple OSS Distributions */
202*0f4c859eSApple OSS Distributions int
lf_advlock(struct vnop_advlock_args * ap)203*0f4c859eSApple OSS Distributions lf_advlock(struct vnop_advlock_args *ap)
204*0f4c859eSApple OSS Distributions {
205*0f4c859eSApple OSS Distributions struct vnode *vp = ap->a_vp;
206*0f4c859eSApple OSS Distributions struct flock *fl = ap->a_fl;
207*0f4c859eSApple OSS Distributions vfs_context_t context = ap->a_context;
208*0f4c859eSApple OSS Distributions struct lockf *lock;
209*0f4c859eSApple OSS Distributions off_t start, end, oadd;
210*0f4c859eSApple OSS Distributions u_quad_t size;
211*0f4c859eSApple OSS Distributions int error;
212*0f4c859eSApple OSS Distributions struct lockf **head = &vp->v_lockf;
213*0f4c859eSApple OSS Distributions
214*0f4c859eSApple OSS Distributions /* XXX HFS may need a !vnode_isreg(vp) EISDIR error here */
215*0f4c859eSApple OSS Distributions
216*0f4c859eSApple OSS Distributions /*
217*0f4c859eSApple OSS Distributions * Avoid the common case of unlocking when inode has no locks.
218*0f4c859eSApple OSS Distributions */
219*0f4c859eSApple OSS Distributions if (*head == (struct lockf *)0) {
220*0f4c859eSApple OSS Distributions if (ap->a_op != F_SETLK) {
221*0f4c859eSApple OSS Distributions fl->l_type = F_UNLCK;
222*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE,
223*0f4c859eSApple OSS Distributions "lf_advlock: '%s' unlock without lock\n",
224*0f4c859eSApple OSS Distributions vfs_context_proc(context)->p_comm);
225*0f4c859eSApple OSS Distributions return 0;
226*0f4c859eSApple OSS Distributions }
227*0f4c859eSApple OSS Distributions }
228*0f4c859eSApple OSS Distributions
229*0f4c859eSApple OSS Distributions /*
230*0f4c859eSApple OSS Distributions * Convert the flock structure into a start and end.
231*0f4c859eSApple OSS Distributions */
232*0f4c859eSApple OSS Distributions switch (fl->l_whence) {
233*0f4c859eSApple OSS Distributions case SEEK_SET:
234*0f4c859eSApple OSS Distributions case SEEK_CUR:
235*0f4c859eSApple OSS Distributions /*
236*0f4c859eSApple OSS Distributions * Caller is responsible for adding any necessary offset
237*0f4c859eSApple OSS Distributions * when SEEK_CUR is used.
238*0f4c859eSApple OSS Distributions */
239*0f4c859eSApple OSS Distributions start = fl->l_start;
240*0f4c859eSApple OSS Distributions break;
241*0f4c859eSApple OSS Distributions
242*0f4c859eSApple OSS Distributions case SEEK_END:
243*0f4c859eSApple OSS Distributions
244*0f4c859eSApple OSS Distributions /*
245*0f4c859eSApple OSS Distributions * It's OK to cast the u_quad_t to and off_t here, since they
246*0f4c859eSApple OSS Distributions * are the same storage size, and the value of the returned
247*0f4c859eSApple OSS Distributions * contents will never overflow into the sign bit. We need to
248*0f4c859eSApple OSS Distributions * do this because we will use size to force range checks.
249*0f4c859eSApple OSS Distributions */
250*0f4c859eSApple OSS Distributions if ((error = vnode_size(vp, (off_t *)&size, context))) {
251*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE,
252*0f4c859eSApple OSS Distributions "lf_advlock: vnode_getattr failed: %d\n", error);
253*0f4c859eSApple OSS Distributions return error;
254*0f4c859eSApple OSS Distributions }
255*0f4c859eSApple OSS Distributions
256*0f4c859eSApple OSS Distributions if (size > OFF_MAX ||
257*0f4c859eSApple OSS Distributions (fl->l_start > 0 &&
258*0f4c859eSApple OSS Distributions size > (u_quad_t)(OFF_MAX - fl->l_start))) {
259*0f4c859eSApple OSS Distributions return EOVERFLOW;
260*0f4c859eSApple OSS Distributions }
261*0f4c859eSApple OSS Distributions start = size + fl->l_start;
262*0f4c859eSApple OSS Distributions break;
263*0f4c859eSApple OSS Distributions
264*0f4c859eSApple OSS Distributions default:
265*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE, "lf_advlock: unknown whence %d\n",
266*0f4c859eSApple OSS Distributions fl->l_whence);
267*0f4c859eSApple OSS Distributions return EINVAL;
268*0f4c859eSApple OSS Distributions }
269*0f4c859eSApple OSS Distributions if (start < 0) {
270*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE, "lf_advlock: start < 0 (%qd)\n",
271*0f4c859eSApple OSS Distributions start);
272*0f4c859eSApple OSS Distributions return EINVAL;
273*0f4c859eSApple OSS Distributions }
274*0f4c859eSApple OSS Distributions if (fl->l_len < 0) {
275*0f4c859eSApple OSS Distributions if (start == 0) {
276*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE,
277*0f4c859eSApple OSS Distributions "lf_advlock: len < 0 & start == 0\n");
278*0f4c859eSApple OSS Distributions return EINVAL;
279*0f4c859eSApple OSS Distributions }
280*0f4c859eSApple OSS Distributions end = start - 1;
281*0f4c859eSApple OSS Distributions start += fl->l_len;
282*0f4c859eSApple OSS Distributions if (start < 0) {
283*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE,
284*0f4c859eSApple OSS Distributions "lf_advlock: start < 0 (%qd)\n", start);
285*0f4c859eSApple OSS Distributions return EINVAL;
286*0f4c859eSApple OSS Distributions }
287*0f4c859eSApple OSS Distributions } else if (fl->l_len == 0) {
288*0f4c859eSApple OSS Distributions end = -1;
289*0f4c859eSApple OSS Distributions } else {
290*0f4c859eSApple OSS Distributions oadd = fl->l_len - 1;
291*0f4c859eSApple OSS Distributions if (oadd > (off_t)(OFF_MAX - start)) {
292*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE, "lf_advlock: overflow\n");
293*0f4c859eSApple OSS Distributions return EOVERFLOW;
294*0f4c859eSApple OSS Distributions }
295*0f4c859eSApple OSS Distributions end = start + oadd;
296*0f4c859eSApple OSS Distributions }
297*0f4c859eSApple OSS Distributions /*
298*0f4c859eSApple OSS Distributions * Create the lockf structure
299*0f4c859eSApple OSS Distributions */
300*0f4c859eSApple OSS Distributions lock = zalloc_flags(KT_LOCKF, Z_WAITOK | Z_NOFAIL);
301*0f4c859eSApple OSS Distributions lock->lf_start = start;
302*0f4c859eSApple OSS Distributions lock->lf_end = end;
303*0f4c859eSApple OSS Distributions lock->lf_id = ap->a_id;
304*0f4c859eSApple OSS Distributions lock->lf_vnode = vp;
305*0f4c859eSApple OSS Distributions lock->lf_type = fl->l_type;
306*0f4c859eSApple OSS Distributions lock->lf_head = head;
307*0f4c859eSApple OSS Distributions lock->lf_next = (struct lockf *)0;
308*0f4c859eSApple OSS Distributions TAILQ_INIT(&lock->lf_blkhd);
309*0f4c859eSApple OSS Distributions lock->lf_flags = (short)ap->a_flags;
310*0f4c859eSApple OSS Distributions #if IMPORTANCE_INHERITANCE
311*0f4c859eSApple OSS Distributions lock->lf_boosted = LF_NOT_BOOSTED;
312*0f4c859eSApple OSS Distributions #endif
313*0f4c859eSApple OSS Distributions if (ap->a_flags & F_POSIX) {
314*0f4c859eSApple OSS Distributions lock->lf_owner = (struct proc *)lock->lf_id;
315*0f4c859eSApple OSS Distributions } else {
316*0f4c859eSApple OSS Distributions lock->lf_owner = NULL;
317*0f4c859eSApple OSS Distributions }
318*0f4c859eSApple OSS Distributions
319*0f4c859eSApple OSS Distributions if (ap->a_flags & F_FLOCK) {
320*0f4c859eSApple OSS Distributions lock->lf_flags |= F_WAKE1_SAFE;
321*0f4c859eSApple OSS Distributions }
322*0f4c859eSApple OSS Distributions
323*0f4c859eSApple OSS Distributions lck_mtx_lock(&vp->v_lock); /* protect the lockf list */
324*0f4c859eSApple OSS Distributions /*
325*0f4c859eSApple OSS Distributions * Do the requested operation.
326*0f4c859eSApple OSS Distributions */
327*0f4c859eSApple OSS Distributions switch (ap->a_op) {
328*0f4c859eSApple OSS Distributions case F_SETLK:
329*0f4c859eSApple OSS Distributions /*
330*0f4c859eSApple OSS Distributions * For OFD locks, lf_id is derived from the fileglob.
331*0f4c859eSApple OSS Distributions * Record an "lf_owner" iff this is a confined fd
332*0f4c859eSApple OSS Distributions * i.e. it cannot escape this process and will be
333*0f4c859eSApple OSS Distributions * F_UNLCKed before the owner exits. (This is
334*0f4c859eSApple OSS Distributions * the implicit guarantee needed to ensure lf_owner
335*0f4c859eSApple OSS Distributions * remains a valid reference.)
336*0f4c859eSApple OSS Distributions */
337*0f4c859eSApple OSS Distributions if ((ap->a_flags & F_OFD_LOCK) && (ap->a_flags & F_CONFINED)) {
338*0f4c859eSApple OSS Distributions lock->lf_owner = current_proc();
339*0f4c859eSApple OSS Distributions }
340*0f4c859eSApple OSS Distributions error = lf_setlock(lock, ap->a_timeout);
341*0f4c859eSApple OSS Distributions break;
342*0f4c859eSApple OSS Distributions
343*0f4c859eSApple OSS Distributions case F_UNLCK:
344*0f4c859eSApple OSS Distributions error = lf_clearlock(lock);
345*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
346*0f4c859eSApple OSS Distributions break;
347*0f4c859eSApple OSS Distributions
348*0f4c859eSApple OSS Distributions case F_TRANSFER:
349*0f4c859eSApple OSS Distributions /*
350*0f4c859eSApple OSS Distributions * The new owner is passed in the context, set the new owner
351*0f4c859eSApple OSS Distributions * in the lf_owner field.
352*0f4c859eSApple OSS Distributions */
353*0f4c859eSApple OSS Distributions lock->lf_owner = vfs_context_proc(context);
354*0f4c859eSApple OSS Distributions assert(lock->lf_owner != current_proc());
355*0f4c859eSApple OSS Distributions error = lf_transferlock(lock);
356*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
357*0f4c859eSApple OSS Distributions break;
358*0f4c859eSApple OSS Distributions
359*0f4c859eSApple OSS Distributions case F_GETLK:
360*0f4c859eSApple OSS Distributions error = lf_getlock(lock, fl, -1);
361*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
362*0f4c859eSApple OSS Distributions break;
363*0f4c859eSApple OSS Distributions
364*0f4c859eSApple OSS Distributions case F_GETLKPID:
365*0f4c859eSApple OSS Distributions error = lf_getlock(lock, fl, fl->l_pid);
366*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
367*0f4c859eSApple OSS Distributions break;
368*0f4c859eSApple OSS Distributions
369*0f4c859eSApple OSS Distributions default:
370*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
371*0f4c859eSApple OSS Distributions error = EINVAL;
372*0f4c859eSApple OSS Distributions break;
373*0f4c859eSApple OSS Distributions }
374*0f4c859eSApple OSS Distributions lck_mtx_unlock(&vp->v_lock); /* done manipulating the list */
375*0f4c859eSApple OSS Distributions
376*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_TRACE, "lf_advlock: normal exit: %d\n", error);
377*0f4c859eSApple OSS Distributions return error;
378*0f4c859eSApple OSS Distributions }
379*0f4c859eSApple OSS Distributions
380*0f4c859eSApple OSS Distributions /*
381*0f4c859eSApple OSS Distributions * Empty the queue of msleeping requests for a lock on the given vnode.
382*0f4c859eSApple OSS Distributions * Called with the vnode already locked. Used for forced unmount, where
383*0f4c859eSApple OSS Distributions * a flock(2) invoker sleeping on a blocked lock holds an iocount reference
384*0f4c859eSApple OSS Distributions * that prevents the vnode from ever being drained. Force unmounting wins.
385*0f4c859eSApple OSS Distributions */
386*0f4c859eSApple OSS Distributions void
lf_abort_advlocks(vnode_t vp)387*0f4c859eSApple OSS Distributions lf_abort_advlocks(vnode_t vp)
388*0f4c859eSApple OSS Distributions {
389*0f4c859eSApple OSS Distributions struct lockf *lock;
390*0f4c859eSApple OSS Distributions
391*0f4c859eSApple OSS Distributions if ((lock = vp->v_lockf) == NULL) {
392*0f4c859eSApple OSS Distributions return;
393*0f4c859eSApple OSS Distributions }
394*0f4c859eSApple OSS Distributions
395*0f4c859eSApple OSS Distributions lck_mtx_assert(&vp->v_lock, LCK_MTX_ASSERT_OWNED);
396*0f4c859eSApple OSS Distributions
397*0f4c859eSApple OSS Distributions if (!TAILQ_EMPTY(&lock->lf_blkhd)) {
398*0f4c859eSApple OSS Distributions struct lockf *tlock;
399*0f4c859eSApple OSS Distributions
400*0f4c859eSApple OSS Distributions TAILQ_FOREACH(tlock, &lock->lf_blkhd, lf_block) {
401*0f4c859eSApple OSS Distributions /*
402*0f4c859eSApple OSS Distributions * Setting this flag should cause all
403*0f4c859eSApple OSS Distributions * currently blocked F_SETLK request to
404*0f4c859eSApple OSS Distributions * return to userland with an errno.
405*0f4c859eSApple OSS Distributions */
406*0f4c859eSApple OSS Distributions tlock->lf_flags |= F_ABORT;
407*0f4c859eSApple OSS Distributions }
408*0f4c859eSApple OSS Distributions lf_wakelock(lock, TRUE);
409*0f4c859eSApple OSS Distributions }
410*0f4c859eSApple OSS Distributions }
411*0f4c859eSApple OSS Distributions
412*0f4c859eSApple OSS Distributions /*
413*0f4c859eSApple OSS Distributions * Take any lock attempts which are currently blocked by a given lock ("from")
414*0f4c859eSApple OSS Distributions * and mark them as blocked by a different lock ("to"). Used in the case
415*0f4c859eSApple OSS Distributions * where a byte range currently occupied by "from" is to be occupied by "to."
416*0f4c859eSApple OSS Distributions */
417*0f4c859eSApple OSS Distributions static void
lf_move_blocked(struct lockf * to,struct lockf * from)418*0f4c859eSApple OSS Distributions lf_move_blocked(struct lockf *to, struct lockf *from)
419*0f4c859eSApple OSS Distributions {
420*0f4c859eSApple OSS Distributions struct lockf *tlock;
421*0f4c859eSApple OSS Distributions
422*0f4c859eSApple OSS Distributions TAILQ_FOREACH(tlock, &from->lf_blkhd, lf_block) {
423*0f4c859eSApple OSS Distributions tlock->lf_next = to;
424*0f4c859eSApple OSS Distributions }
425*0f4c859eSApple OSS Distributions
426*0f4c859eSApple OSS Distributions TAILQ_CONCAT(&to->lf_blkhd, &from->lf_blkhd, lf_block);
427*0f4c859eSApple OSS Distributions }
428*0f4c859eSApple OSS Distributions
429*0f4c859eSApple OSS Distributions /*
430*0f4c859eSApple OSS Distributions * lf_coalesce_adjacent
431*0f4c859eSApple OSS Distributions *
432*0f4c859eSApple OSS Distributions * Description: Helper function: when setting a lock, coalesce adjacent
433*0f4c859eSApple OSS Distributions * locks. Needed because adjacent locks are not overlapping,
434*0f4c859eSApple OSS Distributions * but POSIX requires that they be coalesced.
435*0f4c859eSApple OSS Distributions *
436*0f4c859eSApple OSS Distributions * Parameters: lock The new lock which may be adjacent
437*0f4c859eSApple OSS Distributions * to already locked regions, and which
438*0f4c859eSApple OSS Distributions * should therefore be coalesced with them
439*0f4c859eSApple OSS Distributions *
440*0f4c859eSApple OSS Distributions * Returns: <void>
441*0f4c859eSApple OSS Distributions */
442*0f4c859eSApple OSS Distributions static void
lf_coalesce_adjacent(struct lockf * lock)443*0f4c859eSApple OSS Distributions lf_coalesce_adjacent(struct lockf *lock)
444*0f4c859eSApple OSS Distributions {
445*0f4c859eSApple OSS Distributions struct lockf **lf = lock->lf_head;
446*0f4c859eSApple OSS Distributions
447*0f4c859eSApple OSS Distributions while (*lf != NOLOCKF) {
448*0f4c859eSApple OSS Distributions /* reject locks that obviously could not be coalesced */
449*0f4c859eSApple OSS Distributions if ((*lf == lock) ||
450*0f4c859eSApple OSS Distributions ((*lf)->lf_id != lock->lf_id) ||
451*0f4c859eSApple OSS Distributions ((*lf)->lf_type != lock->lf_type)) {
452*0f4c859eSApple OSS Distributions lf = &(*lf)->lf_next;
453*0f4c859eSApple OSS Distributions continue;
454*0f4c859eSApple OSS Distributions }
455*0f4c859eSApple OSS Distributions
456*0f4c859eSApple OSS Distributions /*
457*0f4c859eSApple OSS Distributions * NOTE: Assumes that if two locks are adjacent on the number line
458*0f4c859eSApple OSS Distributions * and belong to the same owner, then they are adjacent on the list.
459*0f4c859eSApple OSS Distributions */
460*0f4c859eSApple OSS Distributions if (LF_END(*lf) < OFF_MAX &&
461*0f4c859eSApple OSS Distributions (LF_END(*lf) + 1) == lock->lf_start) {
462*0f4c859eSApple OSS Distributions struct lockf *adjacent = *lf;
463*0f4c859eSApple OSS Distributions
464*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "lf_coalesce_adjacent: coalesce adjacent previous\n");
465*0f4c859eSApple OSS Distributions lock->lf_start = (*lf)->lf_start;
466*0f4c859eSApple OSS Distributions *lf = lock;
467*0f4c859eSApple OSS Distributions lf = &(*lf)->lf_next;
468*0f4c859eSApple OSS Distributions
469*0f4c859eSApple OSS Distributions lf_move_blocked(lock, adjacent);
470*0f4c859eSApple OSS Distributions
471*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, adjacent);
472*0f4c859eSApple OSS Distributions continue;
473*0f4c859eSApple OSS Distributions }
474*0f4c859eSApple OSS Distributions /* If the lock starts adjacent to us, we can coalesce it */
475*0f4c859eSApple OSS Distributions if (LF_END(lock) < OFF_MAX &&
476*0f4c859eSApple OSS Distributions (LF_END(lock) + 1) == (*lf)->lf_start) {
477*0f4c859eSApple OSS Distributions struct lockf *adjacent = *lf;
478*0f4c859eSApple OSS Distributions
479*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "lf_coalesce_adjacent: coalesce adjacent following\n");
480*0f4c859eSApple OSS Distributions lock->lf_end = (*lf)->lf_end;
481*0f4c859eSApple OSS Distributions lock->lf_next = (*lf)->lf_next;
482*0f4c859eSApple OSS Distributions lf = &lock->lf_next;
483*0f4c859eSApple OSS Distributions
484*0f4c859eSApple OSS Distributions lf_move_blocked(lock, adjacent);
485*0f4c859eSApple OSS Distributions
486*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, adjacent);
487*0f4c859eSApple OSS Distributions continue;
488*0f4c859eSApple OSS Distributions }
489*0f4c859eSApple OSS Distributions
490*0f4c859eSApple OSS Distributions /* no matching conditions; go on to next lock */
491*0f4c859eSApple OSS Distributions lf = &(*lf)->lf_next;
492*0f4c859eSApple OSS Distributions }
493*0f4c859eSApple OSS Distributions }
494*0f4c859eSApple OSS Distributions
495*0f4c859eSApple OSS Distributions /*
496*0f4c859eSApple OSS Distributions * lf_setlock
497*0f4c859eSApple OSS Distributions *
498*0f4c859eSApple OSS Distributions * Description: Set a byte-range lock.
499*0f4c859eSApple OSS Distributions *
500*0f4c859eSApple OSS Distributions * Parameters: lock The lock structure describing the lock
501*0f4c859eSApple OSS Distributions * to be set; allocated by the caller, it
502*0f4c859eSApple OSS Distributions * will be linked into the lock list if
503*0f4c859eSApple OSS Distributions * the set is successful, and freed if the
504*0f4c859eSApple OSS Distributions * set is unsuccessful.
505*0f4c859eSApple OSS Distributions *
506*0f4c859eSApple OSS Distributions * timeout Timeout specified in the case of
507*0f4c859eSApple OSS Distributions * SETLKWTIMEOUT.
508*0f4c859eSApple OSS Distributions *
509*0f4c859eSApple OSS Distributions * Returns: 0 Success
510*0f4c859eSApple OSS Distributions * EAGAIN
511*0f4c859eSApple OSS Distributions * EDEADLK
512*0f4c859eSApple OSS Distributions * lf_split:ENOLCK
513*0f4c859eSApple OSS Distributions * lf_clearlock:ENOLCK
514*0f4c859eSApple OSS Distributions * msleep:EINTR
515*0f4c859eSApple OSS Distributions * msleep:ETIMEDOUT
516*0f4c859eSApple OSS Distributions *
517*0f4c859eSApple OSS Distributions * Notes: We add the lock to the provisional lock list. We do not
518*0f4c859eSApple OSS Distributions * coalesce at this time; this has implications for other lock
519*0f4c859eSApple OSS Distributions * requestors in the blocker search mechanism.
520*0f4c859eSApple OSS Distributions */
521*0f4c859eSApple OSS Distributions static int
lf_setlock(struct lockf * lock,struct timespec * timeout)522*0f4c859eSApple OSS Distributions lf_setlock(struct lockf *lock, struct timespec *timeout)
523*0f4c859eSApple OSS Distributions {
524*0f4c859eSApple OSS Distributions struct lockf *block;
525*0f4c859eSApple OSS Distributions struct lockf **head = lock->lf_head;
526*0f4c859eSApple OSS Distributions struct lockf **prev, *overlap;
527*0f4c859eSApple OSS Distributions static const char lockstr[] = "lockf";
528*0f4c859eSApple OSS Distributions int priority, needtolink, error;
529*0f4c859eSApple OSS Distributions struct vnode *vp = lock->lf_vnode;
530*0f4c859eSApple OSS Distributions overlap_t ovcase;
531*0f4c859eSApple OSS Distributions
532*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
533*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
534*0f4c859eSApple OSS Distributions lf_print("lf_setlock", lock);
535*0f4c859eSApple OSS Distributions lf_printlist("lf_setlock(in)", lock);
536*0f4c859eSApple OSS Distributions }
537*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
538*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p Looking for deadlock, vnode %p\n", lock, lock->lf_vnode);
539*0f4c859eSApple OSS Distributions
540*0f4c859eSApple OSS Distributions /*
541*0f4c859eSApple OSS Distributions * Set the priority
542*0f4c859eSApple OSS Distributions */
543*0f4c859eSApple OSS Distributions priority = PLOCK;
544*0f4c859eSApple OSS Distributions if (lock->lf_type == F_WRLCK) {
545*0f4c859eSApple OSS Distributions priority += 4;
546*0f4c859eSApple OSS Distributions }
547*0f4c859eSApple OSS Distributions priority |= PCATCH;
548*0f4c859eSApple OSS Distributions scan:
549*0f4c859eSApple OSS Distributions /*
550*0f4c859eSApple OSS Distributions * Scan lock list for this file looking for locks that would block us.
551*0f4c859eSApple OSS Distributions */
552*0f4c859eSApple OSS Distributions while ((block = lf_getblock(lock, -1))) {
553*0f4c859eSApple OSS Distributions /*
554*0f4c859eSApple OSS Distributions * Free the structure and return if nonblocking.
555*0f4c859eSApple OSS Distributions */
556*0f4c859eSApple OSS Distributions if ((lock->lf_flags & F_WAIT) == 0) {
557*0f4c859eSApple OSS Distributions DTRACE_FSINFO(advlock__nowait, vnode_t, vp);
558*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
559*0f4c859eSApple OSS Distributions return EAGAIN;
560*0f4c859eSApple OSS Distributions }
561*0f4c859eSApple OSS Distributions
562*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p found blocking lock %p\n", lock, block);
563*0f4c859eSApple OSS Distributions
564*0f4c859eSApple OSS Distributions /*
565*0f4c859eSApple OSS Distributions * We are blocked. Since flock style locks cover
566*0f4c859eSApple OSS Distributions * the whole file, there is no chance for deadlock.
567*0f4c859eSApple OSS Distributions *
568*0f4c859eSApple OSS Distributions * OFD byte-range locks currently do NOT support
569*0f4c859eSApple OSS Distributions * deadlock detection.
570*0f4c859eSApple OSS Distributions *
571*0f4c859eSApple OSS Distributions * For POSIX byte-range locks we must check for deadlock.
572*0f4c859eSApple OSS Distributions *
573*0f4c859eSApple OSS Distributions * Deadlock detection is done by looking through the
574*0f4c859eSApple OSS Distributions * wait channels to see if there are any cycles that
575*0f4c859eSApple OSS Distributions * involve us.
576*0f4c859eSApple OSS Distributions */
577*0f4c859eSApple OSS Distributions if ((lock->lf_flags & F_POSIX) &&
578*0f4c859eSApple OSS Distributions (block->lf_flags & F_POSIX)) {
579*0f4c859eSApple OSS Distributions lck_mtx_lock(&lf_dead_lock);
580*0f4c859eSApple OSS Distributions
581*0f4c859eSApple OSS Distributions /* The blocked process is waiting on something */
582*0f4c859eSApple OSS Distributions struct proc *wproc = block->lf_owner;
583*0f4c859eSApple OSS Distributions proc_lock(wproc);
584*0f4c859eSApple OSS Distributions
585*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p owned by pid %d\n", lock, proc_pid(wproc));
586*0f4c859eSApple OSS Distributions
587*0f4c859eSApple OSS Distributions struct uthread *ut;
588*0f4c859eSApple OSS Distributions TAILQ_FOREACH(ut, &wproc->p_uthlist, uu_list) {
589*0f4c859eSApple OSS Distributions /*
590*0f4c859eSApple OSS Distributions * If the thread is (a) asleep (uu_wchan != 0)
591*0f4c859eSApple OSS Distributions * and (b) in this code (uu_wmesg == lockstr)
592*0f4c859eSApple OSS Distributions * then check to see if the lock is blocked behind
593*0f4c859eSApple OSS Distributions * someone blocked behind us.
594*0f4c859eSApple OSS Distributions *
595*0f4c859eSApple OSS Distributions * Note: (i) vp->v_lock is held, preventing other
596*0f4c859eSApple OSS Distributions * threads from mutating the blocking list for our vnode.
597*0f4c859eSApple OSS Distributions * and (ii) the proc_lock is held i.e the thread list
598*0f4c859eSApple OSS Distributions * is stable.
599*0f4c859eSApple OSS Distributions *
600*0f4c859eSApple OSS Distributions * HOWEVER some thread in wproc might be sleeping on a lockf
601*0f4c859eSApple OSS Distributions * structure for a different vnode, and be woken at any
602*0f4c859eSApple OSS Distributions * time. Thus the waitblock list could mutate while
603*0f4c859eSApple OSS Distributions * it's being inspected by this thread, and what
604*0f4c859eSApple OSS Distributions * ut->uu_wchan was just pointing at could even be freed.
605*0f4c859eSApple OSS Distributions *
606*0f4c859eSApple OSS Distributions * Nevertheless this is safe here because of lf_dead_lock; if
607*0f4c859eSApple OSS Distributions * any thread blocked with uu_wmesg == lockstr wakes (see below)
608*0f4c859eSApple OSS Distributions * it will try to acquire lf_dead_lock which is already held
609*0f4c859eSApple OSS Distributions * here. Holding that lock prevents the lockf structure being
610*0f4c859eSApple OSS Distributions * pointed at by ut->uu_wchan from going away. Thus the vnode
611*0f4c859eSApple OSS Distributions * involved can be found and locked, and the corresponding
612*0f4c859eSApple OSS Distributions * blocking chain can then be examined safely.
613*0f4c859eSApple OSS Distributions */
614*0f4c859eSApple OSS Distributions const struct lockf *waitblock = (const void *)ut->uu_wchan;
615*0f4c859eSApple OSS Distributions if ((waitblock != NULL) && (ut->uu_wmesg == lockstr)) {
616*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p which is also blocked on lock %p vnode %p\n", lock, waitblock, waitblock->lf_vnode);
617*0f4c859eSApple OSS Distributions
618*0f4c859eSApple OSS Distributions vnode_t othervp = NULL;
619*0f4c859eSApple OSS Distributions if (waitblock->lf_vnode != vp) {
620*0f4c859eSApple OSS Distributions /*
621*0f4c859eSApple OSS Distributions * This thread in wproc is waiting for a lock
622*0f4c859eSApple OSS Distributions * on a different vnode; grab the lock on it
623*0f4c859eSApple OSS Distributions * that protects lf_next while we examine it.
624*0f4c859eSApple OSS Distributions */
625*0f4c859eSApple OSS Distributions othervp = waitblock->lf_vnode;
626*0f4c859eSApple OSS Distributions if (!lck_mtx_try_lock(&othervp->v_lock)) {
627*0f4c859eSApple OSS Distributions /*
628*0f4c859eSApple OSS Distributions * avoid kernel deadlock: drop all
629*0f4c859eSApple OSS Distributions * locks, pause for a bit to let the
630*0f4c859eSApple OSS Distributions * other thread do what it needs to do,
631*0f4c859eSApple OSS Distributions * then (because we drop and retake
632*0f4c859eSApple OSS Distributions * v_lock) retry the scan.
633*0f4c859eSApple OSS Distributions */
634*0f4c859eSApple OSS Distributions proc_unlock(wproc);
635*0f4c859eSApple OSS Distributions lck_mtx_unlock(&lf_dead_lock);
636*0f4c859eSApple OSS Distributions static struct timespec ts = {
637*0f4c859eSApple OSS Distributions .tv_sec = 0,
638*0f4c859eSApple OSS Distributions .tv_nsec = 2 * NSEC_PER_MSEC,
639*0f4c859eSApple OSS Distributions };
640*0f4c859eSApple OSS Distributions static const char pausestr[] = "lockf:pause";
641*0f4c859eSApple OSS Distributions (void) msleep(lock, &vp->v_lock, priority, pausestr, &ts);
642*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p contention for vp %p => restart\n", lock, othervp);
643*0f4c859eSApple OSS Distributions goto scan;
644*0f4c859eSApple OSS Distributions }
645*0f4c859eSApple OSS Distributions }
646*0f4c859eSApple OSS Distributions
647*0f4c859eSApple OSS Distributions /*
648*0f4c859eSApple OSS Distributions * Get the lock blocking the lock
649*0f4c859eSApple OSS Distributions * which would block us, and make
650*0f4c859eSApple OSS Distributions * certain it hasn't become unblocked
651*0f4c859eSApple OSS Distributions * (been granted, e.g. between the time
652*0f4c859eSApple OSS Distributions * we called lf_getblock, and the time
653*0f4c859eSApple OSS Distributions * we successfully acquired the
654*0f4c859eSApple OSS Distributions * proc_lock).
655*0f4c859eSApple OSS Distributions */
656*0f4c859eSApple OSS Distributions const struct lockf *nextblock = waitblock->lf_next;
657*0f4c859eSApple OSS Distributions if (nextblock == NULL) {
658*0f4c859eSApple OSS Distributions if (othervp) {
659*0f4c859eSApple OSS Distributions lck_mtx_unlock(&othervp->v_lock);
660*0f4c859eSApple OSS Distributions }
661*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p with waitblock %p and no lf_next; othervp %p\n", lock, waitblock, othervp);
662*0f4c859eSApple OSS Distributions continue;
663*0f4c859eSApple OSS Distributions }
664*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p which is also blocked on lock %p vnode %p\n", lock, nextblock, nextblock->lf_vnode);
665*0f4c859eSApple OSS Distributions
666*0f4c859eSApple OSS Distributions /*
667*0f4c859eSApple OSS Distributions * Make sure it's an advisory range
668*0f4c859eSApple OSS Distributions * lock and not any other kind of lock;
669*0f4c859eSApple OSS Distributions * if we mix lock types, it's our own
670*0f4c859eSApple OSS Distributions * fault.
671*0f4c859eSApple OSS Distributions */
672*0f4c859eSApple OSS Distributions if ((nextblock->lf_flags & F_POSIX) == 0) {
673*0f4c859eSApple OSS Distributions if (othervp) {
674*0f4c859eSApple OSS Distributions lck_mtx_unlock(&othervp->v_lock);
675*0f4c859eSApple OSS Distributions }
676*0f4c859eSApple OSS Distributions continue;
677*0f4c859eSApple OSS Distributions }
678*0f4c859eSApple OSS Distributions
679*0f4c859eSApple OSS Distributions /*
680*0f4c859eSApple OSS Distributions * If the owner of the lock that's
681*0f4c859eSApple OSS Distributions * blocking a lock that's blocking us
682*0f4c859eSApple OSS Distributions * getting the requested lock, then we
683*0f4c859eSApple OSS Distributions * would deadlock, so error out.
684*0f4c859eSApple OSS Distributions */
685*0f4c859eSApple OSS Distributions struct proc *bproc = nextblock->lf_owner;
686*0f4c859eSApple OSS Distributions const boolean_t deadlocked = bproc == lock->lf_owner;
687*0f4c859eSApple OSS Distributions
688*0f4c859eSApple OSS Distributions if (othervp) {
689*0f4c859eSApple OSS Distributions lck_mtx_unlock(&othervp->v_lock);
690*0f4c859eSApple OSS Distributions }
691*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p owned by pid %d\n", lock, proc_pid(bproc));
692*0f4c859eSApple OSS Distributions if (deadlocked) {
693*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p which is me, so EDEADLK\n", lock);
694*0f4c859eSApple OSS Distributions proc_unlock(wproc);
695*0f4c859eSApple OSS Distributions lck_mtx_unlock(&lf_dead_lock);
696*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
697*0f4c859eSApple OSS Distributions return EDEADLK;
698*0f4c859eSApple OSS Distributions }
699*0f4c859eSApple OSS Distributions }
700*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_DEADLOCK, "lock %p bottom of thread loop\n", lock);
701*0f4c859eSApple OSS Distributions }
702*0f4c859eSApple OSS Distributions proc_unlock(wproc);
703*0f4c859eSApple OSS Distributions lck_mtx_unlock(&lf_dead_lock);
704*0f4c859eSApple OSS Distributions }
705*0f4c859eSApple OSS Distributions
706*0f4c859eSApple OSS Distributions /*
707*0f4c859eSApple OSS Distributions * For flock type locks, we must first remove
708*0f4c859eSApple OSS Distributions * any shared locks that we hold before we sleep
709*0f4c859eSApple OSS Distributions * waiting for an exclusive lock.
710*0f4c859eSApple OSS Distributions */
711*0f4c859eSApple OSS Distributions if ((lock->lf_flags & F_FLOCK) &&
712*0f4c859eSApple OSS Distributions lock->lf_type == F_WRLCK) {
713*0f4c859eSApple OSS Distributions lock->lf_type = F_UNLCK;
714*0f4c859eSApple OSS Distributions if ((error = lf_clearlock(lock)) != 0) {
715*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
716*0f4c859eSApple OSS Distributions return error;
717*0f4c859eSApple OSS Distributions }
718*0f4c859eSApple OSS Distributions lock->lf_type = F_WRLCK;
719*0f4c859eSApple OSS Distributions }
720*0f4c859eSApple OSS Distributions /*
721*0f4c859eSApple OSS Distributions * Add our lock to the blocked list and sleep until we're free.
722*0f4c859eSApple OSS Distributions * Remember who blocked us (for deadlock detection).
723*0f4c859eSApple OSS Distributions */
724*0f4c859eSApple OSS Distributions lock->lf_next = block;
725*0f4c859eSApple OSS Distributions TAILQ_INSERT_TAIL(&block->lf_blkhd, lock, lf_block);
726*0f4c859eSApple OSS Distributions
727*0f4c859eSApple OSS Distributions if (!(lock->lf_flags & F_FLOCK)) {
728*0f4c859eSApple OSS Distributions block->lf_flags &= ~F_WAKE1_SAFE;
729*0f4c859eSApple OSS Distributions }
730*0f4c859eSApple OSS Distributions
731*0f4c859eSApple OSS Distributions #if IMPORTANCE_INHERITANCE
732*0f4c859eSApple OSS Distributions /*
733*0f4c859eSApple OSS Distributions * Importance donation is done only for cases where the
734*0f4c859eSApple OSS Distributions * owning task can be unambiguously determined.
735*0f4c859eSApple OSS Distributions *
736*0f4c859eSApple OSS Distributions * POSIX type locks are not inherited by child processes;
737*0f4c859eSApple OSS Distributions * we maintain a 1:1 mapping between a lock and its owning
738*0f4c859eSApple OSS Distributions * process.
739*0f4c859eSApple OSS Distributions *
740*0f4c859eSApple OSS Distributions * Flock type locks are inherited across fork() and there is
741*0f4c859eSApple OSS Distributions * no 1:1 mapping in the general case. However, the fileglobs
742*0f4c859eSApple OSS Distributions * used by OFD locks *may* be confined to the process that
743*0f4c859eSApple OSS Distributions * created them, and thus have an "owner", in which case
744*0f4c859eSApple OSS Distributions * we also attempt importance donation.
745*0f4c859eSApple OSS Distributions */
746*0f4c859eSApple OSS Distributions if ((lock->lf_flags & block->lf_flags & F_POSIX) != 0) {
747*0f4c859eSApple OSS Distributions lf_boost_blocking_proc(lock, block);
748*0f4c859eSApple OSS Distributions } else if ((lock->lf_flags & block->lf_flags & F_OFD_LOCK) &&
749*0f4c859eSApple OSS Distributions lock->lf_owner != block->lf_owner &&
750*0f4c859eSApple OSS Distributions NULL != lock->lf_owner && NULL != block->lf_owner) {
751*0f4c859eSApple OSS Distributions lf_boost_blocking_proc(lock, block);
752*0f4c859eSApple OSS Distributions }
753*0f4c859eSApple OSS Distributions #endif /* IMPORTANCE_INHERITANCE */
754*0f4c859eSApple OSS Distributions
755*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
756*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
757*0f4c859eSApple OSS Distributions lf_print("lf_setlock: blocking on", block);
758*0f4c859eSApple OSS Distributions lf_printlist("lf_setlock(block)", block);
759*0f4c859eSApple OSS Distributions }
760*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
761*0f4c859eSApple OSS Distributions DTRACE_FSINFO(advlock__wait, vnode_t, vp);
762*0f4c859eSApple OSS Distributions
763*0f4c859eSApple OSS Distributions if (lock->lf_flags & F_POSIX) {
764*0f4c859eSApple OSS Distributions error = msleep(lock, &vp->v_lock, priority, lockstr, timeout);
765*0f4c859eSApple OSS Distributions /*
766*0f4c859eSApple OSS Distributions * Ensure that 'lock' doesn't get mutated or freed if a
767*0f4c859eSApple OSS Distributions * wakeup occurs while hunting for deadlocks (and holding
768*0f4c859eSApple OSS Distributions * lf_dead_lock - see above)
769*0f4c859eSApple OSS Distributions */
770*0f4c859eSApple OSS Distributions lck_mtx_lock(&lf_dead_lock);
771*0f4c859eSApple OSS Distributions lck_mtx_unlock(&lf_dead_lock);
772*0f4c859eSApple OSS Distributions } else {
773*0f4c859eSApple OSS Distributions static const char lockstr_np[] = "lockf:np";
774*0f4c859eSApple OSS Distributions error = msleep(lock, &vp->v_lock, priority, lockstr_np, timeout);
775*0f4c859eSApple OSS Distributions }
776*0f4c859eSApple OSS Distributions
777*0f4c859eSApple OSS Distributions if (error == 0 && (lock->lf_flags & F_ABORT) != 0) {
778*0f4c859eSApple OSS Distributions error = EBADF;
779*0f4c859eSApple OSS Distributions }
780*0f4c859eSApple OSS Distributions
781*0f4c859eSApple OSS Distributions if (lock->lf_next) {
782*0f4c859eSApple OSS Distributions /*
783*0f4c859eSApple OSS Distributions * lf_wakelock() always sets wakelock->lf_next to
784*0f4c859eSApple OSS Distributions * NULL before a wakeup; so we've been woken early
785*0f4c859eSApple OSS Distributions * - perhaps by a debugger, signal or other event.
786*0f4c859eSApple OSS Distributions *
787*0f4c859eSApple OSS Distributions * Remove 'lock' from the block list (avoids double-add
788*0f4c859eSApple OSS Distributions * in the spurious case, which would create a cycle)
789*0f4c859eSApple OSS Distributions */
790*0f4c859eSApple OSS Distributions TAILQ_REMOVE(&lock->lf_next->lf_blkhd, lock, lf_block);
791*0f4c859eSApple OSS Distributions #if IMPORTANCE_INHERITANCE
792*0f4c859eSApple OSS Distributions /*
793*0f4c859eSApple OSS Distributions * Adjust the boost on lf_next.
794*0f4c859eSApple OSS Distributions */
795*0f4c859eSApple OSS Distributions lf_adjust_assertion(lock->lf_next);
796*0f4c859eSApple OSS Distributions #endif /* IMPORTANCE_INHERITANCE */
797*0f4c859eSApple OSS Distributions lock->lf_next = NULL;
798*0f4c859eSApple OSS Distributions
799*0f4c859eSApple OSS Distributions if (error == 0) {
800*0f4c859eSApple OSS Distributions /*
801*0f4c859eSApple OSS Distributions * If this was a spurious wakeup, retry
802*0f4c859eSApple OSS Distributions */
803*0f4c859eSApple OSS Distributions printf("%s: spurious wakeup, retrying lock\n",
804*0f4c859eSApple OSS Distributions __func__);
805*0f4c859eSApple OSS Distributions continue;
806*0f4c859eSApple OSS Distributions }
807*0f4c859eSApple OSS Distributions }
808*0f4c859eSApple OSS Distributions
809*0f4c859eSApple OSS Distributions if (!TAILQ_EMPTY(&lock->lf_blkhd)) {
810*0f4c859eSApple OSS Distributions if ((block = lf_getblock(lock, -1)) != NULL) {
811*0f4c859eSApple OSS Distributions lf_move_blocked(block, lock);
812*0f4c859eSApple OSS Distributions }
813*0f4c859eSApple OSS Distributions }
814*0f4c859eSApple OSS Distributions
815*0f4c859eSApple OSS Distributions if (error) {
816*0f4c859eSApple OSS Distributions if (!TAILQ_EMPTY(&lock->lf_blkhd)) {
817*0f4c859eSApple OSS Distributions lf_wakelock(lock, TRUE);
818*0f4c859eSApple OSS Distributions }
819*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
820*0f4c859eSApple OSS Distributions /* Return ETIMEDOUT if timeout occoured. */
821*0f4c859eSApple OSS Distributions if (error == EWOULDBLOCK) {
822*0f4c859eSApple OSS Distributions error = ETIMEDOUT;
823*0f4c859eSApple OSS Distributions }
824*0f4c859eSApple OSS Distributions return error;
825*0f4c859eSApple OSS Distributions }
826*0f4c859eSApple OSS Distributions }
827*0f4c859eSApple OSS Distributions
828*0f4c859eSApple OSS Distributions /*
829*0f4c859eSApple OSS Distributions * No blocks!! Add the lock. Note that we will
830*0f4c859eSApple OSS Distributions * downgrade or upgrade any overlapping locks this
831*0f4c859eSApple OSS Distributions * process already owns.
832*0f4c859eSApple OSS Distributions *
833*0f4c859eSApple OSS Distributions * Skip over locks owned by other processes.
834*0f4c859eSApple OSS Distributions * Handle any locks that overlap and are owned by ourselves.
835*0f4c859eSApple OSS Distributions */
836*0f4c859eSApple OSS Distributions prev = head;
837*0f4c859eSApple OSS Distributions block = *head;
838*0f4c859eSApple OSS Distributions needtolink = 1;
839*0f4c859eSApple OSS Distributions for (;;) {
840*0f4c859eSApple OSS Distributions const off_t lkend = LF_END(lock);
841*0f4c859eSApple OSS Distributions ovcase = lf_findoverlap(block, lock, SELF, &prev, &overlap);
842*0f4c859eSApple OSS Distributions if (ovcase) {
843*0f4c859eSApple OSS Distributions block = overlap->lf_next;
844*0f4c859eSApple OSS Distributions }
845*0f4c859eSApple OSS Distributions /*
846*0f4c859eSApple OSS Distributions * Six cases:
847*0f4c859eSApple OSS Distributions * 0) no overlap
848*0f4c859eSApple OSS Distributions * 1) overlap == lock
849*0f4c859eSApple OSS Distributions * 2) overlap contains lock
850*0f4c859eSApple OSS Distributions * 3) lock contains overlap
851*0f4c859eSApple OSS Distributions * 4) overlap starts before lock
852*0f4c859eSApple OSS Distributions * 5) overlap ends after lock
853*0f4c859eSApple OSS Distributions */
854*0f4c859eSApple OSS Distributions switch (ovcase) {
855*0f4c859eSApple OSS Distributions case OVERLAP_NONE:
856*0f4c859eSApple OSS Distributions if (needtolink) {
857*0f4c859eSApple OSS Distributions *prev = lock;
858*0f4c859eSApple OSS Distributions lock->lf_next = overlap;
859*0f4c859eSApple OSS Distributions }
860*0f4c859eSApple OSS Distributions break;
861*0f4c859eSApple OSS Distributions
862*0f4c859eSApple OSS Distributions case OVERLAP_EQUALS_LOCK:
863*0f4c859eSApple OSS Distributions /*
864*0f4c859eSApple OSS Distributions * If downgrading lock, others may be
865*0f4c859eSApple OSS Distributions * able to acquire it.
866*0f4c859eSApple OSS Distributions */
867*0f4c859eSApple OSS Distributions if (lock->lf_type == F_RDLCK &&
868*0f4c859eSApple OSS Distributions overlap->lf_type == F_WRLCK) {
869*0f4c859eSApple OSS Distributions lf_wakelock(overlap, TRUE);
870*0f4c859eSApple OSS Distributions }
871*0f4c859eSApple OSS Distributions overlap->lf_type = lock->lf_type;
872*0f4c859eSApple OSS Distributions lf_move_blocked(overlap, lock);
873*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
874*0f4c859eSApple OSS Distributions lock = overlap; /* for lf_coalesce_adjacent() */
875*0f4c859eSApple OSS Distributions break;
876*0f4c859eSApple OSS Distributions
877*0f4c859eSApple OSS Distributions case OVERLAP_CONTAINS_LOCK:
878*0f4c859eSApple OSS Distributions /*
879*0f4c859eSApple OSS Distributions * Check for common starting point and different types.
880*0f4c859eSApple OSS Distributions */
881*0f4c859eSApple OSS Distributions if (overlap->lf_type == lock->lf_type) {
882*0f4c859eSApple OSS Distributions lf_move_blocked(overlap, lock);
883*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
884*0f4c859eSApple OSS Distributions lock = overlap; /* for lf_coalesce_adjacent() */
885*0f4c859eSApple OSS Distributions break;
886*0f4c859eSApple OSS Distributions }
887*0f4c859eSApple OSS Distributions if (overlap->lf_start == lock->lf_start) {
888*0f4c859eSApple OSS Distributions *prev = lock;
889*0f4c859eSApple OSS Distributions lock->lf_next = overlap;
890*0f4c859eSApple OSS Distributions assert(lkend < OFF_MAX);
891*0f4c859eSApple OSS Distributions overlap->lf_start = lkend + 1;
892*0f4c859eSApple OSS Distributions } else {
893*0f4c859eSApple OSS Distributions /*
894*0f4c859eSApple OSS Distributions * If we can't split the lock, we can't
895*0f4c859eSApple OSS Distributions * grant it. Claim a system limit for the
896*0f4c859eSApple OSS Distributions * resource shortage.
897*0f4c859eSApple OSS Distributions */
898*0f4c859eSApple OSS Distributions if (lf_split(overlap, lock)) {
899*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, lock);
900*0f4c859eSApple OSS Distributions return ENOLCK;
901*0f4c859eSApple OSS Distributions }
902*0f4c859eSApple OSS Distributions }
903*0f4c859eSApple OSS Distributions lf_wakelock(overlap, TRUE);
904*0f4c859eSApple OSS Distributions break;
905*0f4c859eSApple OSS Distributions
906*0f4c859eSApple OSS Distributions case OVERLAP_CONTAINED_BY_LOCK:
907*0f4c859eSApple OSS Distributions /*
908*0f4c859eSApple OSS Distributions * If downgrading lock, others may be able to
909*0f4c859eSApple OSS Distributions * acquire it, otherwise take the list.
910*0f4c859eSApple OSS Distributions */
911*0f4c859eSApple OSS Distributions if (lock->lf_type == F_RDLCK &&
912*0f4c859eSApple OSS Distributions overlap->lf_type == F_WRLCK) {
913*0f4c859eSApple OSS Distributions lf_wakelock(overlap, TRUE);
914*0f4c859eSApple OSS Distributions } else {
915*0f4c859eSApple OSS Distributions lf_move_blocked(lock, overlap);
916*0f4c859eSApple OSS Distributions }
917*0f4c859eSApple OSS Distributions /*
918*0f4c859eSApple OSS Distributions * Add the new lock if necessary and delete the overlap.
919*0f4c859eSApple OSS Distributions */
920*0f4c859eSApple OSS Distributions if (needtolink) {
921*0f4c859eSApple OSS Distributions *prev = lock;
922*0f4c859eSApple OSS Distributions lock->lf_next = overlap->lf_next;
923*0f4c859eSApple OSS Distributions prev = &lock->lf_next;
924*0f4c859eSApple OSS Distributions needtolink = 0;
925*0f4c859eSApple OSS Distributions } else {
926*0f4c859eSApple OSS Distributions *prev = overlap->lf_next;
927*0f4c859eSApple OSS Distributions }
928*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, overlap);
929*0f4c859eSApple OSS Distributions continue;
930*0f4c859eSApple OSS Distributions
931*0f4c859eSApple OSS Distributions case OVERLAP_STARTS_BEFORE_LOCK:
932*0f4c859eSApple OSS Distributions /*
933*0f4c859eSApple OSS Distributions * Add lock after overlap on the list.
934*0f4c859eSApple OSS Distributions */
935*0f4c859eSApple OSS Distributions lock->lf_next = overlap->lf_next;
936*0f4c859eSApple OSS Distributions overlap->lf_next = lock;
937*0f4c859eSApple OSS Distributions assert(lock->lf_start > 0);
938*0f4c859eSApple OSS Distributions overlap->lf_end = lock->lf_start - 1;
939*0f4c859eSApple OSS Distributions prev = &lock->lf_next;
940*0f4c859eSApple OSS Distributions lf_wakelock(overlap, TRUE);
941*0f4c859eSApple OSS Distributions needtolink = 0;
942*0f4c859eSApple OSS Distributions continue;
943*0f4c859eSApple OSS Distributions
944*0f4c859eSApple OSS Distributions case OVERLAP_ENDS_AFTER_LOCK:
945*0f4c859eSApple OSS Distributions /*
946*0f4c859eSApple OSS Distributions * Add the new lock before overlap.
947*0f4c859eSApple OSS Distributions */
948*0f4c859eSApple OSS Distributions if (needtolink) {
949*0f4c859eSApple OSS Distributions *prev = lock;
950*0f4c859eSApple OSS Distributions lock->lf_next = overlap;
951*0f4c859eSApple OSS Distributions }
952*0f4c859eSApple OSS Distributions assert(lkend < OFF_MAX);
953*0f4c859eSApple OSS Distributions overlap->lf_start = lkend + 1;
954*0f4c859eSApple OSS Distributions lf_wakelock(overlap, TRUE);
955*0f4c859eSApple OSS Distributions break;
956*0f4c859eSApple OSS Distributions }
957*0f4c859eSApple OSS Distributions break;
958*0f4c859eSApple OSS Distributions }
959*0f4c859eSApple OSS Distributions /* Coalesce adjacent locks with identical attributes */
960*0f4c859eSApple OSS Distributions lf_coalesce_adjacent(lock);
961*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
962*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
963*0f4c859eSApple OSS Distributions lf_print("lf_setlock: got the lock", lock);
964*0f4c859eSApple OSS Distributions lf_printlist("lf_setlock(out)", lock);
965*0f4c859eSApple OSS Distributions }
966*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
967*0f4c859eSApple OSS Distributions return 0;
968*0f4c859eSApple OSS Distributions }
969*0f4c859eSApple OSS Distributions
970*0f4c859eSApple OSS Distributions
971*0f4c859eSApple OSS Distributions /*
972*0f4c859eSApple OSS Distributions * lf_clearlock
973*0f4c859eSApple OSS Distributions *
974*0f4c859eSApple OSS Distributions * Description: Remove a byte-range lock on an vnode. Generally, find the
975*0f4c859eSApple OSS Distributions * lock (or an overlap to that lock) and remove it (or shrink
976*0f4c859eSApple OSS Distributions * it), then wakeup anyone we can.
977*0f4c859eSApple OSS Distributions *
978*0f4c859eSApple OSS Distributions * Parameters: unlock The lock to clear
979*0f4c859eSApple OSS Distributions *
980*0f4c859eSApple OSS Distributions * Returns: 0 Success
981*0f4c859eSApple OSS Distributions * lf_split:ENOLCK
982*0f4c859eSApple OSS Distributions *
983*0f4c859eSApple OSS Distributions * Notes: A caller may unlock all the locks owned by the caller by
984*0f4c859eSApple OSS Distributions * specifying the entire file range; locks owned by other
985*0f4c859eSApple OSS Distributions * callers are not effected by this operation.
986*0f4c859eSApple OSS Distributions */
987*0f4c859eSApple OSS Distributions static int
lf_clearlock(struct lockf * unlock)988*0f4c859eSApple OSS Distributions lf_clearlock(struct lockf *unlock)
989*0f4c859eSApple OSS Distributions {
990*0f4c859eSApple OSS Distributions struct lockf **head = unlock->lf_head;
991*0f4c859eSApple OSS Distributions struct lockf *lf = *head;
992*0f4c859eSApple OSS Distributions struct lockf *overlap, **prev;
993*0f4c859eSApple OSS Distributions overlap_t ovcase;
994*0f4c859eSApple OSS Distributions
995*0f4c859eSApple OSS Distributions if (lf == NOLOCKF) {
996*0f4c859eSApple OSS Distributions return 0;
997*0f4c859eSApple OSS Distributions }
998*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
999*0f4c859eSApple OSS Distributions if (unlock->lf_type != F_UNLCK) {
1000*0f4c859eSApple OSS Distributions panic("lf_clearlock: bad type");
1001*0f4c859eSApple OSS Distributions }
1002*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
1003*0f4c859eSApple OSS Distributions lf_print("lf_clearlock", unlock);
1004*0f4c859eSApple OSS Distributions }
1005*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1006*0f4c859eSApple OSS Distributions prev = head;
1007*0f4c859eSApple OSS Distributions while ((ovcase = lf_findoverlap(lf, unlock, SELF, &prev, &overlap)) != OVERLAP_NONE) {
1008*0f4c859eSApple OSS Distributions const off_t unlkend = LF_END(unlock);
1009*0f4c859eSApple OSS Distributions /*
1010*0f4c859eSApple OSS Distributions * Wakeup the list of locks to be retried.
1011*0f4c859eSApple OSS Distributions */
1012*0f4c859eSApple OSS Distributions lf_wakelock(overlap, FALSE);
1013*0f4c859eSApple OSS Distributions #if IMPORTANCE_INHERITANCE
1014*0f4c859eSApple OSS Distributions if (overlap->lf_boosted == LF_BOOSTED) {
1015*0f4c859eSApple OSS Distributions lf_drop_assertion(overlap);
1016*0f4c859eSApple OSS Distributions }
1017*0f4c859eSApple OSS Distributions #endif /* IMPORTANCE_INHERITANCE */
1018*0f4c859eSApple OSS Distributions
1019*0f4c859eSApple OSS Distributions switch (ovcase) {
1020*0f4c859eSApple OSS Distributions case OVERLAP_NONE: /* satisfy compiler enum/switch */
1021*0f4c859eSApple OSS Distributions break;
1022*0f4c859eSApple OSS Distributions
1023*0f4c859eSApple OSS Distributions case OVERLAP_EQUALS_LOCK:
1024*0f4c859eSApple OSS Distributions *prev = overlap->lf_next;
1025*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, overlap);
1026*0f4c859eSApple OSS Distributions break;
1027*0f4c859eSApple OSS Distributions
1028*0f4c859eSApple OSS Distributions case OVERLAP_CONTAINS_LOCK: /* split it */
1029*0f4c859eSApple OSS Distributions if (overlap->lf_start == unlock->lf_start) {
1030*0f4c859eSApple OSS Distributions assert(unlkend < OFF_MAX);
1031*0f4c859eSApple OSS Distributions overlap->lf_start = unlkend + 1;
1032*0f4c859eSApple OSS Distributions break;
1033*0f4c859eSApple OSS Distributions }
1034*0f4c859eSApple OSS Distributions /*
1035*0f4c859eSApple OSS Distributions * If we can't split the lock, we can't grant it.
1036*0f4c859eSApple OSS Distributions * Claim a system limit for the resource shortage.
1037*0f4c859eSApple OSS Distributions */
1038*0f4c859eSApple OSS Distributions if (lf_split(overlap, unlock)) {
1039*0f4c859eSApple OSS Distributions return ENOLCK;
1040*0f4c859eSApple OSS Distributions }
1041*0f4c859eSApple OSS Distributions overlap->lf_next = unlock->lf_next;
1042*0f4c859eSApple OSS Distributions break;
1043*0f4c859eSApple OSS Distributions
1044*0f4c859eSApple OSS Distributions case OVERLAP_CONTAINED_BY_LOCK:
1045*0f4c859eSApple OSS Distributions *prev = overlap->lf_next;
1046*0f4c859eSApple OSS Distributions lf = overlap->lf_next;
1047*0f4c859eSApple OSS Distributions zfree(KT_LOCKF, overlap);
1048*0f4c859eSApple OSS Distributions continue;
1049*0f4c859eSApple OSS Distributions
1050*0f4c859eSApple OSS Distributions case OVERLAP_STARTS_BEFORE_LOCK:
1051*0f4c859eSApple OSS Distributions assert(unlock->lf_start > 0);
1052*0f4c859eSApple OSS Distributions overlap->lf_end = unlock->lf_start - 1;
1053*0f4c859eSApple OSS Distributions prev = &overlap->lf_next;
1054*0f4c859eSApple OSS Distributions lf = overlap->lf_next;
1055*0f4c859eSApple OSS Distributions continue;
1056*0f4c859eSApple OSS Distributions
1057*0f4c859eSApple OSS Distributions case OVERLAP_ENDS_AFTER_LOCK:
1058*0f4c859eSApple OSS Distributions assert(unlkend < OFF_MAX);
1059*0f4c859eSApple OSS Distributions overlap->lf_start = unlkend + 1;
1060*0f4c859eSApple OSS Distributions break;
1061*0f4c859eSApple OSS Distributions }
1062*0f4c859eSApple OSS Distributions break;
1063*0f4c859eSApple OSS Distributions }
1064*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1065*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
1066*0f4c859eSApple OSS Distributions lf_printlist("lf_clearlock", unlock);
1067*0f4c859eSApple OSS Distributions }
1068*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1069*0f4c859eSApple OSS Distributions return 0;
1070*0f4c859eSApple OSS Distributions }
1071*0f4c859eSApple OSS Distributions
1072*0f4c859eSApple OSS Distributions
1073*0f4c859eSApple OSS Distributions /*
1074*0f4c859eSApple OSS Distributions * lf_transferlock
1075*0f4c859eSApple OSS Distributions *
1076*0f4c859eSApple OSS Distributions * Description: Transfer a give lock from old_proc to new proc during exec
1077*0f4c859eSApple OSS Distributions *
1078*0f4c859eSApple OSS Distributions * Parameters: unlock The lock to transfer
1079*0f4c859eSApple OSS Distributions *
1080*0f4c859eSApple OSS Distributions * Returns: 0 Success
1081*0f4c859eSApple OSS Distributions *
1082*0f4c859eSApple OSS Distributions * Notes: A caller may transfer all the locks owned by the caller by
1083*0f4c859eSApple OSS Distributions * specifying the entire file range; locks owned by other
1084*0f4c859eSApple OSS Distributions * callers are not effected by this operation.
1085*0f4c859eSApple OSS Distributions */
1086*0f4c859eSApple OSS Distributions static int
lf_transferlock(struct lockf * transfer)1087*0f4c859eSApple OSS Distributions lf_transferlock(struct lockf *transfer)
1088*0f4c859eSApple OSS Distributions {
1089*0f4c859eSApple OSS Distributions struct lockf **head = transfer->lf_head;
1090*0f4c859eSApple OSS Distributions struct lockf *lf = *head;
1091*0f4c859eSApple OSS Distributions struct lockf *overlap, **prev;
1092*0f4c859eSApple OSS Distributions overlap_t ovcase;
1093*0f4c859eSApple OSS Distributions
1094*0f4c859eSApple OSS Distributions if (lf == NOLOCKF) {
1095*0f4c859eSApple OSS Distributions return 0;
1096*0f4c859eSApple OSS Distributions }
1097*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1098*0f4c859eSApple OSS Distributions if (transfer->lf_type != F_TRANSFER) {
1099*0f4c859eSApple OSS Distributions panic("lf_transferlock: bad type");
1100*0f4c859eSApple OSS Distributions }
1101*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
1102*0f4c859eSApple OSS Distributions lf_print("lf_transferlock", transfer);
1103*0f4c859eSApple OSS Distributions }
1104*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1105*0f4c859eSApple OSS Distributions prev = head;
1106*0f4c859eSApple OSS Distributions while ((ovcase = lf_findoverlap(lf, transfer, SELF, &prev, &overlap)) != OVERLAP_NONE) {
1107*0f4c859eSApple OSS Distributions /* For POSIX Locks, change lf_id and lf_owner */
1108*0f4c859eSApple OSS Distributions if (overlap->lf_flags & F_POSIX) {
1109*0f4c859eSApple OSS Distributions overlap->lf_id = (caddr_t)transfer->lf_owner;
1110*0f4c859eSApple OSS Distributions overlap->lf_owner = transfer->lf_owner;
1111*0f4c859eSApple OSS Distributions } else if (overlap->lf_flags & F_OFD_LOCK) {
1112*0f4c859eSApple OSS Distributions /* Change the owner of the ofd style lock, if there is an owner */
1113*0f4c859eSApple OSS Distributions if (overlap->lf_owner) {
1114*0f4c859eSApple OSS Distributions overlap->lf_owner = transfer->lf_owner;
1115*0f4c859eSApple OSS Distributions }
1116*0f4c859eSApple OSS Distributions }
1117*0f4c859eSApple OSS Distributions /* Find the next lock */
1118*0f4c859eSApple OSS Distributions lf = overlap->lf_next;
1119*0f4c859eSApple OSS Distributions }
1120*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1121*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
1122*0f4c859eSApple OSS Distributions lf_printlist("lf_transferlock", transfer);
1123*0f4c859eSApple OSS Distributions }
1124*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1125*0f4c859eSApple OSS Distributions return 0;
1126*0f4c859eSApple OSS Distributions }
1127*0f4c859eSApple OSS Distributions
1128*0f4c859eSApple OSS Distributions
1129*0f4c859eSApple OSS Distributions /*
1130*0f4c859eSApple OSS Distributions * lf_getlock
1131*0f4c859eSApple OSS Distributions *
1132*0f4c859eSApple OSS Distributions * Description: Check whether there is a blocking lock, and if so return
1133*0f4c859eSApple OSS Distributions * its process identifier into the lock being requested.
1134*0f4c859eSApple OSS Distributions *
1135*0f4c859eSApple OSS Distributions * Parameters: lock Pointer to lock to test for blocks
1136*0f4c859eSApple OSS Distributions * fl Pointer to flock structure to receive
1137*0f4c859eSApple OSS Distributions * the blocking lock information, if a
1138*0f4c859eSApple OSS Distributions * blocking lock is found.
1139*0f4c859eSApple OSS Distributions * matchpid -1, or pid value to match in lookup.
1140*0f4c859eSApple OSS Distributions *
1141*0f4c859eSApple OSS Distributions * Returns: 0 Success
1142*0f4c859eSApple OSS Distributions *
1143*0f4c859eSApple OSS Distributions * Implicit Returns:
1144*0f4c859eSApple OSS Distributions * *fl Contents modified to reflect the
1145*0f4c859eSApple OSS Distributions * blocking lock, if one is found; not
1146*0f4c859eSApple OSS Distributions * modified otherwise
1147*0f4c859eSApple OSS Distributions *
1148*0f4c859eSApple OSS Distributions * Notes: fl->l_pid will be (-1) for file locks and will only be set to
1149*0f4c859eSApple OSS Distributions * the blocking process ID for advisory record locks.
1150*0f4c859eSApple OSS Distributions */
1151*0f4c859eSApple OSS Distributions static int
lf_getlock(struct lockf * lock,struct flock * fl,pid_t matchpid)1152*0f4c859eSApple OSS Distributions lf_getlock(struct lockf *lock, struct flock *fl, pid_t matchpid)
1153*0f4c859eSApple OSS Distributions {
1154*0f4c859eSApple OSS Distributions struct lockf *block;
1155*0f4c859eSApple OSS Distributions
1156*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1157*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
1158*0f4c859eSApple OSS Distributions lf_print("lf_getlock", lock);
1159*0f4c859eSApple OSS Distributions }
1160*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1161*0f4c859eSApple OSS Distributions
1162*0f4c859eSApple OSS Distributions if ((block = lf_getblock(lock, matchpid))) {
1163*0f4c859eSApple OSS Distributions fl->l_type = block->lf_type;
1164*0f4c859eSApple OSS Distributions fl->l_whence = SEEK_SET;
1165*0f4c859eSApple OSS Distributions fl->l_start = block->lf_start;
1166*0f4c859eSApple OSS Distributions if (block->lf_end == -1 ||
1167*0f4c859eSApple OSS Distributions (block->lf_start == 0 && LF_END(block) == OFF_MAX)) {
1168*0f4c859eSApple OSS Distributions fl->l_len = 0;
1169*0f4c859eSApple OSS Distributions } else {
1170*0f4c859eSApple OSS Distributions fl->l_len = LF_END(block) - block->lf_start + 1;
1171*0f4c859eSApple OSS Distributions }
1172*0f4c859eSApple OSS Distributions if (NULL != block->lf_owner) {
1173*0f4c859eSApple OSS Distributions /*
1174*0f4c859eSApple OSS Distributions * lf_owner is only non-NULL when the lock
1175*0f4c859eSApple OSS Distributions * "owner" can be unambiguously determined
1176*0f4c859eSApple OSS Distributions */
1177*0f4c859eSApple OSS Distributions fl->l_pid = proc_pid(block->lf_owner);
1178*0f4c859eSApple OSS Distributions } else {
1179*0f4c859eSApple OSS Distributions fl->l_pid = -1;
1180*0f4c859eSApple OSS Distributions }
1181*0f4c859eSApple OSS Distributions } else {
1182*0f4c859eSApple OSS Distributions fl->l_type = F_UNLCK;
1183*0f4c859eSApple OSS Distributions }
1184*0f4c859eSApple OSS Distributions return 0;
1185*0f4c859eSApple OSS Distributions }
1186*0f4c859eSApple OSS Distributions
1187*0f4c859eSApple OSS Distributions /*
1188*0f4c859eSApple OSS Distributions * lf_getblock
1189*0f4c859eSApple OSS Distributions *
1190*0f4c859eSApple OSS Distributions * Description: Walk the list of locks for an inode and return the first
1191*0f4c859eSApple OSS Distributions * blocking lock. A lock is considered blocking if we are not
1192*0f4c859eSApple OSS Distributions * the lock owner; otherwise, we are permitted to upgrade or
1193*0f4c859eSApple OSS Distributions * downgrade it, and it's not considered blocking.
1194*0f4c859eSApple OSS Distributions *
1195*0f4c859eSApple OSS Distributions * Parameters: lock The lock for which we are interested
1196*0f4c859eSApple OSS Distributions * in obtaining the blocking lock, if any
1197*0f4c859eSApple OSS Distributions * matchpid -1, or pid value to match in lookup.
1198*0f4c859eSApple OSS Distributions *
1199*0f4c859eSApple OSS Distributions * Returns: NOLOCKF No blocking lock exists
1200*0f4c859eSApple OSS Distributions * !NOLOCKF The address of the blocking lock's
1201*0f4c859eSApple OSS Distributions * struct lockf.
1202*0f4c859eSApple OSS Distributions */
1203*0f4c859eSApple OSS Distributions static struct lockf *
lf_getblock(struct lockf * lock,pid_t matchpid)1204*0f4c859eSApple OSS Distributions lf_getblock(struct lockf *lock, pid_t matchpid)
1205*0f4c859eSApple OSS Distributions {
1206*0f4c859eSApple OSS Distributions struct lockf **prev, *overlap, *lf = *(lock->lf_head);
1207*0f4c859eSApple OSS Distributions
1208*0f4c859eSApple OSS Distributions for (prev = lock->lf_head;
1209*0f4c859eSApple OSS Distributions lf_findoverlap(lf, lock, OTHERS, &prev, &overlap) != OVERLAP_NONE;
1210*0f4c859eSApple OSS Distributions lf = overlap->lf_next) {
1211*0f4c859eSApple OSS Distributions /*
1212*0f4c859eSApple OSS Distributions * Found an overlap.
1213*0f4c859eSApple OSS Distributions *
1214*0f4c859eSApple OSS Distributions * If we're matching pids, and it's a record lock,
1215*0f4c859eSApple OSS Distributions * or it's an OFD lock on a process-confined fd,
1216*0f4c859eSApple OSS Distributions * but the pid doesn't match, then keep on looking ..
1217*0f4c859eSApple OSS Distributions */
1218*0f4c859eSApple OSS Distributions if (matchpid != -1 &&
1219*0f4c859eSApple OSS Distributions (overlap->lf_flags & (F_POSIX | F_OFD_LOCK)) != 0 &&
1220*0f4c859eSApple OSS Distributions proc_pid(overlap->lf_owner) != matchpid) {
1221*0f4c859eSApple OSS Distributions continue;
1222*0f4c859eSApple OSS Distributions }
1223*0f4c859eSApple OSS Distributions
1224*0f4c859eSApple OSS Distributions /*
1225*0f4c859eSApple OSS Distributions * does it block us?
1226*0f4c859eSApple OSS Distributions */
1227*0f4c859eSApple OSS Distributions if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK)) {
1228*0f4c859eSApple OSS Distributions return overlap;
1229*0f4c859eSApple OSS Distributions }
1230*0f4c859eSApple OSS Distributions }
1231*0f4c859eSApple OSS Distributions return NOLOCKF;
1232*0f4c859eSApple OSS Distributions }
1233*0f4c859eSApple OSS Distributions
1234*0f4c859eSApple OSS Distributions
1235*0f4c859eSApple OSS Distributions /*
1236*0f4c859eSApple OSS Distributions * lf_findoverlap
1237*0f4c859eSApple OSS Distributions *
1238*0f4c859eSApple OSS Distributions * Description: Walk the list of locks to find an overlapping lock (if any).
1239*0f4c859eSApple OSS Distributions *
1240*0f4c859eSApple OSS Distributions * Parameters: lf First lock on lock list
1241*0f4c859eSApple OSS Distributions * lock The lock we are checking for an overlap
1242*0f4c859eSApple OSS Distributions * check Check type
1243*0f4c859eSApple OSS Distributions * prev pointer to pointer pointer to contain
1244*0f4c859eSApple OSS Distributions * address of pointer to previous lock
1245*0f4c859eSApple OSS Distributions * pointer to overlapping lock, if overlap
1246*0f4c859eSApple OSS Distributions * overlap pointer to pointer to contain address
1247*0f4c859eSApple OSS Distributions * of overlapping lock
1248*0f4c859eSApple OSS Distributions *
1249*0f4c859eSApple OSS Distributions * Returns: OVERLAP_NONE
1250*0f4c859eSApple OSS Distributions * OVERLAP_EQUALS_LOCK
1251*0f4c859eSApple OSS Distributions * OVERLAP_CONTAINS_LOCK
1252*0f4c859eSApple OSS Distributions * OVERLAP_CONTAINED_BY_LOCK
1253*0f4c859eSApple OSS Distributions * OVERLAP_STARTS_BEFORE_LOCK
1254*0f4c859eSApple OSS Distributions * OVERLAP_ENDS_AFTER_LOCK
1255*0f4c859eSApple OSS Distributions *
1256*0f4c859eSApple OSS Distributions * Implicit Returns:
1257*0f4c859eSApple OSS Distributions * *prev The address of the next pointer in the
1258*0f4c859eSApple OSS Distributions * lock previous to the overlapping lock;
1259*0f4c859eSApple OSS Distributions * this is generally used to relink the
1260*0f4c859eSApple OSS Distributions * lock list, avoiding a second iteration.
1261*0f4c859eSApple OSS Distributions * *overlap The pointer to the overlapping lock
1262*0f4c859eSApple OSS Distributions * itself; this is used to return data in
1263*0f4c859eSApple OSS Distributions * the check == OTHERS case, and for the
1264*0f4c859eSApple OSS Distributions * caller to modify the overlapping lock,
1265*0f4c859eSApple OSS Distributions * in the check == SELF case
1266*0f4c859eSApple OSS Distributions *
1267*0f4c859eSApple OSS Distributions * Note: This returns only the FIRST overlapping lock. There may be
1268*0f4c859eSApple OSS Distributions * more than one. lf_getlock will return the first blocking lock,
1269*0f4c859eSApple OSS Distributions * while lf_setlock will iterate over all overlapping locks to
1270*0f4c859eSApple OSS Distributions *
1271*0f4c859eSApple OSS Distributions * The check parameter can be SELF, meaning we are looking for
1272*0f4c859eSApple OSS Distributions * overlapping locks owned by us, or it can be OTHERS, meaning
1273*0f4c859eSApple OSS Distributions * we are looking for overlapping locks owned by someone else so
1274*0f4c859eSApple OSS Distributions * we can report a blocking lock on an F_GETLK request.
1275*0f4c859eSApple OSS Distributions *
1276*0f4c859eSApple OSS Distributions * The value of *overlap and *prev are modified, even if there is
1277*0f4c859eSApple OSS Distributions * no overlapping lock found; always check the return code.
1278*0f4c859eSApple OSS Distributions */
1279*0f4c859eSApple OSS Distributions static overlap_t
lf_findoverlap(struct lockf * lf,struct lockf * lock,int type,struct lockf *** prev,struct lockf ** overlap)1280*0f4c859eSApple OSS Distributions lf_findoverlap(struct lockf *lf, struct lockf *lock, int type,
1281*0f4c859eSApple OSS Distributions struct lockf ***prev, struct lockf **overlap)
1282*0f4c859eSApple OSS Distributions {
1283*0f4c859eSApple OSS Distributions int found_self = 0;
1284*0f4c859eSApple OSS Distributions
1285*0f4c859eSApple OSS Distributions *overlap = lf;
1286*0f4c859eSApple OSS Distributions if (lf == NOLOCKF) {
1287*0f4c859eSApple OSS Distributions return 0;
1288*0f4c859eSApple OSS Distributions }
1289*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1290*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LIST)) {
1291*0f4c859eSApple OSS Distributions lf_print("lf_findoverlap: looking for overlap in", lock);
1292*0f4c859eSApple OSS Distributions }
1293*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1294*0f4c859eSApple OSS Distributions const off_t start = lock->lf_start;
1295*0f4c859eSApple OSS Distributions const off_t end = LF_END(lock);
1296*0f4c859eSApple OSS Distributions while (lf != NOLOCKF) {
1297*0f4c859eSApple OSS Distributions if (((type & SELF) && lf->lf_id != lock->lf_id) ||
1298*0f4c859eSApple OSS Distributions ((type & OTHERS) && lf->lf_id == lock->lf_id)) {
1299*0f4c859eSApple OSS Distributions /*
1300*0f4c859eSApple OSS Distributions * Locks belonging to one process are adjacent on the
1301*0f4c859eSApple OSS Distributions * list, so if we've found any locks belonging to us,
1302*0f4c859eSApple OSS Distributions * and we're now seeing something else, then we've
1303*0f4c859eSApple OSS Distributions * examined all "self" locks. Note that bailing out
1304*0f4c859eSApple OSS Distributions * here is quite important; for coalescing, we assume
1305*0f4c859eSApple OSS Distributions * numerically adjacent locks from the same owner to
1306*0f4c859eSApple OSS Distributions * be adjacent on the list.
1307*0f4c859eSApple OSS Distributions */
1308*0f4c859eSApple OSS Distributions if ((type & SELF) && found_self) {
1309*0f4c859eSApple OSS Distributions return OVERLAP_NONE;
1310*0f4c859eSApple OSS Distributions }
1311*0f4c859eSApple OSS Distributions
1312*0f4c859eSApple OSS Distributions *prev = &lf->lf_next;
1313*0f4c859eSApple OSS Distributions *overlap = lf = lf->lf_next;
1314*0f4c859eSApple OSS Distributions continue;
1315*0f4c859eSApple OSS Distributions }
1316*0f4c859eSApple OSS Distributions
1317*0f4c859eSApple OSS Distributions if ((type & SELF)) {
1318*0f4c859eSApple OSS Distributions found_self = 1;
1319*0f4c859eSApple OSS Distributions }
1320*0f4c859eSApple OSS Distributions
1321*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1322*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LIST)) {
1323*0f4c859eSApple OSS Distributions lf_print("\tchecking", lf);
1324*0f4c859eSApple OSS Distributions }
1325*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1326*0f4c859eSApple OSS Distributions /*
1327*0f4c859eSApple OSS Distributions * OK, check for overlap
1328*0f4c859eSApple OSS Distributions */
1329*0f4c859eSApple OSS Distributions const off_t lfstart = lf->lf_start;
1330*0f4c859eSApple OSS Distributions const off_t lfend = LF_END(lf);
1331*0f4c859eSApple OSS Distributions
1332*0f4c859eSApple OSS Distributions if ((start > lfend) || (lfstart > end)) {
1333*0f4c859eSApple OSS Distributions /* Case 0 */
1334*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "no overlap\n");
1335*0f4c859eSApple OSS Distributions
1336*0f4c859eSApple OSS Distributions /*
1337*0f4c859eSApple OSS Distributions * NOTE: assumes that locks for the same process are
1338*0f4c859eSApple OSS Distributions * nonintersecting and ordered.
1339*0f4c859eSApple OSS Distributions */
1340*0f4c859eSApple OSS Distributions if ((type & SELF) && lfstart > end) {
1341*0f4c859eSApple OSS Distributions return OVERLAP_NONE;
1342*0f4c859eSApple OSS Distributions }
1343*0f4c859eSApple OSS Distributions *prev = &lf->lf_next;
1344*0f4c859eSApple OSS Distributions *overlap = lf = lf->lf_next;
1345*0f4c859eSApple OSS Distributions continue;
1346*0f4c859eSApple OSS Distributions }
1347*0f4c859eSApple OSS Distributions if ((lfstart == start) && (lfend == end)) {
1348*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "overlap == lock\n");
1349*0f4c859eSApple OSS Distributions return OVERLAP_EQUALS_LOCK;
1350*0f4c859eSApple OSS Distributions }
1351*0f4c859eSApple OSS Distributions if ((lfstart <= start) && (lfend >= end)) {
1352*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "overlap contains lock\n");
1353*0f4c859eSApple OSS Distributions return OVERLAP_CONTAINS_LOCK;
1354*0f4c859eSApple OSS Distributions }
1355*0f4c859eSApple OSS Distributions if ((start <= lfstart) && (end >= lfend)) {
1356*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "lock contains overlap\n");
1357*0f4c859eSApple OSS Distributions return OVERLAP_CONTAINED_BY_LOCK;
1358*0f4c859eSApple OSS Distributions }
1359*0f4c859eSApple OSS Distributions if ((lfstart < start) && (lfend >= start)) {
1360*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "overlap starts before lock\n");
1361*0f4c859eSApple OSS Distributions return OVERLAP_STARTS_BEFORE_LOCK;
1362*0f4c859eSApple OSS Distributions }
1363*0f4c859eSApple OSS Distributions if ((lfstart > start) && (lfend > end)) {
1364*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_LIST, "overlap ends after lock\n");
1365*0f4c859eSApple OSS Distributions return OVERLAP_ENDS_AFTER_LOCK;
1366*0f4c859eSApple OSS Distributions }
1367*0f4c859eSApple OSS Distributions panic("lf_findoverlap: default");
1368*0f4c859eSApple OSS Distributions }
1369*0f4c859eSApple OSS Distributions return OVERLAP_NONE;
1370*0f4c859eSApple OSS Distributions }
1371*0f4c859eSApple OSS Distributions
1372*0f4c859eSApple OSS Distributions
1373*0f4c859eSApple OSS Distributions /*
1374*0f4c859eSApple OSS Distributions * lf_split
1375*0f4c859eSApple OSS Distributions *
1376*0f4c859eSApple OSS Distributions * Description: Split a lock and a contained region into two or three locks
1377*0f4c859eSApple OSS Distributions * as necessary.
1378*0f4c859eSApple OSS Distributions *
1379*0f4c859eSApple OSS Distributions * Parameters: lock1 Lock to split
1380*0f4c859eSApple OSS Distributions * lock2 Overlapping lock region requiring the
1381*0f4c859eSApple OSS Distributions * split (upgrade/downgrade/unlock)
1382*0f4c859eSApple OSS Distributions *
1383*0f4c859eSApple OSS Distributions * Returns: 0 Success
1384*0f4c859eSApple OSS Distributions * ENOLCK No memory for new lock
1385*0f4c859eSApple OSS Distributions *
1386*0f4c859eSApple OSS Distributions * Implicit Returns:
1387*0f4c859eSApple OSS Distributions * *lock1 Modified original lock
1388*0f4c859eSApple OSS Distributions * *lock2 Overlapping lock (inserted into list)
1389*0f4c859eSApple OSS Distributions * (new lock) Potential new lock inserted into list
1390*0f4c859eSApple OSS Distributions * if split results in 3 locks
1391*0f4c859eSApple OSS Distributions *
1392*0f4c859eSApple OSS Distributions * Notes: This operation can only fail if the split would result in three
1393*0f4c859eSApple OSS Distributions * locks, and there is insufficient memory to allocate the third
1394*0f4c859eSApple OSS Distributions * lock; in that case, neither of the locks will be modified.
1395*0f4c859eSApple OSS Distributions */
1396*0f4c859eSApple OSS Distributions static int
lf_split(struct lockf * lock1,struct lockf * lock2)1397*0f4c859eSApple OSS Distributions lf_split(struct lockf *lock1, struct lockf *lock2)
1398*0f4c859eSApple OSS Distributions {
1399*0f4c859eSApple OSS Distributions struct lockf *splitlock;
1400*0f4c859eSApple OSS Distributions
1401*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1402*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LIST)) {
1403*0f4c859eSApple OSS Distributions lf_print("lf_split", lock1);
1404*0f4c859eSApple OSS Distributions lf_print("splitting from", lock2);
1405*0f4c859eSApple OSS Distributions }
1406*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1407*0f4c859eSApple OSS Distributions /*
1408*0f4c859eSApple OSS Distributions * Check to see if splitting into only two pieces.
1409*0f4c859eSApple OSS Distributions */
1410*0f4c859eSApple OSS Distributions if (lock1->lf_start == lock2->lf_start) {
1411*0f4c859eSApple OSS Distributions assert(LF_END(lock2) < OFF_MAX);
1412*0f4c859eSApple OSS Distributions lock1->lf_start = LF_END(lock2) + 1;
1413*0f4c859eSApple OSS Distributions lock2->lf_next = lock1;
1414*0f4c859eSApple OSS Distributions return 0;
1415*0f4c859eSApple OSS Distributions }
1416*0f4c859eSApple OSS Distributions if (LF_END(lock1) == LF_END(lock2)) {
1417*0f4c859eSApple OSS Distributions assert(lock2->lf_start > 0);
1418*0f4c859eSApple OSS Distributions lock1->lf_end = lock2->lf_start - 1;
1419*0f4c859eSApple OSS Distributions lock2->lf_next = lock1->lf_next;
1420*0f4c859eSApple OSS Distributions lock1->lf_next = lock2;
1421*0f4c859eSApple OSS Distributions return 0;
1422*0f4c859eSApple OSS Distributions }
1423*0f4c859eSApple OSS Distributions /*
1424*0f4c859eSApple OSS Distributions * Make a new lock consisting of the last part of
1425*0f4c859eSApple OSS Distributions * the encompassing lock
1426*0f4c859eSApple OSS Distributions */
1427*0f4c859eSApple OSS Distributions splitlock = zalloc_flags(KT_LOCKF, Z_WAITOK | Z_NOFAIL);
1428*0f4c859eSApple OSS Distributions bcopy(lock1, splitlock, sizeof *splitlock);
1429*0f4c859eSApple OSS Distributions assert(LF_END(lock2) < OFF_MAX);
1430*0f4c859eSApple OSS Distributions splitlock->lf_start = LF_END(lock2) + 1;
1431*0f4c859eSApple OSS Distributions TAILQ_INIT(&splitlock->lf_blkhd);
1432*0f4c859eSApple OSS Distributions assert(lock2->lf_start > 0);
1433*0f4c859eSApple OSS Distributions lock1->lf_end = lock2->lf_start - 1;
1434*0f4c859eSApple OSS Distributions /*
1435*0f4c859eSApple OSS Distributions * OK, now link it in
1436*0f4c859eSApple OSS Distributions */
1437*0f4c859eSApple OSS Distributions splitlock->lf_next = lock1->lf_next;
1438*0f4c859eSApple OSS Distributions lock2->lf_next = splitlock;
1439*0f4c859eSApple OSS Distributions lock1->lf_next = lock2;
1440*0f4c859eSApple OSS Distributions
1441*0f4c859eSApple OSS Distributions return 0;
1442*0f4c859eSApple OSS Distributions }
1443*0f4c859eSApple OSS Distributions
1444*0f4c859eSApple OSS Distributions
1445*0f4c859eSApple OSS Distributions /*
1446*0f4c859eSApple OSS Distributions * lf_wakelock
1447*0f4c859eSApple OSS Distributions *
1448*0f4c859eSApple OSS Distributions * Wakeup a blocklist in the case of a downgrade or unlock, since others
1449*0f4c859eSApple OSS Distributions * waiting on the lock may now be able to acquire it.
1450*0f4c859eSApple OSS Distributions *
1451*0f4c859eSApple OSS Distributions * Parameters: listhead Lock list head on which waiters may
1452*0f4c859eSApple OSS Distributions * have pending locks
1453*0f4c859eSApple OSS Distributions *
1454*0f4c859eSApple OSS Distributions * Returns: <void>
1455*0f4c859eSApple OSS Distributions *
1456*0f4c859eSApple OSS Distributions * Notes: This function iterates a list of locks and wakes all waiters,
1457*0f4c859eSApple OSS Distributions * rather than only waiters for the contended regions. Because
1458*0f4c859eSApple OSS Distributions * of this, for heavily contended files, this can result in a
1459*0f4c859eSApple OSS Distributions * "thundering herd" situation. Refactoring the code could make
1460*0f4c859eSApple OSS Distributions * this operation more efficient, if heavy contention ever results
1461*0f4c859eSApple OSS Distributions * in a real-world performance problem.
1462*0f4c859eSApple OSS Distributions */
1463*0f4c859eSApple OSS Distributions static void
lf_wakelock(struct lockf * listhead,boolean_t force_all)1464*0f4c859eSApple OSS Distributions lf_wakelock(struct lockf *listhead, boolean_t force_all)
1465*0f4c859eSApple OSS Distributions {
1466*0f4c859eSApple OSS Distributions struct lockf *wakelock;
1467*0f4c859eSApple OSS Distributions boolean_t wake_all = TRUE;
1468*0f4c859eSApple OSS Distributions
1469*0f4c859eSApple OSS Distributions if (force_all == FALSE && (listhead->lf_flags & F_WAKE1_SAFE)) {
1470*0f4c859eSApple OSS Distributions wake_all = FALSE;
1471*0f4c859eSApple OSS Distributions }
1472*0f4c859eSApple OSS Distributions
1473*0f4c859eSApple OSS Distributions while (!TAILQ_EMPTY(&listhead->lf_blkhd)) {
1474*0f4c859eSApple OSS Distributions wakelock = TAILQ_FIRST(&listhead->lf_blkhd);
1475*0f4c859eSApple OSS Distributions TAILQ_REMOVE(&listhead->lf_blkhd, wakelock, lf_block);
1476*0f4c859eSApple OSS Distributions
1477*0f4c859eSApple OSS Distributions wakelock->lf_next = NOLOCKF;
1478*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1479*0f4c859eSApple OSS Distributions if (LOCKF_DEBUGP(LF_DBG_LOCKOP)) {
1480*0f4c859eSApple OSS Distributions lf_print("lf_wakelock: awakening", wakelock);
1481*0f4c859eSApple OSS Distributions }
1482*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1483*0f4c859eSApple OSS Distributions if (wake_all == FALSE) {
1484*0f4c859eSApple OSS Distributions /*
1485*0f4c859eSApple OSS Distributions * If there are items on the list head block list,
1486*0f4c859eSApple OSS Distributions * move them to the wakelock list instead, and then
1487*0f4c859eSApple OSS Distributions * correct their lf_next pointers.
1488*0f4c859eSApple OSS Distributions */
1489*0f4c859eSApple OSS Distributions if (!TAILQ_EMPTY(&listhead->lf_blkhd)) {
1490*0f4c859eSApple OSS Distributions TAILQ_CONCAT(&wakelock->lf_blkhd, &listhead->lf_blkhd, lf_block);
1491*0f4c859eSApple OSS Distributions
1492*0f4c859eSApple OSS Distributions struct lockf *tlock;
1493*0f4c859eSApple OSS Distributions
1494*0f4c859eSApple OSS Distributions TAILQ_FOREACH(tlock, &wakelock->lf_blkhd, lf_block) {
1495*0f4c859eSApple OSS Distributions if (TAILQ_NEXT(tlock, lf_block) == tlock) {
1496*0f4c859eSApple OSS Distributions /* See rdar://10887303 */
1497*0f4c859eSApple OSS Distributions panic("cycle in wakelock list");
1498*0f4c859eSApple OSS Distributions }
1499*0f4c859eSApple OSS Distributions tlock->lf_next = wakelock;
1500*0f4c859eSApple OSS Distributions }
1501*0f4c859eSApple OSS Distributions }
1502*0f4c859eSApple OSS Distributions }
1503*0f4c859eSApple OSS Distributions wakeup(wakelock);
1504*0f4c859eSApple OSS Distributions
1505*0f4c859eSApple OSS Distributions if (wake_all == FALSE) {
1506*0f4c859eSApple OSS Distributions break;
1507*0f4c859eSApple OSS Distributions }
1508*0f4c859eSApple OSS Distributions }
1509*0f4c859eSApple OSS Distributions }
1510*0f4c859eSApple OSS Distributions
1511*0f4c859eSApple OSS Distributions
1512*0f4c859eSApple OSS Distributions #ifdef LOCKF_DEBUGGING
1513*0f4c859eSApple OSS Distributions #define GET_LF_OWNER_PID(lf) (proc_pid((lf)->lf_owner))
1514*0f4c859eSApple OSS Distributions
1515*0f4c859eSApple OSS Distributions /*
1516*0f4c859eSApple OSS Distributions * lf_print DEBUG
1517*0f4c859eSApple OSS Distributions *
1518*0f4c859eSApple OSS Distributions * Print out a lock; lock information is prefixed by the string in 'tag'
1519*0f4c859eSApple OSS Distributions *
1520*0f4c859eSApple OSS Distributions * Parameters: tag A string tag for debugging
1521*0f4c859eSApple OSS Distributions * lock The lock whose information should be
1522*0f4c859eSApple OSS Distributions * displayed
1523*0f4c859eSApple OSS Distributions *
1524*0f4c859eSApple OSS Distributions * Returns: <void>
1525*0f4c859eSApple OSS Distributions */
1526*0f4c859eSApple OSS Distributions void
lf_print(const char * tag,struct lockf * lock)1527*0f4c859eSApple OSS Distributions lf_print(const char *tag, struct lockf *lock)
1528*0f4c859eSApple OSS Distributions {
1529*0f4c859eSApple OSS Distributions printf("%s: lock %p for ", tag, (void *)lock);
1530*0f4c859eSApple OSS Distributions if (lock->lf_flags & F_POSIX) {
1531*0f4c859eSApple OSS Distributions printf("proc %p (owner %d)",
1532*0f4c859eSApple OSS Distributions lock->lf_id, GET_LF_OWNER_PID(lock));
1533*0f4c859eSApple OSS Distributions } else if (lock->lf_flags & F_OFD_LOCK) {
1534*0f4c859eSApple OSS Distributions printf("fg %p (owner %d)",
1535*0f4c859eSApple OSS Distributions lock->lf_id, GET_LF_OWNER_PID(lock));
1536*0f4c859eSApple OSS Distributions } else {
1537*0f4c859eSApple OSS Distributions printf("id %p", (void *)lock->lf_id);
1538*0f4c859eSApple OSS Distributions }
1539*0f4c859eSApple OSS Distributions if (lock->lf_vnode != 0) {
1540*0f4c859eSApple OSS Distributions printf(" in vno %p, %s, start 0x%016llx, end 0x%016llx",
1541*0f4c859eSApple OSS Distributions lock->lf_vnode,
1542*0f4c859eSApple OSS Distributions lock->lf_type == F_RDLCK ? "shared" :
1543*0f4c859eSApple OSS Distributions lock->lf_type == F_WRLCK ? "exclusive" :
1544*0f4c859eSApple OSS Distributions lock->lf_type == F_UNLCK ? "unlock" : "unknown",
1545*0f4c859eSApple OSS Distributions (uint64_t)lock->lf_start, (uint64_t)lock->lf_end);
1546*0f4c859eSApple OSS Distributions } else {
1547*0f4c859eSApple OSS Distributions printf(" %s, start 0x%016llx, end 0x%016llx",
1548*0f4c859eSApple OSS Distributions lock->lf_type == F_RDLCK ? "shared" :
1549*0f4c859eSApple OSS Distributions lock->lf_type == F_WRLCK ? "exclusive" :
1550*0f4c859eSApple OSS Distributions lock->lf_type == F_UNLCK ? "unlock" : "unknown",
1551*0f4c859eSApple OSS Distributions (uint64_t)lock->lf_start, (uint64_t)lock->lf_end);
1552*0f4c859eSApple OSS Distributions }
1553*0f4c859eSApple OSS Distributions if (!TAILQ_EMPTY(&lock->lf_blkhd)) {
1554*0f4c859eSApple OSS Distributions printf(" block %p\n", (void *)TAILQ_FIRST(&lock->lf_blkhd));
1555*0f4c859eSApple OSS Distributions } else {
1556*0f4c859eSApple OSS Distributions printf("\n");
1557*0f4c859eSApple OSS Distributions }
1558*0f4c859eSApple OSS Distributions }
1559*0f4c859eSApple OSS Distributions
1560*0f4c859eSApple OSS Distributions
1561*0f4c859eSApple OSS Distributions /*
1562*0f4c859eSApple OSS Distributions * lf_printlist DEBUG
1563*0f4c859eSApple OSS Distributions *
1564*0f4c859eSApple OSS Distributions * Print out a lock list for the vnode associated with 'lock'; lock information
1565*0f4c859eSApple OSS Distributions * is prefixed by the string in 'tag'
1566*0f4c859eSApple OSS Distributions *
1567*0f4c859eSApple OSS Distributions * Parameters: tag A string tag for debugging
1568*0f4c859eSApple OSS Distributions * lock The lock whose vnode's lock list should
1569*0f4c859eSApple OSS Distributions * be displayed
1570*0f4c859eSApple OSS Distributions *
1571*0f4c859eSApple OSS Distributions * Returns: <void>
1572*0f4c859eSApple OSS Distributions */
1573*0f4c859eSApple OSS Distributions void
lf_printlist(const char * tag,struct lockf * lock)1574*0f4c859eSApple OSS Distributions lf_printlist(const char *tag, struct lockf *lock)
1575*0f4c859eSApple OSS Distributions {
1576*0f4c859eSApple OSS Distributions struct lockf *lf, *blk;
1577*0f4c859eSApple OSS Distributions
1578*0f4c859eSApple OSS Distributions if (lock->lf_vnode == 0) {
1579*0f4c859eSApple OSS Distributions return;
1580*0f4c859eSApple OSS Distributions }
1581*0f4c859eSApple OSS Distributions
1582*0f4c859eSApple OSS Distributions printf("%s: Lock list for vno %p:\n",
1583*0f4c859eSApple OSS Distributions tag, lock->lf_vnode);
1584*0f4c859eSApple OSS Distributions for (lf = lock->lf_vnode->v_lockf; lf; lf = lf->lf_next) {
1585*0f4c859eSApple OSS Distributions printf("\tlock %p for ", (void *)lf);
1586*0f4c859eSApple OSS Distributions if (lf->lf_flags & F_POSIX) {
1587*0f4c859eSApple OSS Distributions printf("proc %p (owner %d)",
1588*0f4c859eSApple OSS Distributions lf->lf_id, GET_LF_OWNER_PID(lf));
1589*0f4c859eSApple OSS Distributions } else if (lf->lf_flags & F_OFD_LOCK) {
1590*0f4c859eSApple OSS Distributions printf("fg %p (owner %d)",
1591*0f4c859eSApple OSS Distributions lf->lf_id, GET_LF_OWNER_PID(lf));
1592*0f4c859eSApple OSS Distributions } else {
1593*0f4c859eSApple OSS Distributions printf("id %p", (void *)lf->lf_id);
1594*0f4c859eSApple OSS Distributions }
1595*0f4c859eSApple OSS Distributions printf(", %s, start 0x%016llx, end 0x%016llx",
1596*0f4c859eSApple OSS Distributions lf->lf_type == F_RDLCK ? "shared" :
1597*0f4c859eSApple OSS Distributions lf->lf_type == F_WRLCK ? "exclusive" :
1598*0f4c859eSApple OSS Distributions lf->lf_type == F_UNLCK ? "unlock" :
1599*0f4c859eSApple OSS Distributions "unknown", (uint64_t)lf->lf_start, (uint64_t)lf->lf_end);
1600*0f4c859eSApple OSS Distributions TAILQ_FOREACH(blk, &lf->lf_blkhd, lf_block) {
1601*0f4c859eSApple OSS Distributions printf("\n\t\tlock request %p for ", (void *)blk);
1602*0f4c859eSApple OSS Distributions if (blk->lf_flags & F_POSIX) {
1603*0f4c859eSApple OSS Distributions printf("proc %p (owner %d)",
1604*0f4c859eSApple OSS Distributions blk->lf_id, GET_LF_OWNER_PID(blk));
1605*0f4c859eSApple OSS Distributions } else if (blk->lf_flags & F_OFD_LOCK) {
1606*0f4c859eSApple OSS Distributions printf("fg %p (owner %d)",
1607*0f4c859eSApple OSS Distributions blk->lf_id, GET_LF_OWNER_PID(blk));
1608*0f4c859eSApple OSS Distributions } else {
1609*0f4c859eSApple OSS Distributions printf("id %p", (void *)blk->lf_id);
1610*0f4c859eSApple OSS Distributions }
1611*0f4c859eSApple OSS Distributions printf(", %s, start 0x%016llx, end 0x%016llx",
1612*0f4c859eSApple OSS Distributions blk->lf_type == F_RDLCK ? "shared" :
1613*0f4c859eSApple OSS Distributions blk->lf_type == F_WRLCK ? "exclusive" :
1614*0f4c859eSApple OSS Distributions blk->lf_type == F_UNLCK ? "unlock" :
1615*0f4c859eSApple OSS Distributions "unknown", (uint64_t)blk->lf_start,
1616*0f4c859eSApple OSS Distributions (uint64_t)blk->lf_end);
1617*0f4c859eSApple OSS Distributions if (!TAILQ_EMPTY(&blk->lf_blkhd)) {
1618*0f4c859eSApple OSS Distributions panic("lf_printlist: bad list");
1619*0f4c859eSApple OSS Distributions }
1620*0f4c859eSApple OSS Distributions }
1621*0f4c859eSApple OSS Distributions printf("\n");
1622*0f4c859eSApple OSS Distributions }
1623*0f4c859eSApple OSS Distributions }
1624*0f4c859eSApple OSS Distributions #endif /* LOCKF_DEBUGGING */
1625*0f4c859eSApple OSS Distributions
1626*0f4c859eSApple OSS Distributions #if IMPORTANCE_INHERITANCE
1627*0f4c859eSApple OSS Distributions
1628*0f4c859eSApple OSS Distributions /*
1629*0f4c859eSApple OSS Distributions * lf_hold_assertion
1630*0f4c859eSApple OSS Distributions *
1631*0f4c859eSApple OSS Distributions * Call task importance hold assertion on the owner of the lock.
1632*0f4c859eSApple OSS Distributions *
1633*0f4c859eSApple OSS Distributions * Parameters: block_task Owner of the lock blocking
1634*0f4c859eSApple OSS Distributions * current thread.
1635*0f4c859eSApple OSS Distributions *
1636*0f4c859eSApple OSS Distributions * block lock on which the current thread
1637*0f4c859eSApple OSS Distributions * is blocking on.
1638*0f4c859eSApple OSS Distributions *
1639*0f4c859eSApple OSS Distributions * Returns: <void>
1640*0f4c859eSApple OSS Distributions *
1641*0f4c859eSApple OSS Distributions * Notes: The task reference on block_task is not needed to be hold since
1642*0f4c859eSApple OSS Distributions * the current thread has vnode lock and block_task has a file
1643*0f4c859eSApple OSS Distributions * lock, thus removing file lock in exit requires block_task to
1644*0f4c859eSApple OSS Distributions * grab the vnode lock.
1645*0f4c859eSApple OSS Distributions */
1646*0f4c859eSApple OSS Distributions static void
lf_hold_assertion(task_t block_task,struct lockf * block)1647*0f4c859eSApple OSS Distributions lf_hold_assertion(task_t block_task, struct lockf *block)
1648*0f4c859eSApple OSS Distributions {
1649*0f4c859eSApple OSS Distributions if (task_importance_hold_file_lock_assertion(block_task, 1) == 0) {
1650*0f4c859eSApple OSS Distributions block->lf_boosted = LF_BOOSTED;
1651*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_IMPINH,
1652*0f4c859eSApple OSS Distributions "lf: importance hold file lock assert on pid %d lock %p\n",
1653*0f4c859eSApple OSS Distributions proc_pid(block->lf_owner), block);
1654*0f4c859eSApple OSS Distributions }
1655*0f4c859eSApple OSS Distributions }
1656*0f4c859eSApple OSS Distributions
1657*0f4c859eSApple OSS Distributions
1658*0f4c859eSApple OSS Distributions /*
1659*0f4c859eSApple OSS Distributions * lf_jump_to_queue_head
1660*0f4c859eSApple OSS Distributions *
1661*0f4c859eSApple OSS Distributions * Jump the lock from the tail of the block queue to the head of
1662*0f4c859eSApple OSS Distributions * the queue.
1663*0f4c859eSApple OSS Distributions *
1664*0f4c859eSApple OSS Distributions * Parameters: block lockf struct containing the
1665*0f4c859eSApple OSS Distributions * block queue.
1666*0f4c859eSApple OSS Distributions * lock lockf struct to be jumped to the
1667*0f4c859eSApple OSS Distributions * front.
1668*0f4c859eSApple OSS Distributions *
1669*0f4c859eSApple OSS Distributions * Returns: <void>
1670*0f4c859eSApple OSS Distributions */
1671*0f4c859eSApple OSS Distributions static void
lf_jump_to_queue_head(struct lockf * block,struct lockf * lock)1672*0f4c859eSApple OSS Distributions lf_jump_to_queue_head(struct lockf *block, struct lockf *lock)
1673*0f4c859eSApple OSS Distributions {
1674*0f4c859eSApple OSS Distributions /* Move the lock to the head of the block queue. */
1675*0f4c859eSApple OSS Distributions TAILQ_REMOVE(&block->lf_blkhd, lock, lf_block);
1676*0f4c859eSApple OSS Distributions TAILQ_INSERT_HEAD(&block->lf_blkhd, lock, lf_block);
1677*0f4c859eSApple OSS Distributions }
1678*0f4c859eSApple OSS Distributions
1679*0f4c859eSApple OSS Distributions
1680*0f4c859eSApple OSS Distributions /*
1681*0f4c859eSApple OSS Distributions * lf_drop_assertion
1682*0f4c859eSApple OSS Distributions *
1683*0f4c859eSApple OSS Distributions * Drops the task hold assertion.
1684*0f4c859eSApple OSS Distributions *
1685*0f4c859eSApple OSS Distributions * Parameters: block lockf struct holding the assertion.
1686*0f4c859eSApple OSS Distributions *
1687*0f4c859eSApple OSS Distributions * Returns: <void>
1688*0f4c859eSApple OSS Distributions */
1689*0f4c859eSApple OSS Distributions static void
lf_drop_assertion(struct lockf * block)1690*0f4c859eSApple OSS Distributions lf_drop_assertion(struct lockf *block)
1691*0f4c859eSApple OSS Distributions {
1692*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_IMPINH, "lf: %d: dropping assertion for lock %p\n",
1693*0f4c859eSApple OSS Distributions proc_pid(block->lf_owner), block);
1694*0f4c859eSApple OSS Distributions
1695*0f4c859eSApple OSS Distributions task_t current_task = proc_task(block->lf_owner);
1696*0f4c859eSApple OSS Distributions task_importance_drop_file_lock_assertion(current_task, 1);
1697*0f4c859eSApple OSS Distributions block->lf_boosted = LF_NOT_BOOSTED;
1698*0f4c859eSApple OSS Distributions }
1699*0f4c859eSApple OSS Distributions
1700*0f4c859eSApple OSS Distributions /*
1701*0f4c859eSApple OSS Distributions * lf_adjust_assertion
1702*0f4c859eSApple OSS Distributions *
1703*0f4c859eSApple OSS Distributions * Adjusts importance assertion of file lock. Goes through
1704*0f4c859eSApple OSS Distributions * all the blocking locks and checks if the file lock needs
1705*0f4c859eSApple OSS Distributions * to be boosted anymore.
1706*0f4c859eSApple OSS Distributions *
1707*0f4c859eSApple OSS Distributions * Parameters: block lockf structure which needs to be adjusted.
1708*0f4c859eSApple OSS Distributions *
1709*0f4c859eSApple OSS Distributions * Returns: <void>
1710*0f4c859eSApple OSS Distributions */
1711*0f4c859eSApple OSS Distributions static void
lf_adjust_assertion(struct lockf * block)1712*0f4c859eSApple OSS Distributions lf_adjust_assertion(struct lockf *block)
1713*0f4c859eSApple OSS Distributions {
1714*0f4c859eSApple OSS Distributions boolean_t drop_boost = TRUE;
1715*0f4c859eSApple OSS Distributions struct lockf *next;
1716*0f4c859eSApple OSS Distributions
1717*0f4c859eSApple OSS Distributions /* Return if the lock is not boosted */
1718*0f4c859eSApple OSS Distributions if (block->lf_boosted == LF_NOT_BOOSTED) {
1719*0f4c859eSApple OSS Distributions return;
1720*0f4c859eSApple OSS Distributions }
1721*0f4c859eSApple OSS Distributions
1722*0f4c859eSApple OSS Distributions TAILQ_FOREACH(next, &block->lf_blkhd, lf_block) {
1723*0f4c859eSApple OSS Distributions /* Check if block and next are same type of locks */
1724*0f4c859eSApple OSS Distributions if (((block->lf_flags & next->lf_flags & F_POSIX) != 0) ||
1725*0f4c859eSApple OSS Distributions ((block->lf_flags & next->lf_flags & F_OFD_LOCK) &&
1726*0f4c859eSApple OSS Distributions (block->lf_owner != next->lf_owner) &&
1727*0f4c859eSApple OSS Distributions (NULL != block->lf_owner && NULL != next->lf_owner))) {
1728*0f4c859eSApple OSS Distributions /* Check if next would be boosting block */
1729*0f4c859eSApple OSS Distributions if (task_is_importance_donor(proc_task(next->lf_owner)) &&
1730*0f4c859eSApple OSS Distributions task_is_importance_receiver_type(proc_task(block->lf_owner))) {
1731*0f4c859eSApple OSS Distributions /* Found a lock boosting block */
1732*0f4c859eSApple OSS Distributions drop_boost = FALSE;
1733*0f4c859eSApple OSS Distributions break;
1734*0f4c859eSApple OSS Distributions }
1735*0f4c859eSApple OSS Distributions }
1736*0f4c859eSApple OSS Distributions }
1737*0f4c859eSApple OSS Distributions
1738*0f4c859eSApple OSS Distributions if (drop_boost) {
1739*0f4c859eSApple OSS Distributions lf_drop_assertion(block);
1740*0f4c859eSApple OSS Distributions }
1741*0f4c859eSApple OSS Distributions }
1742*0f4c859eSApple OSS Distributions
1743*0f4c859eSApple OSS Distributions static void
lf_boost_blocking_proc(struct lockf * lock,struct lockf * block)1744*0f4c859eSApple OSS Distributions lf_boost_blocking_proc(struct lockf *lock, struct lockf *block)
1745*0f4c859eSApple OSS Distributions {
1746*0f4c859eSApple OSS Distributions task_t ltask = proc_task(lock->lf_owner);
1747*0f4c859eSApple OSS Distributions task_t btask = proc_task(block->lf_owner);
1748*0f4c859eSApple OSS Distributions
1749*0f4c859eSApple OSS Distributions /*
1750*0f4c859eSApple OSS Distributions * Check if ltask can donate importance. The
1751*0f4c859eSApple OSS Distributions * check of imp_donor bit is done without holding
1752*0f4c859eSApple OSS Distributions * any lock. The value may change after you read it,
1753*0f4c859eSApple OSS Distributions * but it is ok to boost a task while someone else is
1754*0f4c859eSApple OSS Distributions * unboosting you.
1755*0f4c859eSApple OSS Distributions *
1756*0f4c859eSApple OSS Distributions * TODO: Support live inheritance on file locks.
1757*0f4c859eSApple OSS Distributions */
1758*0f4c859eSApple OSS Distributions if (task_is_importance_donor(ltask)) {
1759*0f4c859eSApple OSS Distributions LOCKF_DEBUG(LF_DBG_IMPINH,
1760*0f4c859eSApple OSS Distributions "lf: %d: attempt to boost pid %d that holds lock %p\n",
1761*0f4c859eSApple OSS Distributions proc_pid(lock->lf_owner), proc_pid(block->lf_owner), block);
1762*0f4c859eSApple OSS Distributions
1763*0f4c859eSApple OSS Distributions if (block->lf_boosted != LF_BOOSTED &&
1764*0f4c859eSApple OSS Distributions task_is_importance_receiver_type(btask)) {
1765*0f4c859eSApple OSS Distributions lf_hold_assertion(btask, block);
1766*0f4c859eSApple OSS Distributions }
1767*0f4c859eSApple OSS Distributions lf_jump_to_queue_head(block, lock);
1768*0f4c859eSApple OSS Distributions }
1769*0f4c859eSApple OSS Distributions }
1770*0f4c859eSApple OSS Distributions #endif /* IMPORTANCE_INHERITANCE */
1771