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.15 (Berkeley) 11/01/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 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 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 register struct nqlease *lp, *lq, **lpp; 144 register struct nqhost *lph; 145 struct nqlease *tlp; 146 struct nqm **lphp; 147 struct vattr vattr; 148 fhandle_t fh; 149 int i, ok, error, s; 150 151 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 152 return (0); 153 if (*duration > nqsrv_maxlease) 154 *duration = nqsrv_maxlease; 155 if (error = VOP_GETATTR(vp, &vattr, cred, nd->nd_procp)) 156 return (error); 157 *frev = vattr.va_filerev; 158 s = splsoftclock(); 159 tlp = vp->v_lease; 160 if ((flags & NQL_CHECK) == 0) 161 nfsstats.srvnqnfs_getleases++; 162 if (tlp == (struct nqlease *)0) { 163 164 /* 165 * Find the lease by searching the hash list. 166 */ 167 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 168 if (error = VFS_VPTOFH(vp, &fh.fh_fid)) { 169 splx(s); 170 return (error); 171 } 172 lpp = &nqfhead[NQFHHASH(fh.fh_fid.fid_data)]; 173 for (lp = *lpp; lp; lp = lp->lc_fhnext) 174 if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] && 175 fh.fh_fsid.val[1] == lp->lc_fsid.val[1] && 176 !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata, 177 fh.fh_fid.fid_len - sizeof (long))) { 178 /* Found it */ 179 lp->lc_vp = vp; 180 vp->v_lease = lp; 181 tlp = lp; 182 break; 183 } 184 } 185 lp = tlp; 186 if (lp) { 187 if ((lp->lc_flag & LC_NONCACHABLE) || 188 (lp->lc_morehosts == (struct nqm *)0 && 189 nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host))) 190 goto doreply; 191 if ((flags & NQL_READ) && (lp->lc_flag & LC_WRITE)==0) { 192 if (flags & NQL_CHECK) 193 goto doreply; 194 if (nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host)) 195 goto doreply; 196 i = 0; 197 if (lp->lc_morehosts) { 198 lph = lp->lc_morehosts->lpm_hosts; 199 lphp = &lp->lc_morehosts->lpm_next; 200 ok = 1; 201 } else { 202 lphp = &lp->lc_morehosts; 203 ok = 0; 204 } 205 while (ok && (lph->lph_flag & LC_VALID)) { 206 if (nqsrv_cmpnam(nd->nd_slp, nam, lph)) 207 goto doreply; 208 if (++i == LC_MOREHOSTSIZ) { 209 i = 0; 210 if (*lphp) { 211 lph = (*lphp)->lpm_hosts; 212 lphp = &((*lphp)->lpm_next); 213 } else 214 ok = 0; 215 } else 216 lph++; 217 } 218 nqsrv_locklease(lp); 219 if (!ok) { 220 *lphp = (struct nqm *) 221 malloc(sizeof (struct nqm), 222 M_NQMHOST, M_WAITOK); 223 bzero((caddr_t)*lphp, sizeof (struct nqm)); 224 lph = (*lphp)->lpm_hosts; 225 } 226 nqsrv_addhost(lph, nd->nd_slp, nam); 227 nqsrv_unlocklease(lp); 228 } else { 229 lp->lc_flag |= LC_NONCACHABLE; 230 nqsrv_locklease(lp); 231 VOP_UNLOCK(vp); 232 nqsrv_send_eviction(vp, lp, nd->nd_slp, nam, cred); 233 nqsrv_waitfor_expiry(lp); 234 VOP_LOCK(vp); 235 nqsrv_unlocklease(lp); 236 } 237 doreply: 238 /* 239 * Update the lease and return 240 */ 241 if ((flags & NQL_CHECK) == 0) 242 nqsrv_instimeq(lp, *duration); 243 if (lp->lc_flag & LC_NONCACHABLE) 244 *cachablep = 0; 245 else { 246 *cachablep = 1; 247 if (flags & NQL_WRITE) 248 lp->lc_flag |= LC_WRITTEN; 249 } 250 splx(s); 251 return (0); 252 } 253 splx(s); 254 if (flags & NQL_CHECK) 255 return (0); 256 257 /* 258 * Allocate new lease 259 * The value of nqsrv_maxnumlease should be set generously, so that 260 * the following "printf" happens infrequently. 261 */ 262 if (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease) { 263 printf("Nqnfs server, too many leases\n"); 264 do { 265 (void) tsleep((caddr_t)&lbolt, PSOCK, 266 "nqsrvnuml", 0); 267 } while (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease); 268 } 269 MALLOC(lp, struct nqlease *, sizeof (struct nqlease), M_NQLEASE, M_WAITOK); 270 bzero((caddr_t)lp, sizeof (struct nqlease)); 271 if (flags & NQL_WRITE) 272 lp->lc_flag |= (LC_WRITE | LC_WRITTEN); 273 nqsrv_addhost(&lp->lc_host, nd->nd_slp, nam); 274 lp->lc_vp = vp; 275 lp->lc_fsid = fh.fh_fsid; 276 bcopy(fh.fh_fid.fid_data, lp->lc_fiddata, fh.fh_fid.fid_len - sizeof (long)); 277 if (lq = *lpp) 278 lq->lc_fhprev = &lp->lc_fhnext; 279 lp->lc_fhnext = lq; 280 lp->lc_fhprev = lpp; 281 *lpp = lp; 282 vp->v_lease = lp; 283 s = splsoftclock(); 284 nqsrv_instimeq(lp, *duration); 285 splx(s); 286 *cachablep = 1; 287 if (++nfsstats.srvnqnfs_leases > nfsstats.srvnqnfs_maxleases) 288 nfsstats.srvnqnfs_maxleases = nfsstats.srvnqnfs_leases; 289 return (0); 290 } 291 292 /* 293 * Local lease check for server syscalls. 294 * Just set up args and let nqsrv_getlease() do the rest. 295 */ 296 void 297 lease_check(vp, p, cred, flag) 298 struct vnode *vp; 299 struct proc *p; 300 struct ucred *cred; 301 int flag; 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 = p; 309 (void) nqsrv_getlease(vp, &duration, NQL_CHECK | flag, &nfsd, 310 (struct mbuf *)0, &cache, &frev, cred); 311 } 312 313 /* 314 * Add a host to an nqhost structure for a lease. 315 */ 316 void 317 nqsrv_addhost(lph, slp, nam) 318 register struct nqhost *lph; 319 struct nfssvc_sock *slp; 320 struct mbuf *nam; 321 { 322 register struct sockaddr_in *saddr; 323 324 if (slp == NQLOCALSLP) 325 lph->lph_flag |= (LC_VALID | LC_LOCAL); 326 else if (slp == nfs_udpsock) { 327 saddr = mtod(nam, struct sockaddr_in *); 328 lph->lph_flag |= (LC_VALID | LC_UDP); 329 lph->lph_inetaddr = saddr->sin_addr.s_addr; 330 lph->lph_port = saddr->sin_port; 331 } else if (slp == nfs_cltpsock) { 332 lph->lph_nam = m_copym(nam, 0, M_COPYALL, M_WAIT); 333 lph->lph_flag |= (LC_VALID | LC_CLTP); 334 } else { 335 lph->lph_flag |= (LC_VALID | LC_SREF); 336 lph->lph_slp = slp; 337 slp->ns_sref++; 338 } 339 } 340 341 /* 342 * Update the lease expiry time and position it in the timer queue correctly. 343 */ 344 void 345 nqsrv_instimeq(lp, duration) 346 register struct nqlease *lp; 347 u_long duration; 348 { 349 register struct nqlease *tlp; 350 time_t newexpiry; 351 352 newexpiry = time.tv_sec + duration + nqsrv_clockskew; 353 if (lp->lc_expiry == newexpiry) 354 return; 355 if (lp->lc_chain1[0]) 356 remque(lp); 357 lp->lc_expiry = newexpiry; 358 359 /* 360 * Find where in the queue it should be. 361 */ 362 tlp = nqthead.th_chain[1]; 363 while (tlp->lc_expiry > newexpiry && tlp != (struct nqlease *)&nqthead) 364 tlp = tlp->lc_chain1[1]; 365 if (tlp == nqthead.th_chain[1]) 366 NQSTORENOVRAM(newexpiry); 367 insque(lp, tlp); 368 } 369 370 /* 371 * Compare the requesting host address with the lph entry in the lease. 372 * Return true iff it is the same. 373 * This is somewhat messy due to the union in the nqhost structure. 374 * The local host is indicated by the special value of NQLOCALSLP for slp. 375 */ 376 nqsrv_cmpnam(slp, nam, lph) 377 register struct nfssvc_sock *slp; 378 struct mbuf *nam; 379 register struct nqhost *lph; 380 { 381 register struct sockaddr_in *saddr; 382 struct mbuf *addr; 383 union nethostaddr lhaddr; 384 int ret; 385 386 if (slp == NQLOCALSLP) { 387 if (lph->lph_flag & LC_LOCAL) 388 return (1); 389 else 390 return (0); 391 } 392 if (slp == nfs_udpsock || slp == nfs_cltpsock) 393 addr = nam; 394 else 395 addr = slp->ns_nam; 396 if (lph->lph_flag & LC_UDP) 397 ret = netaddr_match(AF_INET, &lph->lph_haddr, addr); 398 else if (lph->lph_flag & LC_CLTP) 399 ret = netaddr_match(AF_ISO, &lph->lph_claddr, addr); 400 else { 401 if ((lph->lph_slp->ns_flag & SLP_VALID) == 0) 402 return (0); 403 saddr = mtod(lph->lph_slp->ns_nam, struct sockaddr_in *); 404 if (saddr->sin_family == AF_INET) 405 lhaddr.had_inetaddr = saddr->sin_addr.s_addr; 406 else 407 lhaddr.had_nam = lph->lph_slp->ns_nam; 408 ret = netaddr_match(saddr->sin_family, &lhaddr, addr); 409 } 410 return (ret); 411 } 412 413 /* 414 * Send out eviction notice messages to all other hosts for the lease. 415 */ 416 void 417 nqsrv_send_eviction(vp, lp, slp, nam, cred) 418 struct vnode *vp; 419 register struct nqlease *lp; 420 struct nfssvc_sock *slp; 421 struct mbuf *nam; 422 struct ucred *cred; 423 { 424 register struct nqhost *lph = &lp->lc_host; 425 register struct mbuf *m; 426 register int siz; 427 struct nqm *lphnext = lp->lc_morehosts; 428 struct mbuf *mreq, *mb, *mb2, *nam2, *mheadend; 429 struct socket *so; 430 struct sockaddr_in *saddr; 431 fhandle_t *fhp; 432 caddr_t bpos, cp; 433 u_long xid; 434 int len = 1, ok = 1, i = 0; 435 int sotype, *solockp; 436 437 while (ok && (lph->lph_flag & LC_VALID)) { 438 if (nqsrv_cmpnam(slp, nam, lph)) 439 lph->lph_flag |= LC_VACATED; 440 else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) { 441 if (lph->lph_flag & LC_UDP) { 442 MGET(nam2, M_WAIT, MT_SONAME); 443 saddr = mtod(nam2, struct sockaddr_in *); 444 nam2->m_len = saddr->sin_len = 445 sizeof (struct sockaddr_in); 446 saddr->sin_family = AF_INET; 447 saddr->sin_addr.s_addr = lph->lph_inetaddr; 448 saddr->sin_port = lph->lph_port; 449 so = nfs_udpsock->ns_so; 450 } else if (lph->lph_flag & LC_CLTP) { 451 nam2 = lph->lph_nam; 452 so = nfs_cltpsock->ns_so; 453 } else if (lph->lph_slp->ns_flag & SLP_VALID) { 454 nam2 = (struct mbuf *)0; 455 so = lph->lph_slp->ns_so; 456 } else 457 goto nextone; 458 sotype = so->so_type; 459 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 460 solockp = &lph->lph_slp->ns_solock; 461 else 462 solockp = (int *)0; 463 nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED, 464 NFSX_FH); 465 nfsm_build(cp, caddr_t, NFSX_FH); 466 bzero(cp, NFSX_FH); 467 fhp = (fhandle_t *)cp; 468 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 469 VFS_VPTOFH(vp, &fhp->fh_fid); 470 m = mreq; 471 siz = 0; 472 while (m) { 473 siz += m->m_len; 474 m = m->m_next; 475 } 476 if (siz <= 0 || siz > NFS_MAXPACKET) { 477 printf("mbuf siz=%d\n",siz); 478 panic("Bad nfs svc reply"); 479 } 480 m = nfsm_rpchead(cred, TRUE, NQNFSPROC_EVICTED, 481 RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0, 482 mreq, siz, &mheadend, &xid); 483 /* 484 * For stream protocols, prepend a Sun RPC 485 * Record Mark. 486 */ 487 if (sotype == SOCK_STREAM) { 488 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 489 *mtod(m, u_long *) = htonl(0x80000000 | 490 (m->m_pkthdr.len - NFSX_UNSIGNED)); 491 } 492 if (((lph->lph_flag & (LC_UDP | LC_CLTP)) == 0 && 493 (lph->lph_slp->ns_flag & SLP_VALID) == 0) || 494 (solockp && (*solockp & NFSMNT_SNDLOCK))) 495 m_freem(m); 496 else { 497 if (solockp) 498 *solockp |= NFSMNT_SNDLOCK; 499 (void) nfs_send(so, nam2, m, 500 (struct nfsreq *)0); 501 if (solockp) 502 nfs_sndunlock(solockp); 503 } 504 if (lph->lph_flag & LC_UDP) 505 MFREE(nam2, m); 506 } 507 nextone: 508 if (++i == len) { 509 if (lphnext) { 510 i = 0; 511 len = LC_MOREHOSTSIZ; 512 lph = lphnext->lpm_hosts; 513 lphnext = lphnext->lpm_next; 514 } else 515 ok = 0; 516 } else 517 lph++; 518 } 519 } 520 521 /* 522 * Wait for the lease to expire. 523 * This will occur when all clients have sent "vacated" messages to 524 * this server OR when it expires do to timeout. 525 */ 526 void 527 nqsrv_waitfor_expiry(lp) 528 register struct nqlease *lp; 529 { 530 register struct nqhost *lph; 531 register int i; 532 struct nqm *lphnext; 533 int len, ok; 534 535 tryagain: 536 if (time.tv_sec > lp->lc_expiry) 537 return; 538 lph = &lp->lc_host; 539 lphnext = lp->lc_morehosts; 540 len = 1; 541 i = 0; 542 ok = 1; 543 while (ok && (lph->lph_flag & LC_VALID)) { 544 if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) { 545 lp->lc_flag |= LC_EXPIREDWANTED; 546 (void) tsleep((caddr_t)&lp->lc_flag, PSOCK, 547 "nqexp", 0); 548 goto tryagain; 549 } 550 if (++i == len) { 551 if (lphnext) { 552 i = 0; 553 len = LC_MOREHOSTSIZ; 554 lph = lphnext->lpm_hosts; 555 lphnext = lphnext->lpm_next; 556 } else 557 ok = 0; 558 } else 559 lph++; 560 } 561 } 562 563 /* 564 * Nqnfs server timer that maintains the server lease queue. 565 * Scan the lease queue for expired entries: 566 * - when one is found, wakeup anyone waiting for it 567 * else dequeue and free 568 */ 569 void 570 nqnfs_serverd() 571 { 572 register struct nqlease *lp, *lq; 573 register struct nqhost *lph; 574 struct nqlease *nextlp; 575 struct nqm *lphnext, *olphnext; 576 struct mbuf *n; 577 union nqsrvthead *lhp; 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, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 686 nfsm_reply(0); 687 if (rdonly && flags == NQL_WRITE) { 688 error = EROFS; 689 nfsm_reply(0); 690 } 691 (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, nfsd, 692 nam, &cache, &frev, cred); 693 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 694 vput(vp); 695 nfsm_reply(NFSX_NQFATTR + 4*NFSX_UNSIGNED); 696 nfsm_build(tl, u_long *, 4*NFSX_UNSIGNED); 697 *tl++ = txdr_unsigned(cache); 698 *tl++ = txdr_unsigned(nfsd->nd_duration); 699 txdr_hyper(&frev, tl); 700 nfsm_build(fp, struct nfsv2_fattr *, NFSX_NQFATTR); 701 nfsm_srvfillattr; 702 nfsm_srvdone; 703 } 704 705 /* 706 * Called from nfssvc_nfsd() when a "vacated" message is received from a 707 * client. Find the entry and expire it. 708 */ 709 nqnfsrv_vacated(nfsd, mrep, md, dpos, cred, nam, mrq) 710 struct nfsd *nfsd; 711 struct mbuf *mrep, *md; 712 caddr_t dpos; 713 struct ucred *cred; 714 struct mbuf *nam, **mrq; 715 { 716 register struct nqlease *lp; 717 register struct nqhost *lph; 718 struct nqlease *tlp = (struct nqlease *)0; 719 struct vnode *vp; 720 nfsv2fh_t nfh; 721 fhandle_t *fhp; 722 register u_long *tl; 723 register long t1; 724 struct nqm *lphnext; 725 union nqsrvthead *lhp; 726 u_quad_t frev; 727 int error = 0, i, len, ok, rdonly, gotit = 0; 728 char *cp2; 729 730 fhp = &nfh.fh_generic; 731 nfsm_srvmtofh(fhp); 732 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 733 return (error); 734 m_freem(mrep); 735 tlp = vp->v_lease; 736 if (tlp == (struct nqlease *)0) { 737 /* 738 * Find the lease by searching the hash list. 739 */ 740 for (lp = nqfhead[NQFHHASH(fhp->fh_fid.fid_data)]; lp; 741 lp = lp->lc_fhnext) 742 if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] && 743 fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] && 744 !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata, 745 MAXFIDSZ)) { 746 /* Found it */ 747 lp->lc_vp = vp; 748 vp->v_lease = lp; 749 tlp = lp; 750 break; 751 } 752 } 753 vrele(vp); 754 if (tlp) { 755 lp = tlp; 756 len = 1; 757 i = 0; 758 lph = &lp->lc_host; 759 lphnext = lp->lc_morehosts; 760 ok = 1; 761 while (ok && (lph->lph_flag & LC_VALID)) { 762 if (nqsrv_cmpnam(nfsd->nd_slp, nam, lph)) { 763 lph->lph_flag |= LC_VACATED; 764 gotit++; 765 break; 766 } 767 if (++i == len) { 768 if (lphnext) { 769 len = LC_MOREHOSTSIZ; 770 i = 0; 771 lph = lphnext->lpm_hosts; 772 lphnext = lphnext->lpm_next; 773 } else 774 ok = 0; 775 } else 776 lph++; 777 } 778 if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) { 779 lp->lc_flag &= ~LC_EXPIREDWANTED; 780 wakeup((caddr_t)&lp->lc_flag); 781 } 782 nfsmout: 783 return (EPERM); 784 } 785 return (EPERM); 786 } 787 788 /* 789 * Client get lease rpc function. 790 */ 791 nqnfs_getlease(vp, rwflag, cred, p) 792 register struct vnode *vp; 793 int rwflag; 794 struct ucred *cred; 795 struct proc *p; 796 { 797 register u_long *tl; 798 register caddr_t cp; 799 register long t1; 800 register struct nfsnode *np, *tp; 801 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 802 caddr_t bpos, dpos, cp2; 803 time_t reqtime; 804 int error = 0; 805 struct mbuf *mreq, *mrep, *md, *mb, *mb2; 806 int cachable; 807 u_quad_t frev; 808 809 nfsstats.rpccnt[NQNFSPROC_GETLEASE]++; 810 mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_FH+2*NFSX_UNSIGNED, 811 &bpos); 812 nfsm_fhtom(vp); 813 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 814 *tl++ = txdr_unsigned(rwflag); 815 *tl = txdr_unsigned(nmp->nm_leaseterm); 816 reqtime = time.tv_sec; 817 nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred); 818 np = VTONFS(vp); 819 nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 820 cachable = fxdr_unsigned(int, *tl++); 821 reqtime += fxdr_unsigned(int, *tl++); 822 if (reqtime > time.tv_sec) { 823 fxdr_hyper(tl, &frev); 824 nqnfs_clientlease(nmp, np, rwflag, cachable, reqtime, frev); 825 nfsm_loadattr(vp, (struct vattr *)0); 826 } else 827 error = NQNFS_EXPIRED; 828 nfsm_reqdone; 829 return (error); 830 } 831 832 /* 833 * Client vacated message function. 834 */ 835 nqnfs_vacated(vp, cred) 836 register struct vnode *vp; 837 struct ucred *cred; 838 { 839 register caddr_t cp; 840 register struct mbuf *m; 841 register int i; 842 caddr_t bpos; 843 u_long xid; 844 int error = 0; 845 struct mbuf *mreq, *mb, *mb2, *mheadend; 846 struct nfsmount *nmp; 847 struct nfsreq myrep; 848 849 nmp = VFSTONFS(vp->v_mount); 850 nfsstats.rpccnt[NQNFSPROC_VACATED]++; 851 nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH); 852 nfsm_fhtom(vp); 853 m = mreq; 854 i = 0; 855 while (m) { 856 i += m->m_len; 857 m = m->m_next; 858 } 859 m = nfsm_rpchead(cred, TRUE, NQNFSPROC_VACATED, 860 RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0, 861 mreq, i, &mheadend, &xid); 862 if (nmp->nm_sotype == SOCK_STREAM) { 863 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT); 864 *mtod(m, u_long *) = htonl(0x80000000 | (m->m_pkthdr.len - 865 NFSX_UNSIGNED)); 866 } 867 myrep.r_flags = 0; 868 myrep.r_nmp = nmp; 869 if (nmp->nm_soflags & PR_CONNREQUIRED) 870 (void) nfs_sndlock(&nmp->nm_flag, (struct nfsreq *)0); 871 (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep); 872 if (nmp->nm_soflags & PR_CONNREQUIRED) 873 nfs_sndunlock(&nmp->nm_flag); 874 return (error); 875 } 876 877 /* 878 * Called for client side callbacks 879 */ 880 nqnfs_callback(nmp, mrep, md, dpos) 881 struct nfsmount *nmp; 882 struct mbuf *mrep, *md; 883 caddr_t dpos; 884 { 885 register struct vnode *vp; 886 register u_long *tl; 887 register long t1; 888 nfsv2fh_t nfh; 889 fhandle_t *fhp; 890 struct nfsnode *np; 891 struct nfsd nd; 892 int error; 893 char *cp2; 894 895 nd.nd_mrep = mrep; 896 nd.nd_md = md; 897 nd.nd_dpos = dpos; 898 if (error = nfs_getreq(&nd, FALSE)) 899 return (error); 900 md = nd.nd_md; 901 dpos = nd.nd_dpos; 902 if (nd.nd_procnum != NQNFSPROC_EVICTED) { 903 m_freem(mrep); 904 return (EPERM); 905 } 906 fhp = &nfh.fh_generic; 907 nfsm_srvmtofh(fhp); 908 m_freem(mrep); 909 if (error = nfs_nget(nmp->nm_mountp, fhp, &np)) 910 return (error); 911 vp = NFSTOV(np); 912 if (np->n_tnext) { 913 np->n_expiry = 0; 914 np->n_flag |= NQNFSEVICTED; 915 if (np->n_tprev != (struct nfsnode *)nmp) { 916 if (np->n_tnext == (struct nfsnode *)nmp) 917 nmp->nm_tprev = np->n_tprev; 918 else 919 np->n_tnext->n_tprev = np->n_tprev; 920 np->n_tprev->n_tnext = np->n_tnext; 921 np->n_tnext = nmp->nm_tnext; 922 nmp->nm_tnext = np; 923 np->n_tprev = (struct nfsnode *)nmp; 924 if (np->n_tnext == (struct nfsnode *)nmp) 925 nmp->nm_tprev = np; 926 else 927 np->n_tnext->n_tprev = np; 928 } 929 } 930 vrele(vp); 931 nfsm_srvdone; 932 } 933 934 /* 935 * Nqnfs client helper daemon. Runs once a second to expire leases. 936 * It also get authorization strings for "kerb" mounts. 937 * It must start at the beginning of the list again after any potential 938 * "sleep" since nfs_reclaim() called from vclean() can pull a node off 939 * the list asynchronously. 940 */ 941 nqnfs_clientd(nmp, cred, ncd, flag, argp, p) 942 register struct nfsmount *nmp; 943 struct ucred *cred; 944 struct nfsd_cargs *ncd; 945 int flag; 946 caddr_t argp; 947 struct proc *p; 948 { 949 register struct nfsnode *np; 950 struct vnode *vp; 951 int error, vpid; 952 953 /* 954 * First initialize some variables 955 */ 956 nqnfs_prog = txdr_unsigned(NQNFS_PROG); 957 nqnfs_vers = txdr_unsigned(NQNFS_VER1); 958 959 /* 960 * If an authorization string is being passed in, get it. 961 */ 962 if ((flag & NFSSVC_GOTAUTH) && 963 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) { 964 if (nmp->nm_flag & NFSMNT_HASAUTH) 965 panic("cld kerb"); 966 if ((flag & NFSSVC_AUTHINFAIL) == 0) { 967 if (ncd->ncd_authlen <= RPCAUTH_MAXSIZ && 968 copyin(ncd->ncd_authstr, nmp->nm_authstr, 969 ncd->ncd_authlen) == 0) { 970 nmp->nm_authtype = ncd->ncd_authtype; 971 nmp->nm_authlen = ncd->ncd_authlen; 972 } else 973 nmp->nm_flag |= NFSMNT_AUTHERR; 974 } else 975 nmp->nm_flag |= NFSMNT_AUTHERR; 976 nmp->nm_flag |= NFSMNT_HASAUTH; 977 wakeup((caddr_t)&nmp->nm_authlen); 978 } else 979 nmp->nm_flag |= NFSMNT_WAITAUTH; 980 981 /* 982 * Loop every second updating queue until there is a termination sig. 983 */ 984 while ((nmp->nm_flag & NFSMNT_DISMNT) == 0) { 985 if (nmp->nm_flag & NFSMNT_NQNFS) { 986 np = nmp->nm_tnext; 987 while (np != (struct nfsnode *)nmp && 988 (nmp->nm_flag & NFSMNT_DISMINPROG) == 0) { 989 vp = NFSTOV(np); 990 if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash2"); 991 vpid = vp->v_id; 992 if (np->n_expiry < time.tv_sec) { 993 if (vget(vp) == 0) { 994 nmp->nm_inprog = vp; 995 if (vpid == vp->v_id) { 996 if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash3"); 997 if (np->n_tnext == (struct nfsnode *)nmp) 998 nmp->nm_tprev = np->n_tprev; 999 else 1000 np->n_tnext->n_tprev = np->n_tprev; 1001 if (np->n_tprev == (struct nfsnode *)nmp) 1002 nmp->nm_tnext = np->n_tnext; 1003 else 1004 np->n_tprev->n_tnext = np->n_tnext; 1005 np->n_tnext = (struct nfsnode *)0; 1006 if ((np->n_flag & (NMODIFIED | NQNFSEVICTED)) 1007 && vp->v_type == VREG) { 1008 if (np->n_flag & NQNFSEVICTED) { 1009 NFS_VINVBUF(np, vp, 1010 TRUE, cred, p); 1011 np->n_flag &= ~NQNFSEVICTED; 1012 (void) nqnfs_vacated(vp, cred); 1013 } else { 1014 np->n_flag &= ~NMODIFIED; 1015 (void) VOP_FSYNC(vp, cred, 1016 MNT_WAIT, p); 1017 } 1018 } 1019 } 1020 vrele(vp); 1021 nmp->nm_inprog = NULLVP; 1022 } 1023 if (np != nmp->nm_tnext) 1024 np = nmp->nm_tnext; 1025 else 1026 break; 1027 } else if ((np->n_expiry - NQ_RENEWAL) < time.tv_sec) { 1028 if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE)) 1029 == NQNFSWRITE && vp->v_dirtyblkhd.le_next && 1030 vget(vp) == 0) { 1031 nmp->nm_inprog = vp; 1032 if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4"); 1033 if (vpid == vp->v_id && 1034 nqnfs_getlease(vp, NQL_WRITE, cred, p)==0) 1035 np->n_brev = np->n_lrev; 1036 vrele(vp); 1037 nmp->nm_inprog = NULLVP; 1038 } 1039 if (np != nmp->nm_tnext) 1040 np = nmp->nm_tnext; 1041 else 1042 break; 1043 } else 1044 break; 1045 } 1046 } 1047 1048 /* 1049 * Get an authorization string, if required. 1050 */ 1051 if ((nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT | NFSMNT_HASAUTH)) == 0) { 1052 ncd->ncd_authuid = nmp->nm_authuid; 1053 if (copyout((caddr_t)ncd, argp, sizeof (*ncd))) 1054 nmp->nm_flag |= NFSMNT_WAITAUTH; 1055 else 1056 return (ENEEDAUTH); 1057 } 1058 1059 /* 1060 * Wait a bit (no pun) and do it again. 1061 */ 1062 if ((nmp->nm_flag & NFSMNT_DISMNT) == 0 && 1063 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_HASAUTH))) { 1064 error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH, 1065 "nqnfstimr", hz / 3); 1066 if (error == EINTR || error == ERESTART) 1067 (void) dounmount(nmp->nm_mountp, MNT_NOFORCE); 1068 } 1069 } 1070 free((caddr_t)nmp, M_NFSMNT); 1071 if (error == EWOULDBLOCK) 1072 error = 0; 1073 return (error); 1074 } 1075 1076 /* 1077 * Adjust all timer queue expiry times when the time of day clock is changed. 1078 * Called from the settimeofday() syscall. 1079 */ 1080 void 1081 lease_updatetime(deltat) 1082 register int deltat; 1083 { 1084 register struct nqlease *lp; 1085 register struct nfsnode *np; 1086 struct mount *mp; 1087 struct nfsmount *nmp; 1088 int s; 1089 1090 if (nqnfsstarttime != 0) 1091 nqnfsstarttime += deltat; 1092 s = splsoftclock(); 1093 lp = nqthead.th_chain[0]; 1094 while (lp != (struct nqlease *)&nqthead) { 1095 lp->lc_expiry += deltat; 1096 lp = lp->lc_chain1[0]; 1097 } 1098 splx(s); 1099 1100 /* 1101 * Search the mount list for all nqnfs mounts and do their timer 1102 * queues. 1103 */ 1104 mp = rootfs; 1105 do { 1106 if (mp->mnt_stat.f_fsid.val[1] == MOUNT_NFS) { 1107 nmp = VFSTONFS(mp); 1108 if (nmp->nm_flag & NFSMNT_NQNFS) { 1109 np = nmp->nm_tnext; 1110 while (np != (struct nfsnode *)nmp) { 1111 np->n_expiry += deltat; 1112 np = np->n_tnext; 1113 } 1114 } 1115 } 1116 mp = mp->mnt_next; 1117 } while (mp != rootfs); 1118 } 1119 1120 /* 1121 * Lock a server lease. 1122 */ 1123 void 1124 nqsrv_locklease(lp) 1125 struct nqlease *lp; 1126 { 1127 1128 while (lp->lc_flag & LC_LOCKED) { 1129 lp->lc_flag |= LC_WANTED; 1130 (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0); 1131 } 1132 lp->lc_flag |= LC_LOCKED; 1133 lp->lc_flag &= ~LC_WANTED; 1134 } 1135 1136 /* 1137 * Unlock a server lease. 1138 */ 1139 void 1140 nqsrv_unlocklease(lp) 1141 struct nqlease *lp; 1142 { 1143 1144 lp->lc_flag &= ~LC_LOCKED; 1145 if (lp->lc_flag & LC_WANTED) 1146 wakeup((caddr_t)lp); 1147 } 1148 1149 /* 1150 * Update a client lease. 1151 */ 1152 void 1153 nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev) 1154 register struct nfsmount *nmp; 1155 register struct nfsnode *np; 1156 int rwflag, cachable; 1157 time_t expiry; 1158 u_quad_t frev; 1159 { 1160 register struct nfsnode *tp; 1161 1162 if (np->n_tnext) { 1163 if (np->n_tnext == (struct nfsnode *)nmp) 1164 nmp->nm_tprev = np->n_tprev; 1165 else 1166 np->n_tnext->n_tprev = np->n_tprev; 1167 if (np->n_tprev == (struct nfsnode *)nmp) 1168 nmp->nm_tnext = np->n_tnext; 1169 else 1170 np->n_tprev->n_tnext = np->n_tnext; 1171 if (rwflag == NQL_WRITE) 1172 np->n_flag |= NQNFSWRITE; 1173 } else if (rwflag == NQL_READ) 1174 np->n_flag &= ~NQNFSWRITE; 1175 else 1176 np->n_flag |= NQNFSWRITE; 1177 if (cachable) 1178 np->n_flag &= ~NQNFSNONCACHE; 1179 else 1180 np->n_flag |= NQNFSNONCACHE; 1181 np->n_expiry = expiry; 1182 np->n_lrev = frev; 1183 tp = nmp->nm_tprev; 1184 while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry) 1185 tp = tp->n_tprev; 1186 if (tp == (struct nfsnode *)nmp) { 1187 np->n_tnext = nmp->nm_tnext; 1188 nmp->nm_tnext = np; 1189 } else { 1190 np->n_tnext = tp->n_tnext; 1191 tp->n_tnext = np; 1192 } 1193 np->n_tprev = tp; 1194 if (np->n_tnext == (struct nfsnode *)nmp) 1195 nmp->nm_tprev = np; 1196 else 1197 np->n_tnext->n_tprev = np; 1198 } 1199