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.9 (Berkeley) 05/20/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
nqsrv_getlease(vp,duration,flags,slp,procp,nam,cachablep,frev,cred)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
nqnfs_vop_lease_check(ap)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
nqsrv_addhost(lph,slp,nam)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
nqsrv_instimeq(lp,duration)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
nqsrv_cmpnam(slp,nam,lph)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
nqsrv_send_eviction(vp,lp,slp,nam,cred)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
nqsrv_waitfor_expiry(lp)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
nqnfs_serverd()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
nqnfsrv_getlease(nfsd,slp,procp,mrq)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
nqnfsrv_vacated(nfsd,slp,procp,mrq)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
nqnfs_getlease(vp,rwflag,cred,p)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
nqnfs_vacated(vp,cred)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
nqnfs_callback(nmp,mrep,md,dpos)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
nqnfs_clientd(nmp,cred,ncd,flag,argp,p)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, LK_EXCLUSIVE, p) == 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, LK_EXCLUSIVE, p) == 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
nqnfs_lease_updatetime(deltat)1109 nqnfs_lease_updatetime(deltat)
1110 register int deltat;
1111 {
1112 struct proc *p = curproc; /* XXX */
1113 struct nqlease *lp;
1114 struct nfsnode *np;
1115 struct mount *mp, *nxtmp;
1116 struct nfsmount *nmp;
1117 int s;
1118
1119 if (nqnfsstarttime != 0)
1120 nqnfsstarttime += deltat;
1121 s = splsoftclock();
1122 for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead;
1123 lp = lp->lc_timer.cqe_next)
1124 lp->lc_expiry += deltat;
1125 splx(s);
1126
1127 /*
1128 * Search the mount list for all nqnfs mounts and do their timer
1129 * queues.
1130 */
1131 simple_lock(&mountlist_slock);
1132 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nxtmp) {
1133 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
1134 nxtmp = mp->mnt_list.cqe_next;
1135 continue;
1136 }
1137 if (mp->mnt_stat.f_type == nfs_mount_type) {
1138 nmp = VFSTONFS(mp);
1139 if (nmp->nm_flag & NFSMNT_NQNFS) {
1140 for (np = nmp->nm_timerhead.cqh_first;
1141 np != (void *)&nmp->nm_timerhead;
1142 np = np->n_timer.cqe_next) {
1143 np->n_expiry += deltat;
1144 }
1145 }
1146 }
1147 simple_lock(&mountlist_slock);
1148 nxtmp = mp->mnt_list.cqe_next;
1149 vfs_unbusy(mp, p);
1150 }
1151 simple_unlock(&mountlist_slock);
1152 }
1153
1154 /*
1155 * Lock a server lease.
1156 */
1157 void
nqsrv_locklease(lp)1158 nqsrv_locklease(lp)
1159 struct nqlease *lp;
1160 {
1161
1162 while (lp->lc_flag & LC_LOCKED) {
1163 lp->lc_flag |= LC_WANTED;
1164 (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0);
1165 }
1166 lp->lc_flag |= LC_LOCKED;
1167 lp->lc_flag &= ~LC_WANTED;
1168 }
1169
1170 /*
1171 * Unlock a server lease.
1172 */
1173 void
nqsrv_unlocklease(lp)1174 nqsrv_unlocklease(lp)
1175 struct nqlease *lp;
1176 {
1177
1178 lp->lc_flag &= ~LC_LOCKED;
1179 if (lp->lc_flag & LC_WANTED)
1180 wakeup((caddr_t)lp);
1181 }
1182
1183 /*
1184 * Update a client lease.
1185 */
1186 void
nqnfs_clientlease(nmp,np,rwflag,cachable,expiry,frev)1187 nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev)
1188 register struct nfsmount *nmp;
1189 register struct nfsnode *np;
1190 int rwflag, cachable;
1191 time_t expiry;
1192 u_quad_t frev;
1193 {
1194 register struct nfsnode *tp;
1195
1196 if (np->n_timer.cqe_next != 0) {
1197 CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
1198 if (rwflag == ND_WRITE)
1199 np->n_flag |= NQNFSWRITE;
1200 } else if (rwflag == ND_READ)
1201 np->n_flag &= ~NQNFSWRITE;
1202 else
1203 np->n_flag |= NQNFSWRITE;
1204 if (cachable)
1205 np->n_flag &= ~NQNFSNONCACHE;
1206 else
1207 np->n_flag |= NQNFSNONCACHE;
1208 np->n_expiry = expiry;
1209 np->n_lrev = frev;
1210 tp = nmp->nm_timerhead.cqh_last;
1211 while (tp != (void *)&nmp->nm_timerhead && tp->n_expiry > np->n_expiry)
1212 tp = tp->n_timer.cqe_prev;
1213 if (tp == (void *)&nmp->nm_timerhead) {
1214 CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
1215 } else {
1216 CIRCLEQ_INSERT_AFTER(&nmp->nm_timerhead, tp, np, n_timer);
1217 }
1218 }
1219