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