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