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