new queue linkage names
[unix-history] / usr / src / sys / nfs / nfs_nqlease.c
CommitLineData
8cf41015
KM
1/*
2 * Copyright (c) 1992 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * %sccs.include.redist.c%
9 *
b330a7ec 10 * @(#)nfs_nqlease.c 7.12 (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>
39#include <netinet/in.h>
40#include <nfs/rpcv2.h>
41#include <nfs/nfsv2.h>
42#include <nfs/nfs.h>
43#include <nfs/nfsm_subs.h>
44#include <nfs/xdr_subs.h>
45#include <nfs/nqnfs.h>
46#include <nfs/nfsnode.h>
47#include <nfs/nfsmount.h>
8cf41015
KM
48
49/*
50 * List head for the lease queue and other global data.
51 * At any time a lease is linked into a list ordered by increasing expiry time.
52 */
96964be4 53#define NQFHHASH(f) ((*((u_long *)(f)))&nqfheadhash)
8cf41015
KM
54
55union nqsrvthead nqthead;
96964be4
KM
56struct nqlease **nqfhead;
57u_long nqfheadhash;
8cf41015
KM
58time_t nqnfsstarttime = (time_t)0;
59u_long nqnfs_prog, nqnfs_vers;
60int nqsrv_clockskew = NQ_CLOCKSKEW;
61int nqsrv_writeslack = NQ_WRITESLACK;
62int nqsrv_maxlease = NQ_MAXLEASE;
63int nqsrv_maxnumlease = NQ_MAXNUMLEASE;
64void nqsrv_instimeq(), nqsrv_send_eviction(), nfs_sndunlock();
a5a4c300 65void nqsrv_unlocklease(), nqsrv_waitfor_expiry(), nfsrv_slpderef();
8cf41015 66void nqsrv_addhost(), nqsrv_locklease(), nqnfs_serverd();
41f343df 67void nqnfs_clientlease();
8cf41015
KM
68struct mbuf *nfsm_rpchead();
69
70/*
71 * Signifies which rpcs can have piggybacked lease requests
72 */
73int nqnfs_piggy[NFS_NPROCS] = {
74 0,
75 NQL_READ,
76 NQL_WRITE,
77 0,
78 NQL_READ,
79 NQL_READ,
80 NQL_READ,
81 0,
82 NQL_WRITE,
83 0,
84 0,
85 0,
86 0,
87 0,
88 0,
89 0,
90 NQL_READ,
91 0,
92 NQL_READ,
93 0,
94 0,
95 0,
b330a7ec 96 0,
8cf41015
KM
97};
98
99int nnnnnn = sizeof (struct nqlease);
100int oooooo = sizeof (struct nfsnode);
101extern nfstype nfs_type[9];
102extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
103extern struct nfsd nfsd_head;
104extern int nfsd_waiting;
105
106#define TRUE 1
107#define FALSE 0
108
109/*
110 * Get or check for a lease for "vp", based on NQL_CHECK flag.
111 * The rules are as follows:
112 * - if a current non-caching lease, reply non-caching
113 * - if a current lease for same host only, extend lease
114 * - if a read cachable lease and a read lease request
115 * add host to list any reply cachable
116 * - else { set non-cachable for read-write sharing }
117 * send eviction notice messages to all other hosts that have lease
118 * wait for lease termination { either by receiving vacated messages
119 * from all the other hosts or expiry
120 * via. timeout }
121 * modify lease to non-cachable
122 * - else if no current lease, issue new one
123 * - reply
124 * - return boolean TRUE iff nam should be m_freem()'d
125 * NB: Since nqnfs_serverd() is called from a timer, any potential tsleep()
126 * in here must be framed by nqsrv_locklease() and nqsrv_unlocklease().
127 * nqsrv_locklease() is coded such that at least one of LC_LOCKED and
128 * LC_WANTED is set whenever a process is tsleeping in it. The exception
129 * is when a new lease is being allocated, since it is not in the timer
130 * queue yet. (Ditto for the splsoftclock() and splx(s) calls)
131 */
132nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred)
133 struct vnode *vp;
134 u_long *duration;
135 int flags;
136 struct nfsd *nd;
137 struct mbuf *nam;
138 int *cachablep;
139 u_quad_t *frev;
140 struct ucred *cred;
141{
96964be4 142 register struct nqlease *lp, *lq, **lpp;
8cf41015 143 register struct nqhost *lph;
96964be4 144 struct nqlease *tlp;
8cf41015
KM
145 struct nqm **lphp;
146 struct vattr vattr;
8cf41015
KM
147 fhandle_t fh;
148 int i, ok, error, s;
149
150 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
151 return (0);
152 if (*duration > nqsrv_maxlease)
153 *duration = nqsrv_maxlease;
154 if (error = VOP_GETATTR(vp, &vattr, cred, nd->nd_procp))
155 return (error);
156 *frev = vattr.va_filerev;
157 s = splsoftclock();
158 tlp = vp->v_lease;
159 if ((flags & NQL_CHECK) == 0)
160 nfsstats.srvnqnfs_getleases++;
161 if (tlp == (struct nqlease *)0) {
162
163 /*
164 * Find the lease by searching the hash list.
165 */
166 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
167 if (error = VFS_VPTOFH(vp, &fh.fh_fid)) {
168 splx(s);
169 return (error);
170 }
96964be4
KM
171 lpp = &nqfhead[NQFHHASH(fh.fh_fid.fid_data)];
172 for (lp = *lpp; lp; lp = lp->lc_fhnext)
2c5b44a2
KM
173 if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] &&
174 fh.fh_fsid.val[1] == lp->lc_fsid.val[1] &&
8cf41015
KM
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 }
184 lp = tlp;
185 if (lp) {
186 if ((lp->lc_flag & LC_NONCACHABLE) ||
187 (lp->lc_morehosts == (struct nqm *)0 &&
188 nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host)))
189 goto doreply;
190 if ((flags & NQL_READ) && (lp->lc_flag & LC_WRITE)==0) {
191 if (flags & NQL_CHECK)
192 goto doreply;
193 if (nqsrv_cmpnam(nd->nd_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(nd->nd_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 }
a5a4c300 225 nqsrv_addhost(lph, nd->nd_slp, nam);
8cf41015
KM
226 nqsrv_unlocklease(lp);
227 } else {
228 lp->lc_flag |= LC_NONCACHABLE;
229 nqsrv_locklease(lp);
230 VOP_UNLOCK(vp);
231 nqsrv_send_eviction(vp, lp, nd->nd_slp, nam, cred);
232 nqsrv_waitfor_expiry(lp);
233 VOP_LOCK(vp);
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{
302 int duration, cache;
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);
731 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
732 return (error);
733 m_freem(mrep);
734 tlp = vp->v_lease;
735 if (tlp == (struct nqlease *)0) {
736 /*
737 * Find the lease by searching the hash list.
738 */
96964be4
KM
739 for (lp = nqfhead[NQFHHASH(fhp->fh_fid.fid_data)]; lp;
740 lp = lp->lc_fhnext)
2c5b44a2
KM
741 if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] &&
742 fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] &&
8cf41015
KM
743 !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata,
744 MAXFIDSZ)) {
745 /* Found it */
746 lp->lc_vp = vp;
747 vp->v_lease = lp;
748 tlp = lp;
749 break;
750 }
751 }
752 vrele(vp);
753 if (tlp) {
754 lp = tlp;
755 len = 1;
756 i = 0;
757 lph = &lp->lc_host;
758 lphnext = lp->lc_morehosts;
759 ok = 1;
760 while (ok && (lph->lph_flag & LC_VALID)) {
761 if (nqsrv_cmpnam(nfsd->nd_slp, nam, lph)) {
762 lph->lph_flag |= LC_VACATED;
763 gotit++;
764 break;
765 }
766 if (++i == len) {
767 if (lphnext) {
768 len = LC_MOREHOSTSIZ;
769 i = 0;
770 lph = lphnext->lpm_hosts;
771 lphnext = lphnext->lpm_next;
772 } else
773 ok = 0;
774 } else
775 lph++;
776 }
777 if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) {
778 lp->lc_flag &= ~LC_EXPIREDWANTED;
779 wakeup((caddr_t)&lp->lc_flag);
780 }
781nfsmout:
782 return (EPERM);
783 }
784 return (EPERM);
785}
786
787/*
788 * Client get lease rpc function.
789 */
790nqnfs_getlease(vp, rwflag, cred, p)
791 register struct vnode *vp;
792 int rwflag;
793 struct ucred *cred;
794 struct proc *p;
795{
796 register u_long *tl;
797 register caddr_t cp;
798 register long t1;
799 register struct nfsnode *np, *tp;
800 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
801 caddr_t bpos, dpos, cp2;
802 time_t reqtime;
803 int error = 0;
804 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
805 int cachable;
41f343df 806 u_quad_t frev;
8cf41015
KM
807
808 nfsstats.rpccnt[NQNFSPROC_GETLEASE]++;
809 mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_FH+2*NFSX_UNSIGNED,
810 &bpos);
811 nfsm_fhtom(vp);
812 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
813 *tl++ = txdr_unsigned(rwflag);
814 *tl = txdr_unsigned(nmp->nm_leaseterm);
815 reqtime = time.tv_sec;
816 nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred);
817 np = VTONFS(vp);
818 nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
819 cachable = fxdr_unsigned(int, *tl++);
820 reqtime += fxdr_unsigned(int, *tl++);
821 if (reqtime > time.tv_sec) {
41f343df
KM
822 fxdr_hyper(tl, &frev);
823 nqnfs_clientlease(nmp, np, rwflag, cachable, reqtime, frev);
8cf41015
KM
824 nfsm_loadattr(vp, (struct vattr *)0);
825 } else
826 error = NQNFS_EXPIRED;
827 nfsm_reqdone;
828 return (error);
829}
830
831/*
832 * Client vacated message function.
833 */
834nqnfs_vacated(vp, cred)
835 register struct vnode *vp;
836 struct ucred *cred;
837{
838 register caddr_t cp;
839 register struct mbuf *m;
840 register int i;
841 caddr_t bpos;
842 u_long xid;
843 int error = 0;
844 struct mbuf *mreq, *mb, *mb2, *mheadend;
845 struct nfsmount *nmp;
846 struct nfsreq myrep;
847
848 nmp = VFSTONFS(vp->v_mount);
849 nfsstats.rpccnt[NQNFSPROC_VACATED]++;
850 nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH);
851 nfsm_fhtom(vp);
852 m = mreq;
853 i = 0;
854 while (m) {
855 i += m->m_len;
856 m = m->m_next;
857 }
858 m = nfsm_rpchead(cred, TRUE, NQNFSPROC_VACATED,
859 RPCAUTH_UNIX, 5*NFSX_UNSIGNED, (char *)0,
860 mreq, i, &mheadend, &xid);
861 if (nmp->nm_sotype == SOCK_STREAM) {
862 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
863 *mtod(m, u_long *) = htonl(0x80000000 | (m->m_pkthdr.len -
864 NFSX_UNSIGNED));
865 }
866 myrep.r_flags = 0;
867 myrep.r_nmp = nmp;
868 if (nmp->nm_soflags & PR_CONNREQUIRED)
869 (void) nfs_sndlock(&nmp->nm_flag, (struct nfsreq *)0);
870 (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep);
871 if (nmp->nm_soflags & PR_CONNREQUIRED)
872 nfs_sndunlock(&nmp->nm_flag);
873 return (error);
874}
875
876/*
877 * Called for client side callbacks
878 */
879nqnfs_callback(nmp, mrep, md, dpos)
880 struct nfsmount *nmp;
881 struct mbuf *mrep, *md;
882 caddr_t dpos;
883{
884 register struct vnode *vp;
885 register u_long *tl;
886 register long t1;
887 nfsv2fh_t nfh;
888 fhandle_t *fhp;
889 struct nfsnode *np;
890 struct nfsd nd;
891 int error;
892 char *cp2;
893
894 nd.nd_mrep = mrep;
895 nd.nd_md = md;
896 nd.nd_dpos = dpos;
897 if (error = nfs_getreq(&nd, FALSE))
898 return (error);
899 md = nd.nd_md;
900 dpos = nd.nd_dpos;
901 if (nd.nd_procnum != NQNFSPROC_EVICTED) {
902 m_freem(mrep);
903 return (EPERM);
904 }
905 fhp = &nfh.fh_generic;
906 nfsm_srvmtofh(fhp);
907 m_freem(mrep);
908 if (error = nfs_nget(nmp->nm_mountp, fhp, &np))
909 return (error);
910 vp = NFSTOV(np);
911 if (np->n_tnext) {
912 np->n_expiry = 0;
913 np->n_flag |= NQNFSEVICTED;
914 if (np->n_tprev != (struct nfsnode *)nmp) {
915 if (np->n_tnext == (struct nfsnode *)nmp)
916 nmp->nm_tprev = np->n_tprev;
917 else
918 np->n_tnext->n_tprev = np->n_tprev;
919 np->n_tprev->n_tnext = np->n_tnext;
920 np->n_tnext = nmp->nm_tnext;
921 nmp->nm_tnext = np;
922 np->n_tprev = (struct nfsnode *)nmp;
923 if (np->n_tnext == (struct nfsnode *)nmp)
924 nmp->nm_tprev = np;
925 else
926 np->n_tnext->n_tprev = np;
927 }
928 }
929 vrele(vp);
930 nfsm_srvdone;
931}
932
933/*
934 * Nqnfs client helper daemon. Runs once a second to expire leases.
935 * It also get authorization strings for "kerb" mounts.
936 * It must start at the beginning of the list again after any potential
937 * "sleep" since nfs_reclaim() called from vclean() can pull a node off
938 * the list asynchronously.
939 */
940nqnfs_clientd(nmp, cred, ncd, flag, argp, p)
941 register struct nfsmount *nmp;
942 struct ucred *cred;
943 struct nfsd_cargs *ncd;
944 int flag;
945 caddr_t argp;
946 struct proc *p;
947{
948 register struct nfsnode *np;
949 struct vnode *vp;
950 int error, vpid;
951
952 /*
953 * First initialize some variables
954 */
955 nqnfs_prog = txdr_unsigned(NQNFS_PROG);
956 nqnfs_vers = txdr_unsigned(NQNFS_VER1);
957
958 /*
959 * If an authorization string is being passed in, get it.
960 */
961 if ((flag & NFSSVC_GOTAUTH) &&
962 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) {
963 if (nmp->nm_flag & NFSMNT_HASAUTH)
964 panic("cld kerb");
965 if ((flag & NFSSVC_AUTHINFAIL) == 0) {
966 if (ncd->ncd_authlen <= RPCAUTH_MAXSIZ &&
967 copyin(ncd->ncd_authstr, nmp->nm_authstr,
968 ncd->ncd_authlen) == 0) {
969 nmp->nm_authtype = ncd->ncd_authtype;
970 nmp->nm_authlen = ncd->ncd_authlen;
971 } else
972 nmp->nm_flag |= NFSMNT_AUTHERR;
973 } else
974 nmp->nm_flag |= NFSMNT_AUTHERR;
975 nmp->nm_flag |= NFSMNT_HASAUTH;
976 wakeup((caddr_t)&nmp->nm_authlen);
977 } else
978 nmp->nm_flag |= NFSMNT_WAITAUTH;
979
980 /*
981 * Loop every second updating queue until there is a termination sig.
982 */
983 while ((nmp->nm_flag & NFSMNT_DISMNT) == 0) {
984 if (nmp->nm_flag & NFSMNT_NQNFS) {
985 np = nmp->nm_tnext;
986 while (np != (struct nfsnode *)nmp &&
987 (nmp->nm_flag & NFSMNT_DISMINPROG) == 0) {
988 vp = NFSTOV(np);
989if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash2");
990 vpid = vp->v_id;
991 if (np->n_expiry < time.tv_sec) {
992 if (vget(vp) == 0) {
993 nmp->nm_inprog = vp;
994 if (vpid == vp->v_id) {
995if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash3");
996 if (np->n_tnext == (struct nfsnode *)nmp)
997 nmp->nm_tprev = np->n_tprev;
998 else
999 np->n_tnext->n_tprev = np->n_tprev;
1000 if (np->n_tprev == (struct nfsnode *)nmp)
1001 nmp->nm_tnext = np->n_tnext;
1002 else
1003 np->n_tprev->n_tnext = np->n_tnext;
1004 np->n_tnext = (struct nfsnode *)0;
1005 if ((np->n_flag & (NMODIFIED | NQNFSEVICTED))
1006 && vp->v_type == VREG) {
1007 np->n_flag &= ~NMODIFIED;
1008 if (np->n_flag & NQNFSEVICTED) {
4425d7dd
KM
1009 (void) vinvalbuf(vp, TRUE,
1010 cred, p);
8cf41015 1011 np->n_flag &= ~NQNFSEVICTED;
e88c7c85 1012 (void) nqnfs_vacated(vp, cred);
8cf41015 1013 } else
4425d7dd
KM
1014 (void) VOP_FSYNC(vp, cred,
1015 MNT_WAIT, p);
8cf41015
KM
1016 }
1017 }
1018 vrele(vp);
1019 nmp->nm_inprog = NULLVP;
1020 }
1021 if (np != nmp->nm_tnext)
1022 np = nmp->nm_tnext;
1023 else
1024 break;
1025 } else if ((np->n_expiry - NQ_RENEWAL) < time.tv_sec) {
1026 if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE))
1027 == NQNFSWRITE && vp->v_dirtyblkhd &&
1028 vget(vp) == 0) {
1029 nmp->nm_inprog = vp;
1030if (vp->v_mount->mnt_stat.f_fsid.val[1] != MOUNT_NFS) panic("trash4");
1031 if (vpid == vp->v_id &&
1032 nqnfs_getlease(vp, NQL_WRITE, cred, p)==0)
1033 np->n_brev = np->n_lrev;
1034 vrele(vp);
1035 nmp->nm_inprog = NULLVP;
1036 }
1037 if (np != nmp->nm_tnext)
1038 np = nmp->nm_tnext;
1039 else
1040 break;
1041 } else
1042 break;
1043 }
1044 }
1045
1046 /*
1047 * Get an authorization string, if required.
1048 */
1049 if ((nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT | NFSMNT_HASAUTH)) == 0) {
1050 ncd->ncd_authuid = nmp->nm_authuid;
1051 if (copyout((caddr_t)ncd, argp, sizeof (*ncd)))
1052 nmp->nm_flag |= NFSMNT_WAITAUTH;
1053 else
1054 return (ENEEDAUTH);
1055 }
1056
1057 /*
1058 * Wait a bit (no pun) and do it again.
1059 */
1060 if ((nmp->nm_flag & NFSMNT_DISMNT) == 0 &&
1061 (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_HASAUTH))) {
1062 error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH,
1063 "nqnfstimr", hz / 3);
1064 if (error == EINTR || error == ERESTART)
1065 (void) dounmount(nmp->nm_mountp, MNT_NOFORCE);
1066 }
1067 }
1068 free((caddr_t)nmp, M_NFSMNT);
1069 if (error == EWOULDBLOCK)
1070 error = 0;
1071 return (error);
1072}
1073
1074/*
1075 * Adjust all timer queue expiry times when the time of day clock is changed.
1076 * Called from the settimeofday() syscall.
1077 */
1078void
1079lease_updatetime(deltat)
1080 register int deltat;
1081{
1082 register struct nqlease *lp;
1083 register struct nfsnode *np;
1084 struct mount *mp;
1085 struct nfsmount *nmp;
1086 int s;
1087
1088 if (nqnfsstarttime != 0)
1089 nqnfsstarttime += deltat;
1090 s = splsoftclock();
1091 lp = nqthead.th_chain[0];
1092 while (lp != (struct nqlease *)&nqthead) {
1093 lp->lc_expiry += deltat;
1094 lp = lp->lc_chain1[0];
1095 }
1096 splx(s);
1097
1098 /*
1099 * Search the mount list for all nqnfs mounts and do their timer
1100 * queues.
1101 */
1102 mp = rootfs;
1103 do {
1104 if (mp->mnt_stat.f_fsid.val[1] == MOUNT_NFS) {
1105 nmp = VFSTONFS(mp);
1106 if (nmp->nm_flag & NFSMNT_NQNFS) {
1107 np = nmp->nm_tnext;
1108 while (np != (struct nfsnode *)nmp) {
1109 np->n_expiry += deltat;
1110 np = np->n_tnext;
1111 }
1112 }
1113 }
1114 mp = mp->mnt_next;
1115 } while (mp != rootfs);
1116}
1117
1118/*
1119 * Lock a server lease.
1120 */
1121void
1122nqsrv_locklease(lp)
1123 struct nqlease *lp;
1124{
1125
1126 while (lp->lc_flag & LC_LOCKED) {
1127 lp->lc_flag |= LC_WANTED;
1128 (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0);
1129 }
1130 lp->lc_flag |= LC_LOCKED;
1131 lp->lc_flag &= ~LC_WANTED;
1132}
1133
1134/*
1135 * Unlock a server lease.
1136 */
1137void
1138nqsrv_unlocklease(lp)
1139 struct nqlease *lp;
1140{
1141
1142 lp->lc_flag &= ~LC_LOCKED;
1143 if (lp->lc_flag & LC_WANTED)
1144 wakeup((caddr_t)lp);
1145}
41f343df
KM
1146
1147/*
1148 * Update a client lease.
1149 */
1150void
1151nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev)
1152 register struct nfsmount *nmp;
1153 register struct nfsnode *np;
1154 int rwflag, cachable;
1155 time_t expiry;
1156 u_quad_t frev;
1157{
1158 register struct nfsnode *tp;
1159
1160 if (np->n_tnext) {
1161 if (np->n_tnext == (struct nfsnode *)nmp)
1162 nmp->nm_tprev = np->n_tprev;
1163 else
1164 np->n_tnext->n_tprev = np->n_tprev;
1165 if (np->n_tprev == (struct nfsnode *)nmp)
1166 nmp->nm_tnext = np->n_tnext;
1167 else
1168 np->n_tprev->n_tnext = np->n_tnext;
1169 if (rwflag == NQL_WRITE)
1170 np->n_flag |= NQNFSWRITE;
1171 } else if (rwflag == NQL_READ)
1172 np->n_flag &= ~NQNFSWRITE;
1173 else
1174 np->n_flag |= NQNFSWRITE;
1175 if (cachable)
1176 np->n_flag &= ~NQNFSNONCACHE;
1177 else
1178 np->n_flag |= NQNFSNONCACHE;
1179 np->n_expiry = expiry;
1180 np->n_lrev = frev;
1181 tp = nmp->nm_tprev;
1182 while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
1183 tp = tp->n_tprev;
1184 if (tp == (struct nfsnode *)nmp) {
1185 np->n_tnext = nmp->nm_tnext;
1186 nmp->nm_tnext = np;
1187 } else {
1188 np->n_tnext = tp->n_tnext;
1189 tp->n_tnext = np;
1190 }
1191 np->n_tprev = tp;
1192 if (np->n_tnext == (struct nfsnode *)nmp)
1193 nmp->nm_tprev = np;
1194 else
1195 np->n_tnext->n_tprev = np;
1196}