]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_nqlease.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_nqlease.c
1 /*
2 * Copyright (c) 2000-2003 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 struct timeval now;
433
434 microtime(&now);
435 newexpiry = now.tv_sec + duration + nqsrv_clockskew;
436 if (lp->lc_expiry == newexpiry)
437 return;
438 if (lp->lc_timer.cqe_next != 0) {
439 CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer);
440 }
441 lp->lc_expiry = newexpiry;
442
443 /*
444 * Find where in the queue it should be.
445 */
446 tlp = nqtimerhead.cqh_last;
447 while (tlp != (void *)&nqtimerhead && tlp->lc_expiry > newexpiry)
448 tlp = tlp->lc_timer.cqe_prev;
449 #ifdef HASNVRAM
450 if (tlp == nqtimerhead.cqh_last)
451 NQSTORENOVRAM(newexpiry);
452 #endif /* HASNVRAM */
453 if (tlp == (void *)&nqtimerhead) {
454 CIRCLEQ_INSERT_HEAD(&nqtimerhead, lp, lc_timer);
455 } else {
456 CIRCLEQ_INSERT_AFTER(&nqtimerhead, tlp, lp, lc_timer);
457 }
458 }
459
460 /*
461 * Compare the requesting host address with the lph entry in the lease.
462 * Return true iff it is the same.
463 * This is somewhat messy due to the union in the nqhost structure.
464 * The local host is indicated by the special value of NQLOCALSLP for slp.
465 */
466 static int
467 nqsrv_cmpnam(slp, nam, lph)
468 register struct nfssvc_sock *slp;
469 struct mbuf *nam;
470 register struct nqhost *lph;
471 {
472 register struct sockaddr_in *saddr;
473 struct mbuf *addr;
474 union nethostaddr lhaddr;
475 int ret;
476
477 if (slp == NQLOCALSLP) {
478 if (lph->lph_flag & LC_LOCAL)
479 return (1);
480 else
481 return (0);
482 }
483 if (slp == nfs_udpsock || slp == nfs_cltpsock)
484 addr = nam;
485 else
486 addr = slp->ns_nam;
487 if (lph->lph_flag & LC_UDP)
488 ret = netaddr_match(AF_INET, &lph->lph_haddr, addr);
489 else if (lph->lph_flag & LC_CLTP)
490 ret = netaddr_match(AF_ISO, &lph->lph_claddr, addr);
491 else {
492 if ((lph->lph_slp->ns_flag & SLP_VALID) == 0)
493 return (0);
494 saddr = mtod(lph->lph_slp->ns_nam, struct sockaddr_in *);
495 if (saddr->sin_family == AF_INET)
496 lhaddr.had_inetaddr = saddr->sin_addr.s_addr;
497 else
498 lhaddr.had_nam = lph->lph_slp->ns_nam;
499 ret = netaddr_match(saddr->sin_family, &lhaddr, addr);
500 }
501 return (ret);
502 }
503
504 /*
505 * Send out eviction notice messages to all other hosts for the lease.
506 */
507 static void
508 nqsrv_send_eviction(vp, lp, slp, nam, cred)
509 struct vnode *vp;
510 register struct nqlease *lp;
511 struct nfssvc_sock *slp;
512 struct mbuf *nam;
513 struct ucred *cred;
514 {
515 register struct nqhost *lph = &lp->lc_host;
516 register struct mbuf *m;
517 register int siz;
518 struct nqm *lphnext = lp->lc_morehosts;
519 struct mbuf *mreq, *mb, *mb2, *mheadend;
520 struct socket *so;
521 struct mbuf *nam2;
522 struct sockaddr_in *saddr;
523 nfsfh_t nfh;
524 fhandle_t *fhp;
525 caddr_t bpos, cp;
526 u_long xid, *tl;
527 int len = 1, ok = 1, i = 0;
528 int sotype, solock;
529
530 while (ok && (lph->lph_flag & LC_VALID)) {
531 if (nqsrv_cmpnam(slp, nam, lph))
532 lph->lph_flag |= LC_VACATED;
533 else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
534 if (lph->lph_flag & LC_UDP) {
535 MGET(nam2, M_WAIT, MT_SONAME);
536 saddr = mtod(nam2, struct sockaddr_in *);
537 nam2->m_len = saddr->sin_len =
538 sizeof (struct sockaddr_in);
539 saddr->sin_family = AF_INET;
540 saddr->sin_addr.s_addr = lph->lph_inetaddr;
541 saddr->sin_port = lph->lph_port;
542 so = nfs_udpsock->ns_so;
543 } else if (lph->lph_flag & LC_CLTP) {
544 nam2 = lph->lph_nam;
545 so = nfs_cltpsock->ns_so;
546 } else if (lph->lph_slp->ns_flag & SLP_VALID) {
547 nam2 = (struct mbuf *)0;
548 so = lph->lph_slp->ns_so;
549 } else
550 goto nextone;
551 sotype = so->so_type;
552 solock = (so->so_proto->pr_flags & PR_CONNREQUIRED);
553 nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED,
554 NFSX_V3FH + NFSX_UNSIGNED);
555 fhp = &nfh.fh_generic;
556 bzero((caddr_t)fhp, sizeof(nfh));
557 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
558 VFS_VPTOFH(vp, &fhp->fh_fid);
559 nfsm_srvfhtom(fhp, 1);
560 m = mreq;
561 siz = 0;
562 while (m) {
563 siz += m->m_len;
564 m = m->m_next;
565 }
566 if (siz <= 0 || siz > NFS_MAXPACKET) {
567 printf("mbuf siz=%d\n",siz);
568 panic("Bad nfs svc reply");
569 }
570 m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS),
571 NQNFSPROC_EVICTED,
572 RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
573 0, (char *)NULL, mreq, siz, &mheadend, &xid);
574 /*
575 * For stream protocols, prepend a Sun RPC
576 * Record Mark.
577 */
578 if (sotype == SOCK_STREAM) {
579 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
580 *mtod(m, u_long *) = htonl(0x80000000 |
581 (m->m_pkthdr.len - NFSX_UNSIGNED));
582 }
583 if (((lph->lph_flag & (LC_UDP | LC_CLTP)) == 0 &&
584 (lph->lph_slp->ns_flag & SLP_VALID) == 0) ||
585 (solock && nfs_slplock(lph->lph_slp, 0) == 0)) {
586 m_freem(m);
587 } else {
588 (void) nfs_send(so, nam2, m,
589 (struct nfsreq *)0);
590 if (solock)
591 nfs_slpunlock(lph->lph_slp);
592 }
593 if (lph->lph_flag & LC_UDP)
594 MFREE(nam2, m);
595 }
596 nextone:
597 if (++i == len) {
598 if (lphnext) {
599 i = 0;
600 len = LC_MOREHOSTSIZ;
601 lph = lphnext->lpm_hosts;
602 lphnext = lphnext->lpm_next;
603 } else
604 ok = 0;
605 } else
606 lph++;
607 }
608 }
609
610 /*
611 * Wait for the lease to expire.
612 * This will occur when all clients have sent "vacated" messages to
613 * this server OR when it expires do to timeout.
614 */
615 static void
616 nqsrv_waitfor_expiry(lp)
617 register struct nqlease *lp;
618 {
619 register struct nqhost *lph;
620 register int i;
621 struct nqm *lphnext;
622 int len, ok;
623 struct timeval now;
624
625 tryagain:
626 microtime(&now);
627 if (now.tv_sec > lp->lc_expiry)
628 return;
629 lph = &lp->lc_host;
630 lphnext = lp->lc_morehosts;
631 len = 1;
632 i = 0;
633 ok = 1;
634 while (ok && (lph->lph_flag & LC_VALID)) {
635 if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
636 lp->lc_flag |= LC_EXPIREDWANTED;
637 (void) tsleep((caddr_t)&lp->lc_flag, PSOCK,
638 "nqexp", 0);
639 goto tryagain;
640 }
641 if (++i == len) {
642 if (lphnext) {
643 i = 0;
644 len = LC_MOREHOSTSIZ;
645 lph = lphnext->lpm_hosts;
646 lphnext = lphnext->lpm_next;
647 } else
648 ok = 0;
649 } else
650 lph++;
651 }
652 }
653
654 #ifndef NFS_NOSERVER
655
656 /*
657 * Nqnfs server timer that maintains the server lease queue.
658 * Scan the lease queue for expired entries:
659 * - when one is found, wakeup anyone waiting for it
660 * else dequeue and free
661 */
662 void
663 nqnfs_serverd()
664 {
665 register struct nqlease *lp;
666 register struct nqhost *lph;
667 struct nqlease *nextlp;
668 struct nqm *lphnext, *olphnext;
669 struct mbuf *n;
670 int i, len, ok;
671 struct timeval now;
672
673 microtime(&now);
674 for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead;
675 lp = nextlp) {
676 if (lp->lc_expiry >= now.tv_sec)
677 break;
678 nextlp = lp->lc_timer.cqe_next;
679 if (lp->lc_flag & LC_EXPIREDWANTED) {
680 lp->lc_flag &= ~LC_EXPIREDWANTED;
681 wakeup((caddr_t)&lp->lc_flag);
682 } else if ((lp->lc_flag & (LC_LOCKED | LC_WANTED)) == 0) {
683 /*
684 * Make a best effort at keeping a write caching lease long
685 * enough by not deleting it until it has been explicitly
686 * vacated or there have been no writes in the previous
687 * write_slack seconds since expiry and the nfsds are not
688 * all busy. The assumption is that if the nfsds are not
689 * all busy now (no queue of nfs requests), then the client
690 * would have been able to do at least one write to the
691 * file during the last write_slack seconds if it was still
692 * trying to push writes to the server.
693 */
694 if ((lp->lc_flag & (LC_WRITE | LC_VACATED)) == LC_WRITE &&
695 ((lp->lc_flag & LC_WRITTEN) || nfsd_waiting == 0)) {
696 lp->lc_flag &= ~LC_WRITTEN;
697 nqsrv_instimeq(lp, nqsrv_writeslack);
698 } else {
699 CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer);
700 LIST_REMOVE(lp, lc_hash);
701 /*
702 * This soft reference may no longer be valid, but
703 * no harm done. The worst case is if the vnode was
704 * recycled and has another valid lease reference,
705 * which is dereferenced prematurely.
706 */
707 lp->lc_vp->v_lease = (struct nqlease *)0;
708 lph = &lp->lc_host;
709 lphnext = lp->lc_morehosts;
710 olphnext = (struct nqm *)0;
711 len = 1;
712 i = 0;
713 ok = 1;
714 while (ok && (lph->lph_flag & LC_VALID)) {
715 if (lph->lph_flag & LC_CLTP)
716 MFREE(lph->lph_nam, n);
717 if (lph->lph_flag & LC_SREF)
718 nfsrv_slpderef(lph->lph_slp);
719 if (++i == len) {
720 if (olphnext) {
721 FREE_ZONE((caddr_t)olphnext,
722 sizeof (struct nqm),
723 M_NQMHOST);
724 olphnext = (struct nqm *)0;
725 }
726 if (lphnext) {
727 olphnext = lphnext;
728 i = 0;
729 len = LC_MOREHOSTSIZ;
730 lph = lphnext->lpm_hosts;
731 lphnext = lphnext->lpm_next;
732 } else
733 ok = 0;
734 } else
735 lph++;
736 }
737 FREE_ZONE((caddr_t)lp,
738 sizeof (struct nqlease), M_NQLEASE);
739 if (olphnext)
740 FREE_ZONE((caddr_t)olphnext,
741 sizeof (struct nqm), M_NQMHOST);
742 nfsstats.srvnqnfs_leases--;
743 }
744 }
745 }
746 }
747
748 /*
749 * Called from nfssvc_nfsd() for a getlease rpc request.
750 * Do the from/to xdr translation and call nqsrv_getlease() to
751 * do the real work.
752 */
753 int
754 nqnfsrv_getlease(nfsd, slp, procp, mrq)
755 struct nfsrv_descript *nfsd;
756 struct nfssvc_sock *slp;
757 struct proc *procp;
758 struct mbuf **mrq;
759 {
760 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
761 struct mbuf *nam = nfsd->nd_nam;
762 caddr_t dpos = nfsd->nd_dpos;
763 struct ucred *cred = &nfsd->nd_cr;
764 register struct nfs_fattr *fp;
765 struct vattr va;
766 register struct vattr *vap = &va;
767 struct vnode *vp;
768 nfsfh_t nfh;
769 fhandle_t *fhp;
770 register u_long *tl;
771 register long t1;
772 u_quad_t frev;
773 caddr_t bpos;
774 int error = 0;
775 char *cp2;
776 struct mbuf *mb, *mb2, *mreq;
777 int flags, rdonly, cache;
778
779 fhp = &nfh.fh_generic;
780 nfsm_srvmtofh(fhp);
781 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
782 flags = fxdr_unsigned(int, *tl++);
783 nfsd->nd_duration = fxdr_unsigned(int, *tl);
784 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
785 (nfsd->nd_flag & ND_KERBAUTH), TRUE);
786 if (error)
787 nfsm_reply(0);
788 if (rdonly && flags == ND_WRITE) {
789 error = EROFS;
790 vput(vp);
791 nfsm_reply(0);
792 }
793 (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, procp,
794 nam, &cache, &frev, cred);
795 error = VOP_GETATTR(vp, vap, cred, procp);
796 vput(vp);
797 nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
798 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
799 *tl++ = txdr_unsigned(cache);
800 *tl++ = txdr_unsigned(nfsd->nd_duration);
801 txdr_hyper(&frev, tl);
802 nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR);
803 nfsm_srvfillattr(vap, fp);
804 nfsm_srvdone;
805 }
806
807 /*
808 * Called from nfssvc_nfsd() when a "vacated" message is received from a
809 * client. Find the entry and expire it.
810 */
811 int
812 nqnfsrv_vacated(nfsd, slp, procp, mrq)
813 struct nfsrv_descript *nfsd;
814 struct nfssvc_sock *slp;
815 struct proc *procp;
816 struct mbuf **mrq;
817 {
818 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
819 struct mbuf *nam = nfsd->nd_nam;
820 caddr_t dpos = nfsd->nd_dpos;
821 register struct nqlease *lp;
822 register struct nqhost *lph;
823 struct nqlease *tlp = (struct nqlease *)0;
824 nfsfh_t nfh;
825 fhandle_t *fhp;
826 register u_long *tl;
827 register long t1;
828 struct nqm *lphnext;
829 struct mbuf *mreq, *mb;
830 int error = 0, i, len, ok, gotit = 0, cache = 0;
831 char *cp2, *bpos;
832 u_quad_t frev;
833
834 fhp = &nfh.fh_generic;
835 nfsm_srvmtofh(fhp);
836 m_freem(mrep);
837 /*
838 * Find the lease by searching the hash list.
839 */
840 for (lp = NQFHHASH(fhp->fh_fid.fid_data)->lh_first; lp != 0;
841 lp = lp->lc_hash.le_next)
842 if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] &&
843 fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] &&
844 !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata,
845 MAXFIDSZ)) {
846 /* Found it */
847 tlp = lp;
848 break;
849 }
850 if (tlp) {
851 lp = tlp;
852 len = 1;
853 i = 0;
854 lph = &lp->lc_host;
855 lphnext = lp->lc_morehosts;
856 ok = 1;
857 while (ok && (lph->lph_flag & LC_VALID)) {
858 if (nqsrv_cmpnam(slp, nam, lph)) {
859 lph->lph_flag |= LC_VACATED;
860 gotit++;
861 break;
862 }
863 if (++i == len) {
864 if (lphnext) {
865 len = LC_MOREHOSTSIZ;
866 i = 0;
867 lph = lphnext->lpm_hosts;
868 lphnext = lphnext->lpm_next;
869 } else
870 ok = 0;
871 } else
872 lph++;
873 }
874 if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) {
875 lp->lc_flag &= ~LC_EXPIREDWANTED;
876 wakeup((caddr_t)&lp->lc_flag);
877 }
878 nfsmout:
879 return (EPERM);
880 }
881 return (EPERM);
882 }
883
884 #endif /* NFS_NOSERVER */
885
886 /*
887 * Client get lease rpc function.
888 */
889 int
890 nqnfs_getlease(vp, rwflag, cred, p)
891 register struct vnode *vp;
892 int rwflag;
893 struct ucred *cred;
894 struct proc *p;
895 {
896 register u_long *tl;
897 register caddr_t cp;
898 register long t1, t2;
899 register struct nfsnode *np;
900 struct nfsmount *nmp;
901 caddr_t bpos, dpos, cp2;
902 struct timeval now;
903 time_t reqtime;
904 int error = 0;
905 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
906 int cachable;
907 u_quad_t frev;
908 u_int64_t xid;
909
910 nmp = VFSTONFS(vp->v_mount);
911 if (!nmp)
912 return (ENXIO);
913
914 nfsstats.rpccnt[NQNFSPROC_GETLEASE]++;
915 mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED,
916 &bpos);
917 nfsm_fhtom(vp, 1);
918 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
919 *tl++ = txdr_unsigned(rwflag);
920 *tl = txdr_unsigned(nmp->nm_leaseterm);
921 microtime(&now);
922 reqtime = now.tv_sec;
923 nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred, &xid);
924 np = VTONFS(vp);
925 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
926 cachable = fxdr_unsigned(int, *tl++);
927 reqtime += fxdr_unsigned(int, *tl++);
928 microtime(&now);
929 if (reqtime > now.tv_sec) {
930 nmp = VFSTONFS(vp->v_mount);
931 if (!nmp) {
932 error = ENXIO;
933 } else {
934 fxdr_hyper(tl, &frev);
935 nqnfs_clientlease(nmp, np, rwflag, cachable,
936 reqtime, frev);
937 nfsm_loadattr(vp, (struct vattr *)0, &xid);
938 }
939 } else
940 error = NQNFS_EXPIRED;
941 nfsm_reqdone;
942 return (error);
943 }
944
945 /*
946 * Client vacated message function.
947 */
948 static int
949 nqnfs_vacated(vp, cred)
950 register struct vnode *vp;
951 struct ucred *cred;
952 {
953 register caddr_t cp;
954 register struct mbuf *m;
955 register int i;
956 register u_long *tl;
957 register long t2;
958 caddr_t bpos;
959 u_long xid;
960 int error = 0;
961 struct mbuf *mreq, *mb, *mb2, *mheadend;
962 struct nfsmount *nmp;
963 struct nfsreq myrep;
964 int connrequired;
965 int *flagp;
966
967 nmp = VFSTONFS(vp->v_mount);
968 if (!nmp)
969 return (ENXIO);
970 nfsstats.rpccnt[NQNFSPROC_VACATED]++;
971 nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH(1));
972 nfsm_fhtom(vp, 1);
973 m = mreq;
974 i = 0;
975 while (m) {
976 i += m->m_len;
977 m = m->m_next;
978 }
979 m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED,
980 RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
981 0, (char *)NULL, mreq, i, &mheadend, &xid);
982 if (nmp->nm_sotype == SOCK_STREAM) {
983 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
984 *mtod(m, u_long *) = htonl(0x80000000 | (m->m_pkthdr.len -
985 NFSX_UNSIGNED));
986 }
987 myrep.r_flags = 0;
988 myrep.r_nmp = nmp;
989
990 connrequired = (nmp->nm_soflags & PR_CONNREQUIRED);
991 if (connrequired)
992 (void) nfs_sndlock(&myrep);
993
994 (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep);
995
996 if (connrequired)
997 nfs_sndunlock(&myrep);
998 nfsmout:
999 return (error);
1000 }
1001
1002 #ifndef NFS_NOSERVER
1003
1004 /*
1005 * Called for client side callbacks
1006 */
1007 int
1008 nqnfs_callback(nmp, mrep, md, dpos)
1009 struct nfsmount *nmp;
1010 struct mbuf *mrep, *md;
1011 caddr_t dpos;
1012 {
1013 register struct vnode *vp;
1014 register u_long *tl;
1015 register long t1;
1016 nfsfh_t nfh;
1017 fhandle_t *fhp;
1018 struct nfsnode *np;
1019 struct nfsd tnfsd;
1020 struct nfssvc_sock *slp;
1021 struct nfsrv_descript ndesc;
1022 register struct nfsrv_descript *nfsd = &ndesc;
1023 struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq;
1024 int error = 0, cache = 0;
1025 char *cp2, *bpos;
1026 u_quad_t frev;
1027
1028 #ifndef nolint
1029 slp = NULL;
1030 #endif
1031 nfsd->nd_mrep = mrep;
1032 nfsd->nd_md = md;
1033 nfsd->nd_dpos = dpos;
1034 error = nfs_getreq(nfsd, &tnfsd, FALSE);
1035 if (error)
1036 return (error);
1037 md = nfsd->nd_md;
1038 dpos = nfsd->nd_dpos;
1039 if (nfsd->nd_procnum != NQNFSPROC_EVICTED) {
1040 m_freem(mrep);
1041 return (EPERM);
1042 }
1043 fhp = &nfh.fh_generic;
1044 nfsm_srvmtofh(fhp);
1045 m_freem(mrep);
1046 error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np);
1047 if (error)
1048 return (error);
1049 vp = NFSTOV(np);
1050 if (np->n_timer.cqe_next != 0) {
1051 np->n_expiry = 0;
1052 np->n_flag |= NQNFSEVICTED;
1053 if (nmp->nm_timerhead.cqh_first != np) {
1054 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
1055 CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
1056 }
1057 }
1058 vput(vp);
1059 nfsm_srvdone;
1060 }
1061
1062
1063 /*
1064 * Nqnfs client helper daemon. Runs once a second to expire leases.
1065 * It also get authorization strings for "kerb" mounts.
1066 * It must start at the beginning of the list again after any potential
1067 * "sleep" since nfs_reclaim() called from vclean() can pull a node off
1068 * the list asynchronously.
1069 */
1070 int
1071 nqnfs_clientd(nmp, cred, ncd, flag, argp, p)
1072 register struct nfsmount *nmp;
1073 struct ucred *cred;
1074 struct nfsd_cargs *ncd;
1075 int flag;
1076 caddr_t argp;
1077 struct proc *p;
1078 {
1079 register struct nfsnode *np;
1080 struct vnode *vp;
1081 struct nfsreq myrep;
1082 struct nfsuid *nuidp, *nnuidp;
1083 int error = 0, vpid;
1084 register struct nfsreq *rp;
1085 struct timeval now;
1086
1087 /*
1088 * First initialize some variables
1089 */
1090 microtime(&now);
1091
1092 /*
1093 * If an authorization string is being passed in, get it.
1094 */
1095 if ((flag & NFSSVC_GOTAUTH) &&
1096 (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_DISMNT)) == 0) {
1097 if (nmp->nm_state & NFSSTA_HASAUTH)
1098 panic("cld kerb");
1099 if ((flag & NFSSVC_AUTHINFAIL) == 0) {
1100 if (ncd->ncd_authlen <= nmp->nm_authlen &&
1101 ncd->ncd_verflen <= nmp->nm_verflen &&
1102 !copyin(ncd->ncd_authstr,nmp->nm_authstr,ncd->ncd_authlen)&&
1103 !copyin(ncd->ncd_verfstr,nmp->nm_verfstr,ncd->ncd_verflen)){
1104 nmp->nm_authtype = ncd->ncd_authtype;
1105 nmp->nm_authlen = ncd->ncd_authlen;
1106 nmp->nm_verflen = ncd->ncd_verflen;
1107 #if NFSKERB
1108 nmp->nm_key = ncd->ncd_key;
1109 #endif
1110 } else
1111 nmp->nm_state |= NFSSTA_AUTHERR;
1112 } else
1113 nmp->nm_state |= NFSSTA_AUTHERR;
1114 nmp->nm_state |= NFSSTA_HASAUTH;
1115 wakeup((caddr_t)&nmp->nm_authlen);
1116 } else
1117 nmp->nm_state |= NFSSTA_WAITAUTH;
1118
1119 /*
1120 * Loop every second updating queue until there is a termination sig.
1121 */
1122 while ((nmp->nm_state & NFSSTA_DISMNT) == 0) {
1123 if (nmp->nm_flag & NFSMNT_NQNFS) {
1124 /*
1125 * If there are no outstanding requests (and therefore no
1126 * processes in nfs_reply) and there is data in the receive
1127 * queue, poke for callbacks.
1128 */
1129 if (nfs_reqq.tqh_first == 0 && nmp->nm_so &&
1130 nmp->nm_so->so_rcv.sb_cc > 0) {
1131 myrep.r_flags = R_GETONEREP;
1132 myrep.r_nmp = nmp;
1133 myrep.r_mrep = (struct mbuf *)0;
1134 myrep.r_procp = (struct proc *)0;
1135 (void) nfs_reply(&myrep);
1136 }
1137
1138 /*
1139 * Loop through the leases, updating as required.
1140 */
1141 np = nmp->nm_timerhead.cqh_first;
1142 while (np != (void *)&nmp->nm_timerhead &&
1143 (nmp->nm_state & NFSSTA_DISMINPROG) == 0) {
1144 vp = NFSTOV(np);
1145 vpid = vp->v_id;
1146 if (np->n_expiry < now.tv_sec) {
1147 if (vget(vp, LK_EXCLUSIVE, p) == 0) {
1148 nmp->nm_inprog = vp;
1149 if (vpid == vp->v_id) {
1150 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
1151 np->n_timer.cqe_next = 0;
1152 if (np->n_flag & (NMODIFIED | NQNFSEVICTED)) {
1153 if (np->n_flag & NQNFSEVICTED) {
1154 if (vp->v_type == VDIR)
1155 nfs_invaldir(vp);
1156 cache_purge(vp);
1157 (void) nfs_vinvalbuf(vp,
1158 V_SAVE, cred, p, 0);
1159 np->n_flag &= ~NQNFSEVICTED;
1160 (void) nqnfs_vacated(vp, cred);
1161 } else if (vp->v_type == VREG) {
1162 (void) VOP_FSYNC(vp, cred,
1163 MNT_WAIT, p);
1164 np->n_flag &= ~NMODIFIED;
1165 }
1166 }
1167 }
1168 vrele(vp);
1169 nmp->nm_inprog = NULLVP;
1170 }
1171 } else if ((np->n_expiry - NQ_RENEWAL) < now.tv_sec) {
1172 if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE))
1173 == NQNFSWRITE && np->n_dirtyblkhd.lh_first &&
1174 vget(vp, LK_EXCLUSIVE, p) == 0) {
1175 nmp->nm_inprog = vp;
1176 if (vpid == vp->v_id &&
1177 nqnfs_getlease(vp, ND_WRITE, cred, p)==0)
1178 np->n_brev = np->n_lrev;
1179 vrele(vp);
1180 nmp->nm_inprog = NULLVP;
1181 }
1182 } else
1183 break;
1184 if (np == nmp->nm_timerhead.cqh_first)
1185 break;
1186 np = nmp->nm_timerhead.cqh_first;
1187 }
1188 }
1189
1190 /*
1191 * Get an authorization string, if required.
1192 */
1193 if ((nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_DISMNT | NFSSTA_HASAUTH)) == 0) {
1194 ncd->ncd_authuid = nmp->nm_authuid;
1195 if (copyout((caddr_t)ncd, argp, sizeof (struct nfsd_cargs)))
1196 nmp->nm_state |= NFSSTA_WAITAUTH;
1197 else
1198 return (ENEEDAUTH);
1199 }
1200
1201 /*
1202 * Wait a bit (no pun) and do it again.
1203 */
1204 if ((nmp->nm_state & NFSSTA_DISMNT) == 0 &&
1205 (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_HASAUTH))) {
1206 error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH,
1207 "nqnfstimr", hz / 3);
1208 if (error == EINTR || error == ERESTART)
1209 (void) dounmount(nmp->nm_mountp, 0, p);
1210 }
1211 }
1212
1213 /*
1214 * Finally, we can free up the mount structure.
1215 */
1216 for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) {
1217 nnuidp = nuidp->nu_lru.tqe_next;
1218 LIST_REMOVE(nuidp, nu_hash);
1219 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
1220 FREE_ZONE((caddr_t)nuidp, sizeof (struct nfsuid), M_NFSUID);
1221 }
1222 /*
1223 * Loop through outstanding request list and remove dangling
1224 * references to defunct nfsmount struct
1225 */
1226 for (rp = nfs_reqq.tqh_first; rp; rp = rp->r_chain.tqe_next)
1227 if (rp->r_nmp == nmp)
1228 rp->r_nmp = (struct nfsmount *)0;
1229 FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
1230 if (error == EWOULDBLOCK)
1231 error = 0;
1232 return (error);
1233 }
1234
1235 #endif /* NFS_NOSERVER */
1236
1237 /*
1238 * Adjust all timer queue expiry times when the time of day clock is changed.
1239 * Called from the settimeofday() syscall.
1240 */
1241 void
1242 nqnfs_lease_updatetime(deltat)
1243 register int deltat;
1244 {
1245 struct proc *p = current_proc(); /* XXX */
1246 struct nqlease *lp;
1247 struct nfsnode *np;
1248 struct mount *mp, *nxtmp;
1249 struct nfsmount *nmp;
1250 int s;
1251
1252 if (nqnfsstarttime != 0)
1253 nqnfsstarttime += deltat;
1254 s = splsoftclock();
1255 for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead;
1256 lp = lp->lc_timer.cqe_next)
1257 lp->lc_expiry += deltat;
1258 splx(s);
1259
1260 /*
1261 * Search the mount list for all nqnfs mounts and do their timer
1262 * queues.
1263 */
1264 simple_lock(&mountlist_slock);
1265 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nxtmp) {
1266 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
1267 nxtmp = mp->mnt_list.cqe_next;
1268 continue;
1269 }
1270 if (mp->mnt_stat.f_type == nfs_mount_type) {
1271 nmp = VFSTONFS(mp);
1272 if (nmp->nm_flag & NFSMNT_NQNFS) {
1273 for (np = nmp->nm_timerhead.cqh_first;
1274 np != (void *)&nmp->nm_timerhead;
1275 np = np->n_timer.cqe_next) {
1276 np->n_expiry += deltat;
1277 }
1278 }
1279 }
1280 simple_lock(&mountlist_slock);
1281 nxtmp = mp->mnt_list.cqe_next;
1282 vfs_unbusy(mp, p);
1283 }
1284 simple_unlock(&mountlist_slock);
1285 }
1286
1287 /*
1288 * Lock a server lease.
1289 */
1290 static void
1291 nqsrv_locklease(lp)
1292 struct nqlease *lp;
1293 {
1294
1295 while (lp->lc_flag & LC_LOCKED) {
1296 lp->lc_flag |= LC_WANTED;
1297 (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0);
1298 }
1299 lp->lc_flag |= LC_LOCKED;
1300 lp->lc_flag &= ~LC_WANTED;
1301 }
1302
1303 /*
1304 * Unlock a server lease.
1305 */
1306 static void
1307 nqsrv_unlocklease(lp)
1308 struct nqlease *lp;
1309 {
1310
1311 lp->lc_flag &= ~LC_LOCKED;
1312 if (lp->lc_flag & LC_WANTED)
1313 wakeup((caddr_t)lp);
1314 }
1315
1316 /*
1317 * Update a client lease.
1318 */
1319 void
1320 nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev)
1321 register struct nfsmount *nmp;
1322 register struct nfsnode *np;
1323 int rwflag, cachable;
1324 time_t expiry;
1325 u_quad_t frev;
1326 {
1327 register struct nfsnode *tp;
1328
1329 if (np->n_timer.cqe_next != 0) {
1330 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
1331 if (rwflag == ND_WRITE)
1332 np->n_flag |= NQNFSWRITE;
1333 } else if (rwflag == ND_READ)
1334 np->n_flag &= ~NQNFSWRITE;
1335 else
1336 np->n_flag |= NQNFSWRITE;
1337 if (cachable)
1338 np->n_flag &= ~NQNFSNONCACHE;
1339 else
1340 np->n_flag |= NQNFSNONCACHE;
1341 np->n_expiry = expiry;
1342 np->n_lrev = frev;
1343 tp = nmp->nm_timerhead.cqh_last;
1344 while (tp != (void *)&nmp->nm_timerhead && tp->n_expiry > np->n_expiry)
1345 tp = tp->n_timer.cqe_prev;
1346 if (tp == (void *)&nmp->nm_timerhead) {
1347 CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
1348 } else {
1349 CIRCLEQ_INSERT_AFTER(&nmp->nm_timerhead, tp, np, n_timer);
1350 }
1351 }