network - Tokenize NFS, fix MP races
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 10 Sep 2010 19:09:34 +0000 (12:09 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 10 Sep 2010 19:09:34 +0000 (12:09 -0700)
* Now that the rest of the network stack is running MPSAFE, poor NFS is
  hitting races and other issues because it was depending on the MP lock.

* Recombobulate NFS with tokens, protecting all border crossings:

  A global nfs_token is used for the nfs mount list, nfsd list, and
  server socket list.

  A per-socket token (nfssvc_sock->ns_token) governs each served mount.

  A per-mount token (nfsmount->nm_token) governs each client mount.

* Callouts and TCP upcalls are protected.  The per-socket TCP upcall
  is protected by the nfssvc_sock token.

* The NFS iod thread pairs and nfsd threads now run MPSAFE.

* NFSv3 is now holy-shit fast and can trivially max-out a GigE link
  without TSO when the server is not otherwise limited by server-side
  disks.

sys/vfs/nfs/nfs.h
sys/vfs/nfs/nfs_bio.c
sys/vfs/nfs/nfs_iod.c
sys/vfs/nfs/nfs_node.c
sys/vfs/nfs/nfs_socket.c
sys/vfs/nfs/nfs_subs.c
sys/vfs/nfs/nfs_syscalls.c
sys/vfs/nfs/nfs_vfsops.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/nfs/nfsmount.h

index d0fa2c5..050c558 100644 (file)
@@ -47,6 +47,7 @@
 
 #include <sys/vnode.h>
 #include <sys/mutex.h>
+#include <sys/thread.h>
 
 /*
  * Tunable constants for nfs
@@ -485,6 +486,7 @@ struct nfssvc_sock {
        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" */
@@ -647,6 +649,7 @@ extern int32_t (*nfsrv3_procs[NFS_NPROCS]) (struct nfsrv_descript *nd,
                                            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);
@@ -698,7 +701,7 @@ int nfs_savenickauth (struct nfsmount *, struct ucred *, int,
 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 *,
@@ -782,7 +785,9 @@ int nfsrv_symlink (struct nfsrv_descript *nfsd,
 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,
index 0de9d36..bfeab6a 100644 (file)
@@ -59,7 +59,6 @@
 
 #include <sys/buf2.h>
 #include <sys/thread2.h>
-#include <sys/mplock2.h>
 #include <vm/vm_page2.h>
 
 #include "rpcv2.h"
@@ -1360,7 +1359,7 @@ nfs_readrpc_bio_done(nfsm_info_t info)
 
        KKASSERT(info->state == NFSM_STATE_DONE);
 
-       get_mplock();
+       lwkt_gettoken(&nmp->nm_token);
 
        if (info->v3) {
                ERROROUT(nfsm_postop_attr(info, info->vp, &attrflag,
@@ -1400,7 +1399,7 @@ nfs_readrpc_bio_done(nfsm_info_t info)
        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;
@@ -1513,7 +1512,7 @@ nfs_writerpc_bio_done(nfsm_info_t info)
        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) {
                /*
@@ -1630,7 +1629,8 @@ nfsmout:
        }
        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;
@@ -1696,7 +1696,7 @@ nfs_commitrpc_bio_done(nfsm_info_t info)
        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) {
@@ -1723,6 +1723,6 @@ nfsmout:
        } else {
                nfs_writerpc_bio(info->vp, bio);
        }
-       rel_mplock();
+       lwkt_reltoken(&nmp->nm_token);
 }
 
index 33cbd25..1df710d 100644 (file)
@@ -83,11 +83,10 @@ nfssvc_iod_reader(void *arg)
        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 &&
@@ -131,7 +130,6 @@ nfssvc_iod_reader(void *arg)
                                continue;
                        }
                        TAILQ_REMOVE(&nmp->nm_reqrxq, req, r_chain);
-                       crit_exit();
                        info = req->r_info;
                        KKASSERT(info);
                        info->error = nfs_request(info,
@@ -145,12 +143,12 @@ nfssvc_iod_reader(void *arg)
                                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);
 }
 
@@ -173,12 +171,11 @@ nfssvc_iod_writer(void *arg)
        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);
@@ -197,9 +194,7 @@ nfssvc_iod_writer(void *arg)
                                break;
                        TAILQ_REMOVE(&nmp->nm_bioq, bio, bio_act);
                        vp = bio->bio_driver_info;
-                       crit_exit();
                        nfs_startio(vp, bio, NULL);
-                       crit_enter();
                }
 
                /*
@@ -212,11 +207,9 @@ nfssvc_iod_writer(void *arg)
                        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 {
@@ -225,19 +218,17 @@ nfssvc_iod_writer(void *arg)
                        }
                }
        }
-       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
index 281101e..999454a 100644 (file)
@@ -342,9 +342,12 @@ fail:
 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);
@@ -373,6 +376,7 @@ nfs_inactive(struct vop_inactive_args *ap)
        }
 
        np->n_flag &= ~(NWRITEERR | NACC | NUPD | NCHG | NLOCKED | NWANTED);
+       lwkt_reltoken(&nmp->nm_token);
 
        return (0);
 }
@@ -388,10 +392,13 @@ nfs_reclaim(struct vop_reclaim_args *ap)
        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);
 
@@ -419,9 +426,11 @@ nfs_reclaim(struct vop_reclaim_args *ap)
                crfree(np->n_wucred);
                np->n_wucred = NULL;
        }
-
        vp->v_data = NULL;
+
+       lwkt_reltoken(&nmp->nm_token);
        zfree(nfsnode_zone, np);
+
        return (0);
 }
 
index 3d29c18..1b78052 100644 (file)
@@ -1694,7 +1694,7 @@ nfs_rephead(int siz, struct nfsrv_descript *nd, struct nfssvc_sock *slp,
  * 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;
@@ -1703,8 +1703,9 @@ nfs_timer(void *arg /* never used */)
        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)
@@ -1723,6 +1724,7 @@ nfs_timer(void *arg /* never used */)
                                wakeup(req);
                        }
                }
+               lwkt_reltoken(&nmp->nm_token);
        }
 #ifndef NFS_NOSERVER
 
@@ -1731,13 +1733,18 @@ nfs_timer(void *arg /* never used */)
         * 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
@@ -2468,11 +2475,24 @@ nfs_msg(struct thread *td, char *server, char *msg)
 }
 
 #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)
