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