summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsserver
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2012-10-14 22:33:17 +0000
committerrmacklem <rmacklem@FreeBSD.org>2012-10-14 22:33:17 +0000
commit813fc271886f8973789b4c3847329a2c39a4f29c (patch)
treefd9a8026f443d2f981842db8e496af20a034749c /sys/fs/nfsserver
parentb75b22519f1551241f5a6449d248028e60dff704 (diff)
downloadFreeBSD-src-813fc271886f8973789b4c3847329a2c39a4f29c.zip
FreeBSD-src-813fc271886f8973789b4c3847329a2c39a4f29c.tar.gz
Add two new options to the nfssvc(2) syscall that allow
processes running as root to suspend/resume execution of the kernel nfsd threads. An earlier version of this patch was tested by Vincent Hoffman (vince at unsane.co.uk) and John Hickey (jh at deterlab.net). Reviewed by: kib MFC after: 2 weeks
Diffstat (limited to 'sys/fs/nfsserver')
-rw-r--r--sys/fs/nfsserver/nfs_nfsdkrpc.c20
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c24
2 files changed, 43 insertions, 1 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdkrpc.c b/sys/fs/nfsserver/nfs_nfsdkrpc.c
index ae676f3..337951b 100644
--- a/sys/fs/nfsserver/nfs_nfsdkrpc.c
+++ b/sys/fs/nfsserver/nfs_nfsdkrpc.c
@@ -45,6 +45,8 @@ __FBSDID("$FreeBSD$");
#include <security/mac/mac_framework.h>
NFSDLOCKMUTEX;
+NFSV4ROOTLOCKMUTEX;
+struct nfsv4lock nfsd_suspend_lock;
/*
* Mapping of old NFS Version 2 RPC numbers to generic numbers.
@@ -221,9 +223,24 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
#ifdef MAC
mac_cred_associate_nfsd(nd.nd_cred);
#endif
+ /*
+ * Get a refcnt (shared lock) on nfsd_suspend_lock.
+ * NFSSVC_SUSPENDNFSD will take an exclusive lock on
+ * nfsd_suspend_lock to suspend these threads.
+ * This must be done here, before the check of
+ * nfsv4root exports by nfsvno_v4rootexport().
+ */
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_getref(&nfsd_suspend_lock, NULL, NFSV4ROOTLOCKMUTEXPTR,
+ NULL);
+ NFSUNLOCKV4ROOTMUTEX();
+
if ((nd.nd_flag & ND_NFSV4) != 0) {
nd.nd_repstat = nfsvno_v4rootexport(&nd);
if (nd.nd_repstat != 0) {
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_relref(&nfsd_suspend_lock);
+ NFSUNLOCKV4ROOTMUTEX();
svcerr_weakauth(rqst);
svc_freereq(rqst);
m_freem(nd.nd_mrep);
@@ -233,6 +250,9 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
cacherep = nfs_proc(&nd, rqst->rq_xid, xprt->xp_socket,
xprt->xp_sockref, &rp);
+ NFSLOCKV4ROOTMUTEX();
+ nfsv4_relref(&nfsd_suspend_lock);
+ NFSUNLOCKV4ROOTMUTEX();
} else {
NFSMGET(nd.nd_mreq);
nd.nd_mreq->m_len = 0;
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 21d184b..877f990 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -57,6 +57,7 @@ extern struct mount nfsv4root_mnt;
extern struct nfsrv_stablefirst nfsrv_stablefirst;
extern void (*nfsd_call_servertimer)(void);
extern SVCPOOL *nfsrvd_pool;
+extern struct nfsv4lock nfsd_suspend_lock;
struct vfsoptlist nfsv4root_opt, nfsv4root_newopt;
NFSDLOCKMUTEX;
struct mtx nfs_cache_mutex;
@@ -3095,8 +3096,9 @@ nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
struct nfsd_dumplocks *dumplocks;
struct nameidata nd;
vnode_t vp;
- int error = EINVAL;
+ int error = EINVAL, igotlock;
struct proc *procp;
+ static int suspend_nfsd = 0;
if (uap->flag & NFSSVC_PUBLICFH) {
NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data,
@@ -3175,6 +3177,26 @@ nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
nfsd_master_start = procp->p_stats->p_start;
nfsd_master_proc = procp;
PROC_UNLOCK(procp);
+ } else if ((uap->flag & NFSSVC_SUSPENDNFSD) != 0) {
+ NFSLOCKV4ROOTMUTEX();
+ if (suspend_nfsd == 0) {
+ /* Lock out all nfsd threads */
+ do {
+ igotlock = nfsv4_lock(&nfsd_suspend_lock, 1,
+ NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
+ } while (igotlock == 0 && suspend_nfsd == 0);
+ suspend_nfsd = 1;
+ }
+ NFSUNLOCKV4ROOTMUTEX();
+ error = 0;
+ } else if ((uap->flag & NFSSVC_RESUMENFSD) != 0) {
+ NFSLOCKV4ROOTMUTEX();
+ if (suspend_nfsd != 0) {
+ nfsv4_unlock(&nfsd_suspend_lock, 0);
+ suspend_nfsd = 0;
+ }
+ NFSUNLOCKV4ROOTMUTEX();
+ error = 0;
}
NFSEXITCODE(error);
OpenPOWER on IntegriCloud