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