1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)nfs_nqlease.c 7.8 (Berkeley) 07/02/92 11 */ 12 13 /* 14 * References: 15 * Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant 16 * Mechanism for Distributed File Cache Consistency", 17 * In Proc. of the Twelfth ACM Symposium on Operating Systems 18 * Principals, pg. 202-210, Litchfield Park, AZ, Dec. 1989. 19 * Michael N. Nelson, Brent B. Welch and John K. Ousterhout, "Caching 20 * in the Sprite Network File System", ACM TOCS 6(1), 21 * pages 134-154, February 1988. 22 * V. Srinivasan and Jeffrey C. Mogul, "Spritely NFS: Implementation and 23 * Performance of Cache-Consistency Protocols", Digital 24 * Equipment Corporation WRL Research Report 89/5, May 1989. 25 */ 26 #include <sys/param.h> 27 #include <sys/vnode.h> 28 #include <sys/mount.h> 29 #include <sys/kernel.h> 30 #include <sys/proc.h> 31 #include <sys/systm.h> 32 #include <sys/mbuf.h> 33 #include <sys/socket.h> 34 #include <sys/socketvar.h> 35 #include <sys/file.h> 36 #include <sys/buf.h> 37 #include <sys/stat.h> 38 #include <sys/protosw.h> 39 #include <netinet/in.h> 40 #include <nfs/rpcv2.h> 41 #include <nfs/nfsv2.h> 42 #include <nfs/nfs.h> 43 #include <nfs/nfsm_subs.h> 44 #include <nfs/xdr_subs.h> 45 #include <nfs/nqnfs.h> 46 #include <nfs/nfsnode.h> 47 #include <nfs/nfsmount.h> 48 49 /* 50 * List head for the lease queue and other global data. 51 * At any time a lease is linked into a list ordered by increasing expiry time. 52 */ 53 #if ((NQLCHSZ&(NQLCHSZ-1)) == 0) 54 #define NQFHHASH(f) ((*((u_long *)(f)))&(NQLCHSZ-1)) 55 #else 56 #define NQFHHASH(f) ((*((u_long *)(f)))%NQLCHSZ) 57 #endif 58 59 union nqsrvthead nqthead; 60 union nqsrvthead nqfhead[NQLCHSZ]; 61 time_t nqnfsstarttime = (time_t)0; 62 u_long nqnfs_prog, nqnfs_vers; 63 int nqsrv_clockskew = NQ_CLOCKSKEW; 64 int nqsrv_writeslack = NQ_WRITESLACK; 65 int nqsrv_maxlease = NQ_MAXLEASE; 66 int nqsrv_maxnumlease = NQ_MAXNUMLEASE; 67 void nqsrv_instimeq(), nqsrv_send_eviction(), nfs_sndunlock(); 68 void nqsrv_unlocklease(), nqsrv_waitfor_expiry(), nfsrv_slpderef(); 69 void nqsrv_addhost(), nqsrv_locklease(), nqnfs_serverd(); 70 struct mbuf *nfsm_rpchead(); 71 72 /* 73 * Signifies which rpcs can have piggybacked lease requests 74 */ 75 int nqnfs_piggy[NFS_NPROCS] = { 76 0, 77 NQL_READ, 78 NQL_WRITE, 79 0, 80 NQL_READ, 81 NQL_READ, 82 NQL_READ, 83 0, 84 NQL_WRITE, 85 0, 86 0, 87 0, 88 0, 89 0, 90 0, 91 0, 92 NQL_READ, 93 0, 94 NQL_READ, 95 0, 96 0, 97 0, 98 }; 99 100 int nnnnnn = sizeof (struct nqlease); 101 int oooooo = sizeof (struct nfsnode); 102 extern nfstype nfs_type[9]; 103 extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; 104 extern struct nfsd nfsd_head; 105 extern int nfsd_waiting; 106 107 #define TRUE 1 108 #define FALSE 0 109 110 /* 111 * Get or check for a lease for "vp", based on NQL_CHECK flag. 112 * The rules are as follows: 113 * - if a current non-caching lease, reply non-caching 114 * - if a current lease for same host only, extend lease 115 * - if a read cachable lease and a read lease request 116 * add host to list any reply cachable 117 * - else { set non-cachable for read-write sharing } 118 * send eviction notice messages to all other hosts that have lease 119 * wait for lease termination { either by receiving vacated messages 120 * from all the other hosts or expiry 121 * via. timeout } 122 * modify lease to non-cachable 123 * - else if no current lease, issue new one 124 * - reply 125 * - return boolean TRUE iff nam should be m_freem()'d 126 * NB: Since nqnfs_serverd() is called from a timer, any potential tsleep() 127 * in here must be framed by nqsrv_locklease() and nqsrv_unlocklease(). 128 * nqsrv_locklease() is coded such that at least one of LC_LOCKED and 129 * LC_WANTED is set whenever a process is tsleeping in it. The exception 130 * is when a new lease is being allocated, since it is not in the timer 131 * queue yet. (Ditto for the splsoftclock() and splx(s) calls) 132 */ 133 nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) 134 struct vnode *vp; 135 u_long *duration; 136 int flags; 137 struct nfsd *nd; 138 struct mbuf *nam; 139 int *cachablep; 140 u_quad_t *frev; 141 struct ucred *cred; 142 { 143 USES_VOP_GETATTR; 144 USES_VOP_LOCK; 145 USES_VOP_UNLOCK; 146 register struct nqlease *lp; 147 register struct nqhost *lph; 148 struct nqlease *tlp = (struct nqlease *)0; 149 struct nqm **lphp; 150 struct vattr vattr; 151 union nqsrvthead *lhp; 152 fhandle_t fh; 153 int i, ok, error, s; 154 155 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 156 return (0); 157 if (*duration > nqsrv_maxlease) 158 *duration = nqsrv_maxlease; 159 if (error = VOP_GETATTR(vp, &vattr, cred, nd->nd_procp)) 160 return (error); 161 *frev = vattr.va_filerev; 162 s = splsoftclock(); 163 tlp = vp->v_lease; 164 if ((flags & NQL_CHECK) == 0) 165 nfsstats.srvnqnfs_getleases++; 166 if (tlp == (struct nqlease *)0) { 167 168 /* 169 * Find the lease by searching the hash list. 170 */ 171 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 172 if (error = VFS_VPTOFH(vp, &fh.fh_fid)) { 173 splx(s); 174 return (error); 175 } 176 lhp = &nqfhead[NQFHHASH(fh.fh_fid.fid_data)]; 177 for (lp = lhp->th_chain[0]; lp != (struct nqlease *)lhp; 178 lp = lp->lc_fhnext) 179 if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] && 180 fh.fh_fsid.val[1] == lp->lc_fsid.val[1] && 181 !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata, 182 fh.fh_fid.fid_len - sizeof (long))) { 183 /* Found it */ 184 lp->lc_vp = vp; 185 vp->v_lease = lp; 186 tlp = lp; 187 break; 188 } 189 } 190 lp = tlp; 191 if (lp) { 192 if ((lp->lc_flag & LC_NONCACHABLE) || 193 (lp->lc_morehosts == (struct nqm *)0 && 194 nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host))) 195 goto doreply; 196 if ((flags & NQL_READ) && (lp->lc_flag & LC_WRITE)==0) { 197 if (flags & NQL_CHECK) 198 goto doreply; 199 if (nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host)) 200 goto doreply; 201 i = 0; 202 if (lp->lc_morehosts) { 203 lph = lp->lc_morehosts->lpm_hosts; 204 lphp = &lp->lc_morehosts->lpm_next; 205 ok = 1; 206 } else { 207 lphp = &lp->lc_morehosts; 208 ok = 0; 209 } 210 while (ok && (lph->lph_flag & LC_VALID)) { 211 if (nqsrv_cmpnam(nd->nd_slp, nam, lph)) 212 goto doreply; 213 if (++i == LC_MOREHOSTSIZ) { 214 i = 0; 215 if (*lphp) { 216 lph = (*lphp)->lpm_hosts; 217 lphp = &((*lphp)->lpm_next); 218 } else 219 ok = 0; 220 } else 221 lph++; 222 } 223 nqsrv_locklease(lp); 224 if (!ok) { 225 *lphp = (struct nqm *) 226 malloc(sizeof (struct nqm), 227 M_NQMHOST, M_WAITOK); 228 bzero((caddr_t)*lphp, sizeof (struct nqm)); 229 lph = (*lphp)->lpm_hosts; 230 } 231 nqsrv_addhost(lph, nd->nd_slp, nam); 232 nqsrv_unlocklease(lp); 233 } else { 234 lp->lc_flag |= LC_NONCACHABLE; 235 nqsrv_locklease(lp); 236 VOP_UNLOCK(vp); 237 nqsrv_send_eviction(vp, lp, nd->nd_slp, nam, cred); 238 nqsrv_waitfor_expiry(lp); 239 VOP_LOCK(vp); 240 nqsrv_unlocklease(lp); 241 } 242 doreply: 243 /* 244 * Update the lease and return 245 */ 246 if ((flags & NQL_CHECK) == 0) 247 nqsrv_instimeq(lp, *duration); 248 if (lp->lc_flag & LC_NONCACHABLE) 249 *cachablep = 0; 250 else { 251 *cachablep = 1; 252 if (flags & NQL_WRITE) 253 lp->lc_flag |= LC_WRITTEN; 254 } 255 splx(s); 256 return (0); 257 } 258 splx(s); 259 if (flags & NQL_CHECK) 260 return (0); 261 262 /* 263 * Allocate new lease 264 * The value of nqsrv_maxnumlease should be set generously, so that 265 * the following "printf" happens infrequently. 266 */ 267 if (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease) { 268 printf("Nqnfs server, too many leases\n"); 269 do { 270 (void) tsleep((caddr_t)&lbolt, PSOCK, 271 "nqsrvnuml", 0); 272 } while (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease); 273 } 274 MALLOC(lp, struct nqlease *, sizeof (struct nqlease), M_NQLEASE, M_WAITOK); 275 bzero((caddr_t)lp, sizeof (struct nqlease)); 276 if (flags & NQL_WRITE) 277 lp->lc_flag |= (LC_WRITE | LC_WRITTEN); 278 nqsrv_addhost(&lp->lc_host, nd->nd_slp, nam); 279 lp->lc_vp = vp; 280 lp->lc_fsid = fh.fh_fsid; 281 bcopy(fh.fh_fid.fid_data, lp->lc_fiddata, fh.fh_fid.fid_len - sizeof (long)); 282 lp->lc_fhnext = lhp->th_chain[0]; 283 if (lhp->th_head[0] == lhp) 284 lhp->th_chain[1] = lp; 285 else 286 lhp->th_chain[0]->lc_fhprev = lp; 287 lp->lc_fhprev = (struct nqlease *)lhp; 288 lhp->th_chain[0] = lp; 289 vp->v_lease = lp; 290 s = splsoftclock(); 291 nqsrv_instimeq(lp, *duration); 292 splx(s); 293 *cachablep = 1; 294 if (++nfsstats.srvnqnfs_leases > nfsstats.srvnqnfs_maxleases) 295 nfsstats.srvnqnfs_maxleases = nfsstats.srvnqnfs_leases; 296 return (0); 297 } 298 299 /* 300 * Local lease check for server syscalls. 301 * Just set up args and let nqsrv_getlease() do the rest. 302 */ 303 void 304 lease_check(vp, p, cred, flag) 305 struct vnode *vp; 306 struct proc *p; 307 struct ucred *cred; 308 int flag; 309 { 310 int duration, cache; 311 struct nfsd nfsd; 312 u_quad_t frev; 313 314 nfsd.nd_slp = NQLOCALSLP; 315 nfsd.nd_procp = p; 316 (void) nqsrv_getlease(vp, &duration, NQL_CHECK | flag, &nfsd, 317 (struct mbuf *)0, &cache, &frev, cred); 318 } 319 320 /* 321 * Add a host to an nqhost structure for a lease. 322 */ 323 void 324 nqsrv_addhost(lph, slp, nam) 325 register struct nqhost *lph; 326 struct nfssvc_sock *slp; 327 struct mbuf *nam; 328 { 329 register struct sockaddr_in *saddr; 330 331 if (slp == NQLOCALSLP) 332 lph->lph_flag |= (LC_VALID | LC_LOCAL); 333 else if (slp == nfs_udpsock) { 334 saddr = mtod(nam, struct sockaddr_in *); 335 lph->lph_flag |= (LC_VALID | LC_UDP); 336 lph->lph_inetaddr = saddr->sin_addr.s_addr; 337 lph->lph_port = saddr->sin_port; 338 } else if (slp == nfs_cltpsock) { 339 lph->lph_nam = m_copym(nam, 0, M_COPYALL, M_WAIT); 340 lph->lph_flag |= (LC_VALID | LC_CLTP); 341 } else { 342 lph->lph_flag |= (LC_VALID | LC_SREF); 343 lph->lph_slp = slp; 344 slp->ns_sref++; 345 } 346 } 347 348 /* 349 * Update the lease expiry time and position it in the timer queue correctly. 350 */ 351 void 352 nqsrv_instimeq(lp, duration) 353 register struct nqlease *lp; 354 u_long duration; 355 { 356 register struct nqlease *tlp; 357 time_t newexpiry; 358 359 newexpiry = time.tv_sec + duration + nqsrv_clockskew; 360 if (lp->lc_expiry == newexpiry) 361 return; 362 if (lp->lc_chain1[0]) 363 remque(lp); 364 lp->lc_expiry = newexpiry; 365 366 /* 367 * Find where in the queue it should be. 368 */ 369 tlp = nqthead.th_chain[1]; 370 while (tlp->lc_expiry > newexpiry && tlp != (struct nqlease *)&nqthead) 371 tlp = tlp->lc_chain1[1]; 372 if (tlp == nqthead.th_chain[1]) 373 NQSTORENOVRAM(newexpiry); 374 insque(lp, tlp); 375 } 376 377 /* 378 * Compare the requesting host address with the lph entry in the lease. 379 * Return true iff it is the same. 380 * This is somewhat messy due to the union in the nqhost structure. 381 * The local host is indicated by the special value of NQLOCALSLP for slp. 382 */ 383 nqsrv_cmpnam(slp, nam, lph) 384 register struct nfssvc_sock *slp; 385 struct mbuf *nam; 386 register struct nqhost *lph; 387 { 388 register struct sockaddr_in *saddr; 389 struct mbuf *addr; 390 union nethostaddr lhaddr; 391 int ret; 392 393 if (slp == NQLOCALSLP) { 394 if (lph->lph_flag & LC_LOCAL) 395 return (1); 396 else 397 return (0); 398 } 399 if (slp == nfs_udpsock || slp == nfs_cltpsock) 400 addr = nam; 401 else 402 addr = slp->ns_nam; 403 if (lph->lph_flag & LC_UDP) 404 ret = netaddr_match(AF_INET, &lph->lph_haddr, 405 (union nethostaddr *)0, addr); 406 else if (lph->lph_flag & LC_CLTP) 407 ret = netaddr_match(AF_ISO, &lph->lph_claddr, 408 (union nethostaddr *)0, addr); 409 else { 410 if ((lph->lph_slp->ns_flag & SLP_VALID) == 0) 411 return (0); 412 saddr = mtod(lph->lph_slp->ns_nam, struct sockaddr_in *); 413 if (saddr->sin_family == AF_INET) 414 lhaddr.had_inetaddr = saddr->sin_addr.s_addr; 415 else 416 lhaddr.had_nam = lph->lph_slp->ns_nam; 417 ret = netaddr_match(saddr->sin_family, &lhaddr, 418 (union nethostaddr *)0, addr); 419 } 420 return (ret); 421 } 422 423 /* 424 * Send out eviction notice messages to all other hosts for the lease. 425 */ 426 void 427 nqsrv_send_eviction(vp, lp, slp, nam, cred) 428 struct vnode *vp; 429 register struct nqlease *lp; 430 struct nfssvc_sock *slp; 431 struct mbuf *nam; 432 struct ucred *cred; 433 { 434 register struct nqhost *lph = &lp->lc_host; 435 register struct mbuf *m; 436 register int siz; 437 struct nqm *lphnext = lp->lc_morehosts; 438 struct mbuf *mreq, *mb, *mb2, *nam2, *mheadend; 439 struct socket *so; 440 struct sockaddr_in *saddr; 441 fhandle_t *fhp; 442 caddr_t bpos, cp; 443 u_long xid; 444 int len = 1, ok = 1, i = 0; 445 int sotype, *solockp; 446 447 while (ok && (lph->lph_flag & LC_VALID)) { 448 if (nqsrv_cmpnam(slp, nam, lph)) 449 lph->lph_flag |= LC_VACATED; 450 else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) { 451 if (lph->lph_flag & LC_UDP) { 452 MGET(nam2, M_WAIT, MT_SONAME); 453 saddr = mtod(nam2, struct sockaddr_in *); 454 nam2->m_len = saddr->sin_len = 455 sizeof (struct sockaddr_in); 456 saddr->sin_family = AF_INET; 457 saddr->sin_addr.s_addr = lph->lph_inetaddr; 458 saddr->sin_port = lph->lph_port; 459 so = nfs_udpsock->ns_so; 460 } else if (lph->lph_flag & LC_CLTP) { 461 nam2 = lph->lph_nam; 462 so = nfs_cltpsock->ns_so; 463 } else if (lph->lph_slp->ns_flag & SLP_VALID) { 464 nam2 = (struct mbuf *)0; 465 so = lph->lph_slp->ns_so; 466 } else 467 goto nextone; 468 sotype = so->so_type; 469 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 470 solockp = &lph->lph_slp->ns_solock; 471 else 472 solockp = (int *)0; 473 nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED, 474 NFSX_FH); 475 nfsm_build(cp, caddr_t, NFSX_FH); 476 bzero(cp, NFSX_FH); 477 fhp = (fhandle_t *)cp; 478 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 479 VFS_VPTOFH(vp, &fhp->fh_fid); 480 m = mreq; 481 siz = 0; 482 while (m) { 483 siz += m->m_len; 484 m = m->m_next; 485 } 486 if (siz <= 0 || siz > NFS_MAXPACKET) { 487 printf("mbuf siz=%d\n",siz); 488 panic("Bad nfs svc reply"); 489 } 490 m = nfsm_rpchead(cred, TRUE, NQNFSPROC_EVICTED, 491 RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0, 492 mreq, siz, &mheadend, &xid); 493 /* 494 * For stream protocols, prepend a Sun RPC 495 * Record Mark. 496 */ 497 if (sotype == SOCK_STREAM) { 498 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 499 *mtod(m, u_long *) = htonl(0x80000000 | 500 (m->m_pkthdr.len - NFSX_UNSIGNED)); 501 } 502 if (((lph->lph_flag & (LC_UDP | LC_CLTP)) == 0 && 503 (lph->lph_slp->ns_flag & SLP_VALID) == 0) || 504 (solockp && (*solockp & NFSMNT_SNDLOCK))) 505 m_freem(m); 506 else { 507 if (solockp) 508 *solockp |= NFSMNT_SNDLOCK; 509 (void) nfs_send(so, nam2, m, 510 (struct nfsreq *)0); 511 if (solockp) 512 nfs_sndunlock(solockp); 513 } 514 if (lph->lph_flag & LC_UDP) 515 MFREE(nam2, m); 516 } 517 nextone: 518 if (++i == len) { 519 if (lphnext) { 520 i = 0; 521 len = LC_MOREHOSTSIZ; 522 lph = lphnext->lpm_hosts; 523 lphnext = lphnext->lpm_next; 524 } else 525 ok = 0; 526 } else 527 lph++; 528 } 529 } 530 531 /* 532 * Wait for the lease to expire. 533 * This will occur when all clients have sent "vacated" messages to 534 * this server OR when it expires do to timeout. 535 */ 536 void 537 nqsrv_waitfor_expiry(lp) 538 register struct nqlease *lp; 539 { 540 register struct nqhost *lph; 541 register int i; 542 struct nqm *lphnext; 543 int len, ok; 544 545 tryagain: 546 if (time.tv_sec > lp->lc_expiry) 547 return; 548 lph = &lp->lc_host; 549 lphnext = lp->lc_morehosts; 550 len = 1; 551 i = 0; 552 ok = 1; 553 while (ok && (lph->lph_flag & LC_VALID)) { 554 if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) { 555 lp->lc_flag |= LC_EXPIREDWANTED; 556 (void) tsleep((caddr_t)&lp->lc_flag, PSOCK, 557 "nqexp", 0); 558 goto tryagain; 559 } 560 if (++i == len) { 561 if (lphnext) { 562 i = 0; 563 len = LC_MOREHOSTSIZ; 564 lph = lphnext->lpm_hosts; 565 lphnext = lphnext->lpm_next; 566 } else 567 ok = 0; 568 } else 569 lph++; 570 } 571 } 572 573 /* 574 * Nqnfs server timer that maintains the server lease queue. 575 * Scan the lease queue for expired entries: 576 * - when one is found, wakeup anyone waiting for it 577 * else dequeue and free 578 */ 579 void 580 nqnfs_serverd() 581 { 582 register struct nqlease *lp; 583 register struct nqhost *lph; 584 struct nqlease *nextlp; 585 struct nqm *lphnext, *olphnext; 586 struct mbuf *n; 587 union nqsrvthead *lhp; 588 int i, len, ok; 589 590 lp = nqthead.th_chain[0]; 591 while (lp != (struct nqlease *)&nqthead) { 592 if (lp->lc_expiry >= time.tv_sec) 593 break; 594 nextlp = lp->lc_chain1[0]; 595 if (lp->lc_flag & LC_EXPIREDWANTED) { 596 lp->lc_flag &= ~LC_EXPIREDWANTED; 597 wakeup((caddr_t)&lp->lc_flag); 598 } else if ((lp->lc_flag & (LC_LOCKED | LC_WANTED)) == 0) { 599 /* 600 * Make a best effort at keeping a write caching lease long 601 * enough by not deleting it until it has been explicitly 602 * vacated or there have been no writes in the previous 603 * write_slack seconds since expiry and the nfsds are not 604 * all busy. The assumption is that if the nfsds are not 605 * all busy now (no queue of nfs requests), then the client 606 * would have been able to do at least one write to the 607 * file during the last write_slack seconds if it was still 608 * trying to push writes to the server. 609 */ 610 if ((lp->lc_flag & (LC_WRITE | LC_VACATED)) == LC_WRITE && 611 ((lp->lc_flag & LC_WRITTEN) || nfsd_waiting == 0)) { 612 lp->lc_flag &= ~LC_WRITTEN; 613 nqsrv_instimeq(lp, nqsrv_writeslack); 614 } else { 615 remque(lp); 616 lhp = &nqfhead[NQFHHASH(lp->lc_fiddata)]; 617 if (lp->lc_fhprev == (struct nqlease *)lhp) 618 lhp->th_chain[0] = lp->lc_fhnext; 619 else 620 lp->lc_fhprev->lc_fhnext = lp->lc_fhnext; 621 if (lp->lc_fhnext == (struct nqlease *)lhp) 622 lhp->th_chain[1] = lp->lc_fhprev; 623 else 624 lp->lc_fhnext->lc_fhprev = lp->lc_fhprev; 625 /* 626 * This soft reference may no longer be valid, but 627 * no harm done. The worst case is if the vnode was 628 * recycled and has another valid lease reference, 629 * which is dereferenced prematurely. 630 */ 631 lp->lc_vp->v_lease = (struct nqlease *)0; 632 lph = &lp->lc_host; 633 lphnext = lp->lc_morehosts; 634 olphnext = (struct nqm *)0; 635 len = 1; 636 i = 0; 637 ok = 1; 638 while (ok && (lph->lph_flag & LC_VALID)) { 639 if (lph->lph_flag & LC_CLTP) 640 MFREE(lph->lph_nam, n); 641 if (lph->lph_flag & LC_SREF) 642 nfsrv_slpderef(lph->lph_slp); 643 if (++i == len) { 644 if (olphnext) { 645 free((caddr_t)olphnext, M_NQMHOST); 646 olphnext = (struct nqm *)0; 647 } 648 if (lphnext) { 649 olphnext = lphnext; 650 i = 0; 651 len = LC_MOREHOSTSIZ; 652 lph = lphnext->lpm_hosts; 653 lphnext = lphnext->lpm_next; 654 } else 655 ok = 0; 656 } else 657 lph++; 658 } 659 FREE((caddr_t)lp, M_NQLEASE); 660 if (olphnext) 661 free((caddr_t)olphnext, M_NQMHOST); 662 nfsstats.srvnqnfs_leases--; 663 } 664 } 665 lp = nextlp; 666 } 667 } 668 669 /* 670 * Called from nfssvc_nfsd() for a getlease rpc request. 671 * Do the from/to xdr translation and call nqsrv_getlease() to 672 * do the real work. 673 */ 674 nqnfsrv_getlease(nfsd, mrep, md, dpos, cred, nam, mrq) 675 struct nfsd *nfsd; 676 struct mbuf *mrep, *md; 677 caddr_t dpos; 678 struct ucred *cred; 679 struct mbuf *nam, **mrq; 680 { 681 USES_VOP_GETATTR; 682 register struct nfsv2_fattr *fp; 683 struct vattr va; 684 register struct vattr *vap = &va; 685 struct vnode *vp; 686 nfsv2fh_t nfh; 687 fhandle_t *fhp; 688 register u_long *tl; 689 register long t1; 690 u_quad_t frev; 691 caddr_t bpos; 692 int error = 0; 693 char *cp2; 694 struct mbuf *mb, *mb2, *mreq; 695 int flags, rdonly, cache; 696 697 fhp = &nfh.fh_generic; 698 nfsm_srvmtofh(fhp); 699 nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 700 flags = fxdr_unsigned(int, *tl++); 701 nfsd->nd_duration = fxdr_unsigned(int, *tl); 702 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 703 nfsm_reply(0); 704 if (rdonly && flags == NQL_WRITE) { 705 error = EROFS; 706 nfsm_reply(0); 707 } 708 (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, nfsd, 709 nam, &cache, &frev, cred); 710 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 711 vput(vp); 712 nfsm_reply(NFSX_FATTR + 4*NFSX_UNSIGNED); 713 nfsm_build(tl, u_long *, 4*NFSX_UNSIGNED); 714 *tl++ = txdr_unsigned(cache); 715 *tl++ = txdr_unsigned(nfsd->nd_duration); 716 txdr_hyper(&frev, tl); 717 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 718 nfsm_srvfillattr; 719 nfsm_srvdone; 720 } 721 722 /* 723 * Called from nfssvc_nfsd() when a "vacated" message is received from a 724 * client. Find the entry and expire it. 725 */ 726 nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq) 727 struct nfsd *nfsd; 728 struct mbuf *mrep, *md; 729 caddr_t dpos; 730 struct ucred *cred; 731 struct mbuf *nam, **mrq; 732 { 733 register struct nqlease *lp; 734 register struct nqhost *lph; 735 struct nqlease *tlp = (struct nqlease *)0; 736 struct vnode *vp; 737 nfsv2fh_t nfh; 738 fhandle_t *fhp; 739 register u_long *tl; 740 register long t1; 741 struct nqm *lphnext; 742 union nqsrvthead *lhp; 743 u_quad_t frev; 744 int error = 0, i, len, ok, rdonly, gotit = 0; 745 char *cp2; 746 747 fhp = &nfh.fh_generic; 748 nfsm_srvmtofh(fhp); 749 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 750 return (error); 751 m_freem(mrep); 752 tlp = vp->v_lease; 753 if (tlp == (struct nqlease *)0) { 754 /* 755 * Find the lease by searching the hash list. 756 */ 757 lhp = &nqfhead[NQFHHASH(fhp->fh_fid.fid_data)]; 758 for (lp = lhp->th_chain[0]; lp != (struct nqlease *)lhp; 759 lp = lp->lc_fhnext) 760 if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] && 761 fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] && 762 !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata, 763 MAXFIDSZ)) { 764 /* Found it */ 765 lp->lc_vp = vp; 766 vp->v_lease = lp; 767 tlp = lp; 768 break; 769 } 770 } 771 vrele(vp); 772 if (tlp) { 773 lp = tlp; 774 len = 1; 775 i = 0; 776 lph = &lp->lc_host; 777 lphnext = lp->lc_morehosts; 778 ok = 1; 779 while (ok && (lph->lph_flag & LC_VALID)) { 780 if (nqsrv_cmpnam(nfsd->nd_slp, nam, lph)) { 781 lph->lph_flag |= LC_VACATED; 782 gotit++; 783 break; 784 } 785 if (++i == len) { 786 if (lphnext) { 787 len = LC_MOREHOSTSIZ; 788 i = 0; 789 lph = lphnext->lpm_hosts; 790 lphnext = lphnext->lpm_next; 791 } else 792 ok = 0; 793 } else 794 lph++; 795 } 796 if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) { 797 lp->lc_flag &= ~LC_EXPIREDWANTED; 798 wakeup((caddr_t)&lp->lc_flag); 799 } 800 nfsmout: 801 return (EPERM); 802 } 803 return (EPERM); 804 } 805 806 /* 807 * Client get lease rpc function. 808 */ 809 nqnfs_getlease(vp, rwflag, cred, p) 810 register struct vnode *vp; 811 int rwflag; 812 struct ucred *cred; 813 struct proc *p; 814 { 815 register u_long *tl; 816 register caddr_t cp; 817 register long t1; 818 register struct nfsnode *np, *tp; 819 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 820 caddr_t bpos, dpos, cp2; 821 time_t reqtime; 822 int error = 0; 823 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 824 int cachable; 825 826 nfsstats.rpccnt[NQNFSPROC_GETLEASE]++; 827 mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_FH+2*NFSX_UNSIGNED, 828 &bpos); 829 nfsm_fhtom(vp); 830 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 831 *tl++ = txdr_unsigned(rwflag); 832 *tl = txdr_unsigned(nmp->nm_leaseterm); 833 reqtime = time.tv_sec; 834 nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred); 835 np = VTONFS(vp); 836 nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 837 cachable = fxdr_unsigned(int, *tl++); 838 reqtime += fxdr_unsigned(int, *tl++); 839 if (reqtime > time.tv_sec) { 840 if (np->n_tnext) { 841 if (np->n_tnext == (struct nfsnode *)nmp) 842 nmp->nm_tprev = np->n_tprev; 843 else 844 np->n_tnext->n_tprev = np->n_tprev; 845 if (np->n_tprev == (struct nfsnode *)nmp) 846 nmp->nm_tnext = np->n_tnext; 847 else 848 np->n_tprev->n_tnext = np->n_tnext; 849 if (rwflag == NQL_WRITE) 850 np->n_flag |= NQNFSWRITE; 851 } else if (rwflag == NQL_READ) 852 np->n_flag &= ~NQNFSWRITE; 853 else 854 np->n_flag |= NQNFSWRITE; 855 if (cachable) 856 np->n_flag &= ~NQNFSNONCACHE; 857 else 858 np->n_flag |= NQNFSNONCACHE; 859 np->n_expiry = reqtime; 860 fxdr_hyper(tl, &np->n_lrev); 861 tp = nmp->nm_tprev; 862 while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 863 tp = tp->n_tprev; 864 if (tp == (struct nfsnode *)nmp) { 865 np->n_tnext = nmp->nm_tnext; 866 nmp->nm_tnext = np; 867 } else { 868 np->n_tnext = tp->n_tnext; 869 tp->n_tnext = np; 870 } 871 np->n_tprev = tp; 872 if (np->n_tnext == (struct nfsnode *)nmp) 873 nmp->nm_tprev = np; 874 else 875 np->n_tnext->n_tprev = np; 876 nfsm_loadattr(vp, (struct vattr *)0); 877 } else 878 error = NQNFS_EXPIRED; 879 nfsm_reqdone; 880 return (error); 881 } 882 883 /* 884 * Client vacated message function. 885 */ 886 nqnfs_vacated(vp, cred) 887 register struct vnode *vp; 888 struct ucred *cred; 889 { 890 register caddr_t cp; 891 register struct mbuf *m; 892 register int i; 893 caddr_t bpos; 894 u_long xid; 895 int error = 0; 896 struct mbuf *mreq, *mb, *mb2, *mheadend; 897 struct nfsmount *nmp; 898 struct nfsreq myrep; 899 900 nmp = VFSTONFS(vp->v_mount); 901 nfsstats.rpccnt[NQNFSPROC_VACATED]++; 902 nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH); 903 nfsm_fhtom(vp); 904 m = mreq; 905 i = 0; 906 while (m) { 907 i += m->m_len; 908 m = m->m_next; 909 } 910 m = nfsm_rpchead(cred, TRUE, NQNFSPROC_VACATED, 911 RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0, 912 mreq, i, &mheadend, &xid); 913 if (nmp->nm_sotype == SOCK_STREAM) { 914 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 915 *mtod(m, u_long *) = htonl(0x80000000 | (m->m_pkthdr.len - 916 NFSX_UNSIGNED)); 917 } 918 myrep.r_flags = 0; 919 myrep.r_nmp = nmp; 920 if (nmp->nm_soflags & PR_CONNREQUIRED) 921 (void) nfs_sndlock(&nmp->nm_flag, (struct nfsreq *)0); 922 (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep); 923 if (nmp->nm_soflags & PR_CONNREQUIRED) 924 nfs_sndunlock(&nmp->nm_flag); 925 return (error); 926 } 927 928 /* 929 * Called for client side callbacks 930 */ 931 nqnfs_callback(nmp, mrep, md, dpos) 932 struct nfsmount *nmp; 933 struct mbuf *mrep, *md; 934 caddr_t dpos; 935 { 936 register struct vnode *vp; 937 register u_long *tl; 938 register long t1; 939 nfsv2fh_t nfh; 940 fhandle_t *fhp; 941 struct nfsnode *np; 942 struct nfsd nd; 943 int error; 944 char *cp2; 945 946 nd.nd_mrep = mrep; 947 nd.nd_md = md; 948 nd.nd_dpos = dpos; 949 if (error = nfs_getreq(&nd, FALSE)) 950 return (error); 951 md = nd.nd_md; 952 dpos = nd.nd_dpos; 953 if (nd.nd_procnum != NQNFSPROC_EVICTED) { 954 m_freem(mrep); 955 return (EPERM); 956 } 957 fhp = &nfh.fh_generic; 958 nfsm_srvmtofh(fhp); 959 m_freem(mrep); 960 if (error = nfs_nget(nmp->nm_mountp, fhp, &np)) 961 return (error); 962 vp = NFSTOV(np); 963 if (np->n_tnext) { 964 np->n_expiry = 0; 965 np->n_flag |= NQNFSEVICTED; 966 if (np->n_tprev != (struct nfsnode *)nmp) { 967 if (np->n_tnext == (struct nfsnode *)nmp) 968 nmp->nm_tprev = np->n_tprev; 969 else 970 np->n_tnext->n_tprev = np->n_tprev; 971 np->n_tprev->n_tnext = np->n_tnext; 972 np->n_tnext = nmp->nm_tnext; 973 nmp->nm_tnext = np; 974 np->n_tprev = (struct nfsnode *)nmp; 975 if (np->n_tnext == (struct nfsnode *)nmp) 976 nmp->nm_tprev = np; 977 else 978 np->n_tnext->n_tprev = np; 979 } 980 } 981 vrele(vp); 982 nfsm_srvdone; 983 } 984 985 /* 986 * Nqnfs client helper daemon. Runs once a second to expire leases. 987 * It also get authorization strings for "kerb" mounts. 988 * It must start at the beginning of the list again after any potential 989 * "sleep" since nfs_reclaim() called from vclean() can pull a node off 990 * the list asynchronously. 991 */ 992 nqnfs_clientd(nmp, cred, ncd, flag, argp, p) 993 register struct nfsmount *nmp; 994 struct ucred *cred; 995 struct nfsd_cargs *ncd; 996 int flag; 997 caddr_t argp; 998 struct proc *p; 999 { 1000 USES_VOP_FSYNC; 1001 register struct nfsnode *np; 1002 struct vnode *vp; 1003 int error, vpid; 1004 1005 /* 1006 * First initialize some variables 1007 */ 1008 nqnfs_prog = txdr_unsigned(NQNFS_PROG); 1009 nqnfs_vers = txdr_unsigned(NQNFS_VER1); 1010 1011 /* 1012 * If an authorization string is being passed in, get it. 1013 */ 1014 if ((flag & NFSSVC_GOTAUTH) && 1015 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) { 1016 if (nmp->nm_flag & NFSMNT_HASAUTH) 1017 panic("cld kerb"); 1018 if ((flag & NFSSVC_AUTHINFAIL) == 0) { 1019 if (ncd->ncd_authlen <= RPCAUTH_MAXSIZ && 1020 copyin(ncd->ncd_authstr, nmp->nm_authstr, 1021 ncd->ncd_authlen) == 0) { 1022 nmp->nm_authtype = ncd->ncd_authtype; 1023 nmp->nm_authlen = ncd->ncd_authlen; 1024 } else 1025 nmp->nm_flag |= NFSMNT_AUTHERR; 1026 } else 1027 nmp->nm_flag |= NFSMNT_AUTHERR; 1028 nmp->nm_flag |= NFSMNT_HASAUTH; 1029 wakeup((caddr_t)&nmp->nm_authlen); 1030 } else 1031 nmp->nm_flag |= NFSMNT_WAITAUTH; 1032 1033 /* 1034 * Loop every second updating queue until there is a termination sig. 1035 */ 1036 while ((nmp->nm_flag & NFSMNT_DISMNT) == 0) { 1037 if (nmp->nm_flag & NFSMNT_NQNFS) { 1038 np = nmp->nm_tnext; 1039 while (np != (struct nfsnode *)nmp && 1040 (nmp->nm_flag & NFSMNT_DISMINPROG) == 0) { 1041 vp = NFSTOV(np); 1042 if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash2"); 1043 vpid = vp->v_id; 1044 if (np->n_expiry < time.tv_sec) { 1045 if (vget(vp) == 0) { 1046 nmp->nm_inprog = vp; 1047 if (vpid == vp->v_id) { 1048 if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash3"); 1049 if (np->n_tnext == (struct nfsnode *)nmp) 1050 nmp->nm_tprev = np->n_tprev; 1051 else 1052 np->n_tnext->n_tprev = np->n_tprev; 1053 if (np->n_tprev == (struct nfsnode *)nmp) 1054 nmp->nm_tnext = np->n_tnext; 1055 else 1056 np->n_tprev->n_tnext = np->n_tnext; 1057 np->n_tnext = (struct nfsnode *)0; 1058 if ((np->n_flag & (NMODIFIED | NQNFSEVICTED)) 1059 && vp->v_type == VREG) { 1060 np->n_flag &= ~NMODIFIED; 1061 if (np->n_flag & NQNFSEVICTED) { 1062 (void) vinvalbuf(vp, TRUE, 1063 cred, p); 1064 np->n_flag &= ~NQNFSEVICTED; 1065 (void) nqnfs_vacated(vp, cred); 1066 } else 1067 (void) VOP_FSYNC(vp, cred, 1068 MNT_WAIT, p); 1069 } 1070 } 1071 vrele(vp); 1072 nmp->nm_inprog = NULLVP; 1073 } 1074 if (np != nmp->nm_tnext) 1075 np = nmp->nm_tnext; 1076 else 1077 break; 1078 } else if ((np->n_expiry - NQ_RENEWAL) < time.tv_sec) { 1079 if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE)) 1080 == NQNFSWRITE && vp->v_dirtyblkhd && 1081 vget(vp) == 0) { 1082 nmp->nm_inprog = vp; 1083 if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4"); 1084 if (vpid == vp->v_id && 1085 nqnfs_getlease(vp, NQL_WRITE, cred, p)==0) 1086 np->n_brev = np->n_lrev; 1087 vrele(vp); 1088 nmp->nm_inprog = NULLVP; 1089 } 1090 if (np != nmp->nm_tnext) 1091 np = nmp->nm_tnext; 1092 else 1093 break; 1094 } else 1095 break; 1096 } 1097 } 1098 1099 /* 1100 * Get an authorization string, if required. 1101 */ 1102 if ((nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT | NFSMNT_HASAUTH)) == 0) { 1103 ncd->ncd_authuid = nmp->nm_authuid; 1104 if (copyout((caddr_t)ncd, argp, sizeof (*ncd))) 1105 nmp->nm_flag |= NFSMNT_WAITAUTH; 1106 else 1107 return (ENEEDAUTH); 1108 } 1109 1110 /* 1111 * Wait a bit (no pun) and do it again. 1112 */ 1113 if ((nmp->nm_flag & NFSMNT_DISMNT) == 0 && 1114 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_HASAUTH))) { 1115 error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH, 1116 "nqnfstimr", hz / 3); 1117 if (error == EINTR || error == ERESTART) 1118 (void) dounmount(nmp->nm_mountp, MNT_NOFORCE); 1119 } 1120 } 1121 free((caddr_t)nmp, M_NFSMNT); 1122 if (error == EWOULDBLOCK) 1123 error = 0; 1124 return (error); 1125 } 1126 1127 /* 1128 * Adjust all timer queue expiry times when the time of day clock is changed. 1129 * Called from the settimeofday() syscall. 1130 */ 1131 void 1132 lease_updatetime(deltat) 1133 register int deltat; 1134 { 1135 register struct nqlease *lp; 1136 register struct nfsnode *np; 1137 struct mount *mp; 1138 struct nfsmount *nmp; 1139 int s; 1140 1141 if (nqnfsstarttime != 0) 1142 nqnfsstarttime += deltat; 1143 s = splsoftclock(); 1144 lp = nqthead.th_chain[0]; 1145 while (lp != (struct nqlease *)&nqthead) { 1146 lp->lc_expiry += deltat; 1147 lp = lp->lc_chain1[0]; 1148 } 1149 splx(s); 1150 1151 /* 1152 * Search the mount list for all nqnfs mounts and do their timer 1153 * queues. 1154 */ 1155 mp = rootfs; 1156 do { 1157 if (mp->mnt_stat.f_fsid.val[1] == MOUNT_NFS) { 1158 nmp = VFSTONFS(mp); 1159 if (nmp->nm_flag & NFSMNT_NQNFS) { 1160 np = nmp->nm_tnext; 1161 while (np != (struct nfsnode *)nmp) { 1162 np->n_expiry += deltat; 1163 np = np->n_tnext; 1164 } 1165 } 1166 } 1167 mp = mp->mnt_next; 1168 } while (mp != rootfs); 1169 } 1170 1171 /* 1172 * Lock a server lease. 1173 */ 1174 void 1175 nqsrv_locklease(lp) 1176 struct nqlease *lp; 1177 { 1178 1179 while (lp->lc_flag & LC_LOCKED) { 1180 lp->lc_flag |= LC_WANTED; 1181 (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0); 1182 } 1183 lp->lc_flag |= LC_LOCKED; 1184 lp->lc_flag &= ~LC_WANTED; 1185 } 1186 1187 /* 1188 * Unlock a server lease. 1189 */ 1190 void 1191 nqsrv_unlocklease(lp) 1192 struct nqlease *lp; 1193 { 1194 1195 lp->lc_flag &= ~LC_LOCKED; 1196 if (lp->lc_flag & LC_WANTED) 1197 wakeup((caddr_t)lp); 1198 } 1199