]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_nqlease.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_nqlease.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26 /*
27 * Copyright (c) 1992, 1993
28 * The Regents of the University of California. All rights reserved.
29 *
30 * This code is derived from software contributed to Berkeley by
31 * Rick Macklem at The University of Guelph.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95
62 * FreeBSD-Id: nfs_nqlease.c,v 1.32 1997/11/07 08:53:23 phk Exp $
63 */
64
65
66 /*
67 * References:
68 * Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant
69 * Mechanism for Distributed File Cache Consistency",
70 * In Proc. of the Twelfth ACM Symposium on Operating Systems
71 * Principals, pg. 202-210, Litchfield Park, AZ, Dec. 1989.
72 * Michael N. Nelson, Brent B. Welch and John K. Ousterhout, "Caching
73 * in the Sprite Network File System", ACM TOCS 6(1),
74 * pages 134-154, February 1988.
75 * V. Srinivasan and Jeffrey C. Mogul, "Spritely NFS: Implementation and
76 * Performance of Cache-Consistency Protocols", Digital
77 * Equipment Corporation WRL Research Report 89/5, May 1989.
78 */
79 #include <sys/param.h>
80 #include <sys/vnode.h>
81 #include <sys/mount.h>
82 #include <sys/kernel.h>
83 #include <sys/proc.h>
84 #include <sys/systm.h>
85 #include <sys/malloc.h>
86 #include <sys/mbuf.h>
87 #include <sys/socket.h>
88 #include <sys/socketvar.h>
89 #include <sys/protosw.h>
90 #include <machine/spl.h>
91
92 #include <netinet/in.h>
93 #include <nfs/rpcv2.h>
94 #include <nfs/nfsproto.h>
95 #include <nfs/nfs.h>
96 #include <nfs/nfsm_subs.h>
97 #include <nfs/xdr_subs.h>
98 #include <nfs/nqnfs.h>
99 #include <nfs/nfsnode.h>
100 #include <nfs/nfsmount.h>
101
102 time_t nqnfsstarttime = (time_t)0;
103 int nqsrv_clockskew = NQ_CLOCKSKEW;
104 int nqsrv_writeslack = NQ_WRITESLACK;
105 int nqsrv_maxlease = NQ_MAXLEASE;
106 static int nqsrv_maxnumlease = NQ_MAXNUMLEASE;
107
108 struct vop_lease_args;
109
110 static int nqsrv_cmpnam __P((struct nfssvc_sock *, struct mbuf *,
111 struct nqhost *));
112 extern void nqnfs_lease_updatetime __P((int deltat));
113 static int nqnfs_vacated __P((struct vnode *vp, struct ucred *cred));
114 static void nqsrv_addhost __P((struct nqhost *lph, struct nfssvc_sock *slp,
115 struct mbuf *nam));
116 static void nqsrv_instimeq __P((struct nqlease *lp, u_long duration));
117 static void nqsrv_locklease __P((struct nqlease *lp));
118 static void nqsrv_send_eviction __P((struct vnode *vp, struct nqlease *lp,
119 struct nfssvc_sock *slp,
120 struct mbuf *nam, struct ucred *cred));
121 static void nqsrv_unlocklease __P((struct nqlease *lp));
122 static void nqsrv_waitfor_expiry __P((struct nqlease *lp));
123
124 /*
125 * Signifies which rpcs can have piggybacked lease requests
126 */
127 int nqnfs_piggy[NFS_NPROCS] = {
128 0,
129 0,
130 ND_WRITE,
131 ND_READ,
132 0,
133 ND_READ,
134 ND_READ,
135 ND_WRITE,
136 0,
137 0,
138 0,
139 0,
140 0,
141 0,
142 0,
143 0,
144 ND_READ,
145 ND_READ,
146 0,
147 0,
148 0,
149 0,
150 0,
151 0,
152 0,
153 0,
154 };
155
156 extern nfstype nfsv2_type[9];
157 extern nfstype nfsv3_type[9];
158 extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
159 extern int nfsd_waiting;
160 extern struct nfsstats nfsstats;
161 extern int nfs_mount_type;
162
163 #define TRUE 1
164 #define FALSE 0
165
166 #ifndef NFS_NOSERVER
167 /*
168 * Get or check for a lease for "vp", based on ND_CHECK flag.
169 * The rules are as follows:
170 * - if a current non-caching lease, reply non-caching
171 * - if a current lease for same host only, extend lease
172 * - if a read cachable lease and a read lease request
173 * add host to list any reply cachable
174 * - else { set non-cachable for read-write sharing }
175 * send eviction notice messages to all other hosts that have lease
176 * wait for lease termination { either by receiving vacated messages
177 * from all the other hosts or expiry
178 * via. timeout }
179 * modify lease to non-cachable
180 * - else if no current lease, issue new one
181 * - reply
182 * - return boolean TRUE iff nam should be m_freem()'d
183 * NB: Since nqnfs_serverd() is called from a timer, any potential tsleep()
184 * in here must be framed by nqsrv_locklease() and nqsrv_unlocklease().
185 * nqsrv_locklease() is coded such that at least one of LC_LOCKED and
186 * LC_WANTED is set whenever a process is tsleeping in it. The exception
187 * is when a new lease is being allocated, since it is not in the timer
188 * queue yet. (Ditto for the splsoftclock() and splx(s) calls)
189 */
190 int
191 nqsrv_getlease(vp, duration, flags, slp, procp, nam, cachablep, frev, cred)
192 struct vnode *vp;
193 u_long *duration;
194 int flags;
195 struct nfssvc_sock *slp;
196 struct proc *procp;
197 struct mbuf *nam;
198 int *cachablep;
199 u_quad_t *frev;
200 struct ucred *cred;
201 {
202 register struct nqlease *lp;
203 register struct nqfhhashhead *lpp = 0;
204 register struct nqhost *lph = 0;
205 struct nqlease *tlp;
206 struct nqm **lphp;
207 struct vattr vattr;
208 fhandle_t fh;
209 int i, ok, error, s;
210
211 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
212 return (0);
213 if (*duration > nqsrv_maxlease)
214 *duration = nqsrv_maxlease;
215 error = VOP_GETATTR(vp, &vattr, cred, procp);
216 if (error)
217 return (error);
218 *frev = vattr.va_filerev;
219 s = splsoftclock();
220 tlp = vp->v_lease;
221 if ((flags & ND_CHECK) == 0)
222 nfsstats.srvnqnfs_getleases++;
223 if (tlp == (struct nqlease *)0) {
224
225 /*
226 * Find the lease by searching the hash list.
227 */
228 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
229 error = VFS_VPTOFH(vp, &fh.fh_fid);
230 if (error) {
231 splx(s);
232 return (error);
233 }
234 lpp = NQFHHASH(fh.fh_fid.fid_data);
235 for (lp = lpp->lh_first; lp != 0; lp = lp->lc_hash.le_next)
236 if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] &&
237 fh.fh_fsid.val[1] == lp->lc_fsid.val[1] &&
238 !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata,
239 fh.fh_fid.fid_len - sizeof (long))) {
240 /* Found it */
241 lp->lc_vp = vp;
242 vp->v_lease = lp;
243 tlp = lp;
244 break;
245 }
246 } else
247 lp = tlp;
248 if (lp) {
249 if ((lp->lc_flag & LC_NONCACHABLE) ||
250 (lp->lc_morehosts == (struct nqm *)0 &&
251 nqsrv_cmpnam(slp, nam, &lp->lc_host)))
252 goto doreply;
253 if ((flags & ND_READ) && (lp->lc_flag & LC_WRITE) == 0) {
254 if (flags & ND_CHECK)
255 goto doreply;
256 if (nqsrv_cmpnam(slp, nam, &lp->lc_host))
257 goto doreply;
258 i = 0;
259 if (lp->lc_morehosts) {
260 lph = lp->lc_morehosts->lpm_hosts;
261 lphp = &lp->lc_morehosts->lpm_next;
262 ok = 1;
263 } else {
264 lphp = &lp->lc_morehosts;
265 ok = 0;
266 }
267 while (ok && (lph->lph_flag & LC_VALID)) {
268 if (nqsrv_cmpnam(slp, nam, lph))
269 goto doreply;
270 if (++i == LC_MOREHOSTSIZ) {
271 i = 0;
272 if (*lphp) {
273 lph = (*lphp)->lpm_hosts;
274 lphp = &((*lphp)->lpm_next);
275 } else
276 ok = 0;
277 } else
278 lph++;
279 }
280 nqsrv_locklease(lp);
281 if (!ok) {
282 MALLOC_ZONE(*lphp, struct nqm *,
283 sizeof(struct nqm),
284 M_NQMHOST, M_WAITOK);
285 bzero((caddr_t)*lphp, sizeof (struct nqm));
286 lph = (*lphp)->lpm_hosts;
287 }
288 nqsrv_addhost(lph, slp, nam);
289 nqsrv_unlocklease(lp);
290 } else {
291 lp->lc_flag |= LC_NONCACHABLE;
292 nqsrv_locklease(lp);
293 nqsrv_send_eviction(vp, lp, slp, nam, cred);
294 nqsrv_waitfor_expiry(lp);
295 nqsrv_unlocklease(lp);
296 }
297 doreply:
298 /*
299 * Update the lease and return
300 */
301 if ((flags & ND_CHECK) == 0)
302 nqsrv_instimeq(lp, *duration);
303 if (lp->lc_flag & LC_NONCACHABLE)
304 *cachablep = 0;
305 else {
306 *cachablep = 1;
307 if (flags & ND_WRITE)
308 lp->lc_flag |= LC_WRITTEN;
309 }
310 splx(s);
311 return (0);
312 }
313 splx(s);
314 if (flags & ND_CHECK)
315 return (0);
316
317 /*
318 * Allocate new lease
319 * The value of nqsrv_maxnumlease should be set generously, so that
320 * the following "printf" happens infrequently.
321 */
322 if (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease) {
323 printf("Nqnfs server, too many leases\n");
324 do {
325 (void) tsleep((caddr_t)&lbolt, PSOCK,
326 "nqsrvnuml", 0);
327 } while (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease);
328 }
329 MALLOC_ZONE(lp, struct nqlease *,
330 sizeof (struct nqlease), M_NQLEASE, M_WAITOK);
331 bzero((caddr_t)lp, sizeof (struct nqlease));
332 if (flags & ND_WRITE)
333 lp->lc_flag |= (LC_WRITE | LC_WRITTEN);
334 nqsrv_addhost(&lp->lc_host, slp, nam);
335 lp->lc_vp = vp;
336 lp->lc_fsid = fh.fh_fsid;
337 bcopy(fh.fh_fid.fid_data, lp->lc_fiddata,
338 fh.fh_fid.fid_len - sizeof (long));
339 if(!lpp)
340 panic("nfs_nqlease.c: Phoney lpp");
341 LIST_INSERT_HEAD(lpp, lp, lc_hash);
342 vp->v_lease = lp;
343 s = splsoftclock();
344 nqsrv_instimeq(lp, *duration);
345 splx(s);
346 *cachablep = 1;
347 if (++nfsstats.srvnqnfs_leases > nfsstats.srvnqnfs_maxleases)
348 nfsstats.srvnqnfs_maxleases = nfsstats.srvnqnfs_leases;
349 return (0);
350 }
351
352 /*
353 * Local lease check for server syscalls.
354 * Just set up args and let nqsrv_getlease() do the rest.
355 * nqnfs_vop_lease_check() is the VOP_LEASE() form of the same routine.
356 * Ifdef'd code in nfsnode.h renames these routines to whatever a particular
357 * OS needs.
358 */
359 void
360 nqnfs_lease_check(vp, p, cred, flag)
361 struct vnode *vp;
362 struct proc *p;
363 struct ucred *cred;
364 int flag;
365 {
366 u_long duration = 0;
367 int cache;
368 u_quad_t frev;
369
370 (void) nqsrv_getlease(vp, &duration, ND_CHECK | flag, NQLOCALSLP,
371 p, (struct mbuf *)0, &cache, &frev, cred);
372 }
373
374 int
375 nqnfs_vop_lease_check(ap)
376 struct vop_lease_args /* {
377 struct vnode *a_vp;
378 struct proc *a_p;
379 struct ucred *a_cred;
380 int a_flag;
381 } */ *ap;
382 {
383 u_long duration = 0;
384 int cache;
385 u_quad_t frev;
386
387 (void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag,
388 NQLOCALSLP, ap->a_p, (struct mbuf *)0, &cache, &frev, ap->a_cred);
389 return (0);
390 }
391
392 #endif /* NFS_NOSERVER */
393
394 /*
395 * Add a host to an nqhost structure for a lease.
396 */
397 static void
398 nqsrv_addhost(lph, slp, nam)
399 register struct nqhost *lph;
400 struct nfssvc_sock *slp;
401 struct mbuf *nam;
402 {
403 register struct sockaddr_in *saddr;
404
405 if (slp == NQLOCALSLP)
406 lph->lph_flag |= (LC_VALID | LC_LOCAL);
407 else if (slp == nfs_udpsock) {
408 saddr = mtod(nam, struct sockaddr_in *);
409 lph->lph_flag |= (LC_VALID | LC_UDP);
410 lph->lph_inetaddr = saddr->sin_addr.s_addr;
411 lph->lph_port = saddr->sin_port;
412 } else if (slp == nfs_cltpsock) {
413 lph->lph_nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
414 lph->lph_flag |= (LC_VALID | LC_CLTP);
415 } else {
416 lph->lph_flag |= (LC_VALID | LC_SREF);
417 lph->lph_slp = slp;
418 slp->ns_sref++;
419 }
420 }
421
422 /*
423 * Update the lease expiry time and position it in the timer queue correctly.
424 */
425 static void
426 nqsrv_instimeq(lp, duration)
427 register struct nqlease *lp;
428 u_long duration;
429 {
430 register struct nqlease *tlp;
431 time_t newexpiry;
432
433 newexpiry = time.tv_sec + duration + nqsrv_clockskew;
434 if (lp->lc_expiry == newexpiry)
435 return;
436 if (lp->lc_timer.cqe_next != 0) {
437 CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer);
438 }
439 lp->lc_expiry = newexpiry;
440
441 /*
442 * Find where in the queue it should be.
443 */
444 tlp = nqtimerhead.cqh_last;
445 while (tlp != (void *)&nqtimerhead && tlp->lc_expiry > newexpiry)
446 tlp = tlp->lc_timer.cqe_prev;
447 #ifdef HASNVRAM
448 if (tlp == nqtimerhead.cqh_last)
449 NQSTORENOVRAM(newexpiry);
450 #endif /* HASNVRAM */
451 if (tlp == (void *)&nqtimerhead) {
452 CIRCLEQ_INSERT_HEAD(&nqtimerhead, lp, lc_timer);
453 } else {
454 CIRCLEQ_INSERT_AFTER(&nqtimerhead, tlp, lp, lc_timer);
455 }
456 }
457
458 /*
459 * Compare the requesting host address with the lph entry in the lease.
460 * Return true iff it is the same.
461 * This is somewhat messy due to the union in the nqhost structure.
462 * The local host is indicated by the special value of NQLOCALSLP for slp.
463 */
464 static int
465 nqsrv_cmpnam(slp, nam, lph)
466 register struct nfssvc_sock *slp;
467 struct mbuf *nam;
468 register struct nqhost *lph;
469 {
470 register struct sockaddr_in *saddr;
471 struct mbuf *addr;
472 union nethostaddr lhaddr;
473 int ret;
474
475 if (slp == NQLOCALSLP) {
476 if (lph->lph_flag & LC_LOCAL)
477 return (1);
478 else
479 return (0);
480 }
481 if (slp == nfs_udpsock || slp == nfs_cltpsock)
482 addr = nam;
483 else
484 addr = slp->ns_nam;
485 if (lph->lph_flag & LC_UDP)
486 ret = netaddr_match(AF_INET, &lph->lph_haddr, addr);
487 else if (lph->lph_flag & LC_CLTP)
488 ret = netaddr_match(AF_ISO, &lph->lph_claddr, addr);
489 else {
490 if ((lph->lph_slp->ns_flag & SLP_VALID) == 0)
491 return (0);
492 saddr = mtod(lph->lph_slp->ns_nam, struct sockaddr_in *);
493 if (saddr->sin_family == AF_INET)
494 lhaddr.had_inetaddr = saddr->sin_addr.s_addr;
495 else
496 lhaddr.had_nam = lph->lph_slp->ns_nam;
497 ret = netaddr_match(saddr->sin_family, &lhaddr, addr);
498 }
499 return (ret);
500 }
501
502 /*
503 * Send out eviction notice messages to all other hosts for the lease.
504 */
505 static void
506 nqsrv_send_eviction(vp, lp, slp, nam, cred)
507 struct vnode *vp;
508 register struct nqlease *lp;
509 struct nfssvc_sock *slp;
510 struct mbuf *nam;
511 struct ucred *cred;
512 {
513 register struct nqhost *lph = &lp->lc_host;
514 register struct mbuf *m;
515 register int siz;
516 struct nqm *lphnext = lp->lc_morehosts;
517 struct mbuf *mreq, *mb, *mb2, *mheadend;
518 struct socket *so;
519 struct mbuf *nam2;
520 struct sockaddr_in *saddr;
521 nfsfh_t nfh;
522 fhandle_t *fhp;
523 caddr_t bpos, cp;
524 u_long xid, *tl;
525 int len = 1, ok = 1, i = 0;
526 int sotype, *solockp;
527
528 while (ok && (lph->lph_flag & LC_VALID)) {
529 if (nqsrv_cmpnam(slp, nam, lph))
530 lph->lph_flag |= LC_VACATED;
531 else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
532 if (lph->lph_flag & LC_UDP) {
533 MGET(nam2, M_WAIT, MT_SONAME);
534 saddr = mtod(nam2, struct sockaddr_in *);
535 nam2->m_len = saddr->sin_len =
536 sizeof (struct sockaddr_in);
537 saddr->sin_family = AF_INET;
538 saddr->sin_addr.s_addr = lph->lph_inetaddr;
539 saddr->sin_port = lph->lph_port;
540 so = nfs_udpsock->ns_so;
541 } else if (lph->lph_flag & LC_CLTP) {
542 nam2 = lph->lph_nam;
543 so = nfs_cltpsock->ns_so;
544 } else if (lph->lph_slp->ns_flag & SLP_VALID) {
545 nam2 = (struct mbuf *)0;
546 so = lph->lph_slp->ns_so;
547 } else
548 goto nextone;
549 sotype = so->so_type;
550 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
551 solockp = &lph->lph_slp->ns_solock;
552 else
553 solockp = (int *)0;
554 nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED,
555 NFSX_V3FH + NFSX_UNSIGNED);
556 fhp = &nfh.fh_generic;
557 bzero((caddr_t)fhp, sizeof(nfh));
558 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
559 VFS_VPTOFH(vp, &fhp->fh_fid);
560 nfsm_srvfhtom(fhp, 1);
561 m = mreq;
562 siz = 0;
563 while (m) {
564 siz += m->m_len;
565 m = m->m_next;
566 }
567 if (siz <= 0 || siz > NFS_MAXPACKET) {
568 printf("mbuf siz=%d\n",siz);
569 panic("Bad nfs svc reply");
570 }
571 m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS),
572 NQNFSPROC_EVICTED,
573 RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
574 0, (char *)NULL, mreq, siz, &mheadend, &xid);
575 /*
576 * For stream protocols, prepend a Sun RPC
577 * Record Mark.
578 */
579 if (sotype == SOCK_STREAM) {
580 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
581 *mtod(m, u_long *) = htonl(0x80000000 |
582 (m->m_pkthdr.len - NFSX_UNSIGNED));
583 }
584 if (((lph->lph_flag & (LC_UDP | LC_CLTP)) == 0 &&
585 (lph->lph_slp->ns_flag & SLP_VALID) == 0) ||
586 (solockp && (*solockp & NFSMNT_SNDLOCK)))
587 m_freem(m);
588 else {
589 if (solockp)
590 *solockp |= NFSMNT_SNDLOCK;
591 (void) nfs_send(so, nam2, m,
592 (struct nfsreq *)0);
593 if (solockp)
594 nfs_sndunlock(solockp);
595 }
596 if (lph->lph_flag & LC_UDP)
597 MFREE(nam2, m);
598 }
599 nextone:
600 if (++i == len) {
601 if (lphnext) {
602 i = 0;
603 len = LC_MOREHOSTSIZ;
604 lph = lphnext->lpm_hosts;
605 lphnext = lphnext->lpm_next;
606 } else
607 ok = 0;
608 } else
609 lph++;
610 }
611 }
612
613 /*
614 * Wait for the lease to expire.
615 * This will occur when all clients have sent "vacated" messages to
616 * this server OR when it expires do to timeout.
617 */
618 static void
619 nqsrv_waitfor_expiry(lp)
620 register struct nqlease *lp;
621 {
622 register struct nqhost *lph;
623 register int i;
624 struct nqm *lphnext;
625 int len, ok;
626
627 tryagain:
628 if (time.tv_sec > lp->lc_expiry)
629 return;
630 lph = &lp->lc_host;
631 lphnext = lp->lc_morehosts;
632 len = 1;
633 i = 0;
634 ok = 1;
635 while (ok && (lph->lph_flag & LC_VALID)) {
636 if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
637 lp->lc_flag |= LC_EXPIREDWANTED;
638 (void) tsleep((caddr_t)&lp->lc_flag, PSOCK,
639 "nqexp", 0);
640 goto tryagain;
641 }
642 if (++i == len) {
643 if (lphnext) {
644 i = 0;
645 len = LC_MOREHOSTSIZ;
646 lph = lphnext->lpm_hosts;
647 lphnext = lphnext->lpm_next;
648 } else
649 ok = 0;
650 } else
651 lph++;
652 }
653 }
654
655 #ifndef NFS_NOSERVER
656
657 /*
658 * Nqnfs server timer that maintains the server lease queue.
659 * Scan the lease queue for expired entries:
660 * - when one is found, wakeup anyone waiting for it
661 * else dequeue and free
662 */
663 void
664 nqnfs_serverd()
665 {
666 register struct nqlease *lp;
667 register struct nqhost *lph;
668 struct nqlease *nextlp;
669 struct nqm *lphnext, *olphnext;
670 struct mbuf *n;
671 int i, len, ok;
672
673 for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead;
674 lp = nextlp) {
675 if (lp->lc_expiry >= time.tv_sec)
676 break;
677 nextlp = lp->lc_timer.cqe_next;
678 if (lp->lc_flag & LC_EXPIREDWANTED) {
679 lp->lc_flag &= ~LC_EXPIREDWANTED;
680 wakeup((caddr_t)&lp->lc_flag);
681 } else if ((lp->lc_flag & (LC_LOCKED | LC_WANTED)) == 0) {
682 /*
683 * Make a best effort at keeping a write caching lease long
684 * enough by not deleting it until it has been explicitly
685 * vacated or there have been no writes in the previous
686 * write_slack seconds since expiry and the nfsds are not
687 * all busy. The assumption is that if the nfsds are not
688 * all busy now (no queue of nfs requests), then the client
689 * would have been able to do at least one write to the
690 * file during the last write_slack seconds if it was still
691 * trying to push writes to the server.
692 */
693 if ((lp->lc_flag & (LC_WRITE | LC_VACATED)) == LC_WRITE &&
694 ((lp->lc_flag & LC_WRITTEN) || nfsd_waiting == 0)) {
695 lp->lc_flag &= ~LC_WRITTEN;
696 nqsrv_instimeq(lp, nqsrv_writeslack);
697 } else {
698 CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer);
699 LIST_REMOVE(lp, lc_hash);
700 /*
701 * This soft reference may no longer be valid, but
702 * no harm done. The worst case is if the vnode was
703 * recycled and has another valid lease reference,
704 * which is dereferenced prematurely.
705 */
706 lp->lc_vp->v_lease = (struct nqlease *)0;
707 lph = &lp->lc_host;
708 lphnext = lp->lc_morehosts;
709 olphnext = (struct nqm *)0;
710 len = 1;
711 i = 0;
712 ok = 1;
713 while (ok && (lph->lph_flag & LC_VALID)) {
714 if (lph->lph_flag & LC_CLTP)
715 MFREE(lph->lph_nam, n);
716 if (lph->lph_flag & LC_SREF)
717 nfsrv_slpderef(lph->lph_slp);
718 if (++i == len) {
719 if (olphnext) {
720 _FREE_ZONE((caddr_t)olphnext,
721 sizeof (struct nqm),
722 M_NQMHOST);
723 olphnext = (struct nqm *)0;
724 }
725 if (lphnext) {
726 olphnext = lphnext;
727 i = 0;
728 len = LC_MOREHOSTSIZ;
729 lph = lphnext->lpm_hosts;
730 lphnext = lphnext->lpm_next;
731 } else
732 ok = 0;
733 } else
734 lph++;
735 }
736 FREE_ZONE((caddr_t)lp,
737 sizeof (struct nqlease), M_NQLEASE);
738 if (olphnext)
739 _FREE_ZONE((caddr_t)olphnext,
740 sizeof (struct nqm), M_NQMHOST);
741 nfsstats.srvnqnfs_leases--;
742 }
743 }
744 }
745 }
746
747 /*
748 * Called from nfssvc_nfsd() for a getlease rpc request.
749 * Do the from/to xdr translation and call nqsrv_getlease() to
750 * do the real work.
751 */
752 int
753 nqnfsrv_getlease(nfsd, slp, procp, mrq)
754 struct nfsrv_descript *nfsd;
755 struct nfssvc_sock *slp;
756 struct proc *procp;
757 struct mbuf **mrq;
758 {
759 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
760 struct mbuf *nam = nfsd->nd_nam;
761 caddr_t dpos = nfsd->nd_dpos;
762 struct ucred *cred = &nfsd->nd_cr;
763 register struct nfs_fattr *fp;
764 struct vattr va;
765 register struct vattr *vap = &va;
766 struct vnode *vp;
767 nfsfh_t nfh;
768 fhandle_t *fhp;
769 register u_long *tl;
770 register long t1;
771 u_quad_t frev;
772 caddr_t bpos;
773 int error = 0;
774 char *cp2;
775 struct mbuf *mb, *mb2, *mreq;
776 int flags, rdonly, cache;
777
778 fhp = &nfh.fh_generic;
779 nfsm_srvmtofh(fhp);
780 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
781 flags = fxdr_unsigned(int, *tl++);
782 nfsd->nd_duration = fxdr_unsigned(int, *tl);
783 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
784 (nfsd->nd_flag & ND_KERBAUTH), TRUE);
785 if (error)
786 nfsm_reply(0);
787 if (rdonly && flags == ND_WRITE) {
788 error = EROFS;
789 vput(vp);
790 nfsm_reply(0);
791 }
792 (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, procp,
793 nam, &cache, &frev, cred);
794 error = VOP_GETATTR(vp, vap, cred, procp);
795 vput(vp);
796 nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
797 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
798 *tl++ = txdr_unsigned(cache);
799 *tl++ = txdr_unsigned(nfsd->nd_duration);
800 txdr_hyper(&frev, tl);
801 nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR);
802 nfsm_srvfillattr(vap, fp);
803 nfsm_srvdone;
804 }
805
806 /*
807 * Called from nfssvc_nfsd() when a "vacated" message is received from a
808 * client. Find the entry and expire it.
809 */
810 int
811 nqnfsrv_vacated(nfsd, slp, procp, mrq)
812 struct nfsrv_descript *nfsd;
813 struct nfssvc_sock *slp;
814 struct proc *procp;
815 struct mbuf **mrq;
816 {
817 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
818 struct mbuf *nam = nfsd->nd_nam;
819 caddr_t dpos = nfsd->nd_dpos;
820 register struct nqlease *lp;
821 register struct nqhost *lph;
822 struct nqlease *tlp = (struct nqlease *)0;
823 nfsfh_t nfh;
824 fhandle_t *fhp;
825 register u_long *tl;
826 register long t1;
827 struct nqm *lphnext;
828 struct mbuf *mreq, *mb;
829 int error = 0, i, len, ok, gotit = 0, cache = 0;
830 char *cp2, *bpos;
831 u_quad_t frev;
832
833 fhp = &nfh.fh_generic;
834 nfsm_srvmtofh(fhp);
835 m_freem(mrep);
836 /*
837 * Find the lease by searching the hash list.
838 */
839 for (lp = NQFHHASH(fhp->fh_fid.fid_data)->lh_first; lp != 0;
840 lp = lp->lc_hash.le_next)
841 if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] &&
842 fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] &&
843 !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata,
844 MAXFIDSZ)) {
845 /* Found it */
846 tlp = lp;
847 break;
848 }
849 if (tlp) {
850 lp = tlp;
851 len = 1;
852 i = 0;
853 lph = &lp->lc_host;
854 lphnext = lp->lc_morehosts;
855 ok = 1;
856 while (ok && (lph->lph_flag & LC_VALID)) {
857 if (nqsrv_cmpnam(slp, nam, lph)) {
858 lph->lph_flag |= LC_VACATED;
859 gotit++;
860 break;
861 }
862 if (++i == len) {
863 if (lphnext) {
864 len = LC_MOREHOSTSIZ;
865 i = 0;
866 lph = lphnext->lpm_hosts;
867 lphnext = lphnext->lpm_next;
868 } else
869 ok = 0;
870 } else
871 lph++;
872 }
873 if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) {
874 lp->lc_flag &= ~LC_EXPIREDWANTED;
875 wakeup((caddr_t)&lp->lc_flag);
876 }
877 nfsmout:
878 return (EPERM);
879 }
880 return (EPERM);
881 }
882
883 #endif /* NFS_NOSERVER */
884
885 /*
886 * Client get lease rpc function.
887 */
888 int
889 nqnfs_getlease(vp, rwflag, cred, p)
890 register struct vnode *vp;
891 int rwflag;
892 struct ucred *cred;
893 struct proc *p;
894 {
895 register u_long *tl;
896 register caddr_t cp;
897 register long t1, t2;
898 register struct nfsnode *np;
899 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
900 caddr_t bpos, dpos, cp2;
901 time_t reqtime;
902 int error = 0;
903 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
904 int cachable;
905 u_quad_t frev;
906 u_int64_t xid;
907
908 nfsstats.rpccnt[NQNFSPROC_GETLEASE]++;
909 mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED,
910 &bpos);
911 nfsm_fhtom(vp, 1);
912 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
913 *tl++ = txdr_unsigned(rwflag);
914 *tl = txdr_unsigned(nmp->nm_leaseterm);
915 reqtime = time.tv_sec;
916 nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred, &xid);
917 np = VTONFS(vp);
918 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
919 cachable = fxdr_unsigned(int, *tl++);
920 reqtime += fxdr_unsigned(int, *tl++);
921 if (reqtime > time.tv_sec) {
922 fxdr_hyper(tl, &frev);
923 nqnfs_clientlease(nmp, np, rwflag, cachable, reqtime, frev);
924 nfsm_loadattr(vp, (struct vattr *)0, &xid);
925 } else
926 error = NQNFS_EXPIRED;
927 nfsm_reqdone;
928 return (error);
929 }
930
931 /*
932 * Client vacated message function.
933 */
934 static int
935 nqnfs_vacated(vp, cred)
936 register struct vnode *vp;
937 struct ucred *cred;
938 {
939 register caddr_t cp;
940 register struct mbuf *m;
941 register int i;
942 register u_long *tl;
943 register long t2;
944 caddr_t bpos;
945 u_long xid;
946 int error = 0;
947 struct mbuf *mreq, *mb, *mb2, *mheadend;
948 struct nfsmount *nmp;
949 struct nfsreq myrep;
950
951 nmp = VFSTONFS(vp->v_mount);
952 nfsstats.rpccnt[NQNFSPROC_VACATED]++;
953 nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH(1));
954 nfsm_fhtom(vp, 1);
955 m = mreq;
956 i = 0;
957 while (m) {
958 i += m->m_len;
959 m = m->m_next;
960 }
961 m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED,
962 RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
963 0, (char *)NULL, mreq, i, &mheadend, &xid);
964 if (nmp->nm_sotype == SOCK_STREAM) {
965 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
966 *mtod(m, u_long *) = htonl(0x80000000 | (m->m_pkthdr.len -
967 NFSX_UNSIGNED));
968 }
969 myrep.r_flags = 0;
970 myrep.r_nmp = nmp;
971 if (nmp->nm_soflags & PR_CONNREQUIRED)
972 (void) nfs_sndlock(&nmp->nm_flag, (struct nfsreq *)0);
973 (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep);
974 if (nmp->nm_soflags & PR_CONNREQUIRED)
975 nfs_sndunlock(&nmp->nm_flag);
976 nfsmout:
977 return (error);
978 }
979
980 #ifndef NFS_NOSERVER
981
982 /*
983 * Called for client side callbacks
984 */
985 int
986 nqnfs_callback(nmp, mrep, md, dpos)
987 struct nfsmount *nmp;
988 struct mbuf *mrep, *md;
989 caddr_t dpos;
990 {
991 register struct vnode *vp;
992 register u_long *tl;
993 register long t1;
994 nfsfh_t nfh;
995 fhandle_t *fhp;
996 struct nfsnode *np;
997 struct nfsd tnfsd;
998 struct nfssvc_sock *slp;
999 struct nfsrv_descript ndesc;
1000 register struct nfsrv_descript *nfsd = &ndesc;
1001 struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq;
1002 int error = 0, cache = 0;
1003 char *cp2, *bpos;
1004 u_quad_t frev;
1005
1006 #ifndef nolint
1007 slp = NULL;
1008 #endif
1009 nfsd->nd_mrep = mrep;
1010 nfsd->nd_md = md;
1011 nfsd->nd_dpos = dpos;
1012 error = nfs_getreq(nfsd, &tnfsd, FALSE);
1013 if (error)
1014 return (error);
1015 md = nfsd->nd_md;
1016 dpos = nfsd->nd_dpos;
1017 if (nfsd->nd_procnum != NQNFSPROC_EVICTED) {
1018 m_freem(mrep);
1019 return (EPERM);
1020 }
1021 fhp = &nfh.fh_generic;
1022 nfsm_srvmtofh(fhp);
1023 m_freem(mrep);
1024 error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np);
1025 if (error)
1026 return (error);
1027 vp = NFSTOV(np);
1028 if (np->n_timer.cqe_next != 0) {
1029 np->n_expiry = 0;
1030 np->n_flag |= NQNFSEVICTED;
1031 if (nmp->nm_timerhead.cqh_first != np) {
1032 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
1033 CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
1034 }
1035 }
1036 vput(vp);
1037 nfsm_srvdone;
1038 }
1039
1040
1041 /*
1042 * Nqnfs client helper daemon. Runs once a second to expire leases.
1043 * It also get authorization strings for "kerb" mounts.
1044 * It must start at the beginning of the list again after any potential
1045 * "sleep" since nfs_reclaim() called from vclean() can pull a node off
1046 * the list asynchronously.
1047 */
1048 int
1049 nqnfs_clientd(nmp, cred, ncd, flag, argp, p)
1050 register struct nfsmount *nmp;
1051 struct ucred *cred;
1052 struct nfsd_cargs *ncd;
1053 int flag;
1054 caddr_t argp;
1055 struct proc *p;
1056 {
1057 register struct nfsnode *np;
1058 struct vnode *vp;
1059 struct nfsreq myrep;
1060 struct nfsuid *nuidp, *nnuidp;
1061 int error = 0, vpid;
1062 register struct nfsreq *rp;
1063
1064 /*
1065 * First initialize some variables
1066 */
1067
1068 /*
1069 * If an authorization string is being passed in, get it.
1070 */
1071 if ((flag & NFSSVC_GOTAUTH) &&
1072 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) {
1073 if (nmp->nm_flag & NFSMNT_HASAUTH)
1074 panic("cld kerb");
1075 if ((flag & NFSSVC_AUTHINFAIL) == 0) {
1076 if (ncd->ncd_authlen <= nmp->nm_authlen &&
1077 ncd->ncd_verflen <= nmp->nm_verflen &&
1078 !copyin(ncd->ncd_authstr,nmp->nm_authstr,ncd->ncd_authlen)&&
1079 !copyin(ncd->ncd_verfstr,nmp->nm_verfstr,ncd->ncd_verflen)){
1080 nmp->nm_authtype = ncd->ncd_authtype;
1081 nmp->nm_authlen = ncd->ncd_authlen;
1082 nmp->nm_verflen = ncd->ncd_verflen;
1083 #if NFSKERB
1084 nmp->nm_key = ncd->ncd_key;
1085 #endif
1086 } else
1087 nmp->nm_flag |= NFSMNT_AUTHERR;
1088 } else
1089 nmp->nm_flag |= NFSMNT_AUTHERR;
1090 nmp->nm_flag |= NFSMNT_HASAUTH;
1091 wakeup((caddr_t)&nmp->nm_authlen);
1092 } else
1093 nmp->nm_flag |= NFSMNT_WAITAUTH;
1094
1095 /*
1096 * Loop every second updating queue until there is a termination sig.
1097 */
1098 while ((nmp->nm_flag & NFSMNT_DISMNT) == 0) {
1099 if (nmp->nm_flag & NFSMNT_NQNFS) {
1100 /*
1101 * If there are no outstanding requests (and therefore no
1102 * processes in nfs_reply) and there is data in the receive
1103 * queue, poke for callbacks.
1104 */
1105 if (nfs_reqq.tqh_first == 0 && nmp->nm_so &&
1106 nmp->nm_so->so_rcv.sb_cc > 0) {
1107 myrep.r_flags = R_GETONEREP;
1108 myrep.r_nmp = nmp;
1109 myrep.r_mrep = (struct mbuf *)0;
1110 myrep.r_procp = (struct proc *)0;
1111 (void) nfs_reply(&myrep);
1112 }
1113
1114 /*
1115 * Loop through the leases, updating as required.
1116 */
1117 np = nmp->nm_timerhead.cqh_first;
1118 while (np != (void *)&nmp->nm_timerhead &&
1119 (nmp->nm_flag & NFSMNT_DISMINPROG) == 0) {
1120 vp = NFSTOV(np);
1121 vpid = vp->v_id;
1122 if (np->n_expiry < time.tv_sec) {
1123 if (vget(vp, LK_EXCLUSIVE, p) == 0) {
1124 nmp->nm_inprog = vp;
1125 if (vpid == vp->v_id) {
1126 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
1127 np->n_timer.cqe_next = 0;
1128 if (np->n_flag & (NMODIFIED | NQNFSEVICTED)) {
1129 if (np->n_flag & NQNFSEVICTED) {
1130 if (vp->v_type == VDIR)
1131 nfs_invaldir(vp);
1132 cache_purge(vp);
1133 (void) nfs_vinvalbuf(vp,
1134 V_SAVE, cred, p, 0);
1135 np->n_flag &= ~NQNFSEVICTED;
1136 (void) nqnfs_vacated(vp, cred);
1137 } else if (vp->v_type == VREG) {
1138 (void) VOP_FSYNC(vp, cred,
1139 MNT_WAIT, p);
1140 np->n_flag &= ~NMODIFIED;
1141 }
1142 }
1143 }
1144 vrele(vp);
1145 nmp->nm_inprog = NULLVP;
1146 }
1147 } else if ((np->n_expiry - NQ_RENEWAL) < time.tv_sec) {
1148 if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE))
1149 == NQNFSWRITE && vp->v_dirtyblkhd.lh_first &&
1150 vget(vp, LK_EXCLUSIVE, p) == 0) {
1151 nmp->nm_inprog = vp;
1152 if (vpid == vp->v_id &&
1153 nqnfs_getlease(vp, ND_WRITE, cred, p)==0)
1154 np->n_brev = np->n_lrev;
1155 vrele(vp);
1156 nmp->nm_inprog = NULLVP;
1157 }
1158 } else
1159 break;
1160 if (np == nmp->nm_timerhead.cqh_first)
1161 break;
1162 np = nmp->nm_timerhead.cqh_first;
1163 }
1164 }
1165
1166 /*
1167 * Get an authorization string, if required.
1168 */
1169 if ((nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT | NFSMNT_HASAUTH)) == 0) {
1170 ncd->ncd_authuid = nmp->nm_authuid;
1171 if (copyout((caddr_t)ncd, argp, sizeof (struct nfsd_cargs)))
1172 nmp->nm_flag |= NFSMNT_WAITAUTH;
1173 else
1174 return (ENEEDAUTH);
1175 }
1176
1177 /*
1178 * Wait a bit (no pun) and do it again.
1179 */
1180 if ((nmp->nm_flag & NFSMNT_DISMNT) == 0 &&
1181 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_HASAUTH))) {
1182 error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH,
1183 "nqnfstimr", hz / 3);
1184 if (error == EINTR || error == ERESTART)
1185 (void) dounmount(nmp->nm_mountp, 0, p);
1186 }
1187 }
1188
1189 /*
1190 * Finally, we can free up the mount structure.
1191 */
1192 for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) {
1193 nnuidp = nuidp->nu_lru.tqe_next;
1194 LIST_REMOVE(nuidp, nu_hash);
1195 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
1196 _FREE_ZONE((caddr_t)nuidp, sizeof (struct nfsuid), M_NFSUID);
1197 }
1198 /*
1199 * Loop through outstanding request list and remove dangling
1200 * references to defunct nfsmount struct
1201 */
1202 for (rp = nfs_reqq.tqh_first; rp; rp = rp->r_chain.tqe_next)
1203 if (rp->r_nmp == nmp)
1204 rp->r_nmp = (struct nfsmount *)0;
1205 _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
1206 if (error == EWOULDBLOCK)
1207 error = 0;
1208 return (error);
1209 }
1210
1211 #endif /* NFS_NOSERVER */
1212
1213 /*
1214 * Adjust all timer queue expiry times when the time of day clock is changed.
1215 * Called from the settimeofday() syscall.
1216 */
1217 void
1218 nqnfs_lease_updatetime(deltat)
1219 register int deltat;
1220 {
1221 struct proc *p = current_proc(); /* XXX */
1222 struct nqlease *lp;
1223 struct nfsnode *np;
1224 struct mount *mp, *nxtmp;
1225 struct nfsmount *nmp;
1226 int s;
1227
1228 if (nqnfsstarttime != 0)
1229 nqnfsstarttime += deltat;
1230 s = splsoftclock();
1231 for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead;
1232 lp = lp->lc_timer.cqe_next)
1233 lp->lc_expiry += deltat;
1234 splx(s);
1235
1236 /*
1237 * Search the mount list for all nqnfs mounts and do their timer
1238 * queues.
1239 */
1240 simple_lock(&mountlist_slock);
1241 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nxtmp) {
1242 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
1243 nxtmp = mp->mnt_list.cqe_next;
1244 continue;
1245 }
1246 if (mp->mnt_stat.f_type == nfs_mount_type) {
1247 nmp = VFSTONFS(mp);
1248 if (nmp->nm_flag & NFSMNT_NQNFS) {
1249 for (np = nmp->nm_timerhead.cqh_first;
1250 np != (void *)&nmp->nm_timerhead;
1251 np = np->n_timer.cqe_next) {
1252 np->n_expiry += deltat;
1253 }
1254 }
1255 }
1256 simple_lock(&mountlist_slock);
1257 nxtmp = mp->mnt_list.cqe_next;
1258 vfs_unbusy(mp, p);
1259 }
1260 simple_unlock(&mountlist_slock);
1261 }
1262
1263 /*
1264 * Lock a server lease.
1265 */
1266 static void
1267 nqsrv_locklease(lp)
1268 struct nqlease *lp;
1269 {
1270
1271 while (lp->lc_flag & LC_LOCKED) {
1272 lp->lc_flag |= LC_WANTED;
1273 (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0);
1274 }
1275 lp->lc_flag |= LC_LOCKED;
1276 lp->lc_flag &= ~LC_WANTED;
1277 }
1278
1279 /*
1280 * Unlock a server lease.
1281 */
1282 static void
1283 nqsrv_unlocklease(lp)
1284 struct nqlease *lp;
1285 {
1286
1287 lp->lc_flag &= ~LC_LOCKED;
1288 if (lp->lc_flag & LC_WANTED)
1289 wakeup((caddr_t)lp);
1290 }
1291
1292 /*
1293 * Update a client lease.
1294 */
1295 void
1296 nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev)
1297 register struct nfsmount *nmp;
1298 register struct nfsnode *np;
1299 int rwflag, cachable;
1300 time_t expiry;
1301 u_quad_t frev;
1302 {
1303 register struct nfsnode *tp;
1304
1305 if (np->n_timer.cqe_next != 0) {
1306 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
1307 if (rwflag == ND_WRITE)
1308 np->n_flag |= NQNFSWRITE;
1309 } else if (rwflag == ND_READ)
1310 np->n_flag &= ~NQNFSWRITE;
1311 else
1312 np->n_flag |= NQNFSWRITE;
1313 if (cachable)
1314 np->n_flag &= ~NQNFSNONCACHE;
1315 else
1316 np->n_flag |= NQNFSNONCACHE;
1317 np->n_expiry = expiry;
1318 np->n_lrev = frev;
1319 tp = nmp->nm_timerhead.cqh_last;
1320 while (tp != (void *)&nmp->nm_timerhead && tp->n_expiry > np->n_expiry)
1321 tp = tp->n_timer.cqe_prev;
1322 if (tp == (void *)&nmp->nm_timerhead) {
1323 CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
1324 } else {
1325 CIRCLEQ_INSERT_AFTER(&nmp->nm_timerhead, tp, np, n_timer);
1326 }
1327 }