summaryrefslogtreecommitdiffstats
path: root/sys/nfs/nfs_nqlease.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2001-09-18 23:32:09 +0000
committerpeter <peter@FreeBSD.org>2001-09-18 23:32:09 +0000
commit85182a8d785d189f1e845c7d66810e3977ac161b (patch)
tree626c88f61c1e52e9cd18eaec61b54aaaee5d3bfc /sys/nfs/nfs_nqlease.c
parentabe9cf18de01077e00cd2ee3d47363af647e65e4 (diff)
downloadFreeBSD-src-85182a8d785d189f1e845c7d66810e3977ac161b.zip
FreeBSD-src-85182a8d785d189f1e845c7d66810e3977ac161b.tar.gz
Cleanup and split of nfs client and server code.
This builds on the top of several repo-copies.
Diffstat (limited to 'sys/nfs/nfs_nqlease.c')
-rw-r--r--sys/nfs/nfs_nqlease.c1288
1 files changed, 0 insertions, 1288 deletions
diff --git a/sys/nfs/nfs_nqlease.c b/sys/nfs/nfs_nqlease.c
deleted file mode 100644
index 86b5ef6..0000000
--- a/sys/nfs/nfs_nqlease.c
+++ /dev/null
@@ -1,1288 +0,0 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Rick Macklem at The University of Guelph.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95
- * $FreeBSD$
- */
-
-
-/*
- * References:
- * Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant
- * Mechanism for Distributed File Cache Consistency",
- * In Proc. of the Twelfth ACM Symposium on Operating Systems
- * Principals, pg. 202-210, Litchfield Park, AZ, Dec. 1989.
- * Michael N. Nelson, Brent B. Welch and John K. Ousterhout, "Caching
- * in the Sprite Network File System", ACM TOCS 6(1),
- * pages 134-154, February 1988.
- * V. Srinivasan and Jeffrey C. Mogul, "Spritely NFS: Implementation and
- * Performance of Cache-Consistency Protocols", Digital
- * Equipment Corporation WRL Research Report 89/5, May 1989.
- */
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/mount.h>
-#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/protosw.h>
-#include <sys/socket.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/vnode.h>
-
-#include <vm/vm_zone.h>
-
-#include <machine/mutex.h>
-
-#include <netinet/in.h>
-#include <nfs/rpcv2.h>
-#include <nfs/nfsproto.h>
-#include <nfs/nfs.h>
-#include <nfs/nfsm_subs.h>
-#include <nfs/xdr_subs.h>
-#include <nfs/nqnfs.h>
-#include <nfs/nfsnode.h>
-#include <nfs/nfsmount.h>
-
-static MALLOC_DEFINE(M_NQMHOST, "NQNFS Host", "Nqnfs host address table");
-
-time_t nqnfsstarttime = (time_t)0;
-int nqsrv_clockskew = NQ_CLOCKSKEW;
-int nqsrv_writeslack = NQ_WRITESLACK;
-int nqsrv_maxlease = NQ_MAXLEASE;
-#ifndef NFS_NOSERVER
-static int nqsrv_maxnumlease = NQ_MAXNUMLEASE;
-#endif
-
-struct vop_lease_args;
-
-#ifndef NFS_NOSERVER
-static int nqsrv_cmpnam __P((struct nfssvc_sock *, struct sockaddr *,
- struct nqhost *));
-static int nqnfs_vacated __P((struct vnode *vp, struct ucred *cred));
-static void nqsrv_addhost __P((struct nqhost *lph, struct nfssvc_sock *slp,
- struct sockaddr *nam));
-static void nqsrv_instimeq __P((struct nqlease *lp, u_int32_t duration));
-static void nqsrv_locklease __P((struct nqlease *lp));
-static void nqsrv_send_eviction __P((struct vnode *vp, struct nqlease *lp,
- struct nfssvc_sock *slp,
- struct sockaddr *nam,
- struct ucred *cred));
-static void nqsrv_unlocklease __P((struct nqlease *lp));
-static void nqsrv_waitfor_expiry __P((struct nqlease *lp));
-#endif
-extern void nqnfs_lease_updatetime __P((int deltat));
-
-/*
- * Signifies which rpcs can have piggybacked lease requests
- */
-int nqnfs_piggy[NFS_NPROCS] = {
- 0,
- 0,
- ND_WRITE,
- ND_READ,
- 0,
- ND_READ,
- ND_READ,
- ND_WRITE,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- ND_READ,
- ND_READ,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
-};
-
-extern nfstype nfsv2_type[9];
-extern nfstype nfsv3_type[9];
-extern int nfsd_waiting;
-extern struct nfsstats nfsstats;
-
-#define TRUE 1
-#define FALSE 0
-
-#ifndef NFS_NOSERVER
-/*
- * Get or check for a lease for "vp", based on ND_CHECK flag.
- * The rules are as follows:
- * - if a current non-caching lease, reply non-caching
- * - if a current lease for same host only, extend lease
- * - if a read cachable lease and a read lease request
- * add host to list any reply cachable
- * - else { set non-cachable for read-write sharing }
- * send eviction notice messages to all other hosts that have lease
- * wait for lease termination { either by receiving vacated messages
- * from all the other hosts or expiry
- * via. timeout }
- * modify lease to non-cachable
- * - else if no current lease, issue new one
- * - reply
- * - return boolean TRUE iff nam should be m_freem()'d
- * NB: Since nqnfs_serverd() is called from a timer, any potential tsleep()
- * in here must be framed by nqsrv_locklease() and nqsrv_unlocklease().
- * nqsrv_locklease() is coded such that at least one of LC_LOCKED and
- * LC_WANTED is set whenever a process is tsleeping in it. The exception
- * is when a new lease is being allocated, since it is not in the timer
- * queue yet. (Ditto for the splsoftclock() and splx(s) calls)
- */
-int
-nqsrv_getlease(vp, duration, flags, slp, td, nam, cachablep, frev, cred)
- struct vnode *vp;
- u_int32_t *duration;
- int flags;
- struct nfssvc_sock *slp;
- struct thread *td;
- struct sockaddr *nam;
- int *cachablep;
- u_quad_t *frev;
- struct ucred *cred;
-{
- register struct nqlease *lp;
- register struct nqfhhashhead *lpp = NULL;
- register struct nqhost *lph = NULL;
- struct nqlease *tlp;
- struct nqm **lphp;
- struct vattr vattr;
- fhandle_t fh;
- int i, ok, error, s;
-
- if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
- return (0);
- if (*duration > nqsrv_maxlease)
- *duration = nqsrv_maxlease;
- error = VOP_GETATTR(vp, &vattr, cred, td);
- if (error)
- return (error);
- *frev = vattr.va_filerev;
- s = splsoftclock();
- tlp = vp->v_lease;
- if ((flags & ND_CHECK) == 0)
- nfsstats.srvnqnfs_getleases++;
- if (tlp == 0) {
- /*
- * Find the lease by searching the hash list.
- */
- fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
- error = VFS_VPTOFH(vp, &fh.fh_fid);
- if (error) {
- splx(s);
- return (error);
- }
- lpp = NQFHHASH(fh.fh_fid.fid_data);
- for (lp = lpp->lh_first; lp != 0; lp = lp->lc_hash.le_next)
- if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] &&
- fh.fh_fsid.val[1] == lp->lc_fsid.val[1] &&
- !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata,
- fh.fh_fid.fid_len - sizeof (int32_t))) {
- /* Found it */
- lp->lc_vp = vp;
- vp->v_lease = lp;
- tlp = lp;
- break;
- }
- } else
- lp = tlp;
- if (lp != 0) {
- if ((lp->lc_flag & LC_NONCACHABLE) ||
- (lp->lc_morehosts == (struct nqm *)0 &&
- nqsrv_cmpnam(slp, nam, &lp->lc_host)))
- goto doreply;
- if ((flags & ND_READ) && (lp->lc_flag & LC_WRITE) == 0) {
- if (flags & ND_CHECK)
- goto doreply;
- if (nqsrv_cmpnam(slp, nam, &lp->lc_host))
- goto doreply;
- i = 0;
- if (lp->lc_morehosts) {
- lph = lp->lc_morehosts->lpm_hosts;
- lphp = &lp->lc_morehosts->lpm_next;
- ok = 1;
- } else {
- lphp = &lp->lc_morehosts;
- ok = 0;
- }
- while (ok && (lph->lph_flag & LC_VALID)) {
- if (nqsrv_cmpnam(slp, nam, lph))
- goto doreply;
- if (++i == LC_MOREHOSTSIZ) {
- i = 0;
- if (*lphp) {
- lph = (*lphp)->lpm_hosts;
- lphp = &((*lphp)->lpm_next);
- } else
- ok = 0;
- } else
- lph++;
- }
- nqsrv_locklease(lp);
- if (!ok) {
- *lphp = (struct nqm *)
- malloc(sizeof (struct nqm),
- M_NQMHOST, M_WAITOK | M_ZERO);
- lph = (*lphp)->lpm_hosts;
- }
- nqsrv_addhost(lph, slp, nam);
- nqsrv_unlocklease(lp);
- } else {
- lp->lc_flag |= LC_NONCACHABLE;
- nqsrv_locklease(lp);
- nqsrv_send_eviction(vp, lp, slp, nam, cred);
- nqsrv_waitfor_expiry(lp);
- nqsrv_unlocklease(lp);
- }
-doreply:
- /*
- * Update the lease and return
- */
- if ((flags & ND_CHECK) == 0)
- nqsrv_instimeq(lp, *duration);
- if (lp->lc_flag & LC_NONCACHABLE)
- *cachablep = 0;
- else {
- *cachablep = 1;
- if (flags & ND_WRITE)
- lp->lc_flag |= LC_WRITTEN;
- }
- splx(s);
- return (0);
- }
- splx(s);
- if (flags & ND_CHECK)
- return (0);
-
- /*
- * Allocate new lease
- * The value of nqsrv_maxnumlease should be set generously, so that
- * the following "printf" happens infrequently.
- */
- if (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease) {
- printf("Nqnfs server, too many leases\n");
- do {
- (void) tsleep((caddr_t)&lbolt, PSOCK,
- "nqsrvnuml", 0);
- } while (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease);
- }
- MALLOC(lp, struct nqlease *, sizeof (struct nqlease), M_NQLEASE,
- M_WAITOK | M_ZERO);
- if (flags & ND_WRITE)
- lp->lc_flag |= (LC_WRITE | LC_WRITTEN);
- nqsrv_addhost(&lp->lc_host, slp, nam);
- lp->lc_vp = vp;
- lp->lc_fsid = fh.fh_fsid;
- bcopy(fh.fh_fid.fid_data, lp->lc_fiddata,
- fh.fh_fid.fid_len - sizeof (int32_t));
- if(!lpp)
- panic("nfs_nqlease.c: Phoney lpp");
- LIST_INSERT_HEAD(lpp, lp, lc_hash);
- vp->v_lease = lp;
- s = splsoftclock();
- nqsrv_instimeq(lp, *duration);
- splx(s);
- *cachablep = 1;
- if (++nfsstats.srvnqnfs_leases > nfsstats.srvnqnfs_maxleases)
- nfsstats.srvnqnfs_maxleases = nfsstats.srvnqnfs_leases;
- return (0);
-}
-
-/*
- * Local lease check for server syscalls.
- * Just set up args and let nqsrv_getlease() do the rest.
- * nqnfs_vop_lease_check() is the VOP_LEASE() form of the same routine.
- * Ifdef'd code in nfsnode.h renames these routines to whatever a particular
- * OS needs.
- */
-void
-nqnfs_lease_check(vp, td, cred, flag)
- struct vnode *vp;
- struct thread *td;
- struct ucred *cred;
- int flag;
-{
- u_int32_t duration = 0;
- int cache;
- u_quad_t frev;
-
- (void) nqsrv_getlease(vp, &duration, ND_CHECK | flag, NQLOCALSLP,
- td, (struct sockaddr *)0, &cache, &frev, cred);
-}
-
-int
-nqnfs_vop_lease_check(ap)
- struct vop_lease_args /* {
- struct vnode *a_vp;
- struct thread *a_td;
- struct ucred *a_cred;
- int a_flag;
- } */ *ap;
-{
- u_int32_t duration = 0;
- int cache;
- u_quad_t frev;
-
- (void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag,
- NQLOCALSLP, ap->a_td, (struct sockaddr *)0,
- &cache, &frev, ap->a_cred);
- return (0);
-}
-
-
-/*
- * Add a host to an nqhost structure for a lease.
- */
-static void
-nqsrv_addhost(lph, slp, nam)
- register struct nqhost *lph;
- struct nfssvc_sock *slp;
- struct sockaddr *nam;
-{
- struct sockaddr_in *saddr;
- struct socket *nsso;
-
- if (slp == NQLOCALSLP) {
- lph->lph_flag |= (LC_VALID | LC_LOCAL);
- return;
- }
- nsso = slp->ns_so;
- lph->lph_slp = slp;
- if (nsso && nsso->so_proto->pr_protocol == IPPROTO_UDP) {
- saddr = (struct sockaddr_in *)nam;
- lph->lph_flag |= (LC_VALID | LC_UDP);
- lph->lph_inetaddr = saddr->sin_addr.s_addr;
- lph->lph_port = saddr->sin_port;
- } else {
- lph->lph_flag |= (LC_VALID | LC_SREF);
- slp->ns_sref++;
- }
-}
-
-/*
- * Update the lease expiry time and position it in the timer queue correctly.
- */
-static void
-nqsrv_instimeq(lp, duration)
- register struct nqlease *lp;
- u_int32_t duration;
-{
- register struct nqlease *tlp;
- time_t newexpiry;
-
- newexpiry = time_second + duration + nqsrv_clockskew;
- if (lp->lc_expiry == newexpiry)
- return;
- if (TAILQ_NEXT(lp, lc_timer) != 0) {
- TAILQ_REMOVE(&nqtimerhead, lp, lc_timer);
- }
- lp->lc_expiry = newexpiry;
-
- /*
- * Find where in the queue it should be.
- */
- TAILQ_FOREACH_REVERSE(tlp, &nqtimerhead, nqtimerhead, lc_timer)
- if (tlp->lc_expiry <= newexpiry)
- break;
-#ifdef HASNVRAM
- if (tlp == TAILQ_LAST(&nqtimerhead))
- NQSTORENOVRAM(newexpiry);
-#endif /* HASNVRAM */
- if (tlp == NULL) {
- TAILQ_INSERT_HEAD(&nqtimerhead, lp, lc_timer);
- } else {
- TAILQ_INSERT_AFTER(&nqtimerhead, tlp, lp, lc_timer);
- }
-}
-
-/*
- * Compare the requesting host address with the lph entry in the lease.
- * Return true iff it is the same.
- * This is somewhat messy due to the union in the nqhost structure.
- * The local host is indicated by the special value of NQLOCALSLP for slp.
- */
-static int
-nqsrv_cmpnam(slp, nam, lph)
- register struct nfssvc_sock *slp;
- struct sockaddr *nam;
- register struct nqhost *lph;
-{
- register struct sockaddr_in *saddr;
- struct sockaddr *addr;
- union nethostaddr lhaddr;
- struct socket *nsso;
- int ret;
-
- if (slp == NQLOCALSLP) {
- if (lph->lph_flag & LC_LOCAL)
- return (1);
- else
- return (0);
- }
- nsso = slp->ns_so;
- if (nsso && nsso->so_proto->pr_protocol == IPPROTO_UDP) {
- addr = nam;
- } else {
- addr = slp->ns_nam;
- }
- if (lph->lph_flag & LC_UDP) {
- ret = netaddr_match(AF_INET, &lph->lph_haddr, addr);
- } else {
- if ((lph->lph_slp->ns_flag & SLP_VALID) == 0)
- return (0);
- saddr = (struct sockaddr_in *)lph->lph_slp->ns_nam;
- if (saddr->sin_family == AF_INET)
- lhaddr.had_inetaddr = saddr->sin_addr.s_addr;
- else
- lhaddr.had_nam = lph->lph_slp->ns_nam;
- ret = netaddr_match(saddr->sin_family, &lhaddr, addr);
- }
- return (ret);
-}
-
-/*
- * Send out eviction notice messages to all other hosts for the lease.
- */
-static void
-nqsrv_send_eviction(vp, lp, slp, nam, cred)
- struct vnode *vp;
- register struct nqlease *lp;
- struct nfssvc_sock *slp;
- struct sockaddr *nam;
- struct ucred *cred;
-{
- register struct nqhost *lph = &lp->lc_host;
- register int siz;
- struct nqm *lphnext = lp->lc_morehosts;
- struct mbuf *m, *mreq, *mb, *mb2, *mheadend;
- struct sockaddr *nam2;
- struct sockaddr_in *saddr;
- nfsfh_t nfh;
- fhandle_t *fhp;
- caddr_t bpos, cp;
- u_int32_t xid, *tl;
- int len = 1, ok = 1, i = 0;
-
- while (ok && (lph->lph_flag & LC_VALID)) {
- if (nqsrv_cmpnam(slp, nam, lph)) {
- lph->lph_flag |= LC_VACATED;
- } else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
- struct socket *so;
- int sotype;
- int *solockp = NULL;
-
- so = lph->lph_slp->ns_so;
- if (lph->lph_flag & LC_UDP) {
- MALLOC(nam2, struct sockaddr *,
- sizeof *nam2, M_SONAME, M_WAITOK);
- saddr = (struct sockaddr_in *)nam2;
- saddr->sin_len = sizeof *saddr;
- saddr->sin_family = AF_INET;
- saddr->sin_addr.s_addr = lph->lph_inetaddr;
- saddr->sin_port = lph->lph_port;
- } else if (lph->lph_slp->ns_flag & SLP_VALID) {
- nam2 = (struct sockaddr *)0;
- } else {
- goto nextone;
- }
- sotype = so->so_type;
- if (so->so_proto->pr_flags & PR_CONNREQUIRED)
- solockp = &lph->lph_slp->ns_solock;
- nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED,
- NFSX_V3FH + NFSX_UNSIGNED);
- fhp = &nfh.fh_generic;
- bzero((caddr_t)fhp, sizeof(nfh));
- fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
- VFS_VPTOFH(vp, &fhp->fh_fid);
- nfsm_srvfhtom(fhp, 1);
- m = mreq;
- siz = 0;
- while (m) {
- siz += m->m_len;
- m = m->m_next;
- }
- if (siz <= 0 || siz > NFS_MAXPACKET) {
- printf("mbuf siz=%d\n",siz);
- panic("Bad nfs svc reply");
- }
- m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS),
- NQNFSPROC_EVICTED,
- RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
- 0, (char *)NULL, mreq, siz, &mheadend, &xid);
- /*
- * For stream protocols, prepend a Sun RPC
- * Record Mark.
- */
- if (sotype == SOCK_STREAM) {
- M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT);
- *mtod(m, u_int32_t *) = htonl(0x80000000 |
- (m->m_pkthdr.len - NFSX_UNSIGNED));
- }
- /*
- * nfs_sndlock if PR_CONNREQUIRED XXX
- */
-
- if ((lph->lph_flag & LC_UDP) == 0 &&
- ((lph->lph_slp->ns_flag & SLP_VALID) == 0 ||
- nfs_slplock(lph->lph_slp, 0) == 0)) {
- m_freem(m);
- } else {
- (void) nfs_send(so, nam2, m,
- (struct nfsreq *)0);
- if (solockp)
- nfs_slpunlock(lph->lph_slp);
- }
- if (lph->lph_flag & LC_UDP)
- FREE(nam2, M_SONAME);
- }
-nextone:
- if (++i == len) {
- if (lphnext) {
- i = 0;
- len = LC_MOREHOSTSIZ;
- lph = lphnext->lpm_hosts;
- lphnext = lphnext->lpm_next;
- } else
- ok = 0;
- } else
- lph++;
- }
-}
-
-/*
- * Wait for the lease to expire.
- * This will occur when all clients have sent "vacated" messages to
- * this server OR when it expires do to timeout.
- */
-static void
-nqsrv_waitfor_expiry(lp)
- register struct nqlease *lp;
-{
- register struct nqhost *lph;
- register int i;
- struct nqm *lphnext;
- int len, ok;
-
-tryagain:
- if (time_second > lp->lc_expiry)
- return;
- lph = &lp->lc_host;
- lphnext = lp->lc_morehosts;
- len = 1;
- i = 0;
- ok = 1;
- while (ok && (lph->lph_flag & LC_VALID)) {
- if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
- lp->lc_flag |= LC_EXPIREDWANTED;
- (void) tsleep((caddr_t)&lp->lc_flag, PSOCK,
- "nqexp", 0);
- goto tryagain;
- }
- if (++i == len) {
- if (lphnext) {
- i = 0;
- len = LC_MOREHOSTSIZ;
- lph = lphnext->lpm_hosts;
- lphnext = lphnext->lpm_next;
- } else
- ok = 0;
- } else
- lph++;
- }
-}
-
-/*
- * Nqnfs server timer that maintains the server lease queue.
- * Scan the lease queue for expired entries:
- * - when one is found, wakeup anyone waiting for it
- * else dequeue and free
- */
-void
-nqnfs_serverd()
-{
- register struct nqlease *lp;
- register struct nqhost *lph;
- struct nqlease *nextlp;
- struct nqm *lphnext, *olphnext;
- int i, len, ok;
-
- for (lp = TAILQ_FIRST(&nqtimerhead); lp; lp = nextlp) {
- if (lp->lc_expiry >= time_second)
- break;
- nextlp = TAILQ_NEXT(lp, lc_timer);
- if (lp->lc_flag & LC_EXPIREDWANTED) {
- lp->lc_flag &= ~LC_EXPIREDWANTED;
- wakeup((caddr_t)&lp->lc_flag);
- } else if ((lp->lc_flag & (LC_LOCKED | LC_WANTED)) == 0) {
- /*
- * Make a best effort at keeping a write caching lease long
- * enough by not deleting it until it has been explicitly
- * vacated or there have been no writes in the previous
- * write_slack seconds since expiry and the nfsds are not
- * all busy. The assumption is that if the nfsds are not
- * all busy now (no queue of nfs requests), then the client
- * would have been able to do at least one write to the
- * file during the last write_slack seconds if it was still
- * trying to push writes to the server.
- */
- if ((lp->lc_flag & (LC_WRITE | LC_VACATED)) == LC_WRITE &&
- ((lp->lc_flag & LC_WRITTEN) || nfsd_waiting == 0)) {
- lp->lc_flag &= ~LC_WRITTEN;
- nqsrv_instimeq(lp, nqsrv_writeslack);
- } else {
- TAILQ_REMOVE(&nqtimerhead, lp, lc_timer);
- LIST_REMOVE(lp, lc_hash);
- /*
- * This soft reference may no longer be valid, but
- * no harm done. The worst case is if the vnode was
- * recycled and has another valid lease reference,
- * which is dereferenced prematurely.
- */
- lp->lc_vp->v_lease = (struct nqlease *)0;
- lph = &lp->lc_host;
- lphnext = lp->lc_morehosts;
- olphnext = (struct nqm *)0;
- len = 1;
- i = 0;
- ok = 1;
- while (ok && (lph->lph_flag & LC_VALID)) {
- if (lph->lph_flag & LC_SREF)
- nfsrv_slpderef(lph->lph_slp);
- if (++i == len) {
- if (olphnext) {
- free((caddr_t)olphnext, M_NQMHOST);
- olphnext = (struct nqm *)0;
- }
- if (lphnext) {
- olphnext = lphnext;
- i = 0;
- len = LC_MOREHOSTSIZ;
- lph = lphnext->lpm_hosts;
- lphnext = lphnext->lpm_next;
- } else
- ok = 0;
- } else
- lph++;
- }
- FREE((caddr_t)lp, M_NQLEASE);
- if (olphnext)
- free((caddr_t)olphnext, M_NQMHOST);
- nfsstats.srvnqnfs_leases--;
- }
- }
- }
-}
-
-/*
- * Called from nfssvc_nfsd() for a getlease rpc request.
- * Do the from/to xdr translation and call nqsrv_getlease() to
- * do the real work.
- */
-int
-nqnfsrv_getlease(nfsd, slp, td, mrq)
- struct nfsrv_descript *nfsd;
- struct nfssvc_sock *slp;
- struct thread *td;
- struct mbuf **mrq;
-{
- struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
- struct sockaddr *nam = nfsd->nd_nam;
- caddr_t dpos = nfsd->nd_dpos;
- struct ucred *cred = &nfsd->nd_cr;
- register struct nfs_fattr *fp;
- struct vattr va;
- register struct vattr *vap = &va;
- struct vnode *vp;
- nfsfh_t nfh;
- fhandle_t *fhp;
- register u_int32_t *tl;
- register int32_t t1;
- u_quad_t frev;
- caddr_t bpos;
- int error = 0;
- char *cp2;
- struct mbuf *mb, *mb2, *mreq;
- int flags, rdonly, cache;
-
- fhp = &nfh.fh_generic;
- nfsm_srvmtofh(fhp);
- nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
- flags = fxdr_unsigned(int, *tl++);
- nfsd->nd_duration = fxdr_unsigned(int, *tl);
- error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
- (nfsd->nd_flag & ND_KERBAUTH), TRUE);
- if (error) {
- nfsm_reply(0);
- goto nfsmout;
- }
- if (rdonly && flags == ND_WRITE) {
- error = EROFS;
- vput(vp);
- nfsm_reply(0);
- }
- (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, td,
- nam, &cache, &frev, cred);
- error = VOP_GETATTR(vp, vap, cred, td);
- vput(vp);
- nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
- nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(cache);
- *tl++ = txdr_unsigned(nfsd->nd_duration);
- txdr_hyper(frev, tl);
- nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR);
- nfsm_srvfillattr(vap, fp);
- nfsm_srvdone;
-}
-
-/*
- * Called from nfssvc_nfsd() when a "vacated" message is received from a
- * client. Find the entry and expire it.
- */
-int
-nqnfsrv_vacated(nfsd, slp, td, mrq)
- struct nfsrv_descript *nfsd;
- struct nfssvc_sock *slp;
- struct thread *td;
- struct mbuf **mrq;
-{
- struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
- struct sockaddr *nam = nfsd->nd_nam;
- caddr_t dpos = nfsd->nd_dpos;
- register struct nqlease *lp;
- register struct nqhost *lph;
- struct nqlease *tlp = (struct nqlease *)0;
- nfsfh_t nfh;
- fhandle_t *fhp;
- register u_int32_t *tl;
- register int32_t t1;
- struct nqm *lphnext;
- struct mbuf *mreq, *mb;
- int error = 0, i, len, ok, gotit = 0, cache = 0;
- char *cp2, *bpos;
- u_quad_t frev;
-
- fhp = &nfh.fh_generic;
- nfsm_srvmtofh(fhp);
- m_freem(mrep);
- /*
- * Find the lease by searching the hash list.
- */
- for (lp = NQFHHASH(fhp->fh_fid.fid_data)->lh_first; lp != 0;
- lp = lp->lc_hash.le_next)
- if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] &&
- fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] &&
- !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata,
- MAXFIDSZ)) {
- /* Found it */
- tlp = lp;
- break;
- }
- if (tlp != 0) {
- lp = tlp;
- len = 1;
- i = 0;
- lph = &lp->lc_host;
- lphnext = lp->lc_morehosts;
- ok = 1;
- while (ok && (lph->lph_flag & LC_VALID)) {
- if (nqsrv_cmpnam(slp, nam, lph)) {
- lph->lph_flag |= LC_VACATED;
- gotit++;
- break;
- }
- if (++i == len) {
- if (lphnext) {
- len = LC_MOREHOSTSIZ;
- i = 0;
- lph = lphnext->lpm_hosts;
- lphnext = lphnext->lpm_next;
- } else
- ok = 0;
- } else
- lph++;
- }
- if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) {
- lp->lc_flag &= ~LC_EXPIREDWANTED;
- wakeup((caddr_t)&lp->lc_flag);
- }
-nfsmout:
- return (EPERM);
- }
- return (EPERM);
-}
-
-#endif /* NFS_NOSERVER */
-
-/*
- * Client get lease rpc function.
- */
-int
-nqnfs_getlease(vp, rwflag, cred, td)
- register struct vnode *vp;
- int rwflag;
- struct ucred *cred;
- struct thread *td;
-{
- register u_int32_t *tl;
- register caddr_t cp;
- register int32_t t1, t2;
- register struct nfsnode *np;
- struct nfsmount *nmp = VFSTONFS(vp->v_mount);
- caddr_t bpos, dpos, cp2;
- time_t reqtime;
- int error = 0;
- struct mbuf *mreq, *mrep, *md, *mb, *mb2;
- int cachable;
- u_quad_t frev;
-
- nfsstats.rpccnt[NQNFSPROC_GETLEASE]++;
- mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED,
- &bpos);
- nfsm_fhtom(vp, 1);
- nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
- *tl++ = txdr_unsigned(rwflag);
- *tl = txdr_unsigned(nmp->nm_leaseterm);
- reqtime = time_second;
- nfsm_request(vp, NQNFSPROC_GETLEASE, td, cred);
- np = VTONFS(vp);
- nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
- cachable = fxdr_unsigned(int, *tl++);
- reqtime += fxdr_unsigned(int, *tl++);
- if (reqtime > time_second) {
- frev = fxdr_hyper(tl);
- nqnfs_clientlease(nmp, np, rwflag, cachable, reqtime, frev);
- nfsm_loadattr(vp, (struct vattr *)0);
- } else
- error = NQNFS_EXPIRED;
- nfsm_reqdone;
- return (error);
-}
-
-#ifndef NFS_NOSERVER
-/*
- * Client vacated message function.
- */
-static int
-nqnfs_vacated(vp, cred)
- register struct vnode *vp;
- struct ucred *cred;
-{
- register caddr_t cp;
- register int i;
- register u_int32_t *tl;
- register int32_t t2;
- caddr_t bpos;
- u_int32_t xid;
- int error = 0;
- struct mbuf *m, *mreq, *mb, *mb2, *mheadend;
- struct nfsmount *nmp;
- struct nfsreq myrep;
-
- nmp = VFSTONFS(vp->v_mount);
- nfsstats.rpccnt[NQNFSPROC_VACATED]++;
- nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH(1));
- nfsm_fhtom(vp, 1);
- m = mreq;
- i = 0;
- while (m) {
- i += m->m_len;
- m = m->m_next;
- }
- m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED,
- RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
- 0, (char *)NULL, mreq, i, &mheadend, &xid);
- if (nmp->nm_sotype == SOCK_STREAM) {
- M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT);
- *mtod(m, u_int32_t *) = htonl(0x80000000 | (m->m_pkthdr.len -
- NFSX_UNSIGNED));
- }
- myrep.r_flags = 0;
- myrep.r_nmp = nmp;
- if (nmp->nm_soflags & PR_CONNREQUIRED)
- (void) nfs_sndlock(&myrep);
- (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep);
- if (nmp->nm_soflags & PR_CONNREQUIRED)
- nfs_sndunlock(&myrep);
-nfsmout:
- return (error);
-}
-
-/*
- * Called for client side callbacks
- */
-int
-nqnfs_callback(nmp, mrep, md, dpos)
- struct nfsmount *nmp;
- struct mbuf *mrep, *md;
- caddr_t dpos;
-{
- register struct vnode *vp;
- register u_int32_t *tl;
- register int32_t t1;
- nfsfh_t nfh;
- fhandle_t *fhp;
- struct nfsnode *np;
- struct nfsd tnfsd;
- struct nfssvc_sock *slp;
- struct nfsrv_descript ndesc;
- register struct nfsrv_descript *nfsd = &ndesc;
- struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq;
- int error = 0, cache = 0;
- char *cp2, *bpos;
- u_quad_t frev;
-
-#ifndef nolint
- slp = NULL;
-#endif
- nfsd->nd_mrep = mrep;
- nfsd->nd_md = md;
- nfsd->nd_dpos = dpos;
- error = nfs_getreq(nfsd, &tnfsd, FALSE);
- if (error)
- return (error);
- md = nfsd->nd_md;
- dpos = nfsd->nd_dpos;
- if (nfsd->nd_procnum != NQNFSPROC_EVICTED) {
- m_freem(mrep);
- return (EPERM);
- }
- fhp = &nfh.fh_generic;
- nfsm_srvmtofh(fhp);
- m_freem(mrep);
- error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np);
- if (error)
- return (error);
- vp = NFSTOV(np);
- if (TAILQ_NEXT(np, n_timer) != 0) {
- np->n_expiry = 0;
- np->n_flag |= NQNFSEVICTED;
- if (TAILQ_FIRST(&nmp->nm_timerhead) != np) {
- TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
- TAILQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
- }
- }
- vput(vp);
- nfsm_srvdone;
-}
-
-
-/*
- * Nqnfs client helper daemon. Runs once a second to expire leases.
- * It also get authorization strings for "kerb" mounts.
- * It must start at the beginning of the list again after any potential
- * "sleep" since nfs_reclaim() called from vclean() can pull a node off
- * the list asynchronously.
- */
-int
-nqnfs_clientd(nmp, cred, ncd, flag, argp, td)
- register struct nfsmount *nmp;
- struct ucred *cred;
- struct nfsd_cargs *ncd;
- int flag;
- caddr_t argp;
- struct thread *td;
-{
- register struct nfsnode *np;
- struct vnode *vp;
- struct nfsreq myrep;
- struct nfsuid *nuidp, *nnuidp;
- int error = 0, vpid;
-
- /*
- * First initialize some variables
- */
-
- /*
- * If an authorization string is being passed in, get it.
- */
- if ((flag & NFSSVC_GOTAUTH) &&
- (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_DISMNT)) == 0) {
- if (nmp->nm_state & NFSSTA_HASAUTH)
- panic("cld kerb");
- if ((flag & NFSSVC_AUTHINFAIL) == 0) {
- if (ncd->ncd_authlen <= nmp->nm_authlen &&
- ncd->ncd_verflen <= nmp->nm_verflen &&
- !copyin(ncd->ncd_authstr,nmp->nm_authstr,ncd->ncd_authlen)&&
- !copyin(ncd->ncd_verfstr,nmp->nm_verfstr,ncd->ncd_verflen)){
- nmp->nm_authtype = ncd->ncd_authtype;
- nmp->nm_authlen = ncd->ncd_authlen;
- nmp->nm_verflen = ncd->ncd_verflen;
-#ifdef NFSKERB
- nmp->nm_key = ncd->ncd_key;
-#endif
- } else
- nmp->nm_state |= NFSSTA_AUTHERR;
- } else
- nmp->nm_state |= NFSSTA_AUTHERR;
- nmp->nm_state |= NFSSTA_HASAUTH;
- wakeup((caddr_t)&nmp->nm_authlen);
- } else
- nmp->nm_state |= NFSSTA_WAITAUTH;
-
- /*
- * Loop every second updating queue until there is a termination sig.
- */
- while ((nmp->nm_state & NFSSTA_DISMNT) == 0) {
- if (nmp->nm_flag & NFSMNT_NQNFS) {
- /*
- * If there are no outstanding requests (and therefore no
- * processes in nfs_reply) and there is data in the receive
- * queue, poke for callbacks.
- */
- if (nfs_reqq.tqh_first == 0 && nmp->nm_so &&
- nmp->nm_so->so_rcv.sb_cc > 0) {
- myrep.r_flags = R_GETONEREP;
- myrep.r_nmp = nmp;
- myrep.r_mrep = (struct mbuf *)0;
- myrep.r_td = (struct thread *)0;
- (void) nfs_reply(&myrep);
- }
-
- /*
- * Loop through the leases, updating as required.
- */
- while ((np = TAILQ_FIRST(&nmp->nm_timerhead)) != NULL) {
- if (nmp->nm_state & NFSSTA_DISMINPROG)
- break;
- vp = NFSTOV(np);
- vpid = vp->v_id;
- if (np->n_expiry < time_second) {
- if (vget(vp, LK_EXCLUSIVE, td) == 0) {
- nmp->nm_inprog = vp;
- if (vpid == vp->v_id) {
- TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
- TAILQ_NEXT(np, n_timer) = 0;
- if (np->n_flag & (NMODIFIED | NQNFSEVICTED)) {
- if (np->n_flag & NQNFSEVICTED) {
- if (vp->v_type == VDIR)
- nfs_invaldir(vp);
- cache_purge(vp);
- (void) nfs_vinvalbuf(vp,
- V_SAVE, cred, td, 0);
- np->n_flag &= ~NQNFSEVICTED;
- (void) nqnfs_vacated(vp, cred);
- } else if (vp->v_type == VREG) {
- (void) VOP_FSYNC(vp, cred,
- MNT_WAIT, td);
- np->n_flag &= ~NMODIFIED;
- }
- }
- }
- vput(vp);
- nmp->nm_inprog = NULLVP;
- }
- } else if ((np->n_expiry - NQ_RENEWAL) < time_second) {
- if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE))
- == NQNFSWRITE &&
- !TAILQ_EMPTY(&vp->v_dirtyblkhd) &&
- vget(vp, LK_EXCLUSIVE, td) == 0) {
- nmp->nm_inprog = vp;
- if (vpid == vp->v_id &&
- nqnfs_getlease(vp, ND_WRITE, cred, td)==0)
- np->n_brev = np->n_lrev;
- vput(vp);
- nmp->nm_inprog = NULLVP;
- }
- } else
- break;
- }
- }
-
- /*
- * Get an authorization string, if required.
- */
- if ((nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_DISMNT | NFSSTA_HASAUTH)) == 0) {
- ncd->ncd_authuid = nmp->nm_authuid;
- if (copyout((caddr_t)ncd, argp, sizeof (struct nfsd_cargs)))
- nmp->nm_state |= NFSSTA_WAITAUTH;
- else
- return (ENEEDAUTH);
- }
-
- /*
- * Wait a bit (no pun) and do it again.
- */
- if ((nmp->nm_state & NFSSTA_DISMNT) == 0 &&
- (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_HASAUTH))) {
- error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH,
- "nqnfstimr", hz / 3);
- if (error == EINTR || error == ERESTART)
- (void) dounmount(nmp->nm_mountp, 0, td);
- }
- }
-
- /*
- * Finally, we can free up the mount structure.
- */
- for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) {
- nnuidp = nuidp->nu_lru.tqe_next;
- LIST_REMOVE(nuidp, nu_hash);
- TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
- free((caddr_t)nuidp, M_NFSUID);
- }
- zfree(nfsmount_zone, nmp);
- if (error == EWOULDBLOCK)
- error = 0;
- return (error);
-}
-
-#endif /* NFS_NOSERVER */
-
-/*
- * Adjust all timer queue expiry times when the time of day clock is changed.
- * Called from the settimeofday() syscall.
- */
-void
-nqnfs_lease_updatetime(deltat)
- register int deltat;
-{
- struct thread *td = curthread; /* XXX */
- struct nqlease *lp;
- struct nfsnode *np;
- struct mount *mp, *nxtmp;
- struct nfsmount *nmp;
- int s;
-
- if (nqnfsstarttime != 0)
- nqnfsstarttime += deltat;
- s = splsoftclock();
- TAILQ_FOREACH(lp, &nqtimerhead, lc_timer)
- lp->lc_expiry += deltat;
- splx(s);
-
- /*
- * Search the mount list for all nqnfs mounts and do their timer
- * queues.
- */
- mtx_lock(&mountlist_mtx);
- for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nxtmp) {
- if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
- nxtmp = TAILQ_NEXT(mp, mnt_list);
- continue;
- }
- if (mp->mnt_stat.f_type == nfs_mount_type) {
- nmp = VFSTONFS(mp);
- if (nmp->nm_flag & NFSMNT_NQNFS) {
- TAILQ_FOREACH(np, &nmp->nm_timerhead, n_timer) {
- np->n_expiry += deltat;
- }
- }
- }
- mtx_lock(&mountlist_mtx);
- nxtmp = TAILQ_NEXT(mp, mnt_list);
- vfs_unbusy(mp, td);
- }
- mtx_unlock(&mountlist_mtx);
-}
-
-#ifndef NFS_NOSERVER
-/*
- * Lock a server lease.
- */
-static void
-nqsrv_locklease(lp)
- struct nqlease *lp;
-{
-
- while (lp->lc_flag & LC_LOCKED) {
- lp->lc_flag |= LC_WANTED;
- (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0);
- }
- lp->lc_flag |= LC_LOCKED;
- lp->lc_flag &= ~LC_WANTED;
-}
-
-/*
- * Unlock a server lease.
- */
-static void
-nqsrv_unlocklease(lp)
- struct nqlease *lp;
-{
-
- lp->lc_flag &= ~LC_LOCKED;
- if (lp->lc_flag & LC_WANTED)
- wakeup((caddr_t)lp);
-}
-#endif /* NFS_NOSERVER */
-
-/*
- * Update a client lease.
- */
-void
-nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev)
- register struct nfsmount *nmp;
- register struct nfsnode *np;
- int rwflag, cachable;
- time_t expiry;
- u_quad_t frev;
-{
- register struct nfsnode *tp;
-
- if (TAILQ_NEXT(np, n_timer) != 0) {
- TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
- if (rwflag == ND_WRITE)
- np->n_flag |= NQNFSWRITE;
- } else if (rwflag == ND_READ)
- np->n_flag &= ~NQNFSWRITE;
- else
- np->n_flag |= NQNFSWRITE;
- if (cachable)
- np->n_flag &= ~NQNFSNONCACHE;
- else
- np->n_flag |= NQNFSNONCACHE;
- np->n_expiry = expiry;
- np->n_lrev = frev;
- TAILQ_FOREACH_REVERSE(tp, &nmp->nm_timerhead, timhd, n_timer)
- if (tp->n_expiry <= np->n_expiry)
- break;
- if (tp == NULL) {
- TAILQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
- } else {
- TAILQ_INSERT_AFTER(&nmp->nm_timerhead, tp, np, n_timer);
- }
-}
OpenPOWER on IntegriCloud