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