Changeset View
Standalone View
sys/fs/nfsserver/nfs_nfsdport.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
* portable. | * portable. | ||||
*/ | */ | ||||
#include <fs/nfs/nfsport.h> | #include <fs/nfs/nfsport.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#include <sys/callout.h> | #include <sys/callout.h> | ||||
#include <sys/filio.h> | #include <sys/filio.h> | ||||
#include <sys/hash.h> | #include <sys/hash.h> | ||||
#include <sys/osd.h> | |||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <nlm/nlm_prot.h> | #include <nlm/nlm_prot.h> | ||||
#include <nlm/nlm.h> | #include <nlm/nlm.h> | ||||
FEATURE(nfsd, "NFSv4 server"); | FEATURE(nfsd, "NFSv4 server"); | ||||
extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; | extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; | ||||
extern int nfsrv_useacl; | extern int nfsrv_useacl; | ||||
extern int newnfs_numnfsd; | extern int newnfs_numnfsd; | ||||
extern struct mount nfsv4root_mnt; | |||||
extern struct nfsrv_stablefirst nfsrv_stablefirst; | |||||
extern SVCPOOL *nfsrvd_pool; | |||||
extern struct nfsv4lock nfsd_suspend_lock; | |||||
extern struct nfsclienthashhead *nfsclienthash; | |||||
extern struct nfslockhashhead *nfslockhash; | |||||
extern struct nfssessionhash *nfssessionhash; | |||||
extern int nfsrv_sessionhashsize; | extern int nfsrv_sessionhashsize; | ||||
extern struct nfsstatsv1 nfsstatsv1; | |||||
extern struct nfslayouthash *nfslayouthash; | extern struct nfslayouthash *nfslayouthash; | ||||
extern int nfsrv_layouthashsize; | extern int nfsrv_layouthashsize; | ||||
extern struct mtx nfsrv_dslock_mtx; | extern struct mtx nfsrv_dslock_mtx; | ||||
extern int nfs_pnfsiothreads; | extern int nfs_pnfsiothreads; | ||||
extern struct nfsdontlisthead nfsrv_dontlisthead; | |||||
extern volatile int nfsrv_dontlistlen; | |||||
extern volatile int nfsrv_devidcnt; | extern volatile int nfsrv_devidcnt; | ||||
extern int nfsrv_maxpnfsmirror; | extern int nfsrv_maxpnfsmirror; | ||||
extern uint32_t nfs_srvmaxio; | extern uint32_t nfs_srvmaxio; | ||||
extern int nfs_bufpackets; | extern int nfs_bufpackets; | ||||
extern u_long sb_max_adj; | extern u_long sb_max_adj; | ||||
struct vfsoptlist nfsv4root_opt, nfsv4root_newopt; | |||||
NFSDSTATSDECLARE(nfsstatsv1); | |||||
NFSD_VNET_DECLARE(int, nfsrv_numnfsd); | |||||
NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst); | |||||
NFSD_VNET_DECLARE(SVCPOOL *, nfsrvd_pool); | |||||
NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash); | |||||
NFSD_VNET_DECLARE(struct nfslockhashhead *, nfslockhash); | |||||
NFSD_VNET_DECLARE(struct nfssessionhash *, nfssessionhash); | |||||
NFSD_VNET_DECLARE(struct nfsv4lock, nfsd_suspend_lock); | |||||
NFSDLOCKMUTEX; | NFSDLOCKMUTEX; | ||||
NFSSTATESPINLOCK; | NFSSTATESPINLOCK; | ||||
struct nfsrchash_bucket nfsrchash_table[NFSRVCACHE_HASHSIZE]; | |||||
struct nfsrchash_bucket nfsrcahash_table[NFSRVCACHE_HASHSIZE]; | |||||
struct mtx nfsrc_udpmtx; | struct mtx nfsrc_udpmtx; | ||||
struct mtx nfs_v4root_mutex; | struct mtx nfs_v4root_mutex; | ||||
struct mtx nfsrv_dontlistlock_mtx; | struct mtx nfsrv_dontlistlock_mtx; | ||||
struct mtx nfsrv_recalllock_mtx; | struct mtx nfsrv_recalllock_mtx; | ||||
struct nfsrvfh nfs_rootfh, nfs_pubfh; | struct nfsrvfh nfs_pubfh; | ||||
int nfs_pubfhset = 0, nfs_rootfhset = 0; | int nfs_pubfhset = 0; | ||||
struct proc *nfsd_master_proc = NULL; | |||||
int nfsd_debuglevel = 0; | int nfsd_debuglevel = 0; | ||||
static pid_t nfsd_master_pid = (pid_t)-1; | static pid_t nfsd_master_pid = (pid_t)-1; | ||||
static char nfsd_master_comm[MAXCOMLEN + 1]; | static char nfsd_master_comm[MAXCOMLEN + 1]; | ||||
static struct timeval nfsd_master_start; | static struct timeval nfsd_master_start; | ||||
static uint32_t nfsv4_sysid = 0; | static uint32_t nfsv4_sysid = 0; | ||||
static fhandle_t zerofh; | static fhandle_t zerofh; | ||||
struct callout nfsd_callout; | static int nfsrv_osd_jail_slot; | ||||
NFSD_VNET_DEFINE(struct proc *, nfsd_master_proc) = NULL; | |||||
NFSD_VNET_DEFINE(struct nfsrvhashhead *, nfsrvudphashtbl); | |||||
NFSD_VNET_DEFINE(struct nfsrchash_bucket *, nfsrchash_table); | |||||
NFSD_VNET_DEFINE(struct nfsrchash_bucket *, nfsrcahash_table); | |||||
NFSD_VNET_DEFINE(struct nfsrvfh, nfs_rootfh); | |||||
NFSD_VNET_DEFINE(int, nfs_rootfhset) = 0; | |||||
NFSD_VNET_DEFINE(struct callout, nfsd_callout); | |||||
NFSD_VNET_DEFINE_STATIC(struct mount *, nfsv4root_mnt); | |||||
NFSD_VNET_DEFINE_STATIC(struct vfsoptlist, nfsv4root_opt); | |||||
NFSD_VNET_DEFINE_STATIC(struct vfsoptlist, nfsv4root_newopt); | |||||
NFSD_VNET_DEFINE_STATIC(bool, nfsrv_suspend_nfsd) = false; | |||||
NFSD_VNET_DEFINE_STATIC(bool, nfsrv_mntinited) = false; | |||||
static void nfsrv_cleanup(struct prison *); | |||||
static int nfssvc_srvcall(struct thread *, struct nfssvc_args *, | static int nfssvc_srvcall(struct thread *, struct nfssvc_args *, | ||||
struct ucred *); | struct ucred *); | ||||
static void nfsvno_updateds(struct vnode *, struct ucred *, struct thread *); | static void nfsvno_updateds(struct vnode *, struct ucred *, struct thread *); | ||||
int nfsrv_enable_crossmntpt = 1; | int nfsrv_enable_crossmntpt = 1; | ||||
static int nfs_commit_blks; | static int nfs_commit_blks; | ||||
static int nfs_commit_miss; | static int nfs_commit_miss; | ||||
extern int nfsrv_issuedelegs; | extern int nfsrv_issuedelegs; | ||||
extern int nfsrv_dolocallocks; | extern int nfsrv_dolocallocks; | ||||
extern int nfsd_enable_stringtouid; | |||||
extern struct nfsdevicehead nfsrv_devidhead; | extern struct nfsdevicehead nfsrv_devidhead; | ||||
static int nfsrv_createiovec(int, struct mbuf **, struct mbuf **, | static int nfsrv_createiovec(int, struct mbuf **, struct mbuf **, | ||||
struct iovec **); | struct iovec **); | ||||
static int nfsrv_createiovec_extpgs(int, int, struct mbuf **, | static int nfsrv_createiovec_extpgs(int, int, struct mbuf **, | ||||
struct mbuf **, struct iovec **); | struct mbuf **, struct iovec **); | ||||
static int nfsrv_createiovecw(int, struct mbuf *, char *, struct iovec **, | static int nfsrv_createiovecw(int, struct mbuf *, char *, struct iovec **, | ||||
int *); | int *); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, | SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, | ||||
0, ""); | 0, ""); | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW, | SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW, | ||||
&nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations"); | &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations"); | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW, | SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW, | ||||
&nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files"); | &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files"); | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel, | SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel, | ||||
0, "Debug level for NFS server"); | 0, "Debug level for NFS server"); | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW, | NFSD_VNET_DECLARE(int, nfsd_enable_stringtouid); | ||||
&nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names"); | SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, | ||||
CTLFLAG_NFSD_VNET | CTLFLAG_RW, &NFSD_VNET_NAME(nfsd_enable_stringtouid), | |||||
0, "Enable nfsd to accept numeric owner_names"); | |||||
static int nfsrv_pnfsgetdsattr = 1; | static int nfsrv_pnfsgetdsattr = 1; | ||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, pnfsgetdsattr, CTLFLAG_RW, | SYSCTL_INT(_vfs_nfsd, OID_AUTO, pnfsgetdsattr, CTLFLAG_RW, | ||||
&nfsrv_pnfsgetdsattr, 0, "When set getattr gets DS attributes via RPC"); | &nfsrv_pnfsgetdsattr, 0, "When set getattr gets DS attributes via RPC"); | ||||
/* | /* | ||||
* nfsrv_dsdirsize can only be increased and only when the nfsd threads are | * nfsrv_dsdirsize can only be increased and only when the nfsd threads are | ||||
* not running. | * not running. | ||||
* The dsN subdirectories for the increased values must have been created | * The dsN subdirectories for the increased values must have been created | ||||
▲ Show 20 Lines • Show All 834 Lines • ▼ Show 20 Lines | nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred, | ||||
uiop->uio_offset = off; | uiop->uio_offset = off; | ||||
uiop->uio_resid = len; | uiop->uio_resid = len; | ||||
uiop->uio_rw = UIO_READ; | uiop->uio_rw = UIO_READ; | ||||
uiop->uio_segflg = UIO_SYSSPACE; | uiop->uio_segflg = UIO_SYSSPACE; | ||||
uiop->uio_td = NULL; | uiop->uio_td = NULL; | ||||
nh = nfsrv_sequential_heuristic(uiop, vp); | nh = nfsrv_sequential_heuristic(uiop, vp); | ||||
ioflag |= nh->nh_seqcount << IO_SEQSHIFT; | ioflag |= nh->nh_seqcount << IO_SEQSHIFT; | ||||
/* XXX KDM make this more systematic? */ | /* XXX KDM make this more systematic? */ | ||||
nfsstatsv1.srvbytes[NFSV4OP_READ] += uiop->uio_resid; | NFSDSTATS()->srvbytes[NFSV4OP_READ] += uiop->uio_resid; | ||||
error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); | error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); | ||||
free(iv, M_TEMP); | free(iv, M_TEMP); | ||||
if (error) { | if (error) { | ||||
m_freem(m3); | m_freem(m3); | ||||
*mpp = NULL; | *mpp = NULL; | ||||
goto out; | goto out; | ||||
} | } | ||||
nh->nh_nextoff = uiop->uio_offset; | nh->nh_nextoff = uiop->uio_offset; | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | nfsvno_write(struct vnode *vp, off_t off, int retlen, int *stable, | ||||
uiop->uio_resid = retlen; | uiop->uio_resid = retlen; | ||||
uiop->uio_rw = UIO_WRITE; | uiop->uio_rw = UIO_WRITE; | ||||
uiop->uio_segflg = UIO_SYSSPACE; | uiop->uio_segflg = UIO_SYSSPACE; | ||||
NFSUIOPROC(uiop, p); | NFSUIOPROC(uiop, p); | ||||
uiop->uio_offset = off; | uiop->uio_offset = off; | ||||
nh = nfsrv_sequential_heuristic(uiop, vp); | nh = nfsrv_sequential_heuristic(uiop, vp); | ||||
ioflags |= nh->nh_seqcount << IO_SEQSHIFT; | ioflags |= nh->nh_seqcount << IO_SEQSHIFT; | ||||
/* XXX KDM make this more systematic? */ | /* XXX KDM make this more systematic? */ | ||||
nfsstatsv1.srvbytes[NFSV4OP_WRITE] += uiop->uio_resid; | NFSDSTATS()->srvbytes[NFSV4OP_WRITE] += uiop->uio_resid; | ||||
error = VOP_WRITE(vp, uiop, ioflags, cred); | error = VOP_WRITE(vp, uiop, ioflags, cred); | ||||
if (error == 0) | if (error == 0) | ||||
nh->nh_nextoff = uiop->uio_offset; | nh->nh_nextoff = uiop->uio_offset; | ||||
free(iv, M_TEMP); | free(iv, M_TEMP); | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,073 Lines • ▼ Show 20 Lines | |||||
nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp, | nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp, | ||||
struct ucred **credp) | struct ucred **credp) | ||||
{ | { | ||||
int error; | int error; | ||||
error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, | error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, | ||||
&exp->nes_numsecflavor, exp->nes_secflavors); | &exp->nes_numsecflavor, exp->nes_secflavors); | ||||
if (error) { | if (error) { | ||||
if (nfs_rootfhset) { | if (NFSD_VNET(nfs_rootfhset)) { | ||||
exp->nes_exflag = 0; | exp->nes_exflag = 0; | ||||
exp->nes_numsecflavor = 0; | exp->nes_numsecflavor = 0; | ||||
error = 0; | error = 0; | ||||
} | } | ||||
} else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor > | } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor > | ||||
MAXSECFLAVORS) { | MAXSECFLAVORS) { | ||||
printf("nfsvno_checkexp: numsecflavors out of range\n"); | printf("nfsvno_checkexp: numsecflavors out of range\n"); | ||||
exp->nes_numsecflavor = 0; | exp->nes_numsecflavor = 0; | ||||
Show All 18 Lines | nfsvno_fhtovp(struct mount *mp, fhandle_t *fhp, struct sockaddr *nam, | ||||
error = VFS_FHTOVP(mp, &fhp->fh_fid, lktype, vpp); | error = VFS_FHTOVP(mp, &fhp->fh_fid, lktype, vpp); | ||||
if (error != 0) | if (error != 0) | ||||
/* Make sure the server replies ESTALE to the client. */ | /* Make sure the server replies ESTALE to the client. */ | ||||
error = ESTALE; | error = ESTALE; | ||||
if (nam && !error) { | if (nam && !error) { | ||||
error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, | error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, | ||||
&exp->nes_numsecflavor, exp->nes_secflavors); | &exp->nes_numsecflavor, exp->nes_secflavors); | ||||
if (error) { | if (error) { | ||||
if (nfs_rootfhset) { | if (NFSD_VNET(nfs_rootfhset)) { | ||||
exp->nes_exflag = 0; | exp->nes_exflag = 0; | ||||
exp->nes_numsecflavor = 0; | exp->nes_numsecflavor = 0; | ||||
error = 0; | error = 0; | ||||
} else { | } else { | ||||
vput(*vpp); | vput(*vpp); | ||||
} | } | ||||
} else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor > | } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor > | ||||
MAXSECFLAVORS) { | MAXSECFLAVORS) { | ||||
▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p) | nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p) | ||||
{ | { | ||||
struct nfsex_args *nfsexargp = (struct nfsex_args *)argp; | struct nfsex_args *nfsexargp = (struct nfsex_args *)argp; | ||||
int error = 0; | int error = 0; | ||||
struct nameidata nd; | struct nameidata nd; | ||||
fhandle_t fh; | fhandle_t fh; | ||||
error = vfs_export(&nfsv4root_mnt, &nfsexargp->export); | error = vfs_export(NFSD_VNET(nfsv4root_mnt), &nfsexargp->export); | ||||
if ((nfsexargp->export.ex_flags & MNT_DELEXPORT) != 0) | if ((nfsexargp->export.ex_flags & MNT_DELEXPORT) != 0) | ||||
nfs_rootfhset = 0; | NFSD_VNET(nfs_rootfhset) = 0; | ||||
else if (error == 0) { | else if (error == 0) { | ||||
if (nfsexargp->fspec == NULL) { | if (nfsexargp->fspec == NULL) { | ||||
error = EPERM; | error = EPERM; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* If fspec != NULL, this is the v4root path. | * If fspec != NULL, this is the v4root path. | ||||
*/ | */ | ||||
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, nfsexargp->fspec); | NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, nfsexargp->fspec); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
goto out; | goto out; | ||||
error = nfsvno_getfh(nd.ni_vp, &fh, p); | error = nfsvno_getfh(nd.ni_vp, &fh, p); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
if (!error) { | if (!error) { | ||||
nfs_rootfh.nfsrvfh_len = NFSX_MYFH; | NFSD_VNET(nfs_rootfh).nfsrvfh_len = NFSX_MYFH; | ||||
NFSBCOPY((caddr_t)&fh, | NFSBCOPY((caddr_t)&fh, | ||||
nfs_rootfh.nfsrvfh_data, | NFSD_VNET(nfs_rootfh).nfsrvfh_data, | ||||
sizeof (fhandle_t)); | sizeof (fhandle_t)); | ||||
nfs_rootfhset = 1; | NFSD_VNET(nfs_rootfhset) = 1; | ||||
} | } | ||||
} | } | ||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
Show All 19 Lines | |||||
} | } | ||||
/* | /* | ||||
* BSD specific initialization of a mount point. | * BSD specific initialization of a mount point. | ||||
*/ | */ | ||||
void | void | ||||
nfsd_mntinit(void) | nfsd_mntinit(void) | ||||
{ | { | ||||
static int inited = 0; | |||||
if (inited) | NFSD_LOCK(); | ||||
if (NFSD_VNET(nfsrv_mntinited)) { | |||||
NFSD_UNLOCK(); | |||||
return; | return; | ||||
inited = 1; | |||||
nfsv4root_mnt.mnt_flag = (MNT_RDONLY | MNT_EXPORTED); | |||||
TAILQ_INIT(&nfsv4root_mnt.mnt_nvnodelist); | |||||
TAILQ_INIT(&nfsv4root_mnt.mnt_lazyvnodelist); | |||||
nfsv4root_mnt.mnt_export = NULL; | |||||
TAILQ_INIT(&nfsv4root_opt); | |||||
TAILQ_INIT(&nfsv4root_newopt); | |||||
nfsv4root_mnt.mnt_opt = &nfsv4root_opt; | |||||
nfsv4root_mnt.mnt_optnew = &nfsv4root_newopt; | |||||
nfsv4root_mnt.mnt_nvnodelistsize = 0; | |||||
nfsv4root_mnt.mnt_lazyvnodelistsize = 0; | |||||
} | } | ||||
NFSD_VNET(nfsrv_mntinited) = true; | |||||
NFSD_UNLOCK(); | |||||
#ifdef VIMAGE | |||||
NFSD_VNET(nfsstatsv1_vnet) = malloc(sizeof(struct nfsstatsv1_vnet), | |||||
M_TEMP, M_WAITOK | M_ZERO); | |||||
#endif | |||||
NFSDSTATS()->srvcache_tcppeak = 0; | |||||
NFSDSTATS()->srvcache_size = 0; | |||||
NFSD_VNET(nfsv4root_mnt) = malloc(sizeof(struct mount), M_TEMP, | |||||
M_WAITOK | M_ZERO); | |||||
NFSD_VNET(nfsv4root_mnt)->mnt_flag = (MNT_RDONLY | MNT_EXPORTED); | |||||
mtx_init(&NFSD_VNET(nfsv4root_mnt)->mnt_mtx, "nfs4mnt", NULL, MTX_DEF); | |||||
lockinit(&NFSD_VNET(nfsv4root_mnt)->mnt_explock, PVFS, "explock", 0, 0); | |||||
TAILQ_INIT(&NFSD_VNET(nfsv4root_mnt)->mnt_nvnodelist); | |||||
TAILQ_INIT(&NFSD_VNET(nfsv4root_mnt)->mnt_lazyvnodelist); | |||||
NFSD_VNET(nfsv4root_mnt)->mnt_export = NULL; | |||||
TAILQ_INIT(&NFSD_VNET(nfsv4root_opt)); | |||||
TAILQ_INIT(&NFSD_VNET(nfsv4root_newopt)); | |||||
NFSD_VNET(nfsv4root_mnt)->mnt_opt = &NFSD_VNET(nfsv4root_opt); | |||||
NFSD_VNET(nfsv4root_mnt)->mnt_optnew = &NFSD_VNET(nfsv4root_newopt); | |||||
NFSD_VNET(nfsv4root_mnt)->mnt_nvnodelistsize = 0; | |||||
NFSD_VNET(nfsv4root_mnt)->mnt_lazyvnodelistsize = 0; | |||||
callout_init(&NFSD_VNET(nfsd_callout), 1); | |||||
nfsrvd_initcache(); | |||||
nfsd_init(); | |||||
} | |||||
static void | static void | ||||
nfsd_timer(void *arg) | nfsd_timer(void *arg) | ||||
{ | { | ||||
struct vnet *vnetp; | |||||
nfsrv_servertimer(); | vnetp = (struct vnet *)arg; | ||||
callout_reset_sbt(&nfsd_callout, SBT_1S, SBT_1S, nfsd_timer, NULL, 0); | NFSD_CURVNET_SET_QUIET(vnetp); | ||||
nfsrv_servertimer(vnetp); | |||||
callout_reset_sbt(&NFSD_VNET(nfsd_callout), SBT_1S, SBT_1S, nfsd_timer, | |||||
arg, 0); | |||||
NFSD_CURVNET_RESTORE(); | |||||
} | } | ||||
/* | /* | ||||
* Get a vnode for a file handle, without checking exports, etc. | * Get a vnode for a file handle, without checking exports, etc. | ||||
*/ | */ | ||||
struct vnode * | struct vnode * | ||||
nfsvno_getvp(fhandle_t *fhp) | nfsvno_getvp(fhandle_t *fhp) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
int | int | ||||
nfsvno_v4rootexport(struct nfsrv_descript *nd) | nfsvno_v4rootexport(struct nfsrv_descript *nd) | ||||
{ | { | ||||
struct ucred *credanon; | struct ucred *credanon; | ||||
int error = 0, numsecflavor, secflavors[MAXSECFLAVORS], i; | int error = 0, numsecflavor, secflavors[MAXSECFLAVORS], i; | ||||
uint64_t exflags; | uint64_t exflags; | ||||
error = vfs_stdcheckexp(&nfsv4root_mnt, nd->nd_nam, &exflags, | error = vfs_stdcheckexp(NFSD_VNET(nfsv4root_mnt), nd->nd_nam, &exflags, | ||||
&credanon, &numsecflavor, secflavors); | &credanon, &numsecflavor, secflavors); | ||||
if (error) { | if (error) { | ||||
error = NFSERR_PROGUNAVAIL; | error = NFSERR_PROGUNAVAIL; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (credanon != NULL) | if (credanon != NULL) | ||||
crfree(credanon); | crfree(credanon); | ||||
for (i = 0; i < numsecflavor; i++) { | for (i = 0; i < numsecflavor; i++) { | ||||
Show All 16 Lines | if ((exflags & MNT_EXTLSCERTUSER) != 0) | ||||
nd->nd_flag |= ND_EXTLSCERTUSER; | nd->nd_flag |= ND_EXTLSCERTUSER; | ||||
} | } | ||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* Osd entry for nfsrv_cleanup. */ | |||||
static int | |||||
nfsrv_prison_cleanup(void *obj, void *data __unused) | |||||
{ | |||||
struct prison *pr = obj; | |||||
if ((pr->pr_flags & PR_VNET) == 0) | |||||
return (0); | |||||
nfsrv_cleanup(pr); | |||||
return (0); | |||||
} | |||||
/* | /* | ||||
* Nfs server pseudo system call for the nfsd's | * Nfs server pseudo system call for the nfsd's | ||||
*/ | */ | ||||
/* | /* | ||||
* MPSAFE | * MPSAFE | ||||
*/ | */ | ||||
static int | static int | ||||
nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) | nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap) | ||||
{ | { | ||||
struct file *fp; | struct file *fp; | ||||
struct nfsd_addsock_args sockarg; | struct nfsd_addsock_args sockarg; | ||||
struct nfsd_nfsd_args nfsdarg; | struct nfsd_nfsd_args nfsdarg; | ||||
struct nfsd_nfsd_oargs onfsdarg; | struct nfsd_nfsd_oargs onfsdarg; | ||||
struct nfsd_pnfsd_args pnfsdarg; | struct nfsd_pnfsd_args pnfsdarg; | ||||
struct vnode *vp, *nvp, *curdvp; | struct vnode *vp, *nvp, *curdvp; | ||||
struct pnfsdsfile *pf; | struct pnfsdsfile *pf; | ||||
struct nfsdevice *ds, *fds; | struct nfsdevice *ds, *fds; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
int buflen, error, ret; | int buflen, error, ret; | ||||
char *buf, *cp, *cp2, *cp3; | char *buf, *cp, *cp2, *cp3; | ||||
char fname[PNFS_FILENAME_LEN + 1]; | char fname[PNFS_FILENAME_LEN + 1]; | ||||
NFSD_CURVNET_SET(NFSD_TD_TO_VNET(td)); | |||||
if (uap->flag & NFSSVC_NFSDADDSOCK) { | if (uap->flag & NFSSVC_NFSDADDSOCK) { | ||||
error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg)); | error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg)); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
/* | /* | ||||
* Since we don't know what rights might be required, | * Since we don't know what rights might be required, | ||||
* pretend that we need them all. It is better to be too | * pretend that we need them all. It is better to be too | ||||
* careful than too reckless. | * careful than too reckless. | ||||
*/ | */ | ||||
error = fget(td, sockarg.sock, | error = fget(td, sockarg.sock, | ||||
bz: Why would we need this @jamie if we ever only run with or w/o vnet but never allow this in a… | |||||
Not Done Inline Actions
That's exactly what we're testing for here, no? I'll admit I don't see the logic in prison_check_nfsd() disallowing non-jailed callers (this requiring the explicit jailed() check here). But then I don't know just how separated the vnet-nfsd and regular-nfsd code paths are. jamie: > Why would we need this @jamie if we ever only run with or w/o vnet but never allow this in a… | |||||
Done Inline ActionsYea, when I first did prison_jail_nfsd() it allowed the I really don't care what the semantics is for the If you want me to change it, I can. rmacklem: Yea, when I first did prison_jail_nfsd() it allowed the
non-jailed case, but that seemed… | |||||
Not Done Inline Actions
I think for consistency it should change then. prison_xxx() checks are typically "return true if the prison/cred is allowed to do the thing." Granted, that's not always what you want to know, but this seems like a case where it is. jamie: > If you want me to change it, I can.
I think for consistency it should change then. | |||||
Not Done Inline Actions@jamie I never envisioned this to possibly work without vnets. And if that is what we want, plain-old-jail support as well, then some if these VNET changes highly likely need to be handled differently as well. I just think we need to be very clear about this very quickly as a lot of abstractions and security checks will highly depend on one or the other. bz: @jamie I never envisioned this to possibly work without vnets.
And if that is what we want… | |||||
Done Inline ActionsNo, it will never work in a non-vnet jail. The first test: if (!jailed(cred)) return (false); was only there to simplify the code that calls it: if (...!prison_check_nfsd()) to if (... jailed() && !prison_check_nfs()) but I have no problem with making the change. if (!jailed()) return (true); OR
rmacklem: No, it will never work in a non-vnet jail.
The first test:
if (!jailed(cred))… | |||||
Not Done Inline Actions
I'm all for simplifying the code in multiple locations, so I'll just let this rest. It was only ever a minor nit at most. jamie: > The first test:
> if (!jailed(cred))
> return (false);
>
> was only there to… | |||||
Not Done Inline Actions
No, I don't want it to work without vnets - that part of prison_check_nfsd() would remain as it. The only thing I was considering was if it allows prison0. jamie: > @jamie I never envisioned this to possibly work without vnets.
>
> And if that is what we… | |||||
Not Done Inline ActionsOkay, the comment has long been moved with updates; if we only do vnet can someone explain to me why we need OSD? Why are vnet abstractions not good enough? bz: Okay, the comment has long been moved with updates; if we only do vnet can someone explain to… | |||||
Done Inline ActionsOk, I am assuming you are referring to the use The reason is that VNET_SYSUNINT() did not work. When I use osd_jail_register(), the function does get called Is VNET_SYSUNINT() broken? Maybe, but I'm not the guy to rmacklem: Ok, I am assuming you are referring to the use
of osd_jail_register() down at line#7195.
The… | |||||
Not Done Inline ActionsIf the jail went away entirely (and wasn't stuck dying on other things which makes jls by default no longer to show it but it can with an option) the VNET_SYSUNINT function should have been called. If it wasn't there is a problem somewhere which must be solved. @jamie forgive me for asking as all of the #ifdef options and loadable of the module shouldn't make a difference, was the real problem that the NFS code would hold references somewhere which prevented the jail from actually dying? You two seem to have an implicit understanding of something I missed (never learnt) in the original patch and I am trying to understand that. bz: If the jail went away entirely (and wasn't stuck dying on other things which makes jls by… | |||||
Not Done Inline Actions
Yes, it all comes to holding references somewhere, and I don't think there's anything you're not getting - I don't know what reference this might be or anything like that. So part of why I suggested an earlier cleanup was partly practical: it seems to solve the issue. It could be that whatever reference is held open shouldn't be at that point, or it could be that there's something working completely as it should, which includes that reference not going away until the NFS stuff is shut down. Either way, moving the NFS shutdown earlier avoids the problem, even if it doesn't really identify it. The other half of my reasoning is jail philosophy: I'd like to get rid of this idea of a dying jail being anything other than the last blip while it finishes disposing of itself, and as long as something isn't needed to exist during the orderly shutdown, I'd like it to go away as soon as possible (when it enters dying state). That's what prison_cleanup() is about. jamie: > @jamie forgive me for asking as all of the #ifdef options and loadable of the module… | |||||
Not Done Inline ActionsThe solution to the jail sticking around was to move the nfsd cleanup from the end of prison_deref() to prison_cleanup(), which happens when the jail starts dying instead of when it finishes. It would have sufficed to just add ifdef'd code to prison_cleanup itself, but since nfsd is dynamically loadable, OSD was the canonical way to go. It's not necessary to do it that way, given that VNET_NFSD already has its fingers all over the place; and since the dynamically loading part seems not to work, it may no longer be the right paradigm. But it still works. jamie: The solution to the jail sticking around was to move the nfsd cleanup from the end of… | |||||
Not Done Inline ActionsOkay, then my main concern probably is (was) mixing the two techniques to abstract things (I would still hope the vnet bits were enough but that's investigate this once we are done here). bz: Okay, then my main concern probably is (was) mixing the two techniques to abstract things (I… | |||||
Done Inline ActionsI have added the comment, as requested. Here's a script of killing the vnet jails with JID IP Address Hostname Path 1 foo /foo 2 foo2 /foo2 root@freebsd-mds:~ # jail -r 1 JID IP Address Hostname Path 1 foo /foo root@freebsd-mds:~ # jail -r 1 JID IP Address Hostname Path root@freebsd-mds:~ # ^D Script done on Fri Dec 16 17:38:39 2022 After this, a "ps ax" does not show any processes rmacklem: I have added the comment, as requested.
Here's a script of killing the vnet jails with… | |||||
Not Done Inline Actions
jls -d That will list "dying" jails in addition to others. The definition of a dying jail is one that's not yet gone only because there are still references held to it somewhere. The "somewhere" is almost always a cred, but the list of creds that may be sitting around on a system is huge. When there are no processes left (or child jails, or "persist"), i.e. when there are no user references (pr_uref), that's when the jail starts to die. Or you can force that with jail_remove(2). Then when there are no references at all (pr_ref), it is finished dying. jamie: > After this, a "ps ax" does not show any processes
> marked with "J", so how do I see what is… | |||||
cap_rights_init_one(&rights, CAP_SOCK_SERVER), &fp); | cap_rights_init_one(&rights, CAP_SOCK_SERVER), &fp); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
if (fp->f_type != DTYPE_SOCKET) { | if (fp->f_type != DTYPE_SOCKET) { | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
error = EPERM; | error = EPERM; | ||||
goto out; | goto out; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | if (nfsdarg.addrlen > 0 && nfsdarg.addrlen < 10000 && | ||||
nfsdarg.dnshost = NULL; | nfsdarg.dnshost = NULL; | ||||
nfsdarg.dnshostlen = 0; | nfsdarg.dnshostlen = 0; | ||||
nfsdarg.dspath = NULL; | nfsdarg.dspath = NULL; | ||||
nfsdarg.dspathlen = 0; | nfsdarg.dspathlen = 0; | ||||
nfsdarg.mdspath = NULL; | nfsdarg.mdspath = NULL; | ||||
nfsdarg.mdspathlen = 0; | nfsdarg.mdspathlen = 0; | ||||
nfsdarg.mirrorcnt = 1; | nfsdarg.mirrorcnt = 1; | ||||
} | } | ||||
nfsd_timer(NULL); | nfsd_timer(NFSD_TD_TO_VNET(td)); | ||||
error = nfsrvd_nfsd(td, &nfsdarg); | error = nfsrvd_nfsd(td, &nfsdarg); | ||||
callout_drain(&NFSD_VNET(nfsd_callout)); | |||||
free(nfsdarg.addr, M_TEMP); | free(nfsdarg.addr, M_TEMP); | ||||
free(nfsdarg.dnshost, M_TEMP); | free(nfsdarg.dnshost, M_TEMP); | ||||
free(nfsdarg.dspath, M_TEMP); | free(nfsdarg.dspath, M_TEMP); | ||||
free(nfsdarg.mdspath, M_TEMP); | free(nfsdarg.mdspath, M_TEMP); | ||||
} else if (uap->flag & NFSSVC_PNFSDS) { | } else if (uap->flag & NFSSVC_PNFSDS) { | ||||
error = copyin(uap->argp, &pnfsdarg, sizeof(pnfsdarg)); | error = copyin(uap->argp, &pnfsdarg, sizeof(pnfsdarg)); | ||||
if (error == 0 && (pnfsdarg.op == PNFSDOP_DELDSSERVER || | if (error == 0 && (pnfsdarg.op == PNFSDOP_DELDSSERVER || | ||||
pnfsdarg.op == PNFSDOP_FORCEDELDS)) { | pnfsdarg.op == PNFSDOP_FORCEDELDS)) { | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | if (error == 0 && (pnfsdarg.op == PNFSDOP_DELDSSERVER || | ||||
free(cp3, M_TEMP); | free(cp3, M_TEMP); | ||||
free(buf, M_TEMP); | free(buf, M_TEMP); | ||||
} | } | ||||
} else { | } else { | ||||
error = nfssvc_srvcall(td, uap, td->td_ucred); | error = nfssvc_srvcall(td, uap, td->td_ucred); | ||||
} | } | ||||
out: | out: | ||||
NFSD_CURVNET_RESTORE(); | |||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) | nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) | ||||
{ | { | ||||
struct nfsex_args export; | struct nfsex_args export; | ||||
struct nfsex_oldargs oexp; | struct nfsex_oldargs oexp; | ||||
struct file *fp = NULL; | struct file *fp = NULL; | ||||
int stablefd, i, len; | int stablefd, i, len; | ||||
struct nfsd_clid adminrevoke; | struct nfsd_clid adminrevoke; | ||||
struct nfsd_dumplist dumplist; | struct nfsd_dumplist dumplist; | ||||
struct nfsd_dumpclients *dumpclients; | struct nfsd_dumpclients *dumpclients; | ||||
struct nfsd_dumplocklist dumplocklist; | struct nfsd_dumplocklist dumplocklist; | ||||
struct nfsd_dumplocks *dumplocks; | struct nfsd_dumplocks *dumplocks; | ||||
struct nameidata nd; | struct nameidata nd; | ||||
vnode_t vp; | vnode_t vp; | ||||
int error = EINVAL, igotlock; | int error = EINVAL, igotlock; | ||||
struct proc *procp; | struct proc *procp; | ||||
gid_t *grps; | gid_t *grps; | ||||
static int suspend_nfsd = 0; | |||||
if (uap->flag & NFSSVC_PUBLICFH) { | if (uap->flag & NFSSVC_PUBLICFH) { | ||||
NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data, | NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data, | ||||
sizeof (fhandle_t)); | sizeof (fhandle_t)); | ||||
error = copyin(uap->argp, | error = copyin(uap->argp, | ||||
&nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t)); | &nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t)); | ||||
if (!error) | if (!error) | ||||
nfs_pubfhset = 1; | nfs_pubfhset = 1; | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | if (uap->flag & NFSSVC_PUBLICFH) { | ||||
error = 0; | error = 0; | ||||
} else if (uap->flag & NFSSVC_STABLERESTART) { | } else if (uap->flag & NFSSVC_STABLERESTART) { | ||||
error = copyin(uap->argp, (caddr_t)&stablefd, | error = copyin(uap->argp, (caddr_t)&stablefd, | ||||
sizeof (int)); | sizeof (int)); | ||||
if (!error) | if (!error) | ||||
error = fp_getfvp(p, stablefd, &fp, &vp); | error = fp_getfvp(p, stablefd, &fp, &vp); | ||||
if (!error && (NFSFPFLAG(fp) & (FREAD | FWRITE)) != (FREAD | FWRITE)) | if (!error && (NFSFPFLAG(fp) & (FREAD | FWRITE)) != (FREAD | FWRITE)) | ||||
error = EBADF; | error = EBADF; | ||||
if (!error && newnfs_numnfsd != 0) | if (!error && NFSD_VNET(nfsrv_numnfsd) != 0) | ||||
error = EPERM; | error = EPERM; | ||||
if (!error) { | if (!error) { | ||||
nfsrv_stablefirst.nsf_fp = fp; | NFSD_VNET(nfsrv_stablefirst).nsf_fp = fp; | ||||
nfsrv_setupstable(p); | nfsrv_setupstable(p); | ||||
} | } | ||||
} else if (uap->flag & NFSSVC_ADMINREVOKE) { | } else if (uap->flag & NFSSVC_ADMINREVOKE) { | ||||
error = copyin(uap->argp, (caddr_t)&adminrevoke, | error = copyin(uap->argp, (caddr_t)&adminrevoke, | ||||
sizeof (struct nfsd_clid)); | sizeof (struct nfsd_clid)); | ||||
if (!error) | if (!error) | ||||
error = nfsrv_adminrevoke(&adminrevoke, p); | error = nfsrv_adminrevoke(&adminrevoke, p); | ||||
} else if (uap->flag & NFSSVC_DUMPCLIENTS) { | } else if (uap->flag & NFSSVC_DUMPCLIENTS) { | ||||
Show All 30 Lines | if (!error) { | ||||
free(dumplocks, M_TEMP); | free(dumplocks, M_TEMP); | ||||
} | } | ||||
} else if (uap->flag & NFSSVC_BACKUPSTABLE) { | } else if (uap->flag & NFSSVC_BACKUPSTABLE) { | ||||
procp = p->td_proc; | procp = p->td_proc; | ||||
PROC_LOCK(procp); | PROC_LOCK(procp); | ||||
nfsd_master_pid = procp->p_pid; | nfsd_master_pid = procp->p_pid; | ||||
bcopy(procp->p_comm, nfsd_master_comm, MAXCOMLEN + 1); | bcopy(procp->p_comm, nfsd_master_comm, MAXCOMLEN + 1); | ||||
nfsd_master_start = procp->p_stats->p_start; | nfsd_master_start = procp->p_stats->p_start; | ||||
nfsd_master_proc = procp; | NFSD_VNET(nfsd_master_proc) = procp; | ||||
PROC_UNLOCK(procp); | PROC_UNLOCK(procp); | ||||
} else if ((uap->flag & NFSSVC_SUSPENDNFSD) != 0) { | } else if ((uap->flag & NFSSVC_SUSPENDNFSD) != 0) { | ||||
NFSLOCKV4ROOTMUTEX(); | NFSLOCKV4ROOTMUTEX(); | ||||
if (suspend_nfsd == 0) { | if (!NFSD_VNET(nfsrv_suspend_nfsd)) { | ||||
/* Lock out all nfsd threads */ | /* Lock out all nfsd threads */ | ||||
do { | do { | ||||
igotlock = nfsv4_lock(&nfsd_suspend_lock, 1, | igotlock = nfsv4_lock( | ||||
NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); | &NFSD_VNET(nfsd_suspend_lock), 1, NULL, | ||||
} while (igotlock == 0 && suspend_nfsd == 0); | NFSV4ROOTLOCKMUTEXPTR, NULL); | ||||
suspend_nfsd = 1; | } while (igotlock == 0 && | ||||
!NFSD_VNET(nfsrv_suspend_nfsd)); | |||||
NFSD_VNET(nfsrv_suspend_nfsd) = true; | |||||
} | } | ||||
NFSUNLOCKV4ROOTMUTEX(); | NFSUNLOCKV4ROOTMUTEX(); | ||||
error = 0; | error = 0; | ||||
} else if ((uap->flag & NFSSVC_RESUMENFSD) != 0) { | } else if ((uap->flag & NFSSVC_RESUMENFSD) != 0) { | ||||
NFSLOCKV4ROOTMUTEX(); | NFSLOCKV4ROOTMUTEX(); | ||||
if (suspend_nfsd != 0) { | if (NFSD_VNET(nfsrv_suspend_nfsd)) { | ||||
nfsv4_unlock(&nfsd_suspend_lock, 0); | nfsv4_unlock(&NFSD_VNET(nfsd_suspend_lock), 0); | ||||
suspend_nfsd = 0; | NFSD_VNET(nfsrv_suspend_nfsd) = false; | ||||
} | } | ||||
NFSUNLOCKV4ROOTMUTEX(); | NFSUNLOCKV4ROOTMUTEX(); | ||||
error = 0; | error = 0; | ||||
} | } | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Signal the userland master nfsd to backup the stable restart file. | * Signal the userland master nfsd to backup the stable restart file. | ||||
*/ | */ | ||||
void | void | ||||
nfsrv_backupstable(void) | nfsrv_backupstable(void) | ||||
{ | { | ||||
struct proc *procp; | struct proc *procp; | ||||
if (nfsd_master_proc != NULL) { | if (NFSD_VNET(nfsd_master_proc) != NULL) { | ||||
procp = pfind(nfsd_master_pid); | procp = pfind(nfsd_master_pid); | ||||
/* Try to make sure it is the correct process. */ | /* Try to make sure it is the correct process. */ | ||||
if (procp == nfsd_master_proc && | if (procp == NFSD_VNET(nfsd_master_proc) && | ||||
procp->p_stats->p_start.tv_sec == | procp->p_stats->p_start.tv_sec == | ||||
nfsd_master_start.tv_sec && | nfsd_master_start.tv_sec && | ||||
procp->p_stats->p_start.tv_usec == | procp->p_stats->p_start.tv_usec == | ||||
nfsd_master_start.tv_usec && | nfsd_master_start.tv_usec && | ||||
strcmp(procp->p_comm, nfsd_master_comm) == 0) | strcmp(procp->p_comm, nfsd_master_comm) == 0) | ||||
kern_psignal(procp, SIGUSR2); | kern_psignal(procp, SIGUSR2); | ||||
else | else | ||||
nfsd_master_proc = NULL; | NFSD_VNET(nfsd_master_proc) = NULL; | ||||
if (procp != NULL) | if (procp != NULL) | ||||
PROC_UNLOCK(procp); | PROC_UNLOCK(procp); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Create a DS data file for nfsrv_pnfscreate(). Called for each mirror. | * Create a DS data file for nfsrv_pnfscreate(). Called for each mirror. | ||||
▲ Show 20 Lines • Show All 2,894 Lines • ▼ Show 20 Lines | for (i = 0; i < cnt && error == 0; i++) { | ||||
} | } | ||||
tdevid += NFSX_V4DEVICEID; | tdevid += NFSX_V4DEVICEID; | ||||
} | } | ||||
free(tsf, M_TEMP); | free(tsf, M_TEMP); | ||||
free(dvpp, M_TEMP); | free(dvpp, M_TEMP); | ||||
free(devid, M_TEMP); | free(devid, M_TEMP); | ||||
} | } | ||||
/* | |||||
* Initialize everything that needs to be initialized for a vnet. | |||||
*/ | |||||
static void | |||||
nfsrv_vnetinit(const void *unused __unused) | |||||
{ | |||||
nfsd_mntinit(); | |||||
} | |||||
VNET_SYSINIT(nfsrv_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY, | |||||
nfsrv_vnetinit, NULL); | |||||
/* | |||||
* Clean up everything that is in a vnet and needs to be | |||||
* done when the jail is destroyed or the module unloaded. | |||||
*/ | |||||
static void | |||||
nfsrv_cleanup(struct prison *pr) | |||||
{ | |||||
int i; | |||||
NFSD_CURVNET_SET(pr->pr_vnet); | |||||
NFSD_LOCK(); | |||||
if (!NFSD_VNET(nfsrv_mntinited)) { | |||||
NFSD_UNLOCK(); | |||||
NFSD_CURVNET_RESTORE(); | |||||
return; | |||||
} | |||||
NFSD_VNET(nfsrv_mntinited) = false; | |||||
NFSD_UNLOCK(); | |||||
/* Clean out all NFSv4 state. */ | |||||
nfsrv_throwawayallstate(curthread); | |||||
/* Clean the NFS server reply cache */ | |||||
nfsrvd_cleancache(); | |||||
/* Free up the krpc server pool. */ | |||||
if (NFSD_VNET(nfsrvd_pool) != NULL) | |||||
svcpool_destroy(NFSD_VNET(nfsrvd_pool)); | |||||
/* and get rid of the locks */ | |||||
for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) { | |||||
mtx_destroy(&NFSD_VNET(nfsrchash_table)[i].mtx); | |||||
mtx_destroy(&NFSD_VNET(nfsrcahash_table)[i].mtx); | |||||
} | |||||
mtx_destroy(&NFSD_VNET(nfsv4root_mnt)->mnt_mtx); | |||||
for (i = 0; i < nfsrv_sessionhashsize; i++) | |||||
mtx_destroy(&NFSD_VNET(nfssessionhash)[i].mtx); | |||||
lockdestroy(&NFSD_VNET(nfsv4root_mnt)->mnt_explock); | |||||
free(NFSD_VNET(nfsrvudphashtbl), M_NFSRVCACHE); | |||||
free(NFSD_VNET(nfsrchash_table), M_NFSRVCACHE); | |||||
free(NFSD_VNET(nfsrcahash_table), M_NFSRVCACHE); | |||||
free(NFSD_VNET(nfsclienthash), M_NFSDCLIENT); | |||||
free(NFSD_VNET(nfslockhash), M_NFSDLOCKFILE); | |||||
free(NFSD_VNET(nfssessionhash), M_NFSDSESSION); | |||||
free(NFSD_VNET(nfsv4root_mnt), M_TEMP); | |||||
NFSD_VNET(nfsv4root_mnt) = NULL; | |||||
#ifdef VIMAGE | |||||
free(NFSD_VNET(nfsstatsv1_vnet), M_TEMP); | |||||
NFSD_VNET(nfsstatsv1_vnet) = NULL; | |||||
#endif | |||||
NFSD_CURVNET_RESTORE(); | |||||
} | |||||
extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *); | extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *); | ||||
/* | /* | ||||
* Called once to initialize data structures... | * Called once to initialize data structures... | ||||
*/ | */ | ||||
static int | static int | ||||
nfsd_modevent(module_t mod, int type, void *data) | nfsd_modevent(module_t mod, int type, void *data) | ||||
{ | { | ||||
int error = 0, i; | int error = 0, i; | ||||
osd_method_t methods[PR_MAXMETHOD] = { | |||||
[PR_METHOD_REMOVE] = nfsrv_prison_cleanup, | |||||
}; | |||||
static int loaded = 0; | static int loaded = 0; | ||||
switch (type) { | switch (type) { | ||||
case MOD_LOAD: | case MOD_LOAD: | ||||
if (loaded) | if (loaded) | ||||
goto out; | goto out; | ||||
newnfs_portinit(); | newnfs_portinit(); | ||||
for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) { | |||||
mtx_init(&nfsrchash_table[i].mtx, "nfsrtc", NULL, | |||||
MTX_DEF); | |||||
mtx_init(&nfsrcahash_table[i].mtx, "nfsrtca", NULL, | |||||
MTX_DEF); | |||||
} | |||||
mtx_init(&nfsrc_udpmtx, "nfsuc", NULL, MTX_DEF); | mtx_init(&nfsrc_udpmtx, "nfsuc", NULL, MTX_DEF); | ||||
mtx_init(&nfs_v4root_mutex, "nfs4rt", NULL, MTX_DEF); | mtx_init(&nfs_v4root_mutex, "nfs4rt", NULL, MTX_DEF); | ||||
mtx_init(&nfsv4root_mnt.mnt_mtx, "nfs4mnt", NULL, MTX_DEF); | |||||
mtx_init(&nfsrv_dontlistlock_mtx, "nfs4dnl", NULL, MTX_DEF); | mtx_init(&nfsrv_dontlistlock_mtx, "nfs4dnl", NULL, MTX_DEF); | ||||
mtx_init(&nfsrv_recalllock_mtx, "nfs4rec", NULL, MTX_DEF); | mtx_init(&nfsrv_recalllock_mtx, "nfs4rec", NULL, MTX_DEF); | ||||
lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0); | |||||
callout_init(&nfsd_callout, 1); | |||||
nfsrvd_initcache(); | |||||
nfsd_init(); | |||||
NFSD_LOCK(); | |||||
nfsrvd_init(0); | |||||
NFSD_UNLOCK(); | |||||
nfsd_mntinit(); | |||||
#ifdef VV_DISABLEDELEG | #ifdef VV_DISABLEDELEG | ||||
vn_deleg_ops.vndeleg_recall = nfsd_recalldelegation; | vn_deleg_ops.vndeleg_recall = nfsd_recalldelegation; | ||||
vn_deleg_ops.vndeleg_disable = nfsd_disabledelegation; | vn_deleg_ops.vndeleg_disable = nfsd_disabledelegation; | ||||
#endif | #endif | ||||
nfsd_call_nfsd = nfssvc_nfsd; | nfsd_call_nfsd = nfssvc_nfsd; | ||||
/* XXX-BZ OSD to VNET? */ | |||||
nfsrv_osd_jail_slot = osd_jail_register(NULL, methods); | |||||
loaded = 1; | loaded = 1; | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
if (newnfs_numnfsd != 0) { | if (newnfs_numnfsd != 0) { | ||||
error = EBUSY; | error = EBUSY; | ||||
break; | break; | ||||
} | } | ||||
#ifdef VV_DISABLEDELEG | #ifdef VV_DISABLEDELEG | ||||
vn_deleg_ops.vndeleg_recall = NULL; | vn_deleg_ops.vndeleg_recall = NULL; | ||||
vn_deleg_ops.vndeleg_disable = NULL; | vn_deleg_ops.vndeleg_disable = NULL; | ||||
#endif | #endif | ||||
nfsd_call_nfsd = NULL; | nfsd_call_nfsd = NULL; | ||||
callout_drain(&nfsd_callout); | osd_jail_deregister(nfsrv_osd_jail_slot); | ||||
nfsrv_cleanup(&prison0); | |||||
/* Clean out all NFSv4 state. */ | |||||
nfsrv_throwawayallstate(curthread); | |||||
/* Clean the NFS server reply cache */ | |||||
nfsrvd_cleancache(); | |||||
/* Free up the krpc server pool. */ | |||||
if (nfsrvd_pool != NULL) | |||||
svcpool_destroy(nfsrvd_pool); | |||||
/* and get rid of the locks */ | |||||
for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) { | |||||
mtx_destroy(&nfsrchash_table[i].mtx); | |||||
mtx_destroy(&nfsrcahash_table[i].mtx); | |||||
} | |||||
mtx_destroy(&nfsrc_udpmtx); | mtx_destroy(&nfsrc_udpmtx); | ||||
mtx_destroy(&nfs_v4root_mutex); | mtx_destroy(&nfs_v4root_mutex); | ||||
mtx_destroy(&nfsv4root_mnt.mnt_mtx); | |||||
mtx_destroy(&nfsrv_dontlistlock_mtx); | mtx_destroy(&nfsrv_dontlistlock_mtx); | ||||
mtx_destroy(&nfsrv_recalllock_mtx); | mtx_destroy(&nfsrv_recalllock_mtx); | ||||
for (i = 0; i < nfsrv_sessionhashsize; i++) | |||||
mtx_destroy(&nfssessionhash[i].mtx); | |||||
if (nfslayouthash != NULL) { | if (nfslayouthash != NULL) { | ||||
for (i = 0; i < nfsrv_layouthashsize; i++) | for (i = 0; i < nfsrv_layouthashsize; i++) | ||||
mtx_destroy(&nfslayouthash[i].mtx); | mtx_destroy(&nfslayouthash[i].mtx); | ||||
free(nfslayouthash, M_NFSDSESSION); | free(nfslayouthash, M_NFSDSESSION); | ||||
} | } | ||||
lockdestroy(&nfsv4root_mnt.mnt_explock); | |||||
free(nfsclienthash, M_NFSDCLIENT); | |||||
free(nfslockhash, M_NFSDLOCKFILE); | |||||
free(nfssessionhash, M_NFSDSESSION); | |||||
loaded = 0; | loaded = 0; | ||||
break; | break; | ||||
default: | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
break; | break; | ||||
} | } | ||||
out: | out: | ||||
Show All 16 Lines |
Why would we need this @jamie if we ever only run with or w/o vnet but never allow this in a plain-old-jail?