#include <sys/vnode.h>
#include <sys/mutex.h>
+#include <sys/thread.h>
/*
* Tunable constants for nfs
LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */
LIST_HEAD(, nfsuid) ns_uidhashtbl[NFS_UIDHASHSIZ];
LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ];
+ struct lwkt_token ns_token;
};
/* Bits for "ns_flag" */
struct mbuf **mreqp);
extern struct nfsv3_diskless nfsv3_diskless;
+extern struct lwkt_token nfs_token;
u_quad_t nfs_curusec (void);
int nfs_init (struct vfsconf *vfsp);
int nfs_adv (struct mbuf **, caddr_t *, int, int);
void nfs_nhinit (void);
int nfs_nmcancelreqs (struct nfsmount *);
-void nfs_timer (void*);
+void nfs_timer_callout (void*);
int nfsrv_dorec (struct nfssvc_sock *, struct nfsd *,
struct nfsrv_descript **);
int nfsrv_getcache (struct nfsrv_descript *, struct nfssvc_sock *,
int nfsrv_write (struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct thread *td, struct mbuf **mrq);
void nfsrv_rcv (struct socket *so, void *arg, int waitflag);
+void nfsrv_rcv_upcall (struct socket *so, void *arg, int waitflag);
void nfsrv_slpderef (struct nfssvc_sock *slp);
+void nfsrv_slpref (struct nfssvc_sock *slp);
int nfs_meta_setsize (struct vnode *vp, struct thread *td,
off_t nbase, int trivial);
int nfs_clientd(struct nfsmount *nmp, struct ucred *cred,
#include <sys/buf2.h>
#include <sys/thread2.h>
-#include <sys/mplock2.h>
#include <vm/vm_page2.h>
#include "rpcv2.h"
KKASSERT(info->state == NFSM_STATE_DONE);
- get_mplock();
+ lwkt_gettoken(&nmp->nm_token);
if (info->v3) {
ERROROUT(nfsm_postop_attr(info, info->vp, &attrflag,
bp->b_resid = 0;
/* bp->b_resid = bp->b_bcount - retlen; */
nfsmout:
- rel_mplock();
+ lwkt_reltoken(&nmp->nm_token);
kfree(info, M_NFSREQ);
if (error) {
bp->b_error = error;
int len = bp->b_resid; /* b_resid was set to shortened length */
u_int32_t *tl;
- get_mplock();
+ lwkt_gettoken(&nmp->nm_token);
if (info->v3) {
/*
}
if (info->info_writerpc.must_commit)
nfs_clearcommit(info->vp->v_mount);
- rel_mplock();
+ lwkt_reltoken(&nmp->nm_token);
+
kfree(info, M_NFSREQ);
if (error) {
bp->b_flags |= B_ERROR;
int wccflag = NFSV3_WCCRATTR;
int error = 0;
- get_mplock();
+ lwkt_gettoken(&nmp->nm_token);
ERROROUT(nfsm_wcc_data(info, info->vp, &wccflag));
if (error == 0) {
} else {
nfs_writerpc_bio(info->vp, bio);
}
- rel_mplock();
+ lwkt_reltoken(&nmp->nm_token);
}
struct nfsreq *req;
int error;
- get_mplock();
+ lwkt_gettoken(&nmp->nm_token);
if (nmp->nm_rxstate == NFSSVC_INIT)
nmp->nm_rxstate = NFSSVC_PENDING;
- crit_enter();
for (;;) {
if (nmp->nm_rxstate == NFSSVC_WAITING) {
if (TAILQ_FIRST(&nmp->nm_reqq) == NULL &&
continue;
}
TAILQ_REMOVE(&nmp->nm_reqrxq, req, r_chain);
- crit_exit();
info = req->r_info;
KKASSERT(info);
info->error = nfs_request(info,
atomic_subtract_int(&nmp->nm_bioqlen, 1);
info->done(info);
}
- crit_enter();
}
}
- crit_exit();
nmp->nm_rxthread = NULL;
nmp->nm_rxstate = NFSSVC_DONE;
+
+ lwkt_reltoken(&nmp->nm_token);
wakeup(&nmp->nm_rxthread);
}
struct vnode *vp;
nfsm_info_t info;
- get_mplock();
+ lwkt_gettoken(&nmp->nm_token);
if (nmp->nm_txstate == NFSSVC_INIT)
nmp->nm_txstate = NFSSVC_PENDING;
- crit_enter();
for (;;) {
if (nmp->nm_txstate == NFSSVC_WAITING) {
tsleep(&nmp->nm_txstate, 0, "nfsidl", 0);
break;
TAILQ_REMOVE(&nmp->nm_bioq, bio, bio_act);
vp = bio->bio_driver_info;
- crit_exit();
nfs_startio(vp, bio, NULL);
- crit_enter();
}
/*
TAILQ_REMOVE(&nmp->nm_reqtxq, req, r_chain);
info = req->r_info;
KKASSERT(info);
- crit_exit();
info->error = nfs_request(info,
NFSM_STATE_AUTH,
NFSM_STATE_WAITREPLY);
- crit_enter();
if (info->error == EINPROGRESS) {
;
} else {
}
}
}
- crit_exit();
nmp->nm_txthread = NULL;
nmp->nm_txstate = NFSSVC_DONE;
+ lwkt_reltoken(&nmp->nm_token);
wakeup(&nmp->nm_txthread);
}
void
nfssvc_iod_stop1(struct nfsmount *nmp)
{
- crit_enter();
nmp->nm_txstate = NFSSVC_STOPPING;
nmp->nm_rxstate = NFSSVC_STOPPING;
- crit_exit();
}
void
int
nfs_inactive(struct vop_inactive_args *ap)
{
+ struct nfsmount *nmp = VFSTONFS(ap->a_vp->v_mount);
struct nfsnode *np;
struct sillyrename *sp;
+ lwkt_gettoken(&nmp->nm_token);
+
np = VTONFS(ap->a_vp);
if (prtactive && ap->a_vp->v_sysref.refcnt > 1)
vprint("nfs_inactive: pushing active", ap->a_vp);
}
np->n_flag &= ~(NWRITEERR | NACC | NUPD | NCHG | NLOCKED | NWANTED);
+ lwkt_reltoken(&nmp->nm_token);
return (0);
}
struct vnode *vp = ap->a_vp;
struct nfsnode *np = VTONFS(vp);
struct nfsdmap *dp, *dp2;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
if (prtactive && vp->v_sysref.refcnt > 1)
vprint("nfs_reclaim: pushing active", vp);
+ lwkt_gettoken(&nmp->nm_token);
+
if (np->n_hash.le_prev != NULL)
LIST_REMOVE(np, n_hash);
crfree(np->n_wucred);
np->n_wucred = NULL;
}
-
vp->v_data = NULL;
+
+ lwkt_reltoken(&nmp->nm_token);
zfree(nfsnode_zone, np);
+
return (0);
}
* in a later timer call.
*/
void
-nfs_timer(void *arg /* never used */)
+nfs_timer_callout(void *arg /* never used */)
{
struct nfsmount *nmp;
struct nfsreq *req;
u_quad_t cur_usec;
#endif /* NFS_NOSERVER */
- crit_enter();
+ lwkt_gettoken(&nfs_token);
TAILQ_FOREACH(nmp, &nfs_mountq, nm_entry) {
+ lwkt_gettoken(&nmp->nm_token);
TAILQ_FOREACH(req, &nmp->nm_reqq, r_chain) {
KKASSERT(nmp == req->r_nmp);
if (req->r_mrep)
wakeup(req);
}
}
+ lwkt_reltoken(&nmp->nm_token);
}
#ifndef NFS_NOSERVER
* completed now.
*/
cur_usec = nfs_curusec();
+
TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) {
+ /* XXX race against removal */
+ lwkt_gettoken(&slp->ns_token);
if (slp->ns_tq.lh_first && slp->ns_tq.lh_first->nd_time<=cur_usec)
nfsrv_wakenfsd(slp, 1);
+ lwkt_reltoken(&slp->ns_token);
}
#endif /* NFS_NOSERVER */
- crit_exit();
- callout_reset(&nfs_timer_handle, nfs_ticks, nfs_timer, NULL);
+
+ callout_reset(&nfs_timer_handle, nfs_ticks, nfs_timer_callout, NULL);
+ lwkt_reltoken(&nfs_token);
}
static
}
#ifndef NFS_NOSERVER
+
+void
+nfsrv_rcv_upcall(struct socket *so, void *arg, int waitflag)
+{
+ struct nfssvc_sock *slp = (struct nfssvc_sock *)arg;
+
+ lwkt_gettoken(&slp->ns_token);
+ nfsrv_rcv(so, arg, waitflag);
+ lwkt_reltoken(&slp->ns_token);
+}
+
/*
* Socket upcall routine for the nfsd sockets.
* The caddr_t arg is a pointer to the "struct nfssvc_sock".
* Essentially do as much as possible non-blocking, else punt and it will
* be called with MB_WAIT from an nfsd.
+ *
+ * slp->ns_token is held on call
*/
void
nfsrv_rcv(struct socket *so, void *arg, int waitflag)
int flags, error;
int nparallel_wakeup = 0;
+ ASSERT_LWKT_TOKEN_HELD(&slp->ns_token);
+
if ((slp->ns_flag & SLP_VALID) == 0)
return;
*
* Note that this procedure can be called from any number of
* NFS severs *OR* can be upcalled directly from a TCP
- * protocol thread.
+ * protocol thread without the lock.
*/
if (slp->ns_flag & SLP_GETSTREAM) {
slp->ns_flag |= SLP_NEEDQ;
int nfs_ticks;
+/*
+ * Protect master lists only. Primary protection uses the per-mount
+ * and per nfssvc_sock tokens.
+ */
+struct lwkt_token nfs_token = LWKT_TOKEN_MP_INITIALIZER(unp_token);
+
static int nfs_pbuf_freecnt = -1; /* start out unlimited */
struct nfsmount_head nfs_mountq = TAILQ_HEAD_INITIALIZER(nfs_mountq);
/*
* Initialize reply list and start timer
*/
- nfs_timer(0);
+ nfs_timer_callout(0);
nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
sysent[SYS_nfssvc].sy_narg = 2;
#include <vm/vm_zone.h>
#include <sys/mutex2.h>
-#include <sys/mplock2.h>
+#include <sys/thread2.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
if (error)
return (error);
- get_mplock();
+ lwkt_gettoken(&nfs_token);
+
while (nfssvc_sockhead_flag & SLP_INIT) {
nfssvc_sockhead_flag |= SLP_WANTINIT;
tsleep((caddr_t)&nfssvc_sockhead, 0, "nfsd init", 0);
if (error == EINTR || error == ERESTART)
error = 0;
done:
- rel_mplock();
+ lwkt_reltoken(&nfs_token);
return (error);
}
mtx_init(&slp->ns_solock);
STAILQ_INIT(&slp->ns_rec);
TAILQ_INIT(&slp->ns_uidlruhead);
+ lwkt_token_init(&slp->ns_token, 1, "nfssrv_token");
+
+ lwkt_gettoken(&nfs_token);
TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
+ nfsrv_slpref(slp);
+ lwkt_gettoken(&slp->ns_token);
slp->ns_so = so;
slp->ns_nam = mynam;
fp->f_count++;
slp->ns_fp = fp;
- crit_enter();
+
so->so_upcallarg = (caddr_t)slp;
- so->so_upcall = nfsrv_rcv;
+ so->so_upcall = nfsrv_rcv_upcall;
atomic_set_int(&so->so_rcv.ssb_flags, SSB_UPCALL);
slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
nfsrv_wakenfsd(slp, 1);
- crit_exit();
+
+ lwkt_reltoken(&slp->ns_token);
+ lwkt_reltoken(&nfs_token);
+
return (0);
}
cacherep = RC_DOIT;
writes_todo = 0;
#endif
+ lwkt_gettoken(&nfs_token);
+
if (nfsd == NULL) {
nsd->nsd_nfsd = nfsd = (struct nfsd *)
kmalloc(sizeof (struct nfsd), M_NFSD, M_WAITOK|M_ZERO);
- crit_enter();
nfsd->nfsd_td = td;
TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
nfs_numnfsd++;
- } else
- crit_enter();
+ }
/*
* Loop getting rpc requests until SIGKILL.
if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
== (SLP_VALID | SLP_DOREC)) {
slp->ns_flag &= ~SLP_DOREC;
- slp->ns_sref++;
+ nfsrv_slpref(slp);
nfsd->nfsd_slp = slp;
break;
}
}
if ((slp = nfsd->nfsd_slp) == NULL)
continue;
+
+ lwkt_reltoken(&nfs_token);
+ lwkt_gettoken(&slp->ns_token);
+
if (slp->ns_flag & SLP_VALID) {
if (slp->ns_flag & SLP_DISCONN)
nfsrv_zapsock(slp);
} else {
error = 0;
slp = nfsd->nfsd_slp;
+ lwkt_reltoken(&nfs_token);
+ lwkt_gettoken(&slp->ns_token);
}
+
+ /*
+ * nfs_token not held here. slp token is held.
+ */
if (error || (slp->ns_flag & SLP_VALID) == 0) {
if (nd) {
kfree((caddr_t)nd, M_NFSRVDESC);
}
nfsd->nfsd_slp = NULL;
nfsd->nfsd_flag &= ~NFSD_REQINPROG;
+ lwkt_reltoken(&slp->ns_token);
+ lwkt_gettoken(&nfs_token);
nfsrv_slpderef(slp);
continue;
}
- crit_exit();
+
+ /*
+ * nfs_token not held here. slp token is held.
+ */
sotype = slp->ns_so->so_type;
if (nd) {
getmicrotime(&nd->nd_starttime);
!copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
nfsd->nfsd_verflen) &&
!copyout((caddr_t)nsd, argp, sizeof (*nsd)))
+ lwkt_reltoken(&slp->ns_token);
return (ENEEDAUTH);
cacherep = RC_DROPIT;
} else {
}
/*
- * Loop to get all the write rpc relies that have been
+ * Loop to get all the write rpc replies that have been
* gathered together.
+ *
+ * nfs_token not held here. slp token is held.
*/
do {
switch (cacherep) {
nfs_slpunlock(slp);
if (error == EINTR || error == ERESTART) {
kfree((caddr_t)nd, M_NFSRVDESC);
+ lwkt_reltoken(&slp->ns_token);
+ lwkt_gettoken(&nfs_token);
nfsrv_slpderef(slp);
- crit_enter();
goto done;
}
break;
* need to be serviced.
*/
cur_usec = nfs_curusec();
- crit_enter();
if (slp->ns_tq.lh_first &&
slp->ns_tq.lh_first->nd_time <= cur_usec) {
cacherep = RC_DOIT;
writes_todo = 1;
- } else
+ } else {
writes_todo = 0;
- crit_exit();
+ }
} while (writes_todo);
- crit_enter();
+
+ /*
+ * nfs_token not held here. slp token is held.
+ */
if (nfsrv_dorec(slp, nfsd, &nd)) {
nfsd->nfsd_flag &= ~NFSD_REQINPROG;
nfsd->nfsd_slp = NULL;
+ lwkt_reltoken(&slp->ns_token);
+ lwkt_gettoken(&nfs_token);
nfsrv_slpderef(slp);
+ } else {
+ lwkt_reltoken(&slp->ns_token);
+ lwkt_gettoken(&nfs_token);
}
}
done:
TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
- crit_exit();
kfree((caddr_t)nfsd, M_NFSD);
nsd->nsd_nfsd = NULL;
if (--nfs_numnfsd == 0)
nfsrv_init(TRUE); /* Reinitialize everything */
+
+ lwkt_reltoken(&nfs_token);
return (error);
}
/*
* Derefence a server socket structure. If it has no more references and
* is no longer valid, you can throw it away.
+ *
+ * Must be holding nfs_token!
*/
void
nfsrv_slpderef(struct nfssvc_sock *slp)
{
- if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
+ ASSERT_LWKT_TOKEN_HELD(&nfs_token);
+ if (--slp->ns_sref == 0 && (slp->ns_flag & SLP_VALID) == 0) {
TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
kfree((caddr_t)slp, M_NFSSVC);
}
}
+void
+nfsrv_slpref(struct nfssvc_sock *slp)
+{
+ ASSERT_LWKT_TOKEN_HELD(&nfs_token);
+ ++slp->ns_sref;
+}
+
/*
* Lock a socket against others.
*
{
struct nfssvc_sock *slp, *nslp;
+ lwkt_gettoken(&nfs_token);
if (nfssvc_sockhead_flag & SLP_INIT)
panic("nfsd init");
nfssvc_sockhead_flag |= SLP_INIT;
+
if (terminating) {
TAILQ_FOREACH_MUTABLE(slp, &nfssvc_sockhead, ns_chain, nslp) {
if (slp->ns_flag & SLP_VALID)
kfree((caddr_t)slp, M_NFSSVC);
}
nfsrv_cleancache(); /* And clear out server cache */
- } else
+ } else {
nfs_pub.np_valid = 0;
+ }
TAILQ_INIT(&nfssvc_sockhead);
nfssvc_sockhead_flag &= ~SLP_INIT;
TAILQ_INIT(&nfsd_head);
nfsd_head_flag &= ~NFSD_CHECKSLP;
+ lwkt_reltoken(&nfs_token);
+
#if 0
nfs_udpsock = (struct nfssvc_sock *)
kmalloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK | M_ZERO);
info.mrep = NULL;
info.v3 = (nmp->nm_flag & NFSMNT_NFSV3);
+ lwkt_gettoken(&nmp->nm_token);
+
#ifndef nolint
sfp = NULL;
#endif
error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
- if (error)
+ if (error) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
+ }
vp = NFSTOV(np);
/* ignore the passed cred */
cred = crget();
nfsmout:
vput(vp);
crfree(cred);
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
info.mrep = NULL;
info.v3 = (nmp->nm_flag & NFSMNT_NFSV3);
+ lwkt_gettoken(&nmp->nm_token);
#ifndef nolint
sfp = NULL;
#endif
error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
- if (error)
+ if (error) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
+ }
vp = NFSTOV(np);
/* ignore the passed cred */
cred = crget();
nfsmout:
vput(vp);
crfree(cred);
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
TAILQ_INIT(&nmp->nm_reqtxq);
TAILQ_INIT(&nmp->nm_reqrxq);
mp->mnt_data = (qaddr_t)nmp;
+ lwkt_token_init(&nmp->nm_token, 1, "nfs_token");
}
vfs_getnewfsid(mp);
nmp->nm_mountp = mp;
+ mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
+
+ lwkt_gettoken(&nmp->nm_token);
/*
* V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too
* Lose the lock but keep the ref.
*/
vn_unlock(*vpp);
+ lwkt_gettoken(&nfs_token);
TAILQ_INSERT_TAIL(&nfs_mountq, nmp, nm_entry);
+ lwkt_reltoken(&nfs_token);
#ifdef SMP
switch(ncpus) {
NULL, 0, rxcpu, "nfsiod_rx");
lwkt_create(nfssvc_iod_writer, nmp, &nmp->nm_txthread,
NULL, 0, txcpu, "nfsiod_tx");
-
+ lwkt_reltoken(&nmp->nm_token);
return (0);
bad:
nfs_disconnect(nmp);
+ lwkt_reltoken(&nmp->nm_token);
nfs_free_mount(nmp);
return (error);
}
int error, flags = 0;
nmp = VFSTONFS(mp);
+ lwkt_gettoken(&nmp->nm_token);
if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
nmp->nm_flag |= NFSMNT_FORCE;
error = vflush(mp, 1, flags);
if (error) {
nmp->nm_state &= ~NFSSTA_DISMINPROG;
- if ((flags & FORCECLOSE) == 0)
+ if ((flags & FORCECLOSE) == 0) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
+ }
}
/*
nfssvc_iod_stop1(nmp);
nfs_disconnect(nmp);
nfssvc_iod_stop2(nmp);
+
+ lwkt_gettoken(&nfs_token);
TAILQ_REMOVE(&nfs_mountq, nmp, nm_entry);
+ lwkt_reltoken(&nfs_token);
+
+ lwkt_reltoken(&nmp->nm_token);
if ((nmp->nm_flag & NFSMNT_KERB) == 0) {
nfs_free_mount(nmp);
int error;
nmp = VFSTONFS(mp);
+ lwkt_gettoken(&nmp->nm_token);
error = nfs_nget(mp, (nfsfh_t *)nmp->nm_fh, nmp->nm_fhsize, &np);
- if (error)
+ if (error) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
+ }
vp = NFSTOV(np);
/*
vput(vp);
else
*vpp = vp;
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
static int
nfs_sync(struct mount *mp, int waitfor)
{
+ struct nfsmount *nmp = VFSTONFS(mp);
struct scaninfo scaninfo;
int error;
/*
* Force stale buffer cache information to be flushed.
*/
+ lwkt_gettoken(&nmp->nm_token);
error = 0;
while (error == 0 && scaninfo.rescan) {
scaninfo.rescan = 0;
error = vmntvnodescan(mp, VMSC_GETVP, nfs_sync_scan1,
nfs_sync_scan2, &scaninfo);
}
+ lwkt_reltoken(&nmp->nm_token);
return(error);
}
int error = 0;
u_int32_t mode, wmode;
struct nfsnode *np = VTONFS(vp);
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
int v3 = NFS_ISV3(vp);
+ lwkt_gettoken(&nmp->nm_token);
+
/*
* Disallow write attempts on filesystems mounted read-only;
* unless the file is a socket, fifo, or a block or character
case VREG:
case VDIR:
case VLNK:
+ lwkt_reltoken(&nmp->nm_token);
return (EROFS);
default:
break;
} else {
if ((error = nfs_laccess(ap)) != 0) {
crfree(cred);
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
np->n_wucred = cred;
}
}
+ lwkt_reltoken(&nmp->nm_token);
crfree(cred);
return(error);
}
{
struct vnode *vp = ap->a_vp;
struct nfsnode *np = VTONFS(vp);
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
struct vattr vattr;
int error;
+ lwkt_gettoken(&nmp->nm_token);
+
if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
#ifdef DIAGNOSTIC
kprintf("open eacces vtyp=%d\n",vp->v_type);
#endif
+ lwkt_reltoken(&nmp->nm_token);
return (EOPNOTSUPP);
}
}
}
error = VOP_GETATTR(vp, &vattr);
- if (error)
+ if (error) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
+ }
if (np->n_flag & NRMODIFIED) {
if (vp->v_type == VDIR)
nfs_invaldir(vp);
error = nfs_vinvalbuf(vp, V_SAVE, 1);
- if (error == EINTR)
+ if (error == EINTR) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
+ }
np->n_flag &= ~NRMODIFIED;
}
+ error = vop_stdopen(ap);
+ lwkt_reltoken(&nmp->nm_token);
- return (vop_stdopen(ap));
+ return error;
}
/*
{
struct vnode *vp = ap->a_vp;
struct nfsnode *np = VTONFS(vp);
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
int error = 0;
thread_t td = curthread;
+ lwkt_gettoken(&nmp->nm_token);
+
if (vp->v_type == VREG) {
if (np->n_flag & NLMODIFIED) {
if (NFS_ISV3(vp)) {
}
}
vop_stdclose(ap);
+ lwkt_reltoken(&nmp->nm_token);
+
return (error);
}
info.mrep = NULL;
info.v3 = NFS_ISV3(vp);
nmp = VFSTONFS(vp->v_mount);
+
+ lwkt_gettoken(&nmp->nm_token);
/*
* Update local times for special files.
if ((nmp->nm_flag & NFSMNT_CACHE) && (vp->v_flag & VROOT))
ap->a_vap->va_flags |= UF_CACHE;
nfsmout:
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
{
struct vnode *vp = ap->a_vp;
struct nfsnode *np = VTONFS(vp);
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
struct vattr *vap = ap->a_vap;
int biosize = vp->v_mount->mnt_stat.f_iosize;
int error = 0;
#ifndef nolint
tsize = (off_t)0;
#endif
-
/*
* Setting of flags is not supported.
*/
(vp->v_mount->mnt_flag & MNT_RDONLY))
return (EROFS);
+ lwkt_gettoken(&nmp->nm_token);
+
if (vap->va_size != VNOVAL) {
/*
* truncation requested
*/
switch (vp->v_type) {
case VDIR:
+ lwkt_reltoken(&nmp->nm_token);
return (EISDIR);
case VCHR:
case VBLK:
vap->va_atime.tv_sec == VNOVAL &&
vap->va_mode == (mode_t)VNOVAL &&
vap->va_uid == (uid_t)VNOVAL &&
- vap->va_gid == (gid_t)VNOVAL)
+ vap->va_gid == (gid_t)VNOVAL) {
+ lwkt_reltoken(&nmp->nm_token);
return (0);
+ }
vap->va_size = VNOVAL;
break;
default:
* Disallow write attempts if the filesystem is
* mounted read-only.
*/
- if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+ lwkt_reltoken(&nmp->nm_token);
return (EROFS);
+ }
tsize = np->n_size;
again:
np->n_size = np->n_vattr.va_size = tsize;
nfs_meta_setsize(vp, td, np->n_size, 0);
}
+ lwkt_reltoken(&nmp->nm_token);
+
return (error);
}
{
struct thread *td = curthread;
struct namecache *ncp;
+ struct nfsmount *nmp;
struct ucred *cred;
struct nfsnode *np;
struct vnode *dvp;
cred = ap->a_cred;
dvp = ap->a_dvp;
+ nmp = VFSTONFS(dvp->v_mount);
- if ((error = vget(dvp, LK_SHARED)) != 0)
+ lwkt_gettoken(&nmp->nm_token);
+
+ if ((error = vget(dvp, LK_SHARED)) != 0) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
+ }
info.mrep = NULL;
info.v3 = NFS_ISV3(dvp);
m_freem(info.mrep);
info.mrep = NULL;
vput(dvp);
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
nvp = NFSTOV(np);
m_freem(info.mrep);
info.mrep = NULL;
nfsmout:
+ lwkt_reltoken(&nmp->nm_token);
vput(dvp);
if (nvp) {
if (nvp == dvp)
nmp = VFSTONFS(dvp->v_mount);
np = VTONFS(dvp);
+ lwkt_gettoken(&nmp->nm_token);
+
/*
* Go to the wire.
*/
if (NFS_CMPFH(np, fhp, fhsize)) {
m_freem(info.mrep);
info.mrep = NULL;
+ lwkt_reltoken(&nmp->nm_token);
return (EISDIR);
}
error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
if (error) {
m_freem(info.mrep);
info.mrep = NULL;
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
newvp = NFSTOV(np);
vn_unlock(dvp);
cnp->cn_flags |= CNP_PDIRUNLOCK;
}
+ lwkt_reltoken(&nmp->nm_token);
return (0);
}
if (error) {
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
cnp->cn_flags &= ~CNP_PDIRUNLOCK;
+ lwkt_reltoken(&nmp->nm_token);
return (error); /* NOTE: return error from nget */
}
newvp = NFSTOV(np);
error = vn_lock(dvp, LK_EXCLUSIVE);
if (error) {
vput(newvp);
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
cnp->cn_flags |= CNP_PDIRUNLOCK;
if (error) {
m_freem(info.mrep);
info.mrep = NULL;
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
if (!lockparent) {
error = EJUSTRETURN;
}
}
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
nfs_read(struct vop_read_args *ap)
{
struct vnode *vp = ap->a_vp;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ int error;
+
+ lwkt_gettoken(&nmp->nm_token);
+ error = nfs_bioread(vp, ap->a_uio, ap->a_ioflag);
+ lwkt_reltoken(&nmp->nm_token);
- return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag));
+ return error;
}
/*
nfs_readlink(struct vop_readlink_args *ap)
{
struct vnode *vp = ap->a_vp;
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
+ int error;
if (vp->v_type != VLNK)
return (EINVAL);
- return (nfs_bioread(vp, ap->a_uio, 0));
+
+ lwkt_gettoken(&nmp->nm_token);
+ error = nfs_bioread(vp, ap->a_uio, 0);
+ lwkt_reltoken(&nmp->nm_token);
+
+ return error;
}
/*
eof = 0;
#endif
nmp = VFSTONFS(vp->v_mount);
+
tsiz = uiop->uio_resid;
tmp_off = uiop->uio_offset + tsiz;
if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset)
static int
nfs_mknod(struct vop_old_mknod_args *ap)
{
- return nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
+ struct nfsmount *nmp = VFSTONFS(ap->a_dvp->v_mount);
+ int error;
+
+ lwkt_gettoken(&nmp->nm_token);
+ error = nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
+ lwkt_reltoken(&nmp->nm_token);
+
+ return error;
}
static u_long create_verf;
{
struct vnode *dvp = ap->a_dvp;
struct vattr *vap = ap->a_vap;
+ struct nfsmount *nmp = VFSTONFS(dvp->v_mount);
struct componentname *cnp = ap->a_cnp;
struct nfsv2_sattr *sp;
u_int32_t *tl;
info.mrep = NULL;
info.v3 = NFS_ISV3(dvp);
+ lwkt_gettoken(&nmp->nm_token);
/*
* Oops, not for me..
*/
- if (vap->va_type == VSOCK)
- return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
+ if (vap->va_type == VSOCK) {
+ error = nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap);
+ lwkt_reltoken(&nmp->nm_token);
+ return error;
+ }
if ((error = VOP_GETATTR(dvp, &vattr)) != 0) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
if (vap->va_vaflags & VA_EXCLUSIVE)
VTONFS(dvp)->n_flag |= NLMODIFIED;
if (!wccflag)
VTONFS(dvp)->n_attrstamp = 0;
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
{
struct vnode *vp = ap->a_vp;
struct vnode *dvp = ap->a_dvp;
+ struct nfsmount *nmp = VFSTONFS(dvp->v_mount);
struct componentname *cnp = ap->a_cnp;
struct nfsnode *np = VTONFS(vp);
int error = 0;
struct vattr vattr;
+ lwkt_gettoken(&nmp->nm_token);
#ifndef DIAGNOSTIC
if (vp->v_sysref.refcnt < 1)
panic("nfs_remove: bad v_sysref.refcnt");
#endif
- if (vp->v_type == VDIR)
+ if (vp->v_type == VDIR) {
error = EPERM;
- else if (vp->v_sysref.refcnt == 1 || (np->n_sillyrename &&
- VOP_GETATTR(vp, &vattr) == 0 &&
- vattr.va_nlink > 1)) {
+ } else if (vp->v_sysref.refcnt == 1 || (np->n_sillyrename &&
+ VOP_GETATTR(vp, &vattr) == 0 && vattr.va_nlink > 1)) {
/*
* throw away biocache buffers, mainly to avoid
* unnecessary delayed writes later.
error = nfs_sillyrename(dvp, vp, cnp);
}
np->n_attrstamp = 0;
+ lwkt_reltoken(&nmp->nm_token);
+
return (error);
}
struct vnode *tdvp = ap->a_tdvp;
struct componentname *tcnp = ap->a_tcnp;
struct componentname *fcnp = ap->a_fcnp;
+ struct nfsmount *nmp = VFSTONFS(fdvp->v_mount);
int error;
+ lwkt_gettoken(&nmp->nm_token);
+
/* Check for cross-device rename */
if ((fvp->v_mount != tdvp->v_mount) ||
(tvp && (fvp->v_mount != tvp->v_mount))) {
tcnp->cn_td);
out:
+ lwkt_reltoken(&nmp->nm_token);
if (tdvp == tvp)
vrele(tdvp);
else
{
struct vnode *vp = ap->a_vp;
struct vnode *tdvp = ap->a_tdvp;
+ struct nfsmount *nmp = VFSTONFS(tdvp->v_mount);
struct componentname *cnp = ap->a_cnp;
int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
struct nfsm_info info;
if (vp->v_mount != tdvp->v_mount) {
return (EXDEV);
}
+ lwkt_gettoken(&nmp->nm_token);
/*
* The attribute cache may get out of sync with the server on link.
*/
if (error == EEXIST)
error = 0;
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
{
struct vnode *dvp = ap->a_dvp;
struct vattr *vap = ap->a_vap;
+ struct nfsmount *nmp = VFSTONFS(dvp->v_mount);
struct componentname *cnp = ap->a_cnp;
struct nfsv2_sattr *sp;
int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
info.mrep = NULL;
info.v3 = NFS_ISV3(dvp);
+ lwkt_gettoken(&nmp->nm_token);
nfsstats.rpccnt[NFSPROC_SYMLINK]++;
slen = strlen(ap->a_target);
struct nfsnode *np = NULL;
error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
- cnp->cn_cred, cnp->cn_td, &np);
+ cnp->cn_cred, cnp->cn_td, &np);
if (!error)
newvp = NFSTOV(np);
}
VTONFS(dvp)->n_flag |= NLMODIFIED;
if (!wccflag)
VTONFS(dvp)->n_attrstamp = 0;
+ lwkt_reltoken(&nmp->nm_token);
+
return (error);
}
{
struct vnode *dvp = ap->a_dvp;
struct vattr *vap = ap->a_vap;
+ struct nfsmount *nmp = VFSTONFS(dvp->v_mount);
struct componentname *cnp = ap->a_cnp;
struct nfsv2_sattr *sp;
struct nfsnode *np = NULL;
info.mrep = NULL;
info.v3 = NFS_ISV3(dvp);
+ lwkt_gettoken(&nmp->nm_token);
if ((error = VOP_GETATTR(dvp, &vattr)) != 0) {
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
len = cnp->cn_namelen;
if (error) {
if (newvp)
vrele(newvp);
- } else
+ } else {
*ap->a_vpp = newvp;
+ }
+ lwkt_reltoken(&nmp->nm_token);
return (error);
}
{
struct vnode *vp = ap->a_vp;
struct vnode *dvp = ap->a_dvp;
+ struct nfsmount *nmp = VFSTONFS(dvp->v_mount);
struct componentname *cnp = ap->a_cnp;
int error = 0, wccflag = NFSV3_WCCRATTR;
struct nfsm_info info;
if (dvp == vp)
return (EINVAL);
+
+ lwkt_gettoken(&nmp->nm_token);
+
nfsstats.rpccnt[NFSPROC_RMDIR]++;
nfsm_reqhead(&info, dvp, NFSPROC_RMDIR,
NFSX_FH(info.v3) + NFSX_UNSIGNED +
*/
if (error == ENOENT)
error = 0;
+ lwkt_reltoken(&nmp->nm_token);
+
return (error);
}
{
struct vnode *vp = ap->a_vp;
struct nfsnode *np = VTONFS(vp);
+ struct nfsmount *nmp = VFSTONFS(vp->v_mount);
struct uio *uio = ap->a_uio;
int tresid, error;
struct vattr vattr;
if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
return (error);
+ lwkt_gettoken(&nmp->nm_token);
+
/*
* If we have a valid EOF offset cache we must call VOP_GETATTR()
* and then check that is still valid, or if this is an NQNFS mount
if (!error && uio->uio_resid == tresid)
nfsstats.direofcache_misses++;
done:
+ lwkt_reltoken(&nmp->nm_token);
vn_unlock(vp);
+
return (error);
}
static int
nfs_bmap(struct vop_bmap_args *ap)
{
+ /* no token lock required */
if (ap->a_doffsetp != NULL)
*ap->a_doffsetp = ap->a_loffset;
if (ap->a_runp != NULL)
struct bio *bio = ap->a_bio;
struct bio *nbio;
struct buf *bp __debugvar = bio->bio_buf;
+ struct nfsmount *nmp = VFSTONFS(ap->a_vp->v_mount);
struct thread *td;
int error;
else
td = NULL;
+ lwkt_gettoken(&nmp->nm_token);
+
/*
* We probably don't need to push an nbio any more since no
* block conversion is required due to the use of 64 bit byte
nfs_asyncio(ap->a_vp, nbio);
error = 0;
}
+ lwkt_reltoken(&nmp->nm_token);
+
return (error);
}
static int
nfs_mmap(struct vop_mmap_args *ap)
{
+ /* no token lock required */
return (EINVAL);
}
static int
nfs_fsync(struct vop_fsync_args *ap)
{
- return (nfs_flush(ap->a_vp, ap->a_waitfor, curthread, 1));
+ struct nfsmount *nmp = VFSTONFS(ap->a_vp->v_mount);
+ int error;
+
+ lwkt_gettoken(&nmp->nm_token);
+ error = nfs_flush(ap->a_vp, ap->a_waitfor, curthread, 1);
+ lwkt_reltoken(&nmp->nm_token);
+
+ return error;
}
/*
{
struct nfsnode *np = VTONFS(ap->a_vp);
+ /* no token lock currently required */
/*
* The following kludge is to allow diskless support to work
* until a real NFS lockd is implemented. Basically, just pretend
static int
nfs_laccess(struct vop_access_args *ap)
{
+ struct nfsmount *nmp = VFSTONFS(ap->a_vp->v_mount);
struct vattr vattr;
int error;
+ lwkt_gettoken(&nmp->nm_token);
error = VOP_GETATTR(ap->a_vp, &vattr);
- if (!error)
+ if (error == 0) {
error = vop_helper_access(ap, vattr.va_uid, vattr.va_gid,
- vattr.va_mode, 0);
+ vattr.va_mode, 0);
+ }
+ lwkt_reltoken(&nmp->nm_token);
+
return (error);
}
{
struct nfsnode *np = VTONFS(ap->a_vp);
+ /* no token access required */
/*
* Set access flag.
*/
{
struct nfsnode *np = VTONFS(ap->a_vp);
+ /* no token access required */
/*
* Set update flag.
*/
struct vattr vattr;
struct timespec ts;
+ /* no token access required */
+
if (np->n_flag & (NACC | NUPD)) {
getnanotime(&ts);
if (np->n_flag & NACC)
#define _NFS_NFSMOUNT_H_
#include <sys/mutex.h>
+#include <sys/thread.h> /* token */
enum nfssvc_state {
NFSSVC_INIT,
int nm_reqqlen; /* number of nfsreqs in queue */
u_int64_t nm_maxfilesize; /* maximum file size */
struct ucred *nm_cred; /* 'root' credential */
+ struct lwkt_token nm_token; /* protective token */
};