summaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2019-12-28 22:24:16 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2019-12-28 22:24:16 +0000
commit39ea5e3b5bdea8cbdb3d4e96315610f4d21e9e25 (patch)
tree7c0c7980dde12d1feeaf0c6a6b94fbd347c72993 /sys/fs
parentba1755d072fc1edc8e5a2b4900f64eea509a5083 (diff)
downloadsrc-test2-39ea5e3b5bdea8cbdb3d4e96315610f4d21e9e25.tar.gz
src-test2-39ea5e3b5bdea8cbdb3d4e96315610f4d21e9e25.zip
Notes
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/nfs/nfs.h3
-rw-r--r--sys/fs/nfs/nfs_commonport.c4
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c47
-rw-r--r--sys/fs/nfs/nfsport.h1
4 files changed, 44 insertions, 11 deletions
diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h
index e47f0d130c08..c6fb59fa6b64 100644
--- a/sys/fs/nfs/nfs.h
+++ b/sys/fs/nfs/nfs.h
@@ -797,6 +797,9 @@ struct nfsslot {
struct mbuf *nfssl_reply;
};
+/* Enumerated type for nfsuserd state. */
+typedef enum { NOTRUNNING=0, STARTSTOP=1, RUNNING=2 } nfsuserd_state;
+
#endif /* _KERNEL */
#endif /* _NFS_NFS_H */
diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c
index 71f2726a81cb..1a1e64cd823b 100644
--- a/sys/fs/nfs/nfs_commonport.c
+++ b/sys/fs/nfs/nfs_commonport.c
@@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$");
#include <vm/uma.h>
extern int nfscl_ticks;
-extern int nfsrv_nfsuserd;
+extern nfsuserd_state nfsrv_nfsuserd;
extern struct nfssockreq nfsrv_nfsuserdsock;
extern void (*nfsd_call_recall)(struct vnode *, int, struct ucred *,
struct thread *);
@@ -774,7 +774,7 @@ nfscommon_modevent(module_t mod, int type, void *data)
break;
case MOD_UNLOAD:
- if (newnfs_numnfsd != 0 || nfsrv_nfsuserd != 0 ||
+ if (newnfs_numnfsd != 0 || nfsrv_nfsuserd != NOTRUNNING ||
nfs_numnfscbd != 0) {
error = EBUSY;
break;
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 139aa583e139..9214674b99e1 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -64,7 +64,8 @@ struct timeval nfsboottime; /* Copy boottime once, so it never changes */
int nfscl_ticks;
int nfsrv_useacl = 1;
struct nfssockreq nfsrv_nfsuserdsock;
-int nfsrv_nfsuserd = 0;
+nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
+static int nfsrv_userdupcalls = 0;
struct nfsreqhead nfsd_reqq;
uid_t nfsrv_defaultuid = UID_NOBODY;
gid_t nfsrv_defaultgid = GID_NOGROUP;
@@ -3524,18 +3525,22 @@ nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
int error;
NFSLOCKNAMEID();
- if (nfsrv_nfsuserd) {
+ if (nfsrv_nfsuserd != NOTRUNNING) {
NFSUNLOCKNAMEID();
error = EPERM;
goto out;
}
- nfsrv_nfsuserd = 1;
- NFSUNLOCKNAMEID();
+ nfsrv_nfsuserd = STARTSTOP;
/*
* Set up the socket record and connect.
+ * Set nr_client NULL before unlocking, just to ensure that no other
+ * process/thread/core will use a bogus old value. This could only
+ * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
+ * broken.
*/
rp = &nfsrv_nfsuserdsock;
rp->nr_client = NULL;
+ NFSUNLOCKNAMEID();
rp->nr_sotype = SOCK_DGRAM;
rp->nr_soproto = IPPROTO_UDP;
rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
@@ -3571,9 +3576,15 @@ nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
rp->nr_vers = RPCNFSUSERD_VERS;
if (error == 0)
error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
- if (error) {
+ if (error == 0) {
+ NFSLOCKNAMEID();
+ nfsrv_nfsuserd = RUNNING;
+ NFSUNLOCKNAMEID();
+ } else {
free(rp->nr_nam, M_SONAME);
- nfsrv_nfsuserd = 0;
+ NFSLOCKNAMEID();
+ nfsrv_nfsuserd = NOTRUNNING;
+ NFSUNLOCKNAMEID();
}
out:
NFSEXITCODE(error);
@@ -3588,14 +3599,21 @@ nfsrv_nfsuserddelport(void)
{
NFSLOCKNAMEID();
- if (nfsrv_nfsuserd == 0) {
+ if (nfsrv_nfsuserd != RUNNING) {
NFSUNLOCKNAMEID();
return;
}
- nfsrv_nfsuserd = 0;
+ nfsrv_nfsuserd = STARTSTOP;
+ /* Wait for all upcalls to complete. */
+ while (nfsrv_userdupcalls > 0)
+ msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
+ "nfsupcalls", 0);
NFSUNLOCKNAMEID();
newnfs_disconnect(&nfsrv_nfsuserdsock);
free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
+ NFSLOCKNAMEID();
+ nfsrv_nfsuserd = NOTRUNNING;
+ NFSUNLOCKNAMEID();
}
/*
@@ -3614,12 +3632,19 @@ nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
int error;
NFSLOCKNAMEID();
- if (nfsrv_nfsuserd == 0) {
+ if (nfsrv_nfsuserd != RUNNING) {
NFSUNLOCKNAMEID();
error = EPERM;
goto out;
}
+ /*
+ * Maintain a count of upcalls in progress, so that nfsrv_X()
+ * can wait until no upcalls are in progress.
+ */
+ nfsrv_userdupcalls++;
NFSUNLOCKNAMEID();
+ KASSERT(nfsrv_userdupcalls > 0,
+ ("nfsrv_getuser: non-positive upcalls"));
nd = &nfsd;
cred = newnfs_getcred();
nd->nd_flag = ND_GSSINITREPLY;
@@ -3638,6 +3663,10 @@ nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
}
error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
+ NFSLOCKNAMEID();
+ if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
+ wakeup(&nfsrv_userdupcalls);
+ NFSUNLOCKNAMEID();
NFSFREECRED(cred);
if (!error) {
mbuf_freem(nd->nd_mrep);
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index 560b3bd231c8..8abb6a5d1173 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -669,6 +669,7 @@ void nfsrvd_rcv(struct socket *, void *, int);
#define NFSLOCKSOCK() mtx_lock(&nfs_slock_mutex)
#define NFSUNLOCKSOCK() mtx_unlock(&nfs_slock_mutex)
#define NFSNAMEIDMUTEX extern struct mtx nfs_nameid_mutex
+#define NFSNAMEIDMUTEXPTR (&nfs_nameid_mutex)
#define NFSLOCKNAMEID() mtx_lock(&nfs_nameid_mutex)
#define NFSUNLOCKNAMEID() mtx_unlock(&nfs_nameid_mutex)
#define NFSNAMEIDREQUIRED() mtx_assert(&nfs_nameid_mutex, MA_OWNED)