Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/nfs/nfs_commonport.c
Show All 36 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | /* | ||||
* Functions that need to be different for different versions of BSD | * Functions that need to be different for different versions of BSD | ||||
* kernel should be kept here, along with any global storage specific | * kernel should be kept here, along with any global storage specific | ||||
* to this BSD variant. | * to this BSD variant. | ||||
*/ | */ | ||||
#include <fs/nfs/nfsport.h> | #include <fs/nfs/nfsport.h> | ||||
#include <sys/osd.h> | |||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <rpc/rpc_com.h> | #include <rpc/rpc_com.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
#include <vm/vm_page.h> | #include <vm/vm_page.h> | ||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
extern int nfscl_ticks; | extern int nfscl_ticks; | ||||
extern nfsuserd_state nfsrv_nfsuserd; | |||||
extern struct nfssockreq nfsrv_nfsuserdsock; | |||||
extern void (*nfsd_call_recall)(struct vnode *, int, struct ucred *, | extern void (*nfsd_call_recall)(struct vnode *, int, struct ucred *, | ||||
struct thread *); | struct thread *); | ||||
extern int nfsrv_useacl; | extern int nfsrv_useacl; | ||||
int newnfs_numnfsd = 0; | int newnfs_numnfsd = 0; | ||||
struct nfsstatsv1 nfsstatsv1; | struct nfsstatsv1 nfsstatsv1; | ||||
int nfs_numnfscbd = 0; | int nfs_numnfscbd = 0; | ||||
int nfscl_debuglevel = 0; | int nfscl_debuglevel = 0; | ||||
char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; | char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; | ||||
int nfsrv_lughashsize = 100; | int nfsrv_lughashsize = 100; | ||||
struct mtx nfsrv_dslock_mtx; | struct mtx nfsrv_dslock_mtx; | ||||
struct nfsdevicehead nfsrv_devidhead; | struct nfsdevicehead nfsrv_devidhead; | ||||
volatile int nfsrv_devidcnt = 0; | volatile int nfsrv_devidcnt = 0; | ||||
void (*ncl_call_invalcaches)(struct vnode *) = NULL; | void (*ncl_call_invalcaches)(struct vnode *) = NULL; | ||||
vop_advlock_t *nfs_advlock_p = NULL; | vop_advlock_t *nfs_advlock_p = NULL; | ||||
vop_reclaim_t *nfs_reclaim_p = NULL; | vop_reclaim_t *nfs_reclaim_p = NULL; | ||||
uint32_t nfs_srvmaxio = NFS_SRVMAXIO; | uint32_t nfs_srvmaxio = NFS_SRVMAXIO; | ||||
NFSD_VNET_DECLARE(struct nfsrv_lughash *, nfsuserhash); | |||||
NFSD_VNET_DECLARE(struct nfsrv_lughash *, nfsusernamehash); | |||||
NFSD_VNET_DECLARE(struct nfsrv_lughash *, nfsgrouphash); | |||||
NFSD_VNET_DECLARE(struct nfsrv_lughash *, nfsgroupnamehash); | |||||
NFSD_VNET_DECLARE(u_char *, nfsrv_dnsname); | |||||
NFSD_VNET_DECLARE(struct nfssockreq, nfsrv_nfsuserdsock); | |||||
NFSD_VNET_DECLARE(nfsuserd_state, nfsrv_nfsuserd); | |||||
NFSDSTATSDEFINE(nfsstatsv1); | NFSDSTATSDEFINE(nfsstatsv1); | ||||
int nfs_pnfsio(task_fn_t *, void *); | int nfs_pnfsio(task_fn_t *, void *); | ||||
static int nfs_realign_test; | static int nfs_realign_test; | ||||
static int nfs_realign_count; | static int nfs_realign_count; | ||||
static struct ext_nfsstats oldnfsstats; | static struct ext_nfsstats oldnfsstats; | ||||
static struct nfsstatsov1 nfsstatsov1; | static struct nfsstatsov1 nfsstatsov1; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
struct mtx nfs_state_mutex; | struct mtx nfs_state_mutex; | ||||
struct mtx nfs_nameid_mutex; | struct mtx nfs_nameid_mutex; | ||||
struct mtx nfs_req_mutex; | struct mtx nfs_req_mutex; | ||||
struct mtx nfs_slock_mutex; | struct mtx nfs_slock_mutex; | ||||
struct mtx nfs_clstate_mutex; | struct mtx nfs_clstate_mutex; | ||||
/* local functions */ | /* local functions */ | ||||
static int nfssvc_call(struct thread *, struct nfssvc_args *, struct ucred *); | static int nfssvc_call(struct thread *, struct nfssvc_args *, struct ucred *); | ||||
static void nfsrv_cleanusergroup(struct prison *); | |||||
#ifdef __NO_STRICT_ALIGNMENT | #ifdef __NO_STRICT_ALIGNMENT | ||||
/* | /* | ||||
* These architectures don't need re-alignment, so just return. | * These architectures don't need re-alignment, so just return. | ||||
*/ | */ | ||||
int | int | ||||
newnfs_realign(struct mbuf **pm, int how) | newnfs_realign(struct mbuf **pm, int how) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Lines | nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) | ||||
struct nfsd_idargs nid; | struct nfsd_idargs nid; | ||||
struct nfsd_oidargs onid; | struct nfsd_oidargs onid; | ||||
struct { | struct { | ||||
int vers; /* Just the first field of nfsstats. */ | int vers; /* Just the first field of nfsstats. */ | ||||
} nfsstatver; | } nfsstatver; | ||||
struct nfsstatsv1 *outstats; | struct nfsstatsv1 *outstats; | ||||
if (uap->flag & NFSSVC_IDNAME) { | if (uap->flag & NFSSVC_IDNAME) { | ||||
if (jailed(p->td_ucred)) { | |||||
error = EPERM; | |||||
goto out; | |||||
} | |||||
if ((uap->flag & NFSSVC_NEWSTRUCT) != 0) | if ((uap->flag & NFSSVC_NEWSTRUCT) != 0) | ||||
error = copyin(uap->argp, &nid, sizeof(nid)); | error = copyin(uap->argp, &nid, sizeof(nid)); | ||||
else { | else { | ||||
error = copyin(uap->argp, &onid, sizeof(onid)); | error = copyin(uap->argp, &onid, sizeof(onid)); | ||||
if (error == 0) { | if (error == 0) { | ||||
nid.nid_flag = onid.nid_flag; | nid.nid_flag = onid.nid_flag; | ||||
nid.nid_uid = onid.nid_uid; | nid.nid_uid = onid.nid_uid; | ||||
nid.nid_gid = onid.nid_gid; | nid.nid_gid = onid.nid_gid; | ||||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | |||||
#ifdef VNET_NFSD | #ifdef VNET_NFSD | ||||
free(outstats, M_TEMP); | free(outstats, M_TEMP); | ||||
#endif | #endif | ||||
goto out; | goto out; | ||||
} else if (uap->flag & NFSSVC_NFSUSERDPORT) { | } else if (uap->flag & NFSSVC_NFSUSERDPORT) { | ||||
u_short sockport; | u_short sockport; | ||||
struct nfsuserd_args nargs; | struct nfsuserd_args nargs; | ||||
if (jailed(p->td_ucred)) { | |||||
error = EPERM; | |||||
goto out; | |||||
} | |||||
if ((uap->flag & NFSSVC_NEWSTRUCT) == 0) { | if ((uap->flag & NFSSVC_NEWSTRUCT) == 0) { | ||||
error = copyin(uap->argp, (caddr_t)&sockport, | error = copyin(uap->argp, (caddr_t)&sockport, | ||||
sizeof (u_short)); | sizeof (u_short)); | ||||
if (error == 0) { | if (error == 0) { | ||||
nargs.nuserd_family = AF_INET; | nargs.nuserd_family = AF_INET; | ||||
nargs.nuserd_port = sockport; | nargs.nuserd_port = sockport; | ||||
} | } | ||||
} else { | } else { | ||||
/* | /* | ||||
* New nfsuserd_args structure, which indicates | * New nfsuserd_args structure, which indicates | ||||
* which IP version to use along with the port#. | * which IP version to use along with the port#. | ||||
*/ | */ | ||||
error = copyin(uap->argp, &nargs, sizeof(nargs)); | error = copyin(uap->argp, &nargs, sizeof(nargs)); | ||||
} | } | ||||
if (!error) | if (!error) | ||||
error = nfsrv_nfsuserdport(&nargs, p); | error = nfsrv_nfsuserdport(&nargs, p); | ||||
} else if (uap->flag & NFSSVC_NFSUSERDDELPORT) { | } else if (uap->flag & NFSSVC_NFSUSERDDELPORT) { | ||||
if (jailed(p->td_ucred)) { | |||||
error = EPERM; | |||||
goto out; | |||||
} | |||||
nfsrv_nfsuserddelport(); | nfsrv_nfsuserddelport(); | ||||
error = 0; | error = 0; | ||||
} | } | ||||
out: | out: | ||||
NFSEXITCODE(error); | NFSEXITCODE(error); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | nfs_pnfsio(task_fn_t *func, void *context) | ||||
pio->inprog = 1; | pio->inprog = 1; | ||||
TASK_INIT(&pio->tsk, 0, func, context); | TASK_INIT(&pio->tsk, 0, func, context); | ||||
ret = taskqueue_enqueue(pnfsioq, &pio->tsk); | ret = taskqueue_enqueue(pnfsioq, &pio->tsk); | ||||
if (ret != 0) | if (ret != 0) | ||||
pio->inprog = 0; | pio->inprog = 0; | ||||
return (ret); | return (ret); | ||||
} | } | ||||
/* | |||||
* Free up all the allocations related to the name<-->id cache. | |||||
* This function should only be called when the nfsuserd daemon isn't | |||||
* running, since it doesn't do any locking. | |||||
* This function is meant to be called when a vnet jail is destroyed. | |||||
*/ | |||||
static void | |||||
nfsrv_cleanusergroup(struct prison *pr) | |||||
{ | |||||
struct nfsrv_lughash *hp, *hp2; | |||||
struct nfsusrgrp *nusrp, *usrp; | |||||
int i; | |||||
NFSD_CURVNET_SET(pr->pr_vnet); | |||||
mtx_destroy(&NFSD_VNET(nfsrv_nfsuserdsock).nr_mtx); | |||||
if (NFSD_VNET(nfsuserhash) == NULL) { | |||||
NFSD_CURVNET_RESTORE(); | |||||
return; | |||||
} | |||||
for (i = 0; i < nfsrv_lughashsize; i++) { | |||||
hp = &NFSD_VNET(nfsuserhash)[i]; | |||||
TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { | |||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | |||||
hp2 = NFSUSERNAMEHASH(usrp->lug_name, | |||||
usrp->lug_namelen); | |||||
TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); | |||||
if (usrp->lug_cred != NULL) | |||||
crfree(usrp->lug_cred); | |||||
free(usrp, M_NFSUSERGROUP); | |||||
} | |||||
hp = &NFSD_VNET(nfsgrouphash)[i]; | |||||
TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { | |||||
TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); | |||||
hp2 = NFSGROUPNAMEHASH(usrp->lug_name, | |||||
usrp->lug_namelen); | |||||
TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); | |||||
if (usrp->lug_cred != NULL) | |||||
crfree(usrp->lug_cred); | |||||
free(usrp, M_NFSUSERGROUP); | |||||
} | |||||
mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx); | |||||
mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx); | |||||
mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx); | |||||
mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx); | |||||
} | |||||
free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP); | |||||
free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP); | |||||
free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP); | |||||
free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP); | |||||
free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING); | |||||
NFSD_CURVNET_RESTORE(); | |||||
} | |||||
#ifdef VNET_NFSD | |||||
/* | |||||
* Initialize everything that needs to be initialized for a vnet. | |||||
*/ | |||||
static void | |||||
nfs_vnetinit(const void *unused __unused) | |||||
{ | |||||
mtx_init(&NFSD_VNET(nfsrv_nfsuserdsock).nr_mtx, "nfsuserd", | |||||
NULL, MTX_DEF); | |||||
} | |||||
VNET_SYSINIT(nfs_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY, | |||||
nfs_vnetinit, NULL); | |||||
/* Osd entry for nfsrv_cleanup. */ | |||||
static int | |||||
nfs_prison_cleanup(void *obj, void *data __unused) | |||||
{ | |||||
struct prison *pr = obj; | |||||
if ((pr->pr_flags & PR_VNET) == 0) | |||||
return (0); | |||||
nfsrv_cleanusergroup(pr); | |||||
return (0); | |||||
} | |||||
#endif /* VNET_NFSD */ | |||||
extern int (*nfsd_call_nfscommon)(struct thread *, struct nfssvc_args *); | extern int (*nfsd_call_nfscommon)(struct thread *, struct nfssvc_args *); | ||||
/* | /* | ||||
* Called once to initialize data structures... | * Called once to initialize data structures... | ||||
*/ | */ | ||||
static int | static int | ||||
nfscommon_modevent(module_t mod, int type, void *data) | nfscommon_modevent(module_t mod, int type, void *data) | ||||
{ | { | ||||
int error = 0; | int error = 0; | ||||
#ifdef VNET_NFSD | |||||
osd_method_t methods[PR_MAXMETHOD] = { | |||||
[PR_METHOD_REMOVE] = nfs_prison_cleanup, | |||||
}; | |||||
#endif | |||||
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(); | ||||
mtx_init(&nfs_nameid_mutex, "nfs_nameid_mutex", NULL, MTX_DEF); | mtx_init(&nfs_nameid_mutex, "nfs_nameid_mutex", NULL, MTX_DEF); | ||||
mtx_init(&nfs_sockl_mutex, "nfs_sockl_mutex", NULL, MTX_DEF); | mtx_init(&nfs_sockl_mutex, "nfs_sockl_mutex", NULL, MTX_DEF); | ||||
mtx_init(&nfs_slock_mutex, "nfs_slock_mutex", NULL, MTX_DEF); | mtx_init(&nfs_slock_mutex, "nfs_slock_mutex", NULL, MTX_DEF); | ||||
mtx_init(&nfs_req_mutex, "nfs_req_mutex", NULL, MTX_DEF); | mtx_init(&nfs_req_mutex, "nfs_req_mutex", NULL, MTX_DEF); | ||||
mtx_init(&nfsrv_nfsuserdsock.nr_mtx, "nfsuserd", NULL, | #ifdef VNET_NFSD | ||||
MTX_DEF); | /* XXX-BZ OSD to VNET? */ | ||||
osd_jail_register(NULL, methods); | |||||
#else | |||||
mtx_init(&NFSD_VNET(nfsrv_nfsuserdsock).nr_mtx, "nfsuserd", | |||||
NULL, MTX_DEF); | |||||
#endif | |||||
mtx_init(&nfsrv_dslock_mtx, "nfs4ds", NULL, MTX_DEF); | mtx_init(&nfsrv_dslock_mtx, "nfs4ds", NULL, MTX_DEF); | ||||
TAILQ_INIT(&nfsrv_devidhead); | TAILQ_INIT(&nfsrv_devidhead); | ||||
newnfs_init(); | newnfs_init(); | ||||
nfsd_call_nfscommon = nfssvc_nfscommon; | nfsd_call_nfscommon = nfssvc_nfscommon; | ||||
loaded = 1; | loaded = 1; | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
if (newnfs_numnfsd != 0 || nfsrv_nfsuserd != NOTRUNNING || | if (newnfs_numnfsd != 0 || | ||||
NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING || | |||||
nfs_numnfscbd != 0) { | nfs_numnfscbd != 0) { | ||||
error = EBUSY; | error = EBUSY; | ||||
break; | break; | ||||
} | } | ||||
nfsd_call_nfscommon = NULL; | nfsd_call_nfscommon = NULL; | ||||
/* Clean out the name<-->id cache. */ | /* Clean out the name<-->id cache. */ | ||||
nfsrv_cleanusergroup(); | nfsrv_cleanusergroup(&prison0); | ||||
/* and get rid of the mutexes */ | /* and get rid of the mutexes */ | ||||
mtx_destroy(&nfs_nameid_mutex); | mtx_destroy(&nfs_nameid_mutex); | ||||
mtx_destroy(&newnfsd_mtx); | mtx_destroy(&newnfsd_mtx); | ||||
mtx_destroy(&nfs_state_mutex); | mtx_destroy(&nfs_state_mutex); | ||||
mtx_destroy(&nfs_clstate_mutex); | mtx_destroy(&nfs_clstate_mutex); | ||||
mtx_destroy(&nfs_sockl_mutex); | mtx_destroy(&nfs_sockl_mutex); | ||||
mtx_destroy(&nfs_slock_mutex); | mtx_destroy(&nfs_slock_mutex); | ||||
mtx_destroy(&nfs_req_mutex); | mtx_destroy(&nfs_req_mutex); | ||||
mtx_destroy(&nfsrv_nfsuserdsock.nr_mtx); | |||||
mtx_destroy(&nfsrv_dslock_mtx); | mtx_destroy(&nfsrv_dslock_mtx); | ||||
loaded = 0; | loaded = 0; | ||||
break; | break; | ||||
default: | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
break; | break; | ||||
} | } | ||||
Show All 15 Lines |