📄 nfs_nqlease.c
字号:
/* * 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.3 (Berkeley) 1/4/94 *//* * 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/vnode.h>#include <sys/mount.h>#include <sys/kernel.h>#include <sys/proc.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/file.h>#include <sys/buf.h>#include <sys/stat.h>#include <sys/protosw.h>#include <netinet/in.h>#include <nfs/rpcv2.h>#include <nfs/nfsv2.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>/* * List head for the lease queue and other global data. * At any time a lease is linked into a list ordered by increasing expiry time. */#define NQFHHASH(f) ((*((u_long *)(f)))&nqfheadhash)union nqsrvthead nqthead;struct nqlease **nqfhead;u_long nqfheadhash;time_t nqnfsstarttime = (time_t)0;u_long nqnfs_prog, nqnfs_vers;int nqsrv_clockskew = NQ_CLOCKSKEW;int nqsrv_writeslack = NQ_WRITESLACK;int nqsrv_maxlease = NQ_MAXLEASE;int nqsrv_maxnumlease = NQ_MAXNUMLEASE;void nqsrv_instimeq(), nqsrv_send_eviction(), nfs_sndunlock();void nqsrv_unlocklease(), nqsrv_waitfor_expiry(), nfsrv_slpderef();void nqsrv_addhost(), nqsrv_locklease(), nqnfs_serverd();void nqnfs_clientlease();struct mbuf *nfsm_rpchead();/* * Signifies which rpcs can have piggybacked lease requests */int nqnfs_piggy[NFS_NPROCS] = { 0, NQL_READ, NQL_WRITE, 0, NQL_READ, NQL_READ, NQL_READ, 0, NQL_WRITE, 0, 0, 0, 0, 0, 0, 0, NQL_READ, 0, NQL_READ, 0, 0, 0, 0,};int nnnnnn = sizeof (struct nqlease);int oooooo = sizeof (struct nfsnode);extern nfstype nfs_type[9];extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;extern struct nfsd nfsd_head;extern int nfsd_waiting;extern struct nfsreq nfsreqh;#define TRUE 1#define FALSE 0/* * Get or check for a lease for "vp", based on NQL_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) */nqsrv_getlease(vp, duration, flags, nd, nam, cachablep, frev, cred) struct vnode *vp; u_long *duration; int flags; struct nfsd *nd; struct mbuf *nam; int *cachablep; u_quad_t *frev; struct ucred *cred;{ register struct nqlease *lp, *lq, **lpp; register struct nqhost *lph; 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; if (error = VOP_GETATTR(vp, &vattr, cred, nd->nd_procp)) return (error); *frev = vattr.va_filerev; s = splsoftclock(); tlp = vp->v_lease; if ((flags & NQL_CHECK) == 0) nfsstats.srvnqnfs_getleases++; if (tlp == (struct nqlease *)0) { /* * Find the lease by searching the hash list. */ fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; if (error = VFS_VPTOFH(vp, &fh.fh_fid)) { splx(s); return (error); } lpp = &nqfhead[NQFHHASH(fh.fh_fid.fid_data)]; for (lp = *lpp; lp; lp = lp->lc_fhnext) 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 (long))) { /* Found it */ lp->lc_vp = vp; vp->v_lease = lp; tlp = lp; break; } } lp = tlp; if (lp) { if ((lp->lc_flag & LC_NONCACHABLE) || (lp->lc_morehosts == (struct nqm *)0 && nqsrv_cmpnam(nd->nd_slp, nam, &lp->lc_host))) goto doreply; if ((flags & NQL_READ) && (lp->lc_flag & LC_WRITE)==0) { if (flags & NQL_CHECK) goto doreply; if (nqsrv_cmpnam(nd->nd_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(nd->nd_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); bzero((caddr_t)*lphp, sizeof (struct nqm)); lph = (*lphp)->lpm_hosts; } nqsrv_addhost(lph, nd->nd_slp, nam); nqsrv_unlocklease(lp); } else { lp->lc_flag |= LC_NONCACHABLE; nqsrv_locklease(lp); nqsrv_send_eviction(vp, lp, nd->nd_slp, nam, cred); nqsrv_waitfor_expiry(lp); nqsrv_unlocklease(lp); }doreply: /* * Update the lease and return */ if ((flags & NQL_CHECK) == 0) nqsrv_instimeq(lp, *duration); if (lp->lc_flag & LC_NONCACHABLE) *cachablep = 0; else { *cachablep = 1; if (flags & NQL_WRITE) lp->lc_flag |= LC_WRITTEN; } splx(s); return (0); } splx(s); if (flags & NQL_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); bzero((caddr_t)lp, sizeof (struct nqlease)); if (flags & NQL_WRITE) lp->lc_flag |= (LC_WRITE | LC_WRITTEN); nqsrv_addhost(&lp->lc_host, nd->nd_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 (long)); if (lq = *lpp) lq->lc_fhprev = &lp->lc_fhnext; lp->lc_fhnext = lq; lp->lc_fhprev = lpp; *lpp = lp; 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. */voidlease_check(vp, p, cred, flag) struct vnode *vp; struct proc *p; struct ucred *cred; int flag;{ int duration = 0, cache; struct nfsd nfsd; u_quad_t frev; nfsd.nd_slp = NQLOCALSLP; nfsd.nd_procp = p; (void) nqsrv_getlease(vp, &duration, NQL_CHECK | flag, &nfsd, (struct mbuf *)0, &cache, &frev, cred);}/* * Add a host to an nqhost structure for a lease. */voidnqsrv_addhost(lph, slp, nam) register struct nqhost *lph; struct nfssvc_sock *slp; struct mbuf *nam;{ register struct sockaddr_in *saddr; if (slp == NQLOCALSLP) lph->lph_flag |= (LC_VALID | LC_LOCAL); else if (slp == nfs_udpsock) { saddr = mtod(nam, struct sockaddr_in *); lph->lph_flag |= (LC_VALID | LC_UDP); lph->lph_inetaddr = saddr->sin_addr.s_addr; lph->lph_port = saddr->sin_port; } else if (slp == nfs_cltpsock) { lph->lph_nam = m_copym(nam, 0, M_COPYALL, M_WAIT); lph->lph_flag |= (LC_VALID | LC_CLTP); } else { lph->lph_flag |= (LC_VALID | LC_SREF); lph->lph_slp = slp; slp->ns_sref++; }}/* * Update the lease expiry time and position it in the timer queue correctly. */voidnqsrv_instimeq(lp, duration) register struct nqlease *lp; u_long duration;{ register struct nqlease *tlp; time_t newexpiry; newexpiry = time.tv_sec + duration + nqsrv_clockskew; if (lp->lc_expiry == newexpiry) return; if (lp->lc_chain1[0]) remque(lp); lp->lc_expiry = newexpiry; /* * Find where in the queue it should be. */ tlp = nqthead.th_chain[1]; while (tlp->lc_expiry > newexpiry && tlp != (struct nqlease *)&nqthead) tlp = tlp->lc_chain1[1]; if (tlp == nqthead.th_chain[1]) NQSTORENOVRAM(newexpiry); insque(lp, tlp);}/* * 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. */nqsrv_cmpnam(slp, nam, lph) register struct nfssvc_sock *slp; struct mbuf *nam; register struct nqhost *lph;{ register struct sockaddr_in *saddr; struct mbuf *addr; union nethostaddr lhaddr; int ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -