summaryrefslogtreecommitdiffstats
path: root/sys/nfs/nfs_syscalls.c
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>1995-06-27 11:07:30 +0000
committerdfr <dfr@FreeBSD.org>1995-06-27 11:07:30 +0000
commit666343f7f055c064375d48bb9a608730d7145beb (patch)
tree372bad41f8c547f40d0826ed596c53dc772ab986 /sys/nfs/nfs_syscalls.c
parent6da3ef32238f37b3b45cf709205fcff60bcbda7f (diff)
downloadFreeBSD-src-666343f7f055c064375d48bb9a608730d7145beb.zip
FreeBSD-src-666343f7f055c064375d48bb9a608730d7145beb.tar.gz
Changes to support version 3 of the NFS protocol.
The version 2 support has been tested (client+server) against FreeBSD-2.0, IRIX 5.3 and FreeBSD-current (using a loopback mount). The version 2 support is stable AFAIK. The version 3 support has been tested with a loopback mount and minimally against an IRIX 5.3 server. It needs more testing and may have problems. I have patched amd to support the new variable length filehandles although it will still only use version 2 of the protocol. Before booting a kernel with these changes, nfs clients will need to at least build and install /usr/sbin/mount_nfs. Servers will need to build and install /usr/sbin/mountd. NFS diskless support is untested. Obtained from: Rick Macklem <rick@snowhite.cis.uoguelph.ca>
Diffstat (limited to 'sys/nfs/nfs_syscalls.c')
-rw-r--r--sys/nfs/nfs_syscalls.c571
1 files changed, 409 insertions, 162 deletions
diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c
index f7e159f..35a50f4 100644
--- a/sys/nfs/nfs_syscalls.c
+++ b/sys/nfs/nfs_syscalls.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_syscalls.c 8.3 (Berkeley) 1/4/94
- * $Id: nfs_syscalls.c,v 1.5 1994/10/17 17:47:38 phk Exp $
+ * $Id: nfs_syscalls.c,v 1.6 1995/05/30 08:12:45 rgrimes Exp $
*/
#include <sys/param.h>
@@ -61,9 +61,11 @@
#ifdef ISO
#include <netiso/iso.h>
#endif
+#include <nfs/xdr_subs.h>
#include <nfs/rpcv2.h>
-#include <nfs/nfsv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
+#include <nfs/nfsm_subs.h>
#include <nfs/nfsrvcache.h>
#include <nfs/nfsmount.h>
#include <nfs/nfsnode.h>
@@ -73,13 +75,14 @@
void nfsrv_zapsock __P((struct nfssvc_sock *));
/* Global defs. */
-extern u_long nfs_prog, nfs_vers;
-extern int (*nfsrv_procs[NFS_NPROCS])();
+extern int (*nfsrv3_procs[NFS_NPROCS])();
extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
extern int nfs_numasync;
extern time_t nqnfsstarttime;
extern int nqsrv_writeslack;
extern int nfsrtton;
+extern struct nfsstats nfsstats;
+extern int nfsrvw_procrastinate;
struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
int nuidhash_max = NFS_MAXUIDHASH;
static int nfs_numnfsd = 0;
@@ -225,19 +228,25 @@ nfssvc(p, uap, retval)
if (error)
return (error);
if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) &&
- (nfsd->nd_slp->ns_flag & SLP_VALID)) {
- slp = nfsd->nd_slp;
+ (nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
+ slp = nfsd->nfsd_slp;
/*
* First check to see if another nfsd has already
* added this credential.
*/
- for (nuidp = NUIDHASH(slp, nsd->nsd_uid)->lh_first;
+ for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
- if (nuidp->nu_uid == nsd->nsd_uid)
+ if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
+ (!nfsd->nfsd_nd->nd_nam2 ||
+ netaddr_match(NU_NETFAM(nuidp),
+ &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
break;
}
- if (!nuidp) {
+ if (nuidp) {
+ nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
+ nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
+ } else {
/*
* Nope, so we will.
*/
@@ -257,22 +266,53 @@ nfssvc(p, uap, retval)
LIST_REMOVE(nuidp, nu_hash);
TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
nu_lru);
+ if (nuidp->nu_flag & NU_NAM)
+ m_freem(nuidp->nu_nam);
}
+ nuidp->nu_flag = 0;
nuidp->nu_cr = nsd->nsd_cr;
if (nuidp->nu_cr.cr_ngroups > NGROUPS)
- nuidp->nu_cr.cr_ngroups = NGROUPS;
+ nuidp->nu_cr.cr_ngroups = NGROUPS;
nuidp->nu_cr.cr_ref = 1;
- nuidp->nu_uid = nsd->nsd_uid;
+ nuidp->nu_timestamp = nsd->nsd_timestamp;
+ nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl;
+ /*
+ * and save the session key in nu_key.
+ */
+ bcopy(nsd->nsd_key, nuidp->nu_key,
+ sizeof (nsd->nsd_key));
+ if (nfsd->nfsd_nd->nd_nam2) {
+ struct sockaddr_in *saddr;
+
+ saddr = mtod(nfsd->nfsd_nd->nd_nam2,
+ struct sockaddr_in *);
+ switch (saddr->sin_family) {
+ case AF_INET:
+ nuidp->nu_flag |= NU_INETADDR;
+ nuidp->nu_inetaddr =
+ saddr->sin_addr.s_addr;
+ break;
+ case AF_ISO:
+ default:
+ nuidp->nu_flag |= NU_NAM;
+ nuidp->nu_nam = m_copym(
+ nfsd->nfsd_nd->nd_nam2, 0,
+ M_COPYALL, M_WAIT);
+ break;
+ };
+ }
TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
nu_lru);
LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
nuidp, nu_hash);
-
+ nfsrv_setcred(&nuidp->nu_cr,
+ &nfsd->nfsd_nd->nd_cr);
+ nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
}
}
}
if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd))
- nfsd->nd_flag |= NFSD_AUTHFAIL;
+ nfsd->nfsd_flag |= NFSD_AUTHFAIL;
error = nfssvc_nfsd(nsd, uap->argp, p);
}
if (error == EINTR || error == ERESTART)
@@ -353,8 +393,6 @@ nfssvc_addsock(fp, mynam)
slp = (struct nfssvc_sock *)
malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
bzero((caddr_t)slp, sizeof (struct nfssvc_sock));
- slp->ns_uidhashtbl =
- hashinit(NUIDHASHSIZ, M_NFSSVC, &slp->ns_uidhash);
TAILQ_INIT(&slp->ns_uidlruhead);
TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
}
@@ -381,44 +419,47 @@ nfssvc_nfsd(nsd, argp, p)
caddr_t argp;
struct proc *p;
{
- register struct mbuf *m, *nam2;
+ register struct mbuf *m;
register int siz;
register struct nfssvc_sock *slp;
register struct socket *so;
register int *solockp;
- struct nfsd *nd = nsd->nsd_nfsd;
- struct mbuf *mreq, *nam;
- struct timeval starttime;
+ struct nfsd *nfsd = nsd->nsd_nfsd;
+ struct nfsrv_descript *nd = NULL;
+ struct mbuf *mreq;
struct nfsuid *uidp;
- int error = 0, cacherep, s;
- int sotype;
+ int error = 0, cacherep, s, sotype, writes_todo;
+ u_quad_t cur_usec;
+#ifndef nolint
+ cacherep = RC_DOIT;
+ writes_todo = 0;
+#endif
s = splnet();
- if (nd == (struct nfsd *)0) {
- nsd->nsd_nfsd = nd = (struct nfsd *)
+ if (nfsd == (struct nfsd *)0) {
+ nsd->nsd_nfsd = nfsd = (struct nfsd *)
malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
- bzero((caddr_t)nd, sizeof (struct nfsd));
- nd->nd_procp = p;
- nd->nd_cr.cr_ref = 1;
- TAILQ_INSERT_TAIL(&nfsd_head, nd, nd_chain);
- nd->nd_nqlflag = NQL_NOVAL;
+ bzero((caddr_t)nfsd, sizeof (struct nfsd));
+ nfsd->nfsd_procp = p;
+ TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
nfs_numnfsd++;
}
/*
* Loop getting rpc requests until SIGKILL.
*/
for (;;) {
- if ((nd->nd_flag & NFSD_REQINPROG) == 0) {
- while (nd->nd_slp == (struct nfssvc_sock *)0 &&
+ if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
+ while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
(nfsd_head_flag & NFSD_CHECKSLP) == 0) {
- nd->nd_flag |= NFSD_WAITING;
+ nfsd->nfsd_flag |= NFSD_WAITING;
nfsd_waiting++;
- error = tsleep((caddr_t)nd, PSOCK | PCATCH, "nfsd", 0);
+ error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
+ "nfsd", 0);
nfsd_waiting--;
if (error)
goto done;
}
- if (nd->nd_slp == (struct nfssvc_sock *)0 &&
+ if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
(nfsd_head_flag & NFSD_CHECKSLP) != 0) {
for (slp = nfssvc_sockhead.tqh_first; slp != 0;
slp = slp->ns_chain.tqe_next) {
@@ -426,14 +467,14 @@ nfssvc_nfsd(nsd, argp, p)
== (SLP_VALID | SLP_DOREC)) {
slp->ns_flag &= ~SLP_DOREC;
slp->ns_sref++;
- nd->nd_slp = slp;
+ nfsd->nfsd_slp = slp;
break;
}
}
if (slp == 0)
nfsd_head_flag &= ~NFSD_CHECKSLP;
}
- if ((slp = nd->nd_slp) == (struct nfssvc_sock *)0)
+ if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
continue;
if (slp->ns_flag & SLP_VALID) {
if (slp->ns_flag & SLP_DISCONN)
@@ -446,86 +487,78 @@ nfssvc_nfsd(nsd, argp, p)
M_WAIT);
nfs_sndunlock(&slp->ns_solock);
}
- error = nfsrv_dorec(slp, nd);
- nd->nd_flag |= NFSD_REQINPROG;
+ error = nfsrv_dorec(slp, nfsd, &nd);
+ cur_usec = (u_quad_t)time.tv_sec * 1000000 +
+ (u_quad_t)time.tv_usec;
+ if (error && slp->ns_tq.lh_first &&
+ slp->ns_tq.lh_first->nd_time <= cur_usec) {
+ error = 0;
+ cacherep = RC_DOIT;
+ writes_todo = 1;
+ } else
+ writes_todo = 0;
+ nfsd->nfsd_flag |= NFSD_REQINPROG;
}
} else {
error = 0;
- slp = nd->nd_slp;
+ slp = nfsd->nfsd_slp;
}
if (error || (slp->ns_flag & SLP_VALID) == 0) {
- nd->nd_slp = (struct nfssvc_sock *)0;
- nd->nd_flag &= ~NFSD_REQINPROG;
+ if (nd) {
+ free((caddr_t)nd, M_NFSRVDESC);
+ nd = NULL;
+ }
+ nfsd->nfsd_slp = (struct nfssvc_sock *)0;
+ nfsd->nfsd_flag &= ~NFSD_REQINPROG;
nfsrv_slpderef(slp);
continue;
}
splx(s);
so = slp->ns_so;
sotype = so->so_type;
- starttime = time;
if (so->so_proto->pr_flags & PR_CONNREQUIRED)
solockp = &slp->ns_solock;
else
solockp = (int *)0;
- /*
- * nam == nam2 for connectionless protocols such as UDP
- * nam2 == NULL for connection based protocols to disable
- * recent request caching.
- */
- nam2 = nd->nd_nam;
- if (nam2) {
- nam = nam2;
- cacherep = RC_CHECKIT;
- } else {
- nam = slp->ns_nam;
- cacherep = RC_DOIT;
- }
-
- /*
- * Check to see if authorization is needed.
- */
- if (nd->nd_flag & NFSD_NEEDAUTH) {
- static int logauth = 0;
+ if (nd) {
+ nd->nd_starttime = time;
+ if (nd->nd_nam2)
+ nd->nd_nam = nd->nd_nam2;
+ else
+ nd->nd_nam = slp->ns_nam;
- nd->nd_flag &= ~NFSD_NEEDAUTH;
- /*
- * Check for a mapping already installed.
- */
- for (uidp = NUIDHASH(slp, nd->nd_cr.cr_uid)->lh_first;
- uidp != 0; uidp = uidp->nu_hash.le_next) {
- if (uidp->nu_uid == nd->nd_cr.cr_uid)
- break;
- }
- if (!uidp) {
- nsd->nsd_uid = nd->nd_cr.cr_uid;
- if (nam2 && logauth++ == 0)
- log(LOG_WARNING, "Kerberized NFS using UDP\n");
- nsd->nsd_haddr =
- mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
- nsd->nsd_authlen = nd->nd_authlen;
- if (copyout(nd->nd_authstr, nsd->nsd_authstr,
- nd->nd_authlen) == 0 &&
- copyout((caddr_t)nsd, argp, sizeof (*nsd)) == 0)
- return (ENEEDAUTH);
- cacherep = RC_DROPIT;
- }
- }
- if (cacherep == RC_CHECKIT)
- cacherep = nfsrv_getcache(nam2, nd, &mreq);
+ /*
+ * Check to see if authorization is needed.
+ */
+ if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
+ nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
+ nsd->nsd_haddr = mtod(nd->nd_nam,
+ struct sockaddr_in *)->sin_addr.s_addr;
+ nsd->nsd_authlen = nfsd->nfsd_authlen;
+ nsd->nsd_verflen = nfsd->nfsd_verflen;
+ if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
+ nfsd->nfsd_authlen) &&
+ !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
+ nfsd->nfsd_verflen) &&
+ !copyout((caddr_t)nsd, argp, sizeof (*nsd)))
+ return (ENEEDAUTH);
+ cacherep = RC_DROPIT;
+ } else
+ cacherep = nfsrv_getcache(nd, slp, &mreq);
- /*
- * Check for just starting up for NQNFS and send
- * fake "try again later" replies to the NQNFS clients.
- */
- if (notstarted && nqnfsstarttime <= time.tv_sec) {
+ /*
+ * Check for just starting up for NQNFS and send
+ * fake "try again later" replies to the NQNFS clients.
+ */
+ if (notstarted && nqnfsstarttime <= time.tv_sec) {
if (modify_flag) {
nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
modify_flag = 0;
} else
notstarted = 0;
- }
- if (notstarted) {
- if (nd->nd_nqlflag == NQL_NOVAL)
+ }
+ if (notstarted) {
+ if ((nd->nd_flag & ND_NQNFS) == 0)
cacherep = RC_DROPIT;
else if (nd->nd_procnum != NFSPROC_WRITE) {
nd->nd_procnum = NFSPROC_NOOP;
@@ -533,36 +566,42 @@ nfssvc_nfsd(nsd, argp, p)
cacherep = RC_DOIT;
} else
modify_flag = 1;
- } else if (nd->nd_flag & NFSD_AUTHFAIL) {
- nd->nd_flag &= ~NFSD_AUTHFAIL;
+ } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
+ nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
nd->nd_procnum = NFSPROC_NOOP;
- nd->nd_repstat = NQNFS_AUTHERR;
+ nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
cacherep = RC_DOIT;
+ }
}
- switch (cacherep) {
- case RC_DOIT:
- error = (*(nfsrv_procs[nd->nd_procnum]))(nd,
- nd->nd_mrep, nd->nd_md, nd->nd_dpos, &nd->nd_cr,
- nam, &mreq);
- if (nd->nd_cr.cr_ref != 1) {
- printf("nfssvc cref=%d\n", nd->nd_cr.cr_ref);
- panic("nfssvc cref");
- }
+ /*
+ * Loop to get all the write rpc relies that have been
+ * gathered together.
+ */
+ do {
+ switch (cacherep) {
+ case RC_DOIT:
+ if (writes_todo || (nd->nd_procnum == NFSPROC_WRITE &&
+ nfsrvw_procrastinate > 0 && !notstarted))
+ error = nfsrv_writegather(&nd, slp,
+ nfsd->nfsd_procp, &mreq);
+ else
+ error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
+ slp, nfsd->nfsd_procp, &mreq);
+ if (mreq == NULL)
+ break;
if (error) {
if (nd->nd_procnum != NQNFSPROC_VACATED)
nfsstats.srv_errs++;
- if (nam2) {
- nfsrv_updatecache(nam2, nd, FALSE, mreq);
- m_freem(nam2);
- }
+ nfsrv_updatecache(nd, FALSE, mreq);
+ if (nd->nd_nam2)
+ m_freem(nd->nd_nam2);
break;
}
nfsstats.srvrpccnt[nd->nd_procnum]++;
- if (nam2)
- nfsrv_updatecache(nam2, nd, TRUE, mreq);
+ nfsrv_updatecache(nd, TRUE, mreq);
nd->nd_mrep = (struct mbuf *)0;
- case RC_REPLY:
+ case RC_REPLY:
m = mreq;
siz = 0;
while (m) {
@@ -587,15 +626,15 @@ nfssvc_nfsd(nsd, argp, p)
if (solockp)
(void) nfs_sndlock(solockp, (struct nfsreq *)0);
if (slp->ns_flag & SLP_VALID)
- error = nfs_send(so, nam2, m, (struct nfsreq *)0);
+ error = nfs_send(so, nd->nd_nam2, m, NULL);
else {
error = EPIPE;
m_freem(m);
}
if (nfsrtton)
- nfsd_rt(&starttime, sotype, nd, nam, cacherep);
- if (nam2)
- MFREE(nam2, m);
+ nfsd_rt(sotype, nd, cacherep);
+ if (nd->nd_nam2)
+ MFREE(nd->nd_nam2, m);
if (nd->nd_mrep)
m_freem(nd->nd_mrep);
if (error == EPIPE)
@@ -603,29 +642,50 @@ nfssvc_nfsd(nsd, argp, p)
if (solockp)
nfs_sndunlock(solockp);
if (error == EINTR || error == ERESTART) {
+ free((caddr_t)nd, M_NFSRVDESC);
nfsrv_slpderef(slp);
s = splnet();
goto done;
}
break;
- case RC_DROPIT:
+ case RC_DROPIT:
if (nfsrtton)
- nfsd_rt(&starttime, sotype, nd, nam, cacherep);
+ nfsd_rt(sotype, nd, cacherep);
m_freem(nd->nd_mrep);
- m_freem(nam2);
+ m_freem(nd->nd_nam2);
break;
- };
+ };
+ if (nd) {
+ FREE((caddr_t)nd, M_NFSRVDESC);
+ nd = NULL;
+ }
+
+ /*
+ * Check to see if there are outstanding writes that
+ * need to be serviced.
+ */
+ cur_usec = (u_quad_t)time.tv_sec * 1000000 +
+ (u_quad_t)time.tv_usec;
+ s = splsoftclock();
+ if (slp->ns_tq.lh_first &&
+ slp->ns_tq.lh_first->nd_time <= cur_usec) {
+ cacherep = RC_DOIT;
+ writes_todo = 1;
+ } else
+ writes_todo = 0;
+ splx(s);
+ } while (writes_todo);
s = splnet();
- if (nfsrv_dorec(slp, nd)) {
- nd->nd_flag &= ~NFSD_REQINPROG;
- nd->nd_slp = (struct nfssvc_sock *)0;
+ if (nfsrv_dorec(slp, nfsd, &nd)) {
+ nfsd->nfsd_flag &= ~NFSD_REQINPROG;
+ nfsd->nfsd_slp = NULL;
nfsrv_slpderef(slp);
}
}
done:
- TAILQ_REMOVE(&nfsd_head, nd, nd_chain);
+ TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
splx(s);
- free((caddr_t)nd, M_NFSD);
+ free((caddr_t)nfsd, M_NFSD);
nsd->nsd_nfsd = (struct nfsd *)0;
if (--nfs_numnfsd == 0)
nfsrv_init(TRUE); /* Reinitialize everything */
@@ -641,9 +701,10 @@ int
nfssvc_iod(p)
struct proc *p;
{
- register struct buf *bp;
+ register struct buf *bp, *nbp;
register int i, myiod;
- int error = 0;
+ struct vnode *vp;
+ int error = 0, s;
/*
* Assign my position or return error if too many already running
@@ -662,24 +723,53 @@ nfssvc_iod(p)
* Just loop around doin our stuff until SIGKILL
*/
for (;;) {
- while (nfs_bufq.tqh_first == NULL && error == 0) {
- nfs_iodwant[myiod] = p;
- error = tsleep((caddr_t)&nfs_iodwant[myiod],
- PWAIT | PCATCH, "nfsidl", 0);
- }
- while ((bp = nfs_bufq.tqh_first) != NULL) {
- /* Take one off the front of the list */
- TAILQ_REMOVE(&nfs_bufq, bp, b_freelist);
- if (bp->b_flags & B_READ)
- (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
- else
- (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
- }
- if (error) {
- nfs_asyncdaemon[myiod] = 0;
- nfs_numasync--;
- return (error);
- }
+ while (nfs_bufq.tqh_first == NULL && error == 0) {
+ nfs_iodwant[myiod] = p;
+ error = tsleep((caddr_t)&nfs_iodwant[myiod],
+ PWAIT | PCATCH, "nfsidl", 0);
+ }
+ while ((bp = nfs_bufq.tqh_first) != NULL) {
+ /* Take one off the front of the list */
+ TAILQ_REMOVE(&nfs_bufq, bp, b_freelist);
+ if (bp->b_flags & B_READ)
+ (void) nfs_doio(bp, bp->b_rcred, (struct proc *)0);
+ else do {
+ /*
+ * Look for a delayed write for the same vnode, so I can do
+ * it now. We must grab it before calling nfs_doio() to
+ * avoid any risk of the vnode getting vclean()'d while
+ * we are doing the write rpc.
+ */
+ vp = bp->b_vp;
+ s = splbio();
+ for (nbp = vp->v_dirtyblkhd.lh_first; nbp;
+ nbp = nbp->b_vnbufs.le_next) {
+ if ((nbp->b_flags &
+ (B_BUSY|B_DELWRI|B_NEEDCOMMIT|B_NOCACHE))!=B_DELWRI)
+ continue;
+ bremfree(nbp);
+ vfs_busy_pages(nbp, 1);
+ nbp->b_flags |= (B_BUSY|B_ASYNC);
+ break;
+ }
+ splx(s);
+ /*
+ * For the delayed write, do the first part of nfs_bwrite()
+ * up to, but not including nfs_strategy().
+ */
+ if (nbp) {
+ nbp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
+ reassignbuf(nbp, nbp->b_vp);
+ nbp->b_vp->v_numoutput++;
+ }
+ (void) nfs_doio(bp, bp->b_wcred, (struct proc *)0);
+ } while (bp = nbp);
+ }
+ if (error) {
+ nfs_asyncdaemon[myiod] = 0;
+ nfs_numasync--;
+ return (error);
+ }
}
}
@@ -695,9 +785,11 @@ nfsrv_zapsock(slp)
register struct nfssvc_sock *slp;
{
register struct nfsuid *nuidp, *nnuidp;
+ register struct nfsrv_descript *nwp, *nnwp;
struct socket *so;
struct file *fp;
struct mbuf *m;
+ int s;
slp->ns_flag &= ~SLP_ALLFLAGS;
fp = slp->ns_fp;
@@ -716,8 +808,18 @@ nfsrv_zapsock(slp)
nnuidp = nuidp->nu_lru.tqe_next;
LIST_REMOVE(nuidp, nu_hash);
TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
+ if (nuidp->nu_flag & NU_NAM)
+ m_freem(nuidp->nu_nam);
free((caddr_t)nuidp, M_NFSUID);
}
+ s = splsoftclock();
+ for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
+ nnwp = nwp->nd_tq.le_next;
+ LIST_REMOVE(nwp, nd_tq);
+ free((caddr_t)nwp, M_NFSRVDESC);
+ }
+ LIST_INIT(&slp->ns_tq);
+ splx(s);
}
}
@@ -726,13 +828,15 @@ nfsrv_zapsock(slp)
* on this mount point porpous out of the kernel and do it.
*/
int
-nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
+nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
register struct nfsmount *nmp;
struct nfsreq *rep;
struct ucred *cred;
- int *auth_type;
char **auth_str;
int *auth_len;
+ char *verf_str;
+ int *verf_len;
+ NFSKERBKEY_T key; /* return session key */
{
int error = 0;
@@ -748,6 +852,9 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
}
nmp->nm_flag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
+ nmp->nm_authlen = RPCAUTH_MAXSIZ;
+ nmp->nm_verfstr = verf_str;
+ nmp->nm_verflen = *verf_len;
nmp->nm_authuid = cred->cr_uid;
wakeup((caddr_t)&nmp->nm_authstr);
@@ -766,8 +873,9 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
if (error)
free((caddr_t)*auth_str, M_TEMP);
else {
- *auth_type = nmp->nm_authtype;
*auth_len = nmp->nm_authlen;
+ *verf_len = nmp->nm_verflen;
+ bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key));
}
nmp->nm_flag &= ~NFSMNT_HASAUTH;
nmp->nm_flag |= NFSMNT_WAITAUTH;
@@ -779,6 +887,149 @@ nfs_getauth(nmp, rep, cred, auth_type, auth_str, auth_len)
}
/*
+ * Get a nickname authenticator and verifier.
+ */
+int
+nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
+ struct nfsmount *nmp;
+ struct ucred *cred;
+ char **auth_str;
+ int *auth_len;
+ char *verf_str;
+ int verf_len;
+{
+ register struct nfsuid *nuidp;
+ register u_long *nickp, *verfp;
+ struct timeval ktvin, ktvout;
+ NFSKERBKEYSCHED_T keys; /* stores key schedule */
+
+#ifdef DIAGNOSTIC
+ if (verf_len < (4 * NFSX_UNSIGNED))
+ panic("nfs_getnickauth verf too small");
+#endif
+ for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
+ nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
+ if (nuidp->nu_cr.cr_uid == cred->cr_uid)
+ break;
+ }
+ if (!nuidp || nuidp->nu_expire < time.tv_sec)
+ return (EACCES);
+
+ /*
+ * Move to the end of the lru list (end of lru == most recently used).
+ */
+ TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
+ TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
+
+ nickp = (u_long *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
+ *nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
+ *nickp = txdr_unsigned(nuidp->nu_nickname);
+ *auth_str = (char *)nickp;
+ *auth_len = 2 * NFSX_UNSIGNED;
+
+ /*
+ * Now we must encrypt the verifier and package it up.
+ */
+ verfp = (u_long *)verf_str;
+ *verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
+ if (time.tv_sec > nuidp->nu_timestamp.tv_sec ||
+ (time.tv_sec == nuidp->nu_timestamp.tv_sec &&
+ time.tv_usec > nuidp->nu_timestamp.tv_usec))
+ nuidp->nu_timestamp = time;
+ else
+ nuidp->nu_timestamp.tv_usec++;
+ ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
+ ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
+
+ /*
+ * Now encrypt the timestamp verifier in ecb mode using the session
+ * key.
+ */
+#ifdef NFSKERB
+ XXX
+#endif
+
+ *verfp++ = ktvout.tv_sec;
+ *verfp++ = ktvout.tv_usec;
+ *verfp = 0;
+ return (0);
+}
+
+/*
+ * Save the current nickname in a hash list entry on the mount point.
+ */
+int
+nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
+ register struct nfsmount *nmp;
+ struct ucred *cred;
+ int len;
+ NFSKERBKEY_T key;
+ struct mbuf **mdp;
+ char **dposp;
+ struct mbuf *mrep;
+{
+ register struct nfsuid *nuidp;
+ register u_long *tl;
+ register long t1;
+ struct mbuf *md = *mdp;
+ struct timeval ktvin, ktvout;
+ u_long nick;
+ NFSKERBKEYSCHED_T keys;
+ char *dpos = *dposp, *cp2;
+ int deltasec, error = 0;
+
+ if (len == (3 * NFSX_UNSIGNED)) {
+ nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
+ ktvin.tv_sec = *tl++;
+ ktvin.tv_usec = *tl++;
+ nick = fxdr_unsigned(u_long, *tl);
+
+ /*
+ * Decrypt the timestamp in ecb mode.
+ */
+#ifdef NFSKERB
+ XXX
+#endif
+ ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
+ ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
+ deltasec = time.tv_sec - ktvout.tv_sec;
+ if (deltasec < 0)
+ deltasec = -deltasec;
+ /*
+ * If ok, add it to the hash list for the mount point.
+ */
+ if (deltasec <= NFS_KERBCLOCKSKEW) {
+ if (nmp->nm_numuids < nuidhash_max) {
+ nmp->nm_numuids++;
+ nuidp = (struct nfsuid *)
+ malloc(sizeof (struct nfsuid), M_NFSUID,
+ M_WAITOK);
+ } else {
+ nuidp = nmp->nm_uidlruhead.tqh_first;
+ LIST_REMOVE(nuidp, nu_hash);
+ TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
+ nu_lru);
+ }
+ nuidp->nu_flag = 0;
+ nuidp->nu_cr.cr_uid = cred->cr_uid;
+ nuidp->nu_expire = time.tv_sec + NFS_KERBTTL;
+ nuidp->nu_timestamp = ktvout;
+ nuidp->nu_nickname = nick;
+ bcopy(key, nuidp->nu_key, sizeof (key));
+ TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
+ nu_lru);
+ LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
+ nuidp, nu_hash);
+ }
+ } else
+ nfsm_adv(nfsm_rndup(len));
+nfsmout:
+ *mdp = md;
+ *dposp = dpos;
+ return (error);
+}
+
+/*
* Derefence a server socket structure. If it has no more references and
* is no longer valid, you can throw it away.
*/
@@ -830,16 +1081,12 @@ nfsrv_init(terminating)
nfs_udpsock = (struct nfssvc_sock *)
malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock));
- nfs_udpsock->ns_uidhashtbl =
- hashinit(NUIDHASHSIZ, M_NFSSVC, &nfs_udpsock->ns_uidhash);
TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
nfs_cltpsock = (struct nfssvc_sock *)
malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock));
- nfs_cltpsock->ns_uidhashtbl =
- hashinit(NUIDHASHSIZ, M_NFSSVC, &nfs_cltpsock->ns_uidhash);
TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
}
@@ -848,11 +1095,9 @@ nfsrv_init(terminating)
* Add entries to the server monitor log.
*/
static void
-nfsd_rt(startp, sotype, nd, nam, cacherep)
- struct timeval *startp;
+nfsd_rt(sotype, nd, cacherep)
int sotype;
- register struct nfsd *nd;
- struct mbuf *nam;
+ register struct nfsrv_descript *nd;
int cacherep;
{
register struct drt *rt;
@@ -866,15 +1111,17 @@ nfsd_rt(startp, sotype, nd, nam, cacherep)
rt->flag = DRT_CACHEDROP;
if (sotype == SOCK_STREAM)
rt->flag |= DRT_TCP;
- if (nd->nd_nqlflag != NQL_NOVAL)
+ if (nd->nd_flag & ND_NQNFS)
rt->flag |= DRT_NQNFS;
+ else if (nd->nd_flag & ND_NFSV3)
+ rt->flag |= DRT_NFSV3;
rt->proc = nd->nd_procnum;
- if (mtod(nam, struct sockaddr *)->sa_family == AF_INET)
- rt->ipadr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
+ if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET)
+ rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr;
else
- rt->ipadr = INADDR_ANY;
- rt->resptime = ((time.tv_sec - startp->tv_sec) * 1000000) +
- (time.tv_usec - startp->tv_usec);
+ rt->ipadr = INADDR_ANY;
+ rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
+ (time.tv_usec - nd->nd_starttime.tv_usec);
rt->tstamp = time;
nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
}
OpenPOWER on IntegriCloud