]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_nqlease.c
43ae6b40cac85abce87b8a6d0688427ed1fa6a62
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1992, 1993
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95
59 * FreeBSD-Id: nfs_nqlease.c,v 1.32 1997/11/07 08:53:23 phk Exp $
65 * Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant
66 * Mechanism for Distributed File Cache Consistency",
67 * In Proc. of the Twelfth ACM Symposium on Operating Systems
68 * Principals, pg. 202-210, Litchfield Park, AZ, Dec. 1989.
69 * Michael N. Nelson, Brent B. Welch and John K. Ousterhout, "Caching
70 * in the Sprite Network File System", ACM TOCS 6(1),
71 * pages 134-154, February 1988.
72 * V. Srinivasan and Jeffrey C. Mogul, "Spritely NFS: Implementation and
73 * Performance of Cache-Consistency Protocols", Digital
74 * Equipment Corporation WRL Research Report 89/5, May 1989.
76 #include <sys/param.h>
77 #include <sys/vnode.h>
78 #include <sys/mount.h>
79 #include <sys/kernel.h>
81 #include <sys/systm.h>
82 #include <sys/malloc.h>
84 #include <sys/socket.h>
85 #include <sys/socketvar.h>
86 #include <sys/protosw.h>
87 #include <machine/spl.h>
89 #include <netinet/in.h>
90 #include <nfs/rpcv2.h>
91 #include <nfs/nfsproto.h>
93 #include <nfs/nfsm_subs.h>
94 #include <nfs/xdr_subs.h>
95 #include <nfs/nqnfs.h>
96 #include <nfs/nfsnode.h>
97 #include <nfs/nfsmount.h>
99 time_t nqnfsstarttime
= (time_t)0;
100 int nqsrv_clockskew
= NQ_CLOCKSKEW
;
101 int nqsrv_writeslack
= NQ_WRITESLACK
;
102 int nqsrv_maxlease
= NQ_MAXLEASE
;
103 static int nqsrv_maxnumlease
= NQ_MAXNUMLEASE
;
105 struct vop_lease_args
;
107 static int nqsrv_cmpnam
__P((struct nfssvc_sock
*, struct mbuf
*,
109 extern void nqnfs_lease_updatetime
__P((int deltat
));
110 static int nqnfs_vacated
__P((struct vnode
*vp
, struct ucred
*cred
));
111 static void nqsrv_addhost
__P((struct nqhost
*lph
, struct nfssvc_sock
*slp
,
113 static void nqsrv_instimeq
__P((struct nqlease
*lp
, u_long duration
));
114 static void nqsrv_locklease
__P((struct nqlease
*lp
));
115 static void nqsrv_send_eviction
__P((struct vnode
*vp
, struct nqlease
*lp
,
116 struct nfssvc_sock
*slp
,
117 struct mbuf
*nam
, struct ucred
*cred
));
118 static void nqsrv_unlocklease
__P((struct nqlease
*lp
));
119 static void nqsrv_waitfor_expiry
__P((struct nqlease
*lp
));
122 * Signifies which rpcs can have piggybacked lease requests
124 int nqnfs_piggy
[NFS_NPROCS
] = {
153 extern nfstype nfsv2_type
[9];
154 extern nfstype nfsv3_type
[9];
155 extern struct nfssvc_sock
*nfs_udpsock
, *nfs_cltpsock
;
156 extern int nfsd_waiting
;
157 extern struct nfsstats nfsstats
;
158 extern int nfs_mount_type
;
165 * Get or check for a lease for "vp", based on ND_CHECK flag.
166 * The rules are as follows:
167 * - if a current non-caching lease, reply non-caching
168 * - if a current lease for same host only, extend lease
169 * - if a read cachable lease and a read lease request
170 * add host to list any reply cachable
171 * - else { set non-cachable for read-write sharing }
172 * send eviction notice messages to all other hosts that have lease
173 * wait for lease termination { either by receiving vacated messages
174 * from all the other hosts or expiry
176 * modify lease to non-cachable
177 * - else if no current lease, issue new one
179 * - return boolean TRUE iff nam should be m_freem()'d
180 * NB: Since nqnfs_serverd() is called from a timer, any potential tsleep()
181 * in here must be framed by nqsrv_locklease() and nqsrv_unlocklease().
182 * nqsrv_locklease() is coded such that at least one of LC_LOCKED and
183 * LC_WANTED is set whenever a process is tsleeping in it. The exception
184 * is when a new lease is being allocated, since it is not in the timer
185 * queue yet. (Ditto for the splsoftclock() and splx(s) calls)
188 nqsrv_getlease(vp
, duration
, flags
, slp
, procp
, nam
, cachablep
, frev
, cred
)
192 struct nfssvc_sock
*slp
;
199 register struct nqlease
*lp
;
200 register struct nqfhhashhead
*lpp
= 0;
201 register struct nqhost
*lph
= 0;
208 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
&& vp
->v_type
!= VLNK
)
210 if (*duration
> nqsrv_maxlease
)
211 *duration
= nqsrv_maxlease
;
212 error
= VOP_GETATTR(vp
, &vattr
, cred
, procp
);
215 *frev
= vattr
.va_filerev
;
218 if ((flags
& ND_CHECK
) == 0)
219 nfsstats
.srvnqnfs_getleases
++;
220 if (tlp
== (struct nqlease
*)0) {
223 * Find the lease by searching the hash list.
225 fh
.fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
226 error
= VFS_VPTOFH(vp
, &fh
.fh_fid
);
231 lpp
= NQFHHASH(fh
.fh_fid
.fid_data
);
232 for (lp
= lpp
->lh_first
; lp
!= 0; lp
= lp
->lc_hash
.le_next
)
233 if (fh
.fh_fsid
.val
[0] == lp
->lc_fsid
.val
[0] &&
234 fh
.fh_fsid
.val
[1] == lp
->lc_fsid
.val
[1] &&
235 !bcmp(fh
.fh_fid
.fid_data
, lp
->lc_fiddata
,
236 fh
.fh_fid
.fid_len
- sizeof (long))) {
246 if ((lp
->lc_flag
& LC_NONCACHABLE
) ||
247 (lp
->lc_morehosts
== (struct nqm
*)0 &&
248 nqsrv_cmpnam(slp
, nam
, &lp
->lc_host
)))
250 if ((flags
& ND_READ
) && (lp
->lc_flag
& LC_WRITE
) == 0) {
251 if (flags
& ND_CHECK
)
253 if (nqsrv_cmpnam(slp
, nam
, &lp
->lc_host
))
256 if (lp
->lc_morehosts
) {
257 lph
= lp
->lc_morehosts
->lpm_hosts
;
258 lphp
= &lp
->lc_morehosts
->lpm_next
;
261 lphp
= &lp
->lc_morehosts
;
264 while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
265 if (nqsrv_cmpnam(slp
, nam
, lph
))
267 if (++i
== LC_MOREHOSTSIZ
) {
270 lph
= (*lphp
)->lpm_hosts
;
271 lphp
= &((*lphp
)->lpm_next
);
279 MALLOC_ZONE(*lphp
, struct nqm
*,
281 M_NQMHOST
, M_WAITOK
);
282 bzero((caddr_t
)*lphp
, sizeof (struct nqm
));
283 lph
= (*lphp
)->lpm_hosts
;
285 nqsrv_addhost(lph
, slp
, nam
);
286 nqsrv_unlocklease(lp
);
288 lp
->lc_flag
|= LC_NONCACHABLE
;
290 nqsrv_send_eviction(vp
, lp
, slp
, nam
, cred
);
291 nqsrv_waitfor_expiry(lp
);
292 nqsrv_unlocklease(lp
);
296 * Update the lease and return
298 if ((flags
& ND_CHECK
) == 0)
299 nqsrv_instimeq(lp
, *duration
);
300 if (lp
->lc_flag
& LC_NONCACHABLE
)
304 if (flags
& ND_WRITE
)
305 lp
->lc_flag
|= LC_WRITTEN
;
311 if (flags
& ND_CHECK
)
316 * The value of nqsrv_maxnumlease should be set generously, so that
317 * the following "printf" happens infrequently.
319 if (nfsstats
.srvnqnfs_leases
> nqsrv_maxnumlease
) {
320 printf("Nqnfs server, too many leases\n");
322 (void) tsleep((caddr_t
)&lbolt
, PSOCK
,
324 } while (nfsstats
.srvnqnfs_leases
> nqsrv_maxnumlease
);
326 MALLOC_ZONE(lp
, struct nqlease
*,
327 sizeof (struct nqlease
), M_NQLEASE
, M_WAITOK
);
328 bzero((caddr_t
)lp
, sizeof (struct nqlease
));
329 if (flags
& ND_WRITE
)
330 lp
->lc_flag
|= (LC_WRITE
| LC_WRITTEN
);
331 nqsrv_addhost(&lp
->lc_host
, slp
, nam
);
333 lp
->lc_fsid
= fh
.fh_fsid
;
334 bcopy(fh
.fh_fid
.fid_data
, lp
->lc_fiddata
,
335 fh
.fh_fid
.fid_len
- sizeof (long));
337 panic("nfs_nqlease.c: Phoney lpp");
338 LIST_INSERT_HEAD(lpp
, lp
, lc_hash
);
341 nqsrv_instimeq(lp
, *duration
);
344 if (++nfsstats
.srvnqnfs_leases
> nfsstats
.srvnqnfs_maxleases
)
345 nfsstats
.srvnqnfs_maxleases
= nfsstats
.srvnqnfs_leases
;
350 * Local lease check for server syscalls.
351 * Just set up args and let nqsrv_getlease() do the rest.
352 * nqnfs_vop_lease_check() is the VOP_LEASE() form of the same routine.
353 * Ifdef'd code in nfsnode.h renames these routines to whatever a particular
357 nqnfs_lease_check(vp
, p
, cred
, flag
)
367 (void) nqsrv_getlease(vp
, &duration
, ND_CHECK
| flag
, NQLOCALSLP
,
368 p
, (struct mbuf
*)0, &cache
, &frev
, cred
);
372 nqnfs_vop_lease_check(ap
)
373 struct vop_lease_args
/* {
376 struct ucred *a_cred;
384 (void) nqsrv_getlease(ap
->a_vp
, &duration
, ND_CHECK
| ap
->a_flag
,
385 NQLOCALSLP
, ap
->a_p
, (struct mbuf
*)0, &cache
, &frev
, ap
->a_cred
);
389 #endif /* NFS_NOSERVER */
392 * Add a host to an nqhost structure for a lease.
395 nqsrv_addhost(lph
, slp
, nam
)
396 register struct nqhost
*lph
;
397 struct nfssvc_sock
*slp
;
400 register struct sockaddr_in
*saddr
;
402 if (slp
== NQLOCALSLP
)
403 lph
->lph_flag
|= (LC_VALID
| LC_LOCAL
);
404 else if (slp
== nfs_udpsock
) {
405 saddr
= mtod(nam
, struct sockaddr_in
*);
406 lph
->lph_flag
|= (LC_VALID
| LC_UDP
);
407 lph
->lph_inetaddr
= saddr
->sin_addr
.s_addr
;
408 lph
->lph_port
= saddr
->sin_port
;
409 } else if (slp
== nfs_cltpsock
) {
410 lph
->lph_nam
= m_copym(nam
, 0, M_COPYALL
, M_WAIT
);
411 lph
->lph_flag
|= (LC_VALID
| LC_CLTP
);
413 lph
->lph_flag
|= (LC_VALID
| LC_SREF
);
420 * Update the lease expiry time and position it in the timer queue correctly.
423 nqsrv_instimeq(lp
, duration
)
424 register struct nqlease
*lp
;
427 register struct nqlease
*tlp
;
432 newexpiry
= now
.tv_sec
+ duration
+ nqsrv_clockskew
;
433 if (lp
->lc_expiry
== newexpiry
)
435 if (lp
->lc_timer
.cqe_next
!= 0) {
436 CIRCLEQ_REMOVE(&nqtimerhead
, lp
, lc_timer
);
438 lp
->lc_expiry
= newexpiry
;
441 * Find where in the queue it should be.
443 tlp
= nqtimerhead
.cqh_last
;
444 while (tlp
!= (void *)&nqtimerhead
&& tlp
->lc_expiry
> newexpiry
)
445 tlp
= tlp
->lc_timer
.cqe_prev
;
447 if (tlp
== nqtimerhead
.cqh_last
)
448 NQSTORENOVRAM(newexpiry
);
449 #endif /* HASNVRAM */
450 if (tlp
== (void *)&nqtimerhead
) {
451 CIRCLEQ_INSERT_HEAD(&nqtimerhead
, lp
, lc_timer
);
453 CIRCLEQ_INSERT_AFTER(&nqtimerhead
, tlp
, lp
, lc_timer
);
458 * Compare the requesting host address with the lph entry in the lease.
459 * Return true iff it is the same.
460 * This is somewhat messy due to the union in the nqhost structure.
461 * The local host is indicated by the special value of NQLOCALSLP for slp.
464 nqsrv_cmpnam(slp
, nam
, lph
)
465 register struct nfssvc_sock
*slp
;
467 register struct nqhost
*lph
;
469 register struct sockaddr_in
*saddr
;
471 union nethostaddr lhaddr
;
474 if (slp
== NQLOCALSLP
) {
475 if (lph
->lph_flag
& LC_LOCAL
)
480 if (slp
== nfs_udpsock
|| slp
== nfs_cltpsock
)
484 if (lph
->lph_flag
& LC_UDP
)
485 ret
= netaddr_match(AF_INET
, &lph
->lph_haddr
, addr
);
486 else if (lph
->lph_flag
& LC_CLTP
)
487 ret
= netaddr_match(AF_ISO
, &lph
->lph_claddr
, addr
);
489 if ((lph
->lph_slp
->ns_flag
& SLP_VALID
) == 0)
491 saddr
= mtod(lph
->lph_slp
->ns_nam
, struct sockaddr_in
*);
492 if (saddr
->sin_family
== AF_INET
)
493 lhaddr
.had_inetaddr
= saddr
->sin_addr
.s_addr
;
495 lhaddr
.had_nam
= lph
->lph_slp
->ns_nam
;
496 ret
= netaddr_match(saddr
->sin_family
, &lhaddr
, addr
);
502 * Send out eviction notice messages to all other hosts for the lease.
505 nqsrv_send_eviction(vp
, lp
, slp
, nam
, cred
)
507 register struct nqlease
*lp
;
508 struct nfssvc_sock
*slp
;
512 register struct nqhost
*lph
= &lp
->lc_host
;
513 register struct mbuf
*m
;
515 struct nqm
*lphnext
= lp
->lc_morehosts
;
516 struct mbuf
*mreq
, *mb
, *mb2
, *mheadend
;
519 struct sockaddr_in
*saddr
;
524 int len
= 1, ok
= 1, i
= 0;
527 while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
528 if (nqsrv_cmpnam(slp
, nam
, lph
))
529 lph
->lph_flag
|= LC_VACATED
;
530 else if ((lph
->lph_flag
& (LC_LOCAL
| LC_VACATED
)) == 0) {
531 if (lph
->lph_flag
& LC_UDP
) {
532 MGET(nam2
, M_WAIT
, MT_SONAME
);
533 saddr
= mtod(nam2
, struct sockaddr_in
*);
534 nam2
->m_len
= saddr
->sin_len
=
535 sizeof (struct sockaddr_in
);
536 saddr
->sin_family
= AF_INET
;
537 saddr
->sin_addr
.s_addr
= lph
->lph_inetaddr
;
538 saddr
->sin_port
= lph
->lph_port
;
539 so
= nfs_udpsock
->ns_so
;
540 } else if (lph
->lph_flag
& LC_CLTP
) {
542 so
= nfs_cltpsock
->ns_so
;
543 } else if (lph
->lph_slp
->ns_flag
& SLP_VALID
) {
544 nam2
= (struct mbuf
*)0;
545 so
= lph
->lph_slp
->ns_so
;
548 sotype
= so
->so_type
;
549 solock
= (so
->so_proto
->pr_flags
& PR_CONNREQUIRED
);
550 nfsm_reqhead((struct vnode
*)0, NQNFSPROC_EVICTED
,
551 NFSX_V3FH
+ NFSX_UNSIGNED
);
552 fhp
= &nfh
.fh_generic
;
553 bzero((caddr_t
)fhp
, sizeof(nfh
));
554 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
555 VFS_VPTOFH(vp
, &fhp
->fh_fid
);
556 nfsm_srvfhtom(fhp
, 1);
563 if (siz
<= 0 || siz
> NFS_MAXPACKET
) {
564 printf("mbuf siz=%d\n",siz
);
565 panic("Bad nfs svc reply");
567 m
= nfsm_rpchead(cred
, (NFSMNT_NFSV3
| NFSMNT_NQNFS
),
569 RPCAUTH_UNIX
, 5 * NFSX_UNSIGNED
, (char *)0,
570 0, (char *)NULL
, mreq
, siz
, &mheadend
, &xid
);
572 * For stream protocols, prepend a Sun RPC
575 if (sotype
== SOCK_STREAM
) {
576 M_PREPEND(m
, NFSX_UNSIGNED
, M_WAIT
);
577 *mtod(m
, u_long
*) = htonl(0x80000000 |
578 (m
->m_pkthdr
.len
- NFSX_UNSIGNED
));
580 if (((lph
->lph_flag
& (LC_UDP
| LC_CLTP
)) == 0 &&
581 (lph
->lph_slp
->ns_flag
& SLP_VALID
) == 0) ||
582 (solock
&& nfs_slplock(lph
->lph_slp
, 0) == 0)) {
585 (void) nfs_send(so
, nam2
, m
,
588 nfs_slpunlock(lph
->lph_slp
);
590 if (lph
->lph_flag
& LC_UDP
)
597 len
= LC_MOREHOSTSIZ
;
598 lph
= lphnext
->lpm_hosts
;
599 lphnext
= lphnext
->lpm_next
;
608 * Wait for the lease to expire.
609 * This will occur when all clients have sent "vacated" messages to
610 * this server OR when it expires do to timeout.
613 nqsrv_waitfor_expiry(lp
)
614 register struct nqlease
*lp
;
616 register struct nqhost
*lph
;
624 if (now
.tv_sec
> lp
->lc_expiry
)
627 lphnext
= lp
->lc_morehosts
;
631 while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
632 if ((lph
->lph_flag
& (LC_LOCAL
| LC_VACATED
)) == 0) {
633 lp
->lc_flag
|= LC_EXPIREDWANTED
;
634 (void) tsleep((caddr_t
)&lp
->lc_flag
, PSOCK
,
641 len
= LC_MOREHOSTSIZ
;
642 lph
= lphnext
->lpm_hosts
;
643 lphnext
= lphnext
->lpm_next
;
654 * Nqnfs server timer that maintains the server lease queue.
655 * Scan the lease queue for expired entries:
656 * - when one is found, wakeup anyone waiting for it
657 * else dequeue and free
662 register struct nqlease
*lp
;
663 register struct nqhost
*lph
;
664 struct nqlease
*nextlp
;
665 struct nqm
*lphnext
, *olphnext
;
671 for (lp
= nqtimerhead
.cqh_first
; lp
!= (void *)&nqtimerhead
;
673 if (lp
->lc_expiry
>= now
.tv_sec
)
675 nextlp
= lp
->lc_timer
.cqe_next
;
676 if (lp
->lc_flag
& LC_EXPIREDWANTED
) {
677 lp
->lc_flag
&= ~LC_EXPIREDWANTED
;
678 wakeup((caddr_t
)&lp
->lc_flag
);
679 } else if ((lp
->lc_flag
& (LC_LOCKED
| LC_WANTED
)) == 0) {
681 * Make a best effort at keeping a write caching lease long
682 * enough by not deleting it until it has been explicitly
683 * vacated or there have been no writes in the previous
684 * write_slack seconds since expiry and the nfsds are not
685 * all busy. The assumption is that if the nfsds are not
686 * all busy now (no queue of nfs requests), then the client
687 * would have been able to do at least one write to the
688 * file during the last write_slack seconds if it was still
689 * trying to push writes to the server.
691 if ((lp
->lc_flag
& (LC_WRITE
| LC_VACATED
)) == LC_WRITE
&&
692 ((lp
->lc_flag
& LC_WRITTEN
) || nfsd_waiting
== 0)) {
693 lp
->lc_flag
&= ~LC_WRITTEN
;
694 nqsrv_instimeq(lp
, nqsrv_writeslack
);
696 CIRCLEQ_REMOVE(&nqtimerhead
, lp
, lc_timer
);
697 LIST_REMOVE(lp
, lc_hash
);
699 * This soft reference may no longer be valid, but
700 * no harm done. The worst case is if the vnode was
701 * recycled and has another valid lease reference,
702 * which is dereferenced prematurely.
704 lp
->lc_vp
->v_lease
= (struct nqlease
*)0;
706 lphnext
= lp
->lc_morehosts
;
707 olphnext
= (struct nqm
*)0;
711 while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
712 if (lph
->lph_flag
& LC_CLTP
)
713 MFREE(lph
->lph_nam
, n
);
714 if (lph
->lph_flag
& LC_SREF
)
715 nfsrv_slpderef(lph
->lph_slp
);
718 FREE_ZONE((caddr_t
)olphnext
,
721 olphnext
= (struct nqm
*)0;
726 len
= LC_MOREHOSTSIZ
;
727 lph
= lphnext
->lpm_hosts
;
728 lphnext
= lphnext
->lpm_next
;
734 FREE_ZONE((caddr_t
)lp
,
735 sizeof (struct nqlease
), M_NQLEASE
);
737 FREE_ZONE((caddr_t
)olphnext
,
738 sizeof (struct nqm
), M_NQMHOST
);
739 nfsstats
.srvnqnfs_leases
--;
746 * Called from nfssvc_nfsd() for a getlease rpc request.
747 * Do the from/to xdr translation and call nqsrv_getlease() to
751 nqnfsrv_getlease(nfsd
, slp
, procp
, mrq
)
752 struct nfsrv_descript
*nfsd
;
753 struct nfssvc_sock
*slp
;
757 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
758 struct mbuf
*nam
= nfsd
->nd_nam
;
759 caddr_t dpos
= nfsd
->nd_dpos
;
760 struct ucred
*cred
= &nfsd
->nd_cr
;
761 register struct nfs_fattr
*fp
;
763 register struct vattr
*vap
= &va
;
773 struct mbuf
*mb
, *mb2
, *mreq
;
774 int flags
, rdonly
, cache
;
776 fhp
= &nfh
.fh_generic
;
778 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
779 flags
= fxdr_unsigned(int, *tl
++);
780 nfsd
->nd_duration
= fxdr_unsigned(int, *tl
);
781 error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
, &rdonly
,
782 (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
785 if (rdonly
&& flags
== ND_WRITE
) {
790 (void) nqsrv_getlease(vp
, &nfsd
->nd_duration
, flags
, slp
, procp
,
791 nam
, &cache
, &frev
, cred
);
792 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
794 nfsm_reply(NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
795 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
796 *tl
++ = txdr_unsigned(cache
);
797 *tl
++ = txdr_unsigned(nfsd
->nd_duration
);
798 txdr_hyper(&frev
, tl
);
799 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V3FATTR
);
800 nfsm_srvfillattr(vap
, fp
);
805 * Called from nfssvc_nfsd() when a "vacated" message is received from a
806 * client. Find the entry and expire it.
809 nqnfsrv_vacated(nfsd
, slp
, procp
, mrq
)
810 struct nfsrv_descript
*nfsd
;
811 struct nfssvc_sock
*slp
;
815 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
816 struct mbuf
*nam
= nfsd
->nd_nam
;
817 caddr_t dpos
= nfsd
->nd_dpos
;
818 register struct nqlease
*lp
;
819 register struct nqhost
*lph
;
820 struct nqlease
*tlp
= (struct nqlease
*)0;
826 struct mbuf
*mreq
, *mb
;
827 int error
= 0, i
, len
, ok
, gotit
= 0, cache
= 0;
831 fhp
= &nfh
.fh_generic
;
835 * Find the lease by searching the hash list.
837 for (lp
= NQFHHASH(fhp
->fh_fid
.fid_data
)->lh_first
; lp
!= 0;
838 lp
= lp
->lc_hash
.le_next
)
839 if (fhp
->fh_fsid
.val
[0] == lp
->lc_fsid
.val
[0] &&
840 fhp
->fh_fsid
.val
[1] == lp
->lc_fsid
.val
[1] &&
841 !bcmp(fhp
->fh_fid
.fid_data
, lp
->lc_fiddata
,
852 lphnext
= lp
->lc_morehosts
;
854 while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
855 if (nqsrv_cmpnam(slp
, nam
, lph
)) {
856 lph
->lph_flag
|= LC_VACATED
;
862 len
= LC_MOREHOSTSIZ
;
864 lph
= lphnext
->lpm_hosts
;
865 lphnext
= lphnext
->lpm_next
;
871 if ((lp
->lc_flag
& LC_EXPIREDWANTED
) && gotit
) {
872 lp
->lc_flag
&= ~LC_EXPIREDWANTED
;
873 wakeup((caddr_t
)&lp
->lc_flag
);
881 #endif /* NFS_NOSERVER */
884 * Client get lease rpc function.
887 nqnfs_getlease(vp
, rwflag
, cred
, p
)
888 register struct vnode
*vp
;
895 register long t1
, t2
;
896 register struct nfsnode
*np
;
897 struct nfsmount
*nmp
;
898 caddr_t bpos
, dpos
, cp2
;
902 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
907 nmp
= VFSTONFS(vp
->v_mount
);
911 nfsstats
.rpccnt
[NQNFSPROC_GETLEASE
]++;
912 mb
= mreq
= nfsm_reqh(vp
, NQNFSPROC_GETLEASE
, NFSX_V3FH
+2*NFSX_UNSIGNED
,
915 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
916 *tl
++ = txdr_unsigned(rwflag
);
917 *tl
= txdr_unsigned(nmp
->nm_leaseterm
);
919 reqtime
= now
.tv_sec
;
920 nfsm_request(vp
, NQNFSPROC_GETLEASE
, p
, cred
, &xid
);
922 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
923 cachable
= fxdr_unsigned(int, *tl
++);
924 reqtime
+= fxdr_unsigned(int, *tl
++);
926 if (reqtime
> now
.tv_sec
) {
927 nmp
= VFSTONFS(vp
->v_mount
);
931 fxdr_hyper(tl
, &frev
);
932 nqnfs_clientlease(nmp
, np
, rwflag
, cachable
,
934 nfsm_loadattr(vp
, (struct vattr
*)0, &xid
);
937 error
= NQNFS_EXPIRED
;
943 * Client vacated message function.
946 nqnfs_vacated(vp
, cred
)
947 register struct vnode
*vp
;
951 register struct mbuf
*m
;
958 struct mbuf
*mreq
, *mb
, *mb2
, *mheadend
;
959 struct nfsmount
*nmp
;
964 nmp
= VFSTONFS(vp
->v_mount
);
967 nfsstats
.rpccnt
[NQNFSPROC_VACATED
]++;
968 nfsm_reqhead(vp
, NQNFSPROC_VACATED
, NFSX_FH(1));
976 m
= nfsm_rpchead(cred
, nmp
->nm_flag
, NQNFSPROC_VACATED
,
977 RPCAUTH_UNIX
, 5 * NFSX_UNSIGNED
, (char *)0,
978 0, (char *)NULL
, mreq
, i
, &mheadend
, &xid
);
979 if (nmp
->nm_sotype
== SOCK_STREAM
) {
980 M_PREPEND(m
, NFSX_UNSIGNED
, M_WAIT
);
981 *mtod(m
, u_long
*) = htonl(0x80000000 | (m
->m_pkthdr
.len
-
987 connrequired
= (nmp
->nm_soflags
& PR_CONNREQUIRED
);
989 (void) nfs_sndlock(&myrep
);
991 (void) nfs_send(nmp
->nm_so
, nmp
->nm_nam
, m
, &myrep
);
994 nfs_sndunlock(&myrep
);
1002 * Called for client side callbacks
1005 nqnfs_callback(nmp
, mrep
, md
, dpos
)
1006 struct nfsmount
*nmp
;
1007 struct mbuf
*mrep
, *md
;
1010 register struct vnode
*vp
;
1011 register u_long
*tl
;
1017 struct nfssvc_sock
*slp
;
1018 struct nfsrv_descript ndesc
;
1019 register struct nfsrv_descript
*nfsd
= &ndesc
;
1020 struct mbuf
**mrq
= (struct mbuf
**)0, *mb
, *mreq
;
1021 int error
= 0, cache
= 0;
1028 nfsd
->nd_mrep
= mrep
;
1030 nfsd
->nd_dpos
= dpos
;
1031 error
= nfs_getreq(nfsd
, &tnfsd
, FALSE
);
1035 dpos
= nfsd
->nd_dpos
;
1036 if (nfsd
->nd_procnum
!= NQNFSPROC_EVICTED
) {
1040 fhp
= &nfh
.fh_generic
;
1043 error
= nfs_nget(nmp
->nm_mountp
, (nfsfh_t
*)fhp
, NFSX_V3FH
, &np
);
1047 if (np
->n_timer
.cqe_next
!= 0) {
1049 np
->n_flag
|= NQNFSEVICTED
;
1050 if (nmp
->nm_timerhead
.cqh_first
!= np
) {
1051 CIRCLEQ_REMOVE(&nmp
->nm_timerhead
, np
, n_timer
);
1052 CIRCLEQ_INSERT_HEAD(&nmp
->nm_timerhead
, np
, n_timer
);
1061 * Nqnfs client helper daemon. Runs once a second to expire leases.
1062 * It also get authorization strings for "kerb" mounts.
1063 * It must start at the beginning of the list again after any potential
1064 * "sleep" since nfs_reclaim() called from vclean() can pull a node off
1065 * the list asynchronously.
1068 nqnfs_clientd(nmp
, cred
, ncd
, flag
, argp
, p
)
1069 register struct nfsmount
*nmp
;
1071 struct nfsd_cargs
*ncd
;
1076 register struct nfsnode
*np
;
1078 struct nfsreq myrep
;
1079 struct nfsuid
*nuidp
, *nnuidp
;
1080 int error
= 0, vpid
;
1081 register struct nfsreq
*rp
;
1085 * First initialize some variables
1090 * If an authorization string is being passed in, get it.
1092 if ((flag
& NFSSVC_GOTAUTH
) &&
1093 (nmp
->nm_state
& (NFSSTA_WAITAUTH
| NFSSTA_DISMNT
)) == 0) {
1094 if (nmp
->nm_state
& NFSSTA_HASAUTH
)
1096 if ((flag
& NFSSVC_AUTHINFAIL
) == 0) {
1097 if (ncd
->ncd_authlen
<= nmp
->nm_authlen
&&
1098 ncd
->ncd_verflen
<= nmp
->nm_verflen
&&
1099 !copyin(ncd
->ncd_authstr
,nmp
->nm_authstr
,ncd
->ncd_authlen
)&&
1100 !copyin(ncd
->ncd_verfstr
,nmp
->nm_verfstr
,ncd
->ncd_verflen
)){
1101 nmp
->nm_authtype
= ncd
->ncd_authtype
;
1102 nmp
->nm_authlen
= ncd
->ncd_authlen
;
1103 nmp
->nm_verflen
= ncd
->ncd_verflen
;
1105 nmp
->nm_key
= ncd
->ncd_key
;
1108 nmp
->nm_state
|= NFSSTA_AUTHERR
;
1110 nmp
->nm_state
|= NFSSTA_AUTHERR
;
1111 nmp
->nm_state
|= NFSSTA_HASAUTH
;
1112 wakeup((caddr_t
)&nmp
->nm_authlen
);
1114 nmp
->nm_state
|= NFSSTA_WAITAUTH
;
1117 * Loop every second updating queue until there is a termination sig.
1119 while ((nmp
->nm_state
& NFSSTA_DISMNT
) == 0) {
1120 if (nmp
->nm_flag
& NFSMNT_NQNFS
) {
1122 * If there are no outstanding requests (and therefore no
1123 * processes in nfs_reply) and there is data in the receive
1124 * queue, poke for callbacks.
1126 if (nfs_reqq
.tqh_first
== 0 && nmp
->nm_so
&&
1127 nmp
->nm_so
->so_rcv
.sb_cc
> 0) {
1128 myrep
.r_flags
= R_GETONEREP
;
1130 myrep
.r_mrep
= (struct mbuf
*)0;
1131 myrep
.r_procp
= (struct proc
*)0;
1132 (void) nfs_reply(&myrep
);
1136 * Loop through the leases, updating as required.
1138 np
= nmp
->nm_timerhead
.cqh_first
;
1139 while (np
!= (void *)&nmp
->nm_timerhead
&&
1140 (nmp
->nm_state
& NFSSTA_DISMINPROG
) == 0) {
1143 if (np
->n_expiry
< now
.tv_sec
) {
1144 if (vget(vp
, LK_EXCLUSIVE
, p
) == 0) {
1145 nmp
->nm_inprog
= vp
;
1146 if (vpid
== vp
->v_id
) {
1147 CIRCLEQ_REMOVE(&nmp
->nm_timerhead
, np
, n_timer
);
1148 np
->n_timer
.cqe_next
= 0;
1149 if (np
->n_flag
& (NMODIFIED
| NQNFSEVICTED
)) {
1150 if (np
->n_flag
& NQNFSEVICTED
) {
1151 if (vp
->v_type
== VDIR
)
1154 (void) nfs_vinvalbuf(vp
,
1155 V_SAVE
, cred
, p
, 0);
1156 np
->n_flag
&= ~NQNFSEVICTED
;
1157 (void) nqnfs_vacated(vp
, cred
);
1158 } else if (vp
->v_type
== VREG
) {
1159 (void) VOP_FSYNC(vp
, cred
,
1161 np
->n_flag
&= ~NMODIFIED
;
1166 nmp
->nm_inprog
= NULLVP
;
1168 } else if ((np
->n_expiry
- NQ_RENEWAL
) < now
.tv_sec
) {
1169 if ((np
->n_flag
& (NQNFSWRITE
| NQNFSNONCACHE
))
1170 == NQNFSWRITE
&& np
->n_dirtyblkhd
.lh_first
&&
1171 vget(vp
, LK_EXCLUSIVE
, p
) == 0) {
1172 nmp
->nm_inprog
= vp
;
1173 if (vpid
== vp
->v_id
&&
1174 nqnfs_getlease(vp
, ND_WRITE
, cred
, p
)==0)
1175 np
->n_brev
= np
->n_lrev
;
1177 nmp
->nm_inprog
= NULLVP
;
1181 if (np
== nmp
->nm_timerhead
.cqh_first
)
1183 np
= nmp
->nm_timerhead
.cqh_first
;
1188 * Get an authorization string, if required.
1190 if ((nmp
->nm_state
& (NFSSTA_WAITAUTH
| NFSSTA_DISMNT
| NFSSTA_HASAUTH
)) == 0) {
1191 ncd
->ncd_authuid
= nmp
->nm_authuid
;
1192 if (copyout((caddr_t
)ncd
, argp
, sizeof (struct nfsd_cargs
)))
1193 nmp
->nm_state
|= NFSSTA_WAITAUTH
;
1199 * Wait a bit (no pun) and do it again.
1201 if ((nmp
->nm_state
& NFSSTA_DISMNT
) == 0 &&
1202 (nmp
->nm_state
& (NFSSTA_WAITAUTH
| NFSSTA_HASAUTH
))) {
1203 error
= tsleep((caddr_t
)&nmp
->nm_authstr
, PSOCK
| PCATCH
,
1204 "nqnfstimr", hz
/ 3);
1205 if (error
== EINTR
|| error
== ERESTART
)
1206 (void) dounmount(nmp
->nm_mountp
, 0, p
);
1211 * Finally, we can free up the mount structure.
1213 for (nuidp
= nmp
->nm_uidlruhead
.tqh_first
; nuidp
!= 0; nuidp
= nnuidp
) {
1214 nnuidp
= nuidp
->nu_lru
.tqe_next
;
1215 LIST_REMOVE(nuidp
, nu_hash
);
1216 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1217 FREE_ZONE((caddr_t
)nuidp
, sizeof (struct nfsuid
), M_NFSUID
);
1220 * Loop through outstanding request list and remove dangling
1221 * references to defunct nfsmount struct
1223 for (rp
= nfs_reqq
.tqh_first
; rp
; rp
= rp
->r_chain
.tqe_next
)
1224 if (rp
->r_nmp
== nmp
)
1225 rp
->r_nmp
= (struct nfsmount
*)0;
1226 FREE_ZONE((caddr_t
)nmp
, sizeof (struct nfsmount
), M_NFSMNT
);
1227 if (error
== EWOULDBLOCK
)
1232 #endif /* NFS_NOSERVER */
1235 * Adjust all timer queue expiry times when the time of day clock is changed.
1236 * Called from the settimeofday() syscall.
1239 nqnfs_lease_updatetime(deltat
)
1240 register int deltat
;
1242 struct proc
*p
= current_proc(); /* XXX */
1245 struct mount
*mp
, *nxtmp
;
1246 struct nfsmount
*nmp
;
1249 if (nqnfsstarttime
!= 0)
1250 nqnfsstarttime
+= deltat
;
1252 for (lp
= nqtimerhead
.cqh_first
; lp
!= (void *)&nqtimerhead
;
1253 lp
= lp
->lc_timer
.cqe_next
)
1254 lp
->lc_expiry
+= deltat
;
1258 * Search the mount list for all nqnfs mounts and do their timer
1261 simple_lock(&mountlist_slock
);
1262 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nxtmp
) {
1263 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
1264 nxtmp
= mp
->mnt_list
.cqe_next
;
1267 if (mp
->mnt_stat
.f_type
== nfs_mount_type
) {
1269 if (nmp
->nm_flag
& NFSMNT_NQNFS
) {
1270 for (np
= nmp
->nm_timerhead
.cqh_first
;
1271 np
!= (void *)&nmp
->nm_timerhead
;
1272 np
= np
->n_timer
.cqe_next
) {
1273 np
->n_expiry
+= deltat
;
1277 simple_lock(&mountlist_slock
);
1278 nxtmp
= mp
->mnt_list
.cqe_next
;
1281 simple_unlock(&mountlist_slock
);
1285 * Lock a server lease.
1292 while (lp
->lc_flag
& LC_LOCKED
) {
1293 lp
->lc_flag
|= LC_WANTED
;
1294 (void) tsleep((caddr_t
)lp
, PSOCK
, "nqlc", 0);
1296 lp
->lc_flag
|= LC_LOCKED
;
1297 lp
->lc_flag
&= ~LC_WANTED
;
1301 * Unlock a server lease.
1304 nqsrv_unlocklease(lp
)
1308 lp
->lc_flag
&= ~LC_LOCKED
;
1309 if (lp
->lc_flag
& LC_WANTED
)
1310 wakeup((caddr_t
)lp
);
1314 * Update a client lease.
1317 nqnfs_clientlease(nmp
, np
, rwflag
, cachable
, expiry
, frev
)
1318 register struct nfsmount
*nmp
;
1319 register struct nfsnode
*np
;
1320 int rwflag
, cachable
;
1324 register struct nfsnode
*tp
;
1326 if (np
->n_timer
.cqe_next
!= 0) {
1327 CIRCLEQ_REMOVE(&nmp
->nm_timerhead
, np
, n_timer
);
1328 if (rwflag
== ND_WRITE
)
1329 np
->n_flag
|= NQNFSWRITE
;
1330 } else if (rwflag
== ND_READ
)
1331 np
->n_flag
&= ~NQNFSWRITE
;
1333 np
->n_flag
|= NQNFSWRITE
;
1335 np
->n_flag
&= ~NQNFSNONCACHE
;
1337 np
->n_flag
|= NQNFSNONCACHE
;
1338 np
->n_expiry
= expiry
;
1340 tp
= nmp
->nm_timerhead
.cqh_last
;
1341 while (tp
!= (void *)&nmp
->nm_timerhead
&& tp
->n_expiry
> np
->n_expiry
)
1342 tp
= tp
->n_timer
.cqe_prev
;
1343 if (tp
== (void *)&nmp
->nm_timerhead
) {
1344 CIRCLEQ_INSERT_HEAD(&nmp
->nm_timerhead
, np
, n_timer
);
1346 CIRCLEQ_INSERT_AFTER(&nmp
->nm_timerhead
, tp
, np
, n_timer
);