@@ -2484,6 +2504,8 @@ 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;
 
@@ -2522,7 +2544,7 @@ nfsrv_rcv(struct socket *so, void *arg, int waitflag)
                 *
                 * 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;
index 0cdeebc..065a06a 100644 (file)
@@ -99,6 +99,12 @@ enum vtype nv3tov_type[8]= {
 
 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);
@@ -602,7 +608,7 @@ nfs_init(struct vfsconf *vfsp)
        /*
         * 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;
index 8c71179..3559573 100644 (file)
@@ -62,7 +62,7 @@
 #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>
@@ -150,7 +150,8 @@ sys_nfssvc(struct nfssvc_args *uap)
        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);
@@ -308,7 +309,7 @@ sys_nfssvc(struct nfssvc_args *uap)
        if (error == EINTR || error == ERESTART)
                error = 0;
 done:
-       rel_mplock();
+       lwkt_reltoken(&nfs_token);
        return (error);
 }
 
@@ -401,19 +402,27 @@ nfssvc_addsock(struct file *fp, struct sockaddr *mynam, struct thread *td)
        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);
 }
 
@@ -437,15 +446,15 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
        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.
@@ -467,7 +476,7 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                                    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;
                                    }
@@ -477,6 +486,10 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                        }
                        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);
@@ -501,7 +514,13 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                } 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);
@@ -509,10 +528,15 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                        }
                        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);
@@ -536,6 +560,7 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                            !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 {
@@ -568,8 +593,10 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                }
 
                /*
-                * 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) {
@@ -644,8 +671,9 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                                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;
@@ -667,29 +695,37 @@ nfssvc_nfsd(struct nfsd_srvargs *nsd, caddr_t argp, struct thread *td)
                     * 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);
 }
 
@@ -752,16 +788,26 @@ nfsrv_zapsock(struct nfssvc_sock *slp)
 /*
  * 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.
  *
@@ -803,9 +849,11 @@ nfsrv_init(int terminating)
 {
        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)
@@ -814,8 +862,9 @@ nfsrv_init(int terminating)
                        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;
@@ -827,6 +876,8 @@ nfsrv_init(int terminating)
        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);
index 88431aa..11da476 100644 (file)
@@ -307,12 +307,16 @@ nfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
        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();
@@ -371,6 +375,7 @@ nfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
 nfsmout:
        vput(vp);
        crfree(cred);
+       lwkt_reltoken(&nmp->nm_token);
        return (error);
 }
 
@@ -387,13 +392,16 @@ nfs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
 
        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();
@@ -449,6 +457,7 @@ nfs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
 nfsmout:
        vput(vp);
        crfree(cred);
+       lwkt_reltoken(&nmp->nm_token);
        return (error);
 }
 
@@ -1003,9 +1012,13 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
                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
@@ -1094,7 +1107,9 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
         * 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) {
@@ -1124,10 +1139,11 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
                    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);
 }
@@ -1142,6 +1158,7 @@ nfs_unmount(struct mount *mp, int mntflags)
        int error, flags = 0;
 
        nmp = VFSTONFS(mp);
+       lwkt_gettoken(&nmp->nm_token);
        if (mntflags & MNT_FORCE) {
                flags |= FORCECLOSE;
                nmp->nm_flag |= NFSMNT_FORCE;
@@ -1177,8 +1194,10 @@ nfs_unmount(struct mount *mp, int mntflags)
        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);
+               }
        }
 
        /*
@@ -1190,7 +1209,12 @@ nfs_unmount(struct mount *mp, int mntflags)
        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);
@@ -1225,9 +1249,12 @@ nfs_root(struct mount *mp, struct vnode **vpp)
        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);
 
        /*
@@ -1263,6 +1290,7 @@ nfs_root(struct mount *mp, struct vnode **vpp)
                vput(vp);
        else
                *vpp = vp;
+       lwkt_reltoken(&nmp->nm_token);
        return (error);
 }
 
@@ -1282,6 +1310,7 @@ static int nfs_sync_scan2(struct mount *mp, struct vnode *vp, void *data);
 static int
 nfs_sync(struct mount *mp, int waitfor)
 {
+       struct nfsmount *nmp = VFSTONFS(mp);
        struct scaninfo scaninfo;
        int error;
 
@@ -1292,12 +1321,14 @@ nfs_sync(struct mount *mp, int waitfor)
        /*
         * 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);
 }
 
index 40b26a8..1be659c 100644 (file)
@@ -311,8 +311,11 @@ nfs_access(struct vop_access_args *ap)
        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
@@ -323,6 +326,7 @@ nfs_access(struct vop_access_args *ap)
                case VREG:
                case VDIR:
                case VLNK:
+                       lwkt_reltoken(&nmp->nm_token);
                        return (EROFS);
                default:
                        break;
@@ -401,6 +405,7 @@ nfs_access(struct vop_access_args *ap)
        } else {
                if ((error = nfs_laccess(ap)) != 0) {
                        crfree(cred);
+                       lwkt_reltoken(&nmp->nm_token);
                        return (error);
                }
 
@@ -462,6 +467,7 @@ nfs_access(struct vop_access_args *ap)
                        np->n_wucred = cred;
                }
        }
+       lwkt_reltoken(&nmp->nm_token);
        crfree(cred);
        return(error);
 }
@@ -482,13 +488,17 @@ nfs_open(struct vop_open_args *ap)
 {
        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);
        }
 
@@ -543,18 +553,24 @@ nfs_open(struct vop_open_args *ap)
                }
        }
        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;
 }
 
 /*
@@ -595,9 +611,12 @@ nfs_close(struct vop_close_args *ap)
 {
        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)) {
@@ -628,6 +647,8 @@ nfs_close(struct vop_close_args *ap)
            }
        }
        vop_stdclose(ap);
+       lwkt_reltoken(&nmp->nm_token);
+
        return (error);
 }
 
@@ -649,6 +670,8 @@ nfs_getattr(struct vop_getattr_args *ap)
        info.mrep = NULL;
        info.v3 = NFS_ISV3(vp);
        nmp = VFSTONFS(vp->v_mount);
+
+       lwkt_gettoken(&nmp->nm_token);
        
        /*
         * Update local times for special files.
@@ -686,6 +709,7 @@ done:
        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);
 }
 
@@ -699,6 +723,7 @@ nfs_setattr(struct vop_setattr_args *ap)
 {
        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;
@@ -709,7 +734,6 @@ nfs_setattr(struct vop_setattr_args *ap)
 #ifndef nolint
        tsize = (off_t)0;
 #endif
-
        /*
         * Setting of flags is not supported.
         */
