|
|
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.