]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_lock.c
xnu-1699.32.7.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_lock.c
1 /*
2 * Copyright (c) 2002-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*-
29 * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. Berkeley Software Design Inc's name may not be used to endorse or
40 * promote products derived from this software without specific prior
41 * written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * from BSDI nfs_lock.c,v 2.4 1998/12/14 23:49:56 jch Exp
56 */
57
58 #include <sys/cdefs.h>
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/fcntl.h>
62 #include <sys/kernel.h> /* for hz */
63 #include <sys/file_internal.h>
64 #include <sys/malloc.h>
65 #include <sys/lockf.h> /* for hz */ /* Must come after sys/malloc.h */
66 #include <sys/kpi_mbuf.h>
67 #include <sys/mount_internal.h>
68 #include <sys/proc_internal.h> /* for p_start */
69 #include <sys/kauth.h>
70 #include <sys/resourcevar.h>
71 #include <sys/socket.h>
72 #include <sys/unistd.h>
73 #include <sys/user.h>
74 #include <sys/vnode_internal.h>
75
76 #include <kern/thread.h>
77 #include <kern/host.h>
78
79 #include <machine/limits.h>
80
81 #include <net/if.h>
82
83 #include <nfs/rpcv2.h>
84 #include <nfs/nfsproto.h>
85 #include <nfs/nfs.h>
86 #include <nfs/nfs_gss.h>
87 #include <nfs/nfsmount.h>
88 #include <nfs/nfsnode.h>
89 #include <nfs/nfs_lock.h>
90
91 #include <mach/host_priv.h>
92 #include <mach/mig_errors.h>
93 #include <mach/host_special_ports.h>
94 #include <lockd/lockd_mach.h>
95
96 extern void ipc_port_release_send(ipc_port_t);
97
98 /*
99 * pending lock request messages are kept in this queue which is
100 * kept sorted by transaction ID (xid).
101 */
102 static uint64_t nfs_lockxid = 0;
103 static LOCKD_MSG_QUEUE nfs_pendlockq;
104
105 /* list of mounts that are (potentially) making lockd requests */
106 TAILQ_HEAD(nfs_lockd_mount_list,nfsmount) nfs_lockd_mount_list;
107
108 static lck_grp_t *nfs_lock_lck_grp;
109 static lck_mtx_t *nfs_lock_mutex;
110
111 void nfs_lockdmsg_enqueue(LOCKD_MSG_REQUEST *);
112 void nfs_lockdmsg_dequeue(LOCKD_MSG_REQUEST *);
113 int nfs_lockdmsg_compare_to_answer(LOCKD_MSG_REQUEST *, struct lockd_ans *);
114 LOCKD_MSG_REQUEST *nfs_lockdmsg_find_by_answer(struct lockd_ans *);
115 LOCKD_MSG_REQUEST *nfs_lockdmsg_find_by_xid(uint64_t);
116 uint64_t nfs_lockxid_get(void);
117 int nfs_lockd_send_request(LOCKD_MSG *, int);
118
119 /*
120 * initialize global nfs lock state
121 */
122 void
123 nfs_lockinit(void)
124 {
125 TAILQ_INIT(&nfs_pendlockq);
126 TAILQ_INIT(&nfs_lockd_mount_list);
127
128 nfs_lock_lck_grp = lck_grp_alloc_init("nfs_lock", LCK_GRP_ATTR_NULL);
129 nfs_lock_mutex = lck_mtx_alloc_init(nfs_lock_lck_grp, LCK_ATTR_NULL);
130 }
131
132 /*
133 * Register a mount as (potentially) making lockd requests.
134 */
135 void
136 nfs_lockd_mount_register(struct nfsmount *nmp)
137 {
138 lck_mtx_lock(nfs_lock_mutex);
139 TAILQ_INSERT_HEAD(&nfs_lockd_mount_list, nmp, nm_ldlink);
140 nfs_lockd_mounts++;
141 lck_mtx_unlock(nfs_lock_mutex);
142 }
143
144 /*
145 * Unregister a mount as (potentially) making lockd requests.
146 *
147 * When the lockd mount count drops to zero, then send a shutdown request to
148 * lockd if we've sent any requests to it.
149 */
150 void
151 nfs_lockd_mount_unregister(struct nfsmount *nmp)
152 {
153 int send_shutdown;
154 mach_port_t lockd_port = IPC_PORT_NULL;
155 kern_return_t kr;
156
157 lck_mtx_lock(nfs_lock_mutex);
158 TAILQ_REMOVE(&nfs_lockd_mount_list, nmp, nm_ldlink);
159 nfs_lockd_mounts--;
160
161 /* send a shutdown request if there are no more lockd mounts */
162 send_shutdown = ((nfs_lockd_mounts == 0) && nfs_lockd_request_sent);
163 if (send_shutdown)
164 nfs_lockd_request_sent = 0;
165
166 lck_mtx_unlock(nfs_lock_mutex);
167
168 if (!send_shutdown)
169 return;
170
171 /*
172 * Let lockd know that it is no longer needed for any NFS mounts
173 */
174 kr = host_get_lockd_port(host_priv_self(), &lockd_port);
175 if ((kr != KERN_SUCCESS) || !IPC_PORT_VALID(lockd_port)) {
176 printf("nfs_lockd_mount_change: shutdown couldn't get port, kr %d, port %s\n",
177 kr, (lockd_port == IPC_PORT_NULL) ? "NULL" :
178 (lockd_port == IPC_PORT_DEAD) ? "DEAD" : "VALID");
179 return;
180 }
181
182 kr = lockd_shutdown(lockd_port);
183 if (kr != KERN_SUCCESS)
184 printf("nfs_lockd_mount_change: shutdown %d\n", kr);
185
186 ipc_port_release_send(lockd_port);
187 }
188
189 /*
190 * insert a lock request message into the pending queue
191 * (nfs_lock_mutex must be held)
192 */
193 void
194 nfs_lockdmsg_enqueue(LOCKD_MSG_REQUEST *msgreq)
195 {
196 LOCKD_MSG_REQUEST *mr;
197
198 mr = TAILQ_LAST(&nfs_pendlockq, nfs_lock_msg_queue);
199 if (!mr || (msgreq->lmr_msg.lm_xid > mr->lmr_msg.lm_xid)) {
200 /* fast path: empty queue or new largest xid */
201 TAILQ_INSERT_TAIL(&nfs_pendlockq, msgreq, lmr_next);
202 return;
203 }
204 /* slow path: need to walk list to find insertion point */
205 while (mr && (msgreq->lmr_msg.lm_xid > mr->lmr_msg.lm_xid)) {
206 mr = TAILQ_PREV(mr, nfs_lock_msg_queue, lmr_next);
207 }
208 if (mr) {
209 TAILQ_INSERT_AFTER(&nfs_pendlockq, mr, msgreq, lmr_next);
210 } else {
211 TAILQ_INSERT_HEAD(&nfs_pendlockq, msgreq, lmr_next);
212 }
213 }
214
215 /*
216 * remove a lock request message from the pending queue
217 * (nfs_lock_mutex must be held)
218 */
219 void
220 nfs_lockdmsg_dequeue(LOCKD_MSG_REQUEST *msgreq)
221 {
222 TAILQ_REMOVE(&nfs_pendlockq, msgreq, lmr_next);
223 }
224
225 /*
226 * find a pending lock request message by xid
227 *
228 * We search from the head of the list assuming that the message we're
229 * looking for is for an older request (because we have an answer to it).
230 * This assumes that lock request will be answered primarily in FIFO order.
231 * However, this may not be the case if there are blocked requests. We may
232 * want to move blocked requests to a separate queue (but that'll complicate
233 * duplicate xid checking).
234 *
235 * (nfs_lock_mutex must be held)
236 */
237 LOCKD_MSG_REQUEST *
238 nfs_lockdmsg_find_by_xid(uint64_t lockxid)
239 {
240 LOCKD_MSG_REQUEST *mr;
241
242 TAILQ_FOREACH(mr, &nfs_pendlockq, lmr_next) {
243 if (mr->lmr_msg.lm_xid == lockxid)
244 return mr;
245 if (mr->lmr_msg.lm_xid > lockxid)
246 return NULL;
247 }
248 return mr;
249 }
250
251 /*
252 * Because we can't depend on nlm_granted messages containing the same
253 * cookie we sent with the original lock request, we need code to test
254 * if an nlm_granted answer matches the lock request. We also need code
255 * that can find a lockd message based solely on the nlm_granted answer.
256 */
257
258 /*
259 * compare lockd message to answer
260 *
261 * returns 0 on equality and 1 if different
262 */
263 int
264 nfs_lockdmsg_compare_to_answer(LOCKD_MSG_REQUEST *msgreq, struct lockd_ans *ansp)
265 {
266 if (!(ansp->la_flags & LOCKD_ANS_LOCK_INFO))
267 return 1;
268 if (msgreq->lmr_msg.lm_fl.l_pid != ansp->la_pid)
269 return 1;
270 if (msgreq->lmr_msg.lm_fl.l_start != ansp->la_start)
271 return 1;
272 if (msgreq->lmr_msg.lm_fl.l_len != ansp->la_len)
273 return 1;
274 if (msgreq->lmr_msg.lm_fh_len != ansp->la_fh_len)
275 return 1;
276 if (bcmp(msgreq->lmr_msg.lm_fh, ansp->la_fh, ansp->la_fh_len))
277 return 1;
278 return 0;
279 }
280
281 /*
282 * find a pending lock request message based on the lock info provided
283 * in the lockd_ans/nlm_granted data. We need this because we can't
284 * depend on nlm_granted messages containing the same cookie we sent
285 * with the original lock request.
286 *
287 * We search from the head of the list assuming that the message we're
288 * looking for is for an older request (because we have an answer to it).
289 * This assumes that lock request will be answered primarily in FIFO order.
290 * However, this may not be the case if there are blocked requests. We may
291 * want to move blocked requests to a separate queue (but that'll complicate
292 * duplicate xid checking).
293 *
294 * (nfs_lock_mutex must be held)
295 */
296 LOCKD_MSG_REQUEST *
297 nfs_lockdmsg_find_by_answer(struct lockd_ans *ansp)
298 {
299 LOCKD_MSG_REQUEST *mr;
300
301 if (!(ansp->la_flags & LOCKD_ANS_LOCK_INFO))
302 return NULL;
303 TAILQ_FOREACH(mr, &nfs_pendlockq, lmr_next) {
304 if (!nfs_lockdmsg_compare_to_answer(mr, ansp))
305 break;
306 }
307 return mr;
308 }
309
310 /*
311 * return the next unique lock request transaction ID
312 * (nfs_lock_mutex must be held)
313 */
314 uint64_t
315 nfs_lockxid_get(void)
316 {
317 LOCKD_MSG_REQUEST *mr;
318
319 /* derive initial lock xid from system time */
320 if (!nfs_lockxid) {
321 /*
322 * Note: it's OK if this code inits nfs_lockxid to 0 (for example,
323 * due to a broken clock) because we immediately increment it
324 * and we guarantee to never use xid 0. So, nfs_lockxid should only
325 * ever be 0 the first time this function is called.
326 */
327 struct timeval tv;
328 microtime(&tv);
329 nfs_lockxid = (uint64_t)tv.tv_sec << 12;
330 }
331
332 /* make sure we get a unique xid */
333 do {
334 /* Skip zero xid if it should ever happen. */
335 if (++nfs_lockxid == 0)
336 nfs_lockxid++;
337 if (!(mr = TAILQ_LAST(&nfs_pendlockq, nfs_lock_msg_queue)) ||
338 (mr->lmr_msg.lm_xid < nfs_lockxid)) {
339 /* fast path: empty queue or new largest xid */
340 break;
341 }
342 /* check if xid is already in use */
343 } while (nfs_lockdmsg_find_by_xid(nfs_lockxid));
344
345 return nfs_lockxid;
346 }
347
348 #define MACH_MAX_TRIES 3
349
350 int
351 nfs_lockd_send_request(LOCKD_MSG *msg, int interruptable)
352 {
353 kern_return_t kr;
354 int retries = 0;
355 mach_port_t lockd_port = IPC_PORT_NULL;
356
357 kr = host_get_lockd_port(host_priv_self(), &lockd_port);
358 if (kr != KERN_SUCCESS || !IPC_PORT_VALID(lockd_port))
359 return (ENOTSUP);
360
361 do {
362 /* In the kernel all mach messaging is interruptable */
363 do {
364 kr = lockd_request(
365 lockd_port,
366 msg->lm_version,
367 msg->lm_flags,
368 msg->lm_xid,
369 msg->lm_fl.l_start,
370 msg->lm_fl.l_len,
371 msg->lm_fl.l_pid,
372 msg->lm_fl.l_type,
373 msg->lm_fl.l_whence,
374 (uint32_t *)&msg->lm_addr,
375 (uint32_t *)&msg->lm_cred,
376 msg->lm_fh_len,
377 msg->lm_fh);
378 if (kr != KERN_SUCCESS)
379 printf("lockd_request received %d!\n", kr);
380 } while (!interruptable && kr == MACH_SEND_INTERRUPTED);
381 } while (kr == MIG_SERVER_DIED && retries++ < MACH_MAX_TRIES);
382
383 ipc_port_release_send(lockd_port);
384 switch (kr) {
385 case MACH_SEND_INTERRUPTED:
386 return (EINTR);
387 default:
388 /*
389 * Other MACH or MIG errors we will retry. Eventually
390 * we will call nfs_down and allow the user to disable
391 * locking.
392 */
393 return (EAGAIN);
394 }
395 return (kr);
396 }
397
398
399 /*
400 * NFS advisory byte-level locks (client)
401 */
402 int
403 nfs3_lockd_request(
404 nfsnode_t np,
405 int type,
406 LOCKD_MSG_REQUEST *msgreq,
407 int flags,
408 thread_t thd)
409 {
410 LOCKD_MSG *msg = &msgreq->lmr_msg;
411 int error, error2;
412 int interruptable, slpflag;
413 struct nfsmount *nmp;
414 struct timeval now;
415 int timeo, starttime, endtime, lastmsg, wentdown = 0;
416 struct timespec ts;
417 struct sockaddr *saddr;
418
419 nmp = NFSTONMP(np);
420 if (!nmp || !nmp->nm_saddr)
421 return (ENXIO);
422
423 lck_mtx_lock(&nmp->nm_lock);
424 saddr = nmp->nm_saddr;
425 bcopy(saddr, &msg->lm_addr, min(sizeof msg->lm_addr, saddr->sa_len));
426 if (nmp->nm_vers == NFS_VER3)
427 msg->lm_flags |= LOCKD_MSG_NFSV3;
428 #if 0 /* not yet */
429 if (nmp->nm_sotype != SOCK_DGRAM)
430 msg->lm_flags |= LOCKD_MSG_TCP;
431 #endif
432
433 microuptime(&now);
434 starttime = now.tv_sec;
435 lastmsg = now.tv_sec - ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay));
436 interruptable = NMFLAG(nmp, INTR);
437 lck_mtx_unlock(&nmp->nm_lock);
438
439 lck_mtx_lock(nfs_lock_mutex);
440
441 /* allocate unique xid */
442 msg->lm_xid = nfs_lockxid_get();
443 nfs_lockdmsg_enqueue(msgreq);
444
445 timeo = 4;
446
447 for (;;) {
448 nfs_lockd_request_sent = 1;
449
450 /* need to drop nfs_lock_mutex while calling nfs_lockd_send_request() */
451 lck_mtx_unlock(nfs_lock_mutex);
452 error = nfs_lockd_send_request(msg, interruptable);
453 lck_mtx_lock(nfs_lock_mutex);
454 if (error && error != EAGAIN)
455 break;
456
457 /*
458 * Always wait for an answer. Not waiting for unlocks could
459 * cause a lock to be left if the unlock request gets dropped.
460 */
461
462 /*
463 * Retry if it takes too long to get a response.
464 *
465 * The timeout numbers were picked out of thin air... they start
466 * at 4 and double each timeout with a max of 30 seconds.
467 *
468 * In order to maintain responsiveness, we pass a small timeout
469 * to msleep and calculate the timeouts ourselves. This allows
470 * us to pick up on mount changes quicker.
471 */
472 wait_for_granted:
473 error = EWOULDBLOCK;
474 slpflag = (interruptable && (type != F_UNLCK)) ? PCATCH : 0;
475 ts.tv_sec = 2;
476 ts.tv_nsec = 0;
477 microuptime(&now);
478 endtime = now.tv_sec + timeo;
479 while (now.tv_sec < endtime) {
480 error = error2 = 0;
481 if (!msgreq->lmr_answered) {
482 error = msleep(msgreq, nfs_lock_mutex, slpflag | PUSER, "lockd", &ts);
483 slpflag = 0;
484 }
485 if (msgreq->lmr_answered) {
486 /*
487 * Note: it's possible to have a lock granted at
488 * essentially the same time that we get interrupted.
489 * Since the lock may be granted, we can't return an
490 * error from this request or we might not unlock the
491 * lock that's been granted.
492 */
493 nmp = NFSTONMP(np);
494 if ((msgreq->lmr_errno == ENOTSUP) && nmp &&
495 (nmp->nm_state & NFSSTA_LOCKSWORK)) {
496 /*
497 * We have evidence that locks work, yet lockd
498 * returned ENOTSUP. This is probably because
499 * it was unable to contact the server's lockd
500 * to send it the request.
501 *
502 * Because we know locks work, we'll consider
503 * this failure to be a timeout.
504 */
505 error = EWOULDBLOCK;
506 } else {
507 error = 0;
508 }
509 break;
510 }
511 if (error != EWOULDBLOCK)
512 break;
513 /* check that we still have our mount... */
514 /* ...and that we still support locks */
515 /* ...and that there isn't a recovery pending */
516 nmp = NFSTONMP(np);
517 if ((error2 = nfs_sigintr(nmp, NULL, NULL, 0))) {
518 error = error2;
519 if (type == F_UNLCK)
520 printf("nfs3_lockd_request: aborting unlock request, error %d\n", error);
521 break;
522 }
523 lck_mtx_lock(&nmp->nm_lock);
524 if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) {
525 lck_mtx_unlock(&nmp->nm_lock);
526 break;
527 }
528 if ((nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) {
529 /* recovery pending... return an error that'll get this operation restarted */
530 error = NFSERR_GRACE;
531 lck_mtx_unlock(&nmp->nm_lock);
532 break;
533 }
534 interruptable = NMFLAG(nmp, INTR);
535 lck_mtx_unlock(&nmp->nm_lock);
536 microuptime(&now);
537 }
538 if (error) {
539 /* check that we still have our mount... */
540 nmp = NFSTONMP(np);
541 if ((error2 = nfs_sigintr(nmp, NULL, NULL, 0))) {
542 error = error2;
543 if (error2 != EINTR) {
544 if (type == F_UNLCK)
545 printf("nfs3_lockd_request: aborting unlock request, error %d\n", error);
546 break;
547 }
548 }
549 /* ...and that we still support locks */
550 lck_mtx_lock(&nmp->nm_lock);
551 if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) {
552 if (error == EWOULDBLOCK)
553 error = ENOTSUP;
554 lck_mtx_unlock(&nmp->nm_lock);
555 break;
556 }
557 /* ...and that there isn't a recovery pending */
558 if ((error == EWOULDBLOCK) && (nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) {
559 /* recovery pending... return to allow recovery to occur */
560 error = NFSERR_DENIED;
561 lck_mtx_unlock(&nmp->nm_lock);
562 break;
563 }
564 interruptable = NMFLAG(nmp, INTR);
565 if ((error != EWOULDBLOCK) ||
566 ((nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) ||
567 ((flags & R_RECOVER) && ((now.tv_sec - starttime) > 30))) {
568 if ((error == EWOULDBLOCK) && (flags & R_RECOVER)) {
569 /* give up if this is for recovery and taking too long */
570 error = ETIMEDOUT;
571 } else if ((nmp->nm_state & NFSSTA_RECOVER) && !(flags & R_RECOVER)) {
572 /* recovery pending... return an error that'll get this operation restarted */
573 error = NFSERR_GRACE;
574 }
575 lck_mtx_unlock(&nmp->nm_lock);
576 /*
577 * We're going to bail on this request.
578 * If we were a blocked lock request, send a cancel.
579 */
580 if ((msgreq->lmr_errno == EINPROGRESS) &&
581 !(msg->lm_flags & LOCKD_MSG_CANCEL)) {
582 /* set this request up as a cancel */
583 msg->lm_flags |= LOCKD_MSG_CANCEL;
584 nfs_lockdmsg_dequeue(msgreq);
585 msg->lm_xid = nfs_lockxid_get();
586 nfs_lockdmsg_enqueue(msgreq);
587 msgreq->lmr_saved_errno = error;
588 msgreq->lmr_errno = 0;
589 msgreq->lmr_answered = 0;
590 /* reset timeout */
591 timeo = 2;
592 /* send cancel request */
593 continue;
594 }
595 break;
596 }
597
598 /* warn if we're not getting any response */
599 microuptime(&now);
600 if ((msgreq->lmr_errno != EINPROGRESS) &&
601 !(msg->lm_flags & LOCKD_MSG_DENIED_GRACE) &&
602 (nmp->nm_tprintf_initial_delay != 0) &&
603 ((lastmsg + nmp->nm_tprintf_delay) < now.tv_sec)) {
604 lck_mtx_unlock(&nmp->nm_lock);
605 lastmsg = now.tv_sec;
606 nfs_down(nmp, thd, 0, NFSSTA_LOCKTIMEO, "lockd not responding");
607 wentdown = 1;
608 } else
609 lck_mtx_unlock(&nmp->nm_lock);
610
611 if (msgreq->lmr_errno == EINPROGRESS) {
612 /*
613 * We've got a blocked lock request that we are
614 * going to retry. First, we'll want to try to
615 * send a cancel for the previous request.
616 *
617 * Clear errno so if we don't get a response
618 * to the resend we'll call nfs_down().
619 * Also reset timeout because we'll expect a
620 * quick response to the cancel/resend (even if
621 * it is NLM_BLOCKED).
622 */
623 msg->lm_flags |= LOCKD_MSG_CANCEL;
624 nfs_lockdmsg_dequeue(msgreq);
625 msg->lm_xid = nfs_lockxid_get();
626 nfs_lockdmsg_enqueue(msgreq);
627 msgreq->lmr_saved_errno = msgreq->lmr_errno;
628 msgreq->lmr_errno = 0;
629 msgreq->lmr_answered = 0;
630 timeo = 2;
631 /* send cancel then resend request */
632 continue;
633 }
634
635 /*
636 * We timed out, so we will resend the request.
637 */
638 if (!(flags & R_RECOVER))
639 timeo *= 2;
640 if (timeo > 30)
641 timeo = 30;
642 /* resend request */
643 continue;
644 }
645
646 /* we got a reponse, so the server's lockd is OK */
647 nfs_up(NFSTONMP(np), thd, NFSSTA_LOCKTIMEO,
648 wentdown ? "lockd alive again" : NULL);
649 wentdown = 0;
650
651 if (msgreq->lmr_answered && (msg->lm_flags & LOCKD_MSG_DENIED_GRACE)) {
652 /*
653 * The lock request was denied because the server lockd is
654 * still in its grace period. So, we need to try the
655 * request again in a little bit. Return the GRACE error so
656 * the higher levels can perform the retry.
657 */
658 msgreq->lmr_saved_errno = msgreq->lmr_errno = error = NFSERR_GRACE;
659 }
660
661 if (msgreq->lmr_errno == EINPROGRESS) {
662 /* got NLM_BLOCKED response */
663 /* need to wait for NLM_GRANTED */
664 timeo = 30;
665 msgreq->lmr_answered = 0;
666 goto wait_for_granted;
667 }
668
669 if ((msg->lm_flags & LOCKD_MSG_CANCEL) &&
670 (msgreq->lmr_saved_errno == EINPROGRESS)) {
671 /*
672 * We just got a successful reply to the
673 * cancel of the previous blocked lock request.
674 * Now, go ahead and return a DENIED error so the
675 * higher levels can resend the request.
676 */
677 msg->lm_flags &= ~LOCKD_MSG_CANCEL;
678 nfs_lockdmsg_dequeue(msgreq);
679 error = NFSERR_DENIED;
680 break;
681 }
682
683 /*
684 * If the blocked lock request was cancelled.
685 * Restore the error condition from when we
686 * originally bailed on the request.
687 */
688 if (msg->lm_flags & LOCKD_MSG_CANCEL) {
689 msg->lm_flags &= ~LOCKD_MSG_CANCEL;
690 error = msgreq->lmr_saved_errno;
691 } else {
692 error = msgreq->lmr_errno;
693 }
694
695 nmp = NFSTONMP(np);
696 if ((error == ENOTSUP) && nmp && !(nmp->nm_state & NFSSTA_LOCKSWORK)) {
697 /*
698 * We have NO evidence that locks work and lockd
699 * returned ENOTSUP. Let's take this as a hint
700 * that locks aren't supported and disable them
701 * for this mount.
702 */
703 nfs_lockdmsg_dequeue(msgreq);
704 lck_mtx_unlock(nfs_lock_mutex);
705 lck_mtx_lock(&nmp->nm_lock);
706 if (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED) {
707 nmp->nm_lockmode = NFS_LOCK_MODE_DISABLED;
708 nfs_lockd_mount_unregister(nmp);
709 }
710 nmp->nm_state &= ~NFSSTA_LOCKTIMEO;
711 lck_mtx_unlock(&nmp->nm_lock);
712 printf("lockd returned ENOTSUP, disabling locks for nfs server: %s\n",
713 vfs_statfs(nmp->nm_mountp)->f_mntfromname);
714 return (error);
715 }
716 if (!error) {
717 /* record that NFS file locking has worked on this mount */
718 if (nmp) {
719 lck_mtx_lock(&nmp->nm_lock);
720 if (!(nmp->nm_state & NFSSTA_LOCKSWORK))
721 nmp->nm_state |= NFSSTA_LOCKSWORK;
722 lck_mtx_unlock(&nmp->nm_lock);
723 }
724 }
725 break;
726 }
727
728 nfs_lockdmsg_dequeue(msgreq);
729
730 lck_mtx_unlock(nfs_lock_mutex);
731
732 return (error);
733 }
734
735 /*
736 * Send an NLM LOCK message to the server
737 */
738 int
739 nfs3_setlock_rpc(
740 nfsnode_t np,
741 struct nfs_open_file *nofp,
742 struct nfs_file_lock *nflp,
743 int reclaim,
744 int flags,
745 thread_t thd,
746 kauth_cred_t cred)
747 {
748 struct nfs_lock_owner *nlop = nflp->nfl_owner;
749 struct nfsmount *nmp;
750 int error;
751 LOCKD_MSG_REQUEST msgreq;
752 LOCKD_MSG *msg;
753
754 nmp = NFSTONMP(np);
755 if (!nmp)
756 return (ENXIO);
757
758 if (!nlop->nlo_open_owner) {
759 nfs_open_owner_ref(nofp->nof_owner);
760 nlop->nlo_open_owner = nofp->nof_owner;
761 }
762 if ((error = nfs_lock_owner_set_busy(nlop, thd)))
763 return (error);
764
765 /* set up lock message request structure */
766 bzero(&msgreq, sizeof(msgreq));
767 msg = &msgreq.lmr_msg;
768 msg->lm_version = LOCKD_MSG_VERSION;
769 if ((nflp->nfl_flags & NFS_FILE_LOCK_WAIT) && !reclaim)
770 msg->lm_flags |= LOCKD_MSG_BLOCK;
771 if (reclaim)
772 msg->lm_flags |= LOCKD_MSG_RECLAIM;
773 msg->lm_fh_len = (nmp->nm_vers == NFS_VER2) ? NFSX_V2FH : np->n_fhsize;
774 bcopy(np->n_fhp, msg->lm_fh, msg->lm_fh_len);
775 cru2x(cred, &msg->lm_cred);
776
777 msg->lm_fl.l_whence = SEEK_SET;
778 msg->lm_fl.l_start = nflp->nfl_start;
779 msg->lm_fl.l_len = NFS_FLOCK_LENGTH(nflp->nfl_start, nflp->nfl_end);
780 msg->lm_fl.l_type = nflp->nfl_type;
781 msg->lm_fl.l_pid = nlop->nlo_pid;
782
783 error = nfs3_lockd_request(np, 0, &msgreq, flags, thd);
784
785 nfs_lock_owner_clear_busy(nlop);
786 return (error);
787 }
788
789 /*
790 * Send an NLM UNLOCK message to the server
791 */
792 int
793 nfs3_unlock_rpc(
794 nfsnode_t np,
795 struct nfs_lock_owner *nlop,
796 __unused int type,
797 uint64_t start,
798 uint64_t end,
799 int flags,
800 thread_t thd,
801 kauth_cred_t cred)
802 {
803 struct nfsmount *nmp;
804 LOCKD_MSG_REQUEST msgreq;
805 LOCKD_MSG *msg;
806
807 nmp = NFSTONMP(np);
808 if (!nmp)
809 return (ENXIO);
810
811 /* set up lock message request structure */
812 bzero(&msgreq, sizeof(msgreq));
813 msg = &msgreq.lmr_msg;
814 msg->lm_version = LOCKD_MSG_VERSION;
815 msg->lm_fh_len = (nmp->nm_vers == NFS_VER2) ? NFSX_V2FH : np->n_fhsize;
816 bcopy(np->n_fhp, msg->lm_fh, msg->lm_fh_len);
817 cru2x(cred, &msg->lm_cred);
818
819 msg->lm_fl.l_whence = SEEK_SET;
820 msg->lm_fl.l_start = start;
821 msg->lm_fl.l_len = NFS_FLOCK_LENGTH(start, end);
822 msg->lm_fl.l_type = F_UNLCK;
823 msg->lm_fl.l_pid = nlop->nlo_pid;
824
825 return (nfs3_lockd_request(np, F_UNLCK, &msgreq, flags, thd));
826 }
827
828 /*
829 * Send an NLM LOCK TEST message to the server
830 */
831 int
832 nfs3_getlock_rpc(
833 nfsnode_t np,
834 struct nfs_lock_owner *nlop,
835 struct flock *fl,
836 uint64_t start,
837 uint64_t end,
838 vfs_context_t ctx)
839 {
840 struct nfsmount *nmp;
841 int error;
842 LOCKD_MSG_REQUEST msgreq;
843 LOCKD_MSG *msg;
844
845 nmp = NFSTONMP(np);
846 if (!nmp)
847 return (ENXIO);
848
849 /* set up lock message request structure */
850 bzero(&msgreq, sizeof(msgreq));
851 msg = &msgreq.lmr_msg;
852 msg->lm_version = LOCKD_MSG_VERSION;
853 msg->lm_flags |= LOCKD_MSG_TEST;
854 msg->lm_fh_len = (nmp->nm_vers == NFS_VER2) ? NFSX_V2FH : np->n_fhsize;
855 bcopy(np->n_fhp, msg->lm_fh, msg->lm_fh_len);
856 cru2x(vfs_context_ucred(ctx), &msg->lm_cred);
857
858 msg->lm_fl.l_whence = SEEK_SET;
859 msg->lm_fl.l_start = start;
860 msg->lm_fl.l_len = NFS_FLOCK_LENGTH(start, end);
861 msg->lm_fl.l_type = fl->l_type;
862 msg->lm_fl.l_pid = nlop->nlo_pid;
863
864 error = nfs3_lockd_request(np, 0, &msgreq, 0, vfs_context_thread(ctx));
865
866 if (!error && (msg->lm_flags & LOCKD_MSG_TEST) && !msgreq.lmr_errno) {
867 if (msg->lm_fl.l_type != F_UNLCK) {
868 fl->l_type = msg->lm_fl.l_type;
869 fl->l_pid = msg->lm_fl.l_pid;
870 fl->l_start = msg->lm_fl.l_start;
871 fl->l_len = msg->lm_fl.l_len;
872 fl->l_whence = SEEK_SET;
873 } else
874 fl->l_type = F_UNLCK;
875 }
876
877 return (error);
878 }
879
880 /*
881 * nfslockdans --
882 * NFS advisory byte-level locks answer from the lock daemon.
883 */
884 int
885 nfslockdans(proc_t p, struct lockd_ans *ansp)
886 {
887 LOCKD_MSG_REQUEST *msgreq;
888 int error;
889
890 /* Let root make this call. */
891 error = proc_suser(p);
892 if (error)
893 return (error);
894
895 /* the version should match, or we're out of sync */
896 if (ansp->la_version != LOCKD_ANS_VERSION)
897 return (EINVAL);
898
899 lck_mtx_lock(nfs_lock_mutex);
900
901 /* try to find the lockd message by transaction id (cookie) */
902 msgreq = nfs_lockdmsg_find_by_xid(ansp->la_xid);
903 if (ansp->la_flags & LOCKD_ANS_GRANTED) {
904 /*
905 * We can't depend on the granted message having our cookie,
906 * so we check the answer against the lockd message found.
907 * If no message was found or it doesn't match the answer,
908 * we look for the lockd message by the answer's lock info.
909 */
910 if (!msgreq || nfs_lockdmsg_compare_to_answer(msgreq, ansp))
911 msgreq = nfs_lockdmsg_find_by_answer(ansp);
912 /*
913 * We need to make sure this request isn't being cancelled
914 * If it is, we don't want to accept the granted message.
915 */
916 if (msgreq && (msgreq->lmr_msg.lm_flags & LOCKD_MSG_CANCEL))
917 msgreq = NULL;
918 }
919 if (!msgreq) {
920 lck_mtx_unlock(nfs_lock_mutex);
921 return (EPIPE);
922 }
923
924 msgreq->lmr_errno = ansp->la_errno;
925 if ((msgreq->lmr_msg.lm_flags & LOCKD_MSG_TEST) && msgreq->lmr_errno == 0) {
926 if (ansp->la_flags & LOCKD_ANS_LOCK_INFO) {
927 if (ansp->la_flags & LOCKD_ANS_LOCK_EXCL)
928 msgreq->lmr_msg.lm_fl.l_type = F_WRLCK;
929 else
930 msgreq->lmr_msg.lm_fl.l_type = F_RDLCK;
931 msgreq->lmr_msg.lm_fl.l_pid = ansp->la_pid;
932 msgreq->lmr_msg.lm_fl.l_start = ansp->la_start;
933 msgreq->lmr_msg.lm_fl.l_len = ansp->la_len;
934 } else {
935 msgreq->lmr_msg.lm_fl.l_type = F_UNLCK;
936 }
937 }
938 if (ansp->la_flags & LOCKD_ANS_DENIED_GRACE)
939 msgreq->lmr_msg.lm_flags |= LOCKD_MSG_DENIED_GRACE;
940
941 msgreq->lmr_answered = 1;
942 lck_mtx_unlock(nfs_lock_mutex);
943 wakeup(msgreq);
944
945 return (0);
946 }
947
948 /*
949 * nfslockdnotify --
950 * NFS host restart notification from the lock daemon.
951 *
952 * Used to initiate reclaiming of held locks when a server we
953 * have mounted reboots.
954 */
955 int
956 nfslockdnotify(proc_t p, user_addr_t argp)
957 {
958 int error, i, headsize;
959 struct lockd_notify ln;
960 struct nfsmount *nmp;
961 struct sockaddr *saddr;
962
963 /* Let root make this call. */
964 error = proc_suser(p);
965 if (error)
966 return (error);
967
968 headsize = (char*)&ln.ln_addr[0] - (char*)&ln.ln_version;
969 error = copyin(argp, &ln, headsize);
970 if (error)
971 return (error);
972 if (ln.ln_version != LOCKD_NOTIFY_VERSION)
973 return (EINVAL);
974 if ((ln.ln_addrcount < 1) || (ln.ln_addrcount > 128))
975 return (EINVAL);
976 argp += headsize;
977 saddr = (struct sockaddr *)&ln.ln_addr[0];
978
979 lck_mtx_lock(nfs_lock_mutex);
980
981 for (i=0; i < ln.ln_addrcount; i++) {
982 error = copyin(argp, &ln.ln_addr[0], sizeof(ln.ln_addr[0]));
983 if (error)
984 break;
985 argp += sizeof(ln.ln_addr[0]);
986 /* scan lockd mount list for match to this address */
987 TAILQ_FOREACH(nmp, &nfs_lockd_mount_list, nm_ldlink) {
988 /* check if address matches this mount's server address */
989 if (!nmp->nm_saddr || nfs_sockaddr_cmp(saddr, nmp->nm_saddr))
990 continue;
991 /* We have a match! Mark it as needing recovery. */
992 lck_mtx_lock(&nmp->nm_lock);
993 nfs_need_recover(nmp, 0);
994 lck_mtx_unlock(&nmp->nm_lock);
995 }
996 }
997
998 lck_mtx_unlock(nfs_lock_mutex);
999
1000 return (error);
1001 }
1002