@@ -725,12 +749,15 @@ nfs_setattr(struct vop_setattr_args *ap)
            (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:
@@ -740,8 +767,10 @@ nfs_setattr(struct vop_setattr_args *ap)
                            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:
@@ -749,8 +778,10 @@ nfs_setattr(struct vop_setattr_args *ap)
                         * 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:
@@ -814,6 +845,8 @@ 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);
 }
 
@@ -896,6 +929,7 @@ nfs_nresolve(struct vop_nresolve_args *ap)
 {
        struct thread *td = curthread;
        struct namecache *ncp;
+       struct nfsmount *nmp;
        struct ucred *cred;
        struct nfsnode *np;
        struct vnode *dvp;
@@ -910,9 +944,14 @@ nfs_nresolve(struct vop_nresolve_args *ap)
 
        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);
@@ -979,6 +1018,7 @@ nfs_nresolve(struct vop_nresolve_args *ap)
                        m_freem(info.mrep);
                        info.mrep = NULL;
                        vput(dvp);
+                       lwkt_reltoken(&nmp->nm_token);
                        return (error);
                }
                nvp = NFSTOV(np);
@@ -995,6 +1035,7 @@ nfs_nresolve(struct vop_nresolve_args *ap)
        m_freem(info.mrep);
        info.mrep = NULL;
 nfsmout:
