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