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