+       lwkt_reltoken(&nmp->nm_token);
        vput(dvp);
        if (nvp) {
                if (nvp == dvp)
@@ -1056,6 +1097,8 @@ nfs_lookup(struct vop_old_lookup_args *ap)
        nmp = VFSTONFS(dvp->v_mount);
        np = VTONFS(dvp);
 
+       lwkt_gettoken(&nmp->nm_token);
+
        /*
         * Go to the wire.
         */
@@ -1091,12 +1134,14 @@ nfs_lookup(struct vop_old_lookup_args *ap)
                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);
@@ -1115,6 +1160,7 @@ nfs_lookup(struct vop_old_lookup_args *ap)
                        vn_unlock(dvp);
                        cnp->cn_flags |= CNP_PDIRUNLOCK;
                }
+               lwkt_reltoken(&nmp->nm_token);
                return (0);
        }
 
@@ -1125,6 +1171,7 @@ nfs_lookup(struct vop_old_lookup_args *ap)
                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);
@@ -1132,6 +1179,7 @@ nfs_lookup(struct vop_old_lookup_args *ap)
                        error = vn_lock(dvp, LK_EXCLUSIVE);
                        if (error) {
                                vput(newvp);
+                               lwkt_reltoken(&nmp->nm_token);
                                return (error);
                        }
                        cnp->cn_flags |= CNP_PDIRUNLOCK;
