From: Matthew Dillon Date: Fri, 10 Sep 2010 19:09:34 +0000 (-0700) Subject: network - Tokenize NFS, fix MP races X-Git-Url: https://gitweb.dragonflybsd.org/~lentferj/dragonfly.git/commitdiff_plain/c6b43e93a6cf0a70bde32cd141057a0df9860e13 network - Tokenize NFS, fix MP races * 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. --- diff --git a/sys/vfs/nfs/nfs.h b/sys/vfs/nfs/nfs.h index d0fa2c5284..050c5585e0 100644 --- a/sys/vfs/nfs/nfs.h +++ b/sys/vfs/nfs/nfs.h @@ -47,6 +47,7 @@ #include #include +#include /* * 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, diff --git a/sys/vfs/nfs/nfs_bio.c b/sys/vfs/nfs/nfs_bio.c index 0de9d3667a..bfeab6a639 100644 --- a/sys/vfs/nfs/nfs_bio.c +++ b/sys/vfs/nfs/nfs_bio.c @@ -59,7 +59,6 @@ #include #include -#include #include #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); } diff --git a/sys/vfs/nfs/nfs_iod.c b/sys/vfs/nfs/nfs_iod.c index 33cbd257cb..1df710d7a1 100644 --- a/sys/vfs/nfs/nfs_iod.c +++ b/sys/vfs/nfs/nfs_iod.c @@ -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 diff --git a/sys/vfs/nfs/nfs_node.c b/sys/vfs/nfs/nfs_node.c index 281101e9f5..999454a194 100644 --- a/sys/vfs/nfs/nfs_node.c +++ b/sys/vfs/nfs/nfs_node.c @@ -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); } diff --git a/sys/vfs/nfs/nfs_socket.c b/sys/vfs/nfs/nfs_socket.c index 3d29c18de5..1b78052a0c 100644 --- a/sys/vfs/nfs/nfs_socket.c +++ b/sys/vfs/nfs/nfs_socket.c @@ -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; diff --git a/sys/vfs/nfs/nfs_subs.c b/sys/vfs/nfs/nfs_subs.c index 0cdeebcbb4..065a06a657 100644 --- a/sys/vfs/nfs/nfs_subs.c +++ b/sys/vfs/nfs/nfs_subs.c @@ -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; diff --git a/sys/vfs/nfs/nfs_syscalls.c b/sys/vfs/nfs/nfs_syscalls.c index 8c71179dab..3559573d21 100644 --- a/sys/vfs/nfs/nfs_syscalls.c +++ b/sys/vfs/nfs/nfs_syscalls.c @@ -62,7 +62,7 @@ #include #include -#include +#include #include #include @@ -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); diff --git a/sys/vfs/nfs/nfs_vfsops.c b/sys/vfs/nfs/nfs_vfsops.c index 88431aafd7..11da476799 100644 --- a/sys/vfs/nfs/nfs_vfsops.c +++ b/sys/vfs/nfs/nfs_vfsops.c @@ -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); } diff --git a/sys/vfs/nfs/nfs_vnops.c b/sys/vfs/nfs/nfs_vnops.c index 40b26a8364..1be659c8f7 100644 --- a/sys/vfs/nfs/nfs_vnops.c +++ b/sys/vfs/nfs/nfs_vnops.c @@ -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) diff --git a/sys/vfs/nfs/nfsmount.h b/sys/vfs/nfs/nfsmount.h index 88b86731ee..debf8a1cab 100644 --- a/sys/vfs/nfs/nfsmount.h +++ b/sys/vfs/nfs/nfsmount.h @@ -43,6 +43,7 @@ #define _NFS_NFSMOUNT_H_ #include +#include /* 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 */ };