From 813fc271886f8973789b4c3847329a2c39a4f29c Mon Sep 17 00:00:00 2001 From: rmacklem Date: Sun, 14 Oct 2012 22:33:17 +0000 Subject: 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 --- sys/fs/nfsserver/nfs_nfsdkrpc.c | 20 ++++++++++++++++++++ sys/fs/nfsserver/nfs_nfsdport.c | 24 +++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'sys/fs') 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 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); -- cgit v1.1