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