Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/nfsserver/nfs_nfsdkrpc.c
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
#include <rpc/rpcsec_tls.h> | #include <rpc/rpcsec_tls.h> | ||||
#include <fs/nfsserver/nfs_fha_new.h> | #include <fs/nfsserver/nfs_fha_new.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
NFSDLOCKMUTEX; | NFSDLOCKMUTEX; | ||||
NFSV4ROOTLOCKMUTEX; | NFSV4ROOTLOCKMUTEX; | ||||
struct nfsv4lock nfsd_suspend_lock; | |||||
char *nfsrv_zeropnfsdat = NULL; | char *nfsrv_zeropnfsdat = NULL; | ||||
/* | /* | ||||
* Mapping of old NFS Version 2 RPC numbers to generic numbers. | * Mapping of old NFS Version 2 RPC numbers to generic numbers. | ||||
*/ | */ | ||||
int newnfs_nfsv3_procid[NFS_V3NPROCS] = { | int newnfs_nfsv3_procid[NFS_V3NPROCS] = { | ||||
NFSPROC_NULL, | NFSPROC_NULL, | ||||
NFSPROC_GETATTR, | NFSPROC_GETATTR, | ||||
Show All 16 Lines | int newnfs_nfsv3_procid[NFS_V3NPROCS] = { | ||||
NFSPROC_NOOP, | NFSPROC_NOOP, | ||||
NFSPROC_NOOP, | NFSPROC_NOOP, | ||||
NFSPROC_NOOP, | NFSPROC_NOOP, | ||||
NFSPROC_NOOP, | NFSPROC_NOOP, | ||||
}; | }; | ||||
SYSCTL_DECL(_vfs_nfsd); | SYSCTL_DECL(_vfs_nfsd); | ||||
SVCPOOL *nfsrvd_pool; | NFSD_VNET_DEFINE_STATIC(int, nfs_privport) = 0; | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, nfs_privport, CTLFLAG_NFSD_VNET | CTLFLAG_RWTUN, | |||||
static int nfs_privport = 0; | &NFSD_VNET_NAME(nfs_privport), 0, | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, nfs_privport, CTLFLAG_RWTUN, | |||||
&nfs_privport, 0, | |||||
"Only allow clients using a privileged port for NFSv2, 3 and 4"); | "Only allow clients using a privileged port for NFSv2, 3 and 4"); | ||||
static int nfs_minvers = NFS_VER2; | NFSD_VNET_DEFINE_STATIC(int, nfs_minvers) = NFS_VER2; | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_nfsvers, CTLFLAG_RWTUN, | SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_min_nfsvers, | ||||
&nfs_minvers, 0, "The lowest version of NFS handled by the server"); | CTLFLAG_NFSD_VNET | CTLFLAG_RWTUN, &NFSD_VNET_NAME(nfs_minvers), 0, | ||||
"The lowest version of NFS handled by the server"); | |||||
static int nfs_maxvers = NFS_VER4; | NFSD_VNET_DEFINE_STATIC(int, nfs_maxvers) = NFS_VER4; | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_nfsvers, CTLFLAG_RWTUN, | SYSCTL_INT(_vfs_nfsd, OID_AUTO, server_max_nfsvers, | ||||
&nfs_maxvers, 0, "The highest version of NFS handled by the server"); | CTLFLAG_NFSD_VNET | CTLFLAG_RWTUN, &NFSD_VNET_NAME(nfs_maxvers), 0, | ||||
"The highest version of NFS handled by the server"); | |||||
static int nfs_proc(struct nfsrv_descript *, u_int32_t, SVCXPRT *xprt, | static int nfs_proc(struct nfsrv_descript *, u_int32_t, SVCXPRT *xprt, | ||||
struct nfsrvcache **); | struct nfsrvcache **); | ||||
extern u_long sb_max_adj; | extern u_long sb_max_adj; | ||||
extern int newnfs_numnfsd; | extern int newnfs_numnfsd; | ||||
extern struct proc *nfsd_master_proc; | |||||
extern time_t nfsdev_time; | extern time_t nfsdev_time; | ||||
extern int nfsrv_writerpc[NFS_NPROCS]; | extern int nfsrv_writerpc[NFS_NPROCS]; | ||||
extern volatile int nfsrv_devidcnt; | extern volatile int nfsrv_devidcnt; | ||||
extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS]; | extern struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS]; | ||||
NFSD_VNET_DECLARE(struct proc *, nfsd_master_proc); | |||||
NFSD_VNET_DEFINE(SVCPOOL *, nfsrvd_pool); | |||||
NFSD_VNET_DEFINE(int, nfsrv_numnfsd) = 0; | |||||
NFSD_VNET_DEFINE(struct nfsv4lock, nfsd_suspend_lock); | |||||
NFSD_VNET_DEFINE_STATIC(bool, nfsrvd_inited) = false; | |||||
/* | /* | ||||
* NFS server system calls | * NFS server system calls | ||||
*/ | */ | ||||
static void | static void | ||||
nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt) | nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt) | ||||
{ | { | ||||
struct nfsrv_descript nd; | struct nfsrv_descript nd; | ||||
struct nfsrvcache *rp = NULL; | struct nfsrvcache *rp = NULL; | ||||
int cacherep, credflavor; | int cacherep, credflavor; | ||||
#ifdef KERN_TLS | #ifdef KERN_TLS | ||||
u_int maxlen; | u_int maxlen; | ||||
#endif | #endif | ||||
NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread)); | |||||
memset(&nd, 0, sizeof(nd)); | memset(&nd, 0, sizeof(nd)); | ||||
if (rqst->rq_vers == NFS_VER2) { | if (rqst->rq_vers == NFS_VER2) { | ||||
if (rqst->rq_proc > NFSV2PROC_STATFS || | if (rqst->rq_proc > NFSV2PROC_STATFS || | ||||
newnfs_nfsv3_procid[rqst->rq_proc] == NFSPROC_NOOP) { | newnfs_nfsv3_procid[rqst->rq_proc] == NFSPROC_NOOP) { | ||||
svcerr_noproc(rqst); | svcerr_noproc(rqst); | ||||
svc_freereq(rqst); | svc_freereq(rqst); | ||||
goto out; | goto out; | ||||
} | } | ||||
Show All 28 Lines | #endif | ||||
newnfs_realign(&nd.nd_mrep, M_WAITOK); | newnfs_realign(&nd.nd_mrep, M_WAITOK); | ||||
nd.nd_md = nd.nd_mrep; | nd.nd_md = nd.nd_mrep; | ||||
nd.nd_dpos = mtod(nd.nd_md, caddr_t); | nd.nd_dpos = mtod(nd.nd_md, caddr_t); | ||||
nd.nd_nam = svc_getrpccaller(rqst); | nd.nd_nam = svc_getrpccaller(rqst); | ||||
nd.nd_nam2 = rqst->rq_addr; | nd.nd_nam2 = rqst->rq_addr; | ||||
nd.nd_mreq = NULL; | nd.nd_mreq = NULL; | ||||
nd.nd_cred = NULL; | nd.nd_cred = NULL; | ||||
if (nfs_privport != 0) { | if (NFSD_VNET(nfs_privport) != 0) { | ||||
/* Check if source port is privileged */ | /* Check if source port is privileged */ | ||||
u_short port; | u_short port; | ||||
struct sockaddr *nam = nd.nd_nam; | struct sockaddr *nam = nd.nd_nam; | ||||
struct sockaddr_in *sin; | struct sockaddr_in *sin; | ||||
sin = (struct sockaddr_in *)nam; | sin = (struct sockaddr_in *)nam; | ||||
/* | /* | ||||
* INET/INET6 - same code: | * INET/INET6 - same code: | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | #endif | ||||
* The call to nfsv4_lock() that precedes nfsv4_getref() | * The call to nfsv4_lock() that precedes nfsv4_getref() | ||||
* ensures that the acquisition of the exclusive lock | * ensures that the acquisition of the exclusive lock | ||||
* takes priority over acquisition of the shared lock by | * takes priority over acquisition of the shared lock by | ||||
* waiting for any exclusive lock request to complete. | * waiting for any exclusive lock request to complete. | ||||
* This must be done here, before the check of | * This must be done here, before the check of | ||||
* nfsv4root exports by nfsvno_v4rootexport(). | * nfsv4root exports by nfsvno_v4rootexport(). | ||||
*/ | */ | ||||
NFSLOCKV4ROOTMUTEX(); | NFSLOCKV4ROOTMUTEX(); | ||||
nfsv4_lock(&nfsd_suspend_lock, 0, NULL, NFSV4ROOTLOCKMUTEXPTR, | nfsv4_lock(&NFSD_VNET(nfsd_suspend_lock), 0, NULL, | ||||
NULL); | NFSV4ROOTLOCKMUTEXPTR, NULL); | ||||
nfsv4_getref(&nfsd_suspend_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, | nfsv4_getref(&NFSD_VNET(nfsd_suspend_lock), NULL, | ||||
NULL); | NFSV4ROOTLOCKMUTEXPTR, NULL); | ||||
NFSUNLOCKV4ROOTMUTEX(); | NFSUNLOCKV4ROOTMUTEX(); | ||||
if ((nd.nd_flag & ND_NFSV4) != 0) { | if ((nd.nd_flag & ND_NFSV4) != 0) { | ||||
nd.nd_repstat = nfsvno_v4rootexport(&nd); | nd.nd_repstat = nfsvno_v4rootexport(&nd); | ||||
if (nd.nd_repstat != 0) { | if (nd.nd_repstat != 0) { | ||||
NFSLOCKV4ROOTMUTEX(); | NFSLOCKV4ROOTMUTEX(); | ||||
nfsv4_relref(&nfsd_suspend_lock); | nfsv4_relref(&NFSD_VNET(nfsd_suspend_lock)); | ||||
NFSUNLOCKV4ROOTMUTEX(); | NFSUNLOCKV4ROOTMUTEX(); | ||||
svcerr_weakauth(rqst); | svcerr_weakauth(rqst); | ||||
svc_freereq(rqst); | svc_freereq(rqst); | ||||
m_freem(nd.nd_mrep); | m_freem(nd.nd_mrep); | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
#ifdef KERN_TLS | #ifdef KERN_TLS | ||||
if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0 && | if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0 && | ||||
rpctls_getinfo(&maxlen, false, false)) | rpctls_getinfo(&maxlen, false, false)) | ||||
nd.nd_maxextsiz = maxlen; | nd.nd_maxextsiz = maxlen; | ||||
#endif | #endif | ||||
cacherep = nfs_proc(&nd, rqst->rq_xid, xprt, &rp); | cacherep = nfs_proc(&nd, rqst->rq_xid, xprt, &rp); | ||||
NFSLOCKV4ROOTMUTEX(); | NFSLOCKV4ROOTMUTEX(); | ||||
nfsv4_relref(&nfsd_suspend_lock); | nfsv4_relref(&NFSD_VNET(nfsd_suspend_lock)); | ||||
NFSUNLOCKV4ROOTMUTEX(); | NFSUNLOCKV4ROOTMUTEX(); | ||||
} else { | } else { | ||||
NFSMGET(nd.nd_mreq); | NFSMGET(nd.nd_mreq); | ||||
nd.nd_mreq->m_len = 0; | nd.nd_mreq->m_len = 0; | ||||
cacherep = RC_REPLY; | cacherep = RC_REPLY; | ||||
} | } | ||||
if (nd.nd_mrep != NULL) | if (nd.nd_mrep != NULL) | ||||
m_freem(nd.nd_mrep); | m_freem(nd.nd_mrep); | ||||
Show All 23 Lines | #endif | ||||
} | } | ||||
if (rp != NULL) { | if (rp != NULL) { | ||||
nfsrvd_sentcache(rp, (rqst->rq_reply_seq != 0 || | nfsrvd_sentcache(rp, (rqst->rq_reply_seq != 0 || | ||||
SVC_ACK(xprt, NULL)), rqst->rq_reply_seq); | SVC_ACK(xprt, NULL)), rqst->rq_reply_seq); | ||||
} | } | ||||
svc_freereq(rqst); | svc_freereq(rqst); | ||||
out: | out: | ||||
NFSD_CURVNET_RESTORE(); | |||||
ast_kclear(curthread); | ast_kclear(curthread); | ||||
NFSEXITCODE(0); | NFSEXITCODE(0); | ||||
} | } | ||||
/* | /* | ||||
* Check the cache and, optionally, do the RPC. | * Check the cache and, optionally, do the RPC. | ||||
* Return the appropriate cache response. | * Return the appropriate cache response. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
nfssvc_loss(SVCXPRT *xprt) | nfssvc_loss(SVCXPRT *xprt) | ||||
{ | { | ||||
uint32_t ack; | uint32_t ack; | ||||
ack = 0; | ack = 0; | ||||
SVC_ACK(xprt, &ack); | SVC_ACK(xprt, &ack); | ||||
NFSD_CURVNET_SET(NFSD_TD_TO_VNET(curthread)); | |||||
nfsrc_trimcache(xprt->xp_sockref, ack, 1); | nfsrc_trimcache(xprt->xp_sockref, ack, 1); | ||||
NFSD_CURVNET_RESTORE(); | |||||
} | } | ||||
/* | /* | ||||
* Adds a socket to the list for servicing by nfsds. | * Adds a socket to the list for servicing by nfsds. | ||||
*/ | */ | ||||
int | int | ||||
nfsrvd_addsock(struct file *fp) | nfsrvd_addsock(struct file *fp) | ||||
{ | { | ||||
Show All 10 Lines | nfsrvd_addsock(struct file *fp) | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
/* | /* | ||||
* Steal the socket from userland so that it doesn't close | * Steal the socket from userland so that it doesn't close | ||||
* unexpectedly. | * unexpectedly. | ||||
*/ | */ | ||||
if (so->so_type == SOCK_DGRAM) | if (so->so_type == SOCK_DGRAM) | ||||
xprt = svc_dg_create(nfsrvd_pool, so, 0, 0); | xprt = svc_dg_create(NFSD_VNET(nfsrvd_pool), so, 0, 0); | ||||
else | else | ||||
xprt = svc_vc_create(nfsrvd_pool, so, 0, 0); | xprt = svc_vc_create(NFSD_VNET(nfsrvd_pool), so, 0, 0); | ||||
if (xprt) { | if (xprt) { | ||||
fp->f_ops = &badfileops; | fp->f_ops = &badfileops; | ||||
fp->f_data = NULL; | fp->f_data = NULL; | ||||
xprt->xp_sockref = ++sockref; | xprt->xp_sockref = ++sockref; | ||||
if (nfs_minvers == NFS_VER2) | if (NFSD_VNET(nfs_minvers) == NFS_VER2) | ||||
svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, | svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, | ||||
NULL); | NULL); | ||||
if (nfs_minvers <= NFS_VER3 && nfs_maxvers >= NFS_VER3) | if (NFSD_VNET(nfs_minvers) <= NFS_VER3 && | ||||
NFSD_VNET(nfs_maxvers) >= NFS_VER3) | |||||
svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, | svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, | ||||
NULL); | NULL); | ||||
if (nfs_maxvers >= NFS_VER4) | if (NFSD_VNET(nfs_maxvers) >= NFS_VER4) | ||||
svc_reg(xprt, NFS_PROG, NFS_VER4, nfssvc_program, | svc_reg(xprt, NFS_PROG, NFS_VER4, nfssvc_program, | ||||
NULL); | NULL); | ||||
if (so->so_type == SOCK_STREAM) | if (so->so_type == SOCK_STREAM) | ||||
svc_loss_reg(xprt, nfssvc_loss); | svc_loss_reg(xprt, nfssvc_loss); | ||||
SVC_RELEASE(xprt); | SVC_RELEASE(xprt); | ||||
} | } else | ||||
error = EPERM; | |||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Called by nfssvc() for nfsds. Just loops around servicing rpc requests | * Called by nfssvc() for nfsds. Just loops around servicing rpc requests | ||||
Show All 15 Lines | nfsrvd_nfsd(struct thread *td, struct nfsd_nfsd_args *args) | ||||
/* | /* | ||||
* Only the first nfsd actually does any work. The RPC code | * Only the first nfsd actually does any work. The RPC code | ||||
* adds threads to it as needed. Any extra processes offered | * adds threads to it as needed. Any extra processes offered | ||||
* by nfsd just exit. If nfsd is new enough, it will call us | * by nfsd just exit. If nfsd is new enough, it will call us | ||||
* once with a structure that specifies how many threads to | * once with a structure that specifies how many threads to | ||||
* use. | * use. | ||||
*/ | */ | ||||
NFSD_LOCK(); | NFSD_LOCK(); | ||||
if (newnfs_numnfsd == 0) { | if (NFSD_VNET(nfsrv_numnfsd) == 0) { | ||||
nfsrvd_init(0); | |||||
nfsdev_time = time_second; | nfsdev_time = time_second; | ||||
p = td->td_proc; | p = td->td_proc; | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
p->p_flag2 |= P2_AST_SU; | p->p_flag2 |= P2_AST_SU; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
newnfs_numnfsd++; | newnfs_numnfsd++; /* Total num for all vnets. */ | ||||
NFSD_VNET(nfsrv_numnfsd)++; /* Num for this vnet. */ | |||||
NFSD_UNLOCK(); | NFSD_UNLOCK(); | ||||
error = nfsrv_createdevids(args, td); | error = nfsrv_createdevids(args, td); | ||||
if (error == 0) { | if (error == 0) { | ||||
/* An empty string implies AUTH_SYS only. */ | /* An empty string implies AUTH_SYS only. */ | ||||
if (principal[0] != '\0') { | if (principal[0] != '\0') { | ||||
ret2 = rpc_gss_set_svc_name_call(principal, | ret2 = rpc_gss_set_svc_name_call(principal, | ||||
"kerberosv5", GSS_C_INDEFINITE, NFS_PROG, | "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, | ||||
NFS_VER2); | NFS_VER2); | ||||
ret3 = rpc_gss_set_svc_name_call(principal, | ret3 = rpc_gss_set_svc_name_call(principal, | ||||
"kerberosv5", GSS_C_INDEFINITE, NFS_PROG, | "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, | ||||
NFS_VER3); | NFS_VER3); | ||||
ret4 = rpc_gss_set_svc_name_call(principal, | ret4 = rpc_gss_set_svc_name_call(principal, | ||||
"kerberosv5", GSS_C_INDEFINITE, NFS_PROG, | "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, | ||||
NFS_VER4); | NFS_VER4); | ||||
if (!ret2 || !ret3 || !ret4) | if (!ret2 || !ret3 || !ret4) | ||||
printf( | printf("nfsd: can't register svc " | ||||
"nfsd: can't register svc name\n"); | "name %s jid:%d\n", principal, | ||||
td->td_ucred->cr_prison->pr_id); | |||||
} | } | ||||
nfsrvd_pool->sp_minthreads = args->minthreads; | NFSD_VNET(nfsrvd_pool)->sp_minthreads = | ||||
nfsrvd_pool->sp_maxthreads = args->maxthreads; | args->minthreads; | ||||
NFSD_VNET(nfsrvd_pool)->sp_maxthreads = | |||||
args->maxthreads; | |||||
/* | /* | ||||
* If this is a pNFS service, make Getattr do a | * If this is a pNFS service, make Getattr do a | ||||
* vn_start_write(), so it can do a vn_set_extattr(). | * vn_start_write(), so it can do a vn_set_extattr(). | ||||
*/ | */ | ||||
if (nfsrv_devidcnt > 0) { | if (nfsrv_devidcnt > 0) { | ||||
nfsrv_writerpc[NFSPROC_GETATTR] = 1; | nfsrv_writerpc[NFSPROC_GETATTR] = 1; | ||||
nfsv4_opflag[NFSV4OP_GETATTR].modifyfs = 1; | nfsv4_opflag[NFSV4OP_GETATTR].modifyfs = 1; | ||||
} | } | ||||
svc_run(nfsrvd_pool); | svc_run(NFSD_VNET(nfsrvd_pool)); | ||||
/* Reset Getattr to not do a vn_start_write(). */ | /* Reset Getattr to not do a vn_start_write(). */ | ||||
nfsrv_writerpc[NFSPROC_GETATTR] = 0; | nfsrv_writerpc[NFSPROC_GETATTR] = 0; | ||||
nfsv4_opflag[NFSV4OP_GETATTR].modifyfs = 0; | nfsv4_opflag[NFSV4OP_GETATTR].modifyfs = 0; | ||||
if (principal[0] != '\0') { | if (principal[0] != '\0') { | ||||
rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER2); | rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER2); | ||||
rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER3); | rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER3); | ||||
rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER4); | rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER4); | ||||
} | } | ||||
} | } | ||||
NFSD_LOCK(); | NFSD_LOCK(); | ||||
newnfs_numnfsd--; | newnfs_numnfsd--; | ||||
NFSD_VNET(nfsrv_numnfsd)--; | |||||
nfsrvd_init(1); | nfsrvd_init(1); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
p->p_flag2 &= ~P2_AST_SU; | p->p_flag2 &= ~P2_AST_SU; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
NFSD_UNLOCK(); | NFSD_UNLOCK(); | ||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Initialize the data structures for the server. | * Initialize the data structures for the server. | ||||
* Handshake with any new nfsds starting up to avoid any chance of | * Handshake with any new nfsds starting up to avoid any chance of | ||||
* corruption. | * corruption. | ||||
*/ | */ | ||||
void | void | ||||
nfsrvd_init(int terminating) | nfsrvd_init(int terminating) | ||||
{ | { | ||||
NFSD_LOCK_ASSERT(); | NFSD_LOCK_ASSERT(); | ||||
if (terminating) { | if (terminating) { | ||||
nfsd_master_proc = NULL; | NFSD_VNET(nfsd_master_proc) = NULL; | ||||
NFSD_UNLOCK(); | NFSD_UNLOCK(); | ||||
nfsrv_freealllayoutsanddevids(); | nfsrv_freealllayoutsanddevids(); | ||||
nfsrv_freeallbackchannel_xprts(); | nfsrv_freeallbackchannel_xprts(); | ||||
svcpool_close(nfsrvd_pool); | svcpool_close(NFSD_VNET(nfsrvd_pool)); | ||||
free(nfsrv_zeropnfsdat, M_TEMP); | free(nfsrv_zeropnfsdat, M_TEMP); | ||||
nfsrv_zeropnfsdat = NULL; | nfsrv_zeropnfsdat = NULL; | ||||
NFSD_LOCK(); | NFSD_LOCK(); | ||||
} else { | } else { | ||||
/* Initialize per-vnet globals once per vnet. */ | |||||
if (NFSD_VNET(nfsrvd_inited)) | |||||
return; | |||||
NFSD_VNET(nfsrvd_inited) = true; | |||||
NFSD_UNLOCK(); | NFSD_UNLOCK(); | ||||
nfsrvd_pool = svcpool_create("nfsd", | NFSD_VNET(nfsrvd_pool) = svcpool_create("nfsd", | ||||
SYSCTL_STATIC_CHILDREN(_vfs_nfsd)); | SYSCTL_STATIC_CHILDREN(_vfs_nfsd)); | ||||
nfsrvd_pool->sp_rcache = NULL; | NFSD_VNET(nfsrvd_pool)->sp_rcache = NULL; | ||||
nfsrvd_pool->sp_assign = fhanew_assign; | NFSD_VNET(nfsrvd_pool)->sp_assign = fhanew_assign; | ||||
nfsrvd_pool->sp_done = fhanew_nd_complete; | NFSD_VNET(nfsrvd_pool)->sp_done = fhanew_nd_complete; | ||||
NFSD_LOCK(); | NFSD_LOCK(); | ||||
} | } | ||||
} | } |