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