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