@@ -1144,6 +1192,7 @@ nfs_lookup(struct vop_old_lookup_args *ap)
                if (error) {
                        m_freem(info.mrep);
                        info.mrep = NULL;
+                       lwkt_reltoken(&nmp->nm_token);
                        return (error);
                }
                if (!lockparent) {
@@ -1189,6 +1238,7 @@ nfsmout:
                                error = EJUSTRETURN;
                }
        }
+       lwkt_reltoken(&nmp->nm_token);
        return (error);
 }
 
@@ -1203,8 +1253,14 @@ static int
 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;
 }
 
 /*
@@ -1216,10 +1272,17 @@ static int
 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;
 }
 
 /*
@@ -1278,6 +1341,7 @@ nfs_readrpc_uio(struct vnode *vp, struct uio *uiop)
        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)
@@ -1563,7 +1627,14 @@ nfsmout:
 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;
@@ -1578,6 +1649,7 @@ nfs_create(struct vop_old_create_args *ap)
 {
        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;
@@ -1589,14 +1661,19 @@ nfs_create(struct vop_old_create_args *ap)
 
        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)
@@ -1697,6 +1774,7 @@ nfsmout:
        VTONFS(dvp)->n_flag |= NLMODIFIED;
        if (!wccflag)
                VTONFS(dvp)->n_attrstamp = 0;
+       lwkt_reltoken(&nmp->nm_token);
        return (error);
 }
 
@@ -1719,20 +1797,21 @@ nfs_remove(struct vop_old_remove_args *ap)
 {
        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.
@@ -1754,6 +1833,8 @@ nfs_remove(struct vop_old_remove_args *ap)
                error = nfs_sillyrename(dvp, vp, cnp);
        }
        np->n_attrstamp = 0;
+       lwkt_reltoken(&nmp->nm_token);
+
        return (error);
 }
 
@@ -1814,8 +1895,11 @@ nfs_rename(struct vop_old_rename_args *ap)
        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))) {
@@ -1862,6 +1946,7 @@ nfs_rename(struct vop_old_rename_args *ap)
                tcnp->cn_td);
 
 out:
+       lwkt_reltoken(&nmp->nm_token);
        if (tdvp == tvp)
                vrele(tdvp);
        else
@@ -1939,6 +2024,7 @@ nfs_link(struct vop_old_link_args *ap)
 {
        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;
@@ -1946,6 +2032,7 @@ nfs_link(struct vop_old_link_args *ap)
        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.
@@ -1987,6 +2074,7 @@ nfsmout:
         */
        if (error == EEXIST)
                error = 0;
+       lwkt_reltoken(&nmp->nm_token);
        return (error);
 }
 
@@ -2002,6 +2090,7 @@ nfs_symlink(struct vop_old_symlink_args *ap)
 {
        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;
@@ -2010,6 +2099,7 @@ nfs_symlink(struct vop_old_symlink_args *ap)
 
        info.mrep = NULL;
        info.v3 = NFS_ISV3(dvp);
+       lwkt_gettoken(&nmp->nm_token);
 
        nfsstats.rpccnt[NFSPROC_SYMLINK]++;
        slen = strlen(ap->a_target);
@@ -2075,7 +2165,7 @@ nfsmout:
                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);
        }
@@ -2088,6 +2178,8 @@ nfsmout:
        VTONFS(dvp)->n_flag |= NLMODIFIED;
        if (!wccflag)
                VTONFS(dvp)->n_attrstamp = 0;
+       lwkt_reltoken(&nmp->nm_token);
+
        return (error);
 }
 
@@ -2102,6 +2194,7 @@ nfs_mkdir(struct vop_old_mkdir_args *ap)
 {
        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;
@@ -2114,8 +2207,10 @@ nfs_mkdir(struct vop_old_mkdir_args *ap)
 
        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;
@@ -2170,8 +2265,10 @@ nfsmout:
        if (error) {
                if (newvp)
                        vrele(newvp);
-       } else
+       } else {
                *ap->a_vpp = newvp;
+       }
+       lwkt_reltoken(&nmp->nm_token);
        return (error);
 }
 
@@ -2186,6 +2283,7 @@ nfs_rmdir(struct vop_old_rmdir_args *ap)
 {
        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;
@@ -2195,6 +2293,9 @@ nfs_rmdir(struct vop_old_rmdir_args *ap)
 
        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 +
@@ -2218,6 +2319,8 @@ nfsmout:
         */
        if (error == ENOENT)
                error = 0;
+       lwkt_reltoken(&nmp->nm_token);
+
        return (error);
 }
 
@@ -2231,6 +2334,7 @@ nfs_readdir(struct vop_readdir_args *ap)
 {
        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;
@@ -2241,6 +2345,8 @@ nfs_readdir(struct vop_readdir_args *ap)
        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
@@ -2267,7 +2373,9 @@ nfs_readdir(struct vop_readdir_args *ap)
        if (!error && uio->uio_resid == tresid)
                nfsstats.direofcache_misses++;
 done:
+       lwkt_reltoken(&nmp->nm_token);
        vn_unlock(vp);
+
        return (error);
 }
 
@@ -2967,6 +3075,7 @@ nfsmout:
 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)
@@ -2985,6 +3094,7 @@ nfs_strategy(struct vop_strategy_args *ap)
        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;
 
@@ -2998,6 +3108,8 @@ nfs_strategy(struct vop_strategy_args *ap)
        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
@@ -3023,6 +3135,8 @@ nfs_strategy(struct vop_strategy_args *ap)
                nfs_asyncio(ap->a_vp, nbio);
                error = 0;
        }
+       lwkt_reltoken(&nmp->nm_token);
+
        return (error);
 }
 
@@ -3037,6 +3151,7 @@ nfs_strategy(struct vop_strategy_args *ap)
 static int
 nfs_mmap(struct vop_mmap_args *ap)
 {
+       /* no token lock required */
        return (EINVAL);
 }
 
@@ -3049,7 +3164,14 @@ nfs_mmap(struct vop_mmap_args *ap)
 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;
 }
 
 /*
@@ -3374,6 +3496,7 @@ nfs_advlock(struct vop_advlock_args *ap)
 {
        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
@@ -3409,13 +3532,18 @@ nfs_print(struct vop_print_args *ap)
 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);
 }
 
@@ -3430,6 +3558,7 @@ nfsfifo_read(struct vop_read_args *ap)
 {
        struct nfsnode *np = VTONFS(ap->a_vp);
 
+       /* no token access required */
        /*
         * Set access flag.
         */
@@ -3449,6 +3578,7 @@ nfsfifo_write(struct vop_write_args *ap)
 {
        struct nfsnode *np = VTONFS(ap->a_vp);
 
+       /* no token access required */
        /*
         * Set update flag.
         */
@@ -3472,6 +3602,8 @@ nfsfifo_close(struct vop_close_args *ap)
        struct vattr vattr;
        struct timespec ts;
 
+       /* no token access required */
+
        if (np->n_flag & (NACC | NUPD)) {
                getnanotime(&ts);
                if (np->n_flag & NACC)
index 88b8673..debf8a1 100644 (file)
@@ -43,6 +43,7 @@
 #define _NFS_NFSMOUNT_H_
 
 #include <sys/mutex.h>
+#include <sys/thread.h>        /* token */
 
 enum nfssvc_state {
        NFSSVC_INIT,
@@ -112,6 +113,7 @@ struct      nfsmount {
        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 */
 };