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