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