Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/nfsserver/nfs_nfsdsocket.c
Show All 36 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | /* | ||||
* Socket operations for use by the nfs server. | * Socket operations for use by the nfs server. | ||||
*/ | */ | ||||
#include <fs/nfs/nfsport.h> | #include <fs/nfs/nfsport.h> | ||||
extern struct nfsstatsv1 nfsstatsv1; | extern struct nfsrvfh nfs_pubfh; | ||||
extern struct nfsrvfh nfs_pubfh, nfs_rootfh; | extern int nfs_pubfhset; | ||||
extern int nfs_pubfhset, nfs_rootfhset; | |||||
extern struct nfsv4lock nfsv4rootfs_lock; | extern struct nfsv4lock nfsv4rootfs_lock; | ||||
extern struct nfsrv_stablefirst nfsrv_stablefirst; | |||||
extern struct nfsclienthashhead *nfsclienthash; | |||||
extern int nfsrv_clienthashsize; | extern int nfsrv_clienthashsize; | ||||
extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies; | |||||
extern int nfsd_debuglevel; | extern int nfsd_debuglevel; | ||||
extern int nfsrv_layouthighwater; | extern int nfsrv_layouthighwater; | ||||
extern volatile int nfsrv_layoutcnt; | extern volatile int nfsrv_layoutcnt; | ||||
NFSV4ROOTLOCKMUTEX; | NFSV4ROOTLOCKMUTEX; | ||||
NFSSTATESPINLOCK; | NFSSTATESPINLOCK; | ||||
NFSDSTATSDECLARE(nfsstatsv1); | |||||
NFSD_VNET_DECLARE(struct nfsrv_stablefirst, nfsrv_stablefirst); | |||||
NFSD_VNET_DECLARE(struct nfsclienthashhead *, nfsclienthash); | |||||
NFSD_VNET_DECLARE(int, nfsrc_floodlevel); | |||||
NFSD_VNET_DECLARE(int, nfsrc_tcpsavedreplies); | |||||
NFSD_VNET_DECLARE(struct nfsrvfh, nfs_rootfh); | |||||
NFSD_VNET_DECLARE(int, nfs_rootfhset); | |||||
int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *, | int (*nfsrv3_procs0[NFS_V3NPROCS])(struct nfsrv_descript *, | ||||
int, vnode_t , struct nfsexstuff *) = { | int, vnode_t , struct nfsexstuff *) = { | ||||
(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, | (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, | ||||
nfsrvd_getattr, | nfsrvd_getattr, | ||||
nfsrvd_setattr, | nfsrvd_setattr, | ||||
(int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, | (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0, | ||||
nfsrvd_access, | nfsrvd_access, | ||||
nfsrvd_readlink, | nfsrvd_readlink, | ||||
▲ Show 20 Lines • Show All 399 Lines • ▼ Show 20 Lines | |||||
nfsrvd_statstart(int op, struct bintime *now) | nfsrvd_statstart(int op, struct bintime *now) | ||||
{ | { | ||||
if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) { | if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) { | ||||
printf("%s: op %d invalid\n", __func__, op); | printf("%s: op %d invalid\n", __func__, op); | ||||
return; | return; | ||||
} | } | ||||
mtx_lock(&nfsrvd_statmtx); | mtx_lock(&nfsrvd_statmtx); | ||||
if (nfsstatsv1.srvstartcnt == nfsstatsv1.srvdonecnt) { | if (NFSDSTATS()->srvstartcnt == NFSDSTATS()->srvdonecnt) { | ||||
if (now != NULL) | if (now != NULL) | ||||
nfsstatsv1.busyfrom = *now; | NFSDSTATS()->busyfrom = *now; | ||||
else | else | ||||
binuptime(&nfsstatsv1.busyfrom); | binuptime(&NFSDSTATS()->busyfrom); | ||||
} | } | ||||
nfsstatsv1.srvrpccnt[op]++; | NFSDSTATS()->srvrpccnt[op]++; | ||||
nfsstatsv1.srvstartcnt++; | NFSDSTATS()->srvstartcnt++; | ||||
mtx_unlock(&nfsrvd_statmtx); | mtx_unlock(&nfsrvd_statmtx); | ||||
} | } | ||||
static void | static void | ||||
nfsrvd_statend(int op, uint64_t bytes, struct bintime *now, | nfsrvd_statend(int op, uint64_t bytes, struct bintime *now, | ||||
struct bintime *then) | struct bintime *then) | ||||
{ | { | ||||
struct bintime dt, lnow; | struct bintime dt, lnow; | ||||
if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) { | if (op > (NFSV42_NOPS + NFSV4OP_FAKENOPS)) { | ||||
printf("%s: op %d invalid\n", __func__, op); | printf("%s: op %d invalid\n", __func__, op); | ||||
return; | return; | ||||
} | } | ||||
if (now == NULL) { | if (now == NULL) { | ||||
now = &lnow; | now = &lnow; | ||||
binuptime(now); | binuptime(now); | ||||
} | } | ||||
mtx_lock(&nfsrvd_statmtx); | mtx_lock(&nfsrvd_statmtx); | ||||
nfsstatsv1.srvbytes[op] += bytes; | NFSDSTATS()->srvbytes[op] += bytes; | ||||
nfsstatsv1.srvops[op]++; | NFSDSTATS()->srvops[op]++; | ||||
if (then != NULL) { | if (then != NULL) { | ||||
dt = *now; | dt = *now; | ||||
bintime_sub(&dt, then); | bintime_sub(&dt, then); | ||||
bintime_add(&nfsstatsv1.srvduration[op], &dt); | bintime_add(&NFSDSTATS()->srvduration[op], &dt); | ||||
} | } | ||||
dt = *now; | dt = *now; | ||||
bintime_sub(&dt, &nfsstatsv1.busyfrom); | bintime_sub(&dt, &NFSDSTATS()->busyfrom); | ||||
bintime_add(&nfsstatsv1.busytime, &dt); | bintime_add(&NFSDSTATS()->busytime, &dt); | ||||
nfsstatsv1.busyfrom = *now; | NFSDSTATS()->busyfrom = *now; | ||||
nfsstatsv1.srvdonecnt++; | NFSDSTATS()->srvdonecnt++; | ||||
mtx_unlock(&nfsrvd_statmtx); | mtx_unlock(&nfsrvd_statmtx); | ||||
} | } | ||||
/* | /* | ||||
* Do an RPC. Basically, get the file handles translated to vnode pointers | * Do an RPC. Basically, get the file handles translated to vnode pointers | ||||
* and then call the appropriate server routine. The server routines are | * and then call the appropriate server routine. The server routines are | ||||
* split into groups, based on whether they use a file handle or file | * split into groups, based on whether they use a file handle or file | ||||
▲ Show 20 Lines • Show All 220 Lines • ▼ Show 20 Lines | nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag, | ||||
* also get a reference count, which saves the need for a call to | * also get a reference count, which saves the need for a call to | ||||
* nfsrv_getref() after nfsrv_unlock(). | * nfsrv_getref() after nfsrv_unlock(). | ||||
*/ | */ | ||||
/* | /* | ||||
* First, check to see if we need to wait for an update lock. | * First, check to see if we need to wait for an update lock. | ||||
*/ | */ | ||||
igotlock = 0; | igotlock = 0; | ||||
NFSLOCKV4ROOTMUTEX(); | NFSLOCKV4ROOTMUTEX(); | ||||
if (nfsrv_stablefirst.nsf_flags & NFSNSF_NEEDLOCK) | if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NEEDLOCK) | ||||
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, | igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, | ||||
NFSV4ROOTLOCKMUTEXPTR, NULL); | NFSV4ROOTLOCKMUTEXPTR, NULL); | ||||
else | else | ||||
igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL, | igotlock = nfsv4_lock(&nfsv4rootfs_lock, 0, NULL, | ||||
NFSV4ROOTLOCKMUTEXPTR, NULL); | NFSV4ROOTLOCKMUTEXPTR, NULL); | ||||
NFSUNLOCKV4ROOTMUTEX(); | NFSUNLOCKV4ROOTMUTEX(); | ||||
if (igotlock) { | if (igotlock) { | ||||
/* | /* | ||||
* If I got the lock, I can update the stable storage file. | * If I got the lock, I can update the stable storage file. | ||||
* Done when the grace period is over or a client has long | * Done when the grace period is over or a client has long | ||||
* since expired. | * since expired. | ||||
*/ | */ | ||||
nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NEEDLOCK; | NFSD_VNET(nfsrv_stablefirst).nsf_flags &= ~NFSNSF_NEEDLOCK; | ||||
if ((nfsrv_stablefirst.nsf_flags & | if ((NFSD_VNET(nfsrv_stablefirst).nsf_flags & | ||||
(NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER) | (NFSNSF_GRACEOVER | NFSNSF_UPDATEDONE)) == NFSNSF_GRACEOVER) | ||||
nfsrv_updatestable(p); | nfsrv_updatestable(p); | ||||
/* | /* | ||||
* If at least one client has long since expired, search | * If at least one client has long since expired, search | ||||
* the client list for them, write a REVOKE record on the | * the client list for them, write a REVOKE record on the | ||||
* stable storage file and then remove them from the client | * stable storage file and then remove them from the client | ||||
* list. | * list. | ||||
*/ | */ | ||||
if (nfsrv_stablefirst.nsf_flags & NFSNSF_EXPIREDCLIENT) { | if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & | ||||
nfsrv_stablefirst.nsf_flags &= ~NFSNSF_EXPIREDCLIENT; | NFSNSF_EXPIREDCLIENT) { | ||||
NFSD_VNET(nfsrv_stablefirst).nsf_flags &= | |||||
~NFSNSF_EXPIREDCLIENT; | |||||
for (i = 0; i < nfsrv_clienthashsize; i++) { | for (i = 0; i < nfsrv_clienthashsize; i++) { | ||||
LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, | LIST_FOREACH_SAFE(clp, &NFSD_VNET(nfsclienthash)[i], | ||||
nclp) { | lc_hash, nclp) { | ||||
if (clp->lc_flags & LCL_EXPIREIT) { | if (clp->lc_flags & LCL_EXPIREIT) { | ||||
if (!LIST_EMPTY(&clp->lc_open) || | if (!LIST_EMPTY(&clp->lc_open) || | ||||
!LIST_EMPTY(&clp->lc_deleg)) | !LIST_EMPTY(&clp->lc_deleg)) | ||||
nfsrv_writestable(clp->lc_id, | nfsrv_writestable(clp->lc_id, | ||||
clp->lc_idlen, NFSNST_REVOKE, p); | clp->lc_idlen, NFSNST_REVOKE, p); | ||||
nfsrv_cleanclient(clp, p); | nfsrv_cleanclient(clp, p); | ||||
nfsrv_freedeleglist(&clp->lc_deleg); | nfsrv_freedeleglist(&clp->lc_deleg); | ||||
nfsrv_freedeleglist(&clp->lc_olddeleg); | nfsrv_freedeleglist(&clp->lc_olddeleg); | ||||
Show All 16 Lines | nfsv4_getref(&nfsv4rootfs_lock, NULL, | ||||
NFSV4ROOTLOCKMUTEXPTR, NULL); | NFSV4ROOTLOCKMUTEXPTR, NULL); | ||||
NFSUNLOCKV4ROOTMUTEX(); | NFSUNLOCKV4ROOTMUTEX(); | ||||
} | } | ||||
/* | /* | ||||
* If flagged, search for open owners that haven't had any opens | * If flagged, search for open owners that haven't had any opens | ||||
* for a long time. | * for a long time. | ||||
*/ | */ | ||||
if (nfsrv_stablefirst.nsf_flags & NFSNSF_NOOPENS) { | if (NFSD_VNET(nfsrv_stablefirst).nsf_flags & NFSNSF_NOOPENS) { | ||||
nfsrv_throwawayopens(p); | nfsrv_throwawayopens(p); | ||||
} | } | ||||
/* Do a CBLAYOUTRECALL callback if over the high water mark. */ | /* Do a CBLAYOUTRECALL callback if over the high water mark. */ | ||||
if (nfsrv_layoutcnt > nfsrv_layouthighwater) | if (nfsrv_layoutcnt > nfsrv_layouthighwater) | ||||
nfsrv_recalloldlayout(p); | nfsrv_recalloldlayout(p); | ||||
savevp = vp = NULL; | savevp = vp = NULL; | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | for (i = 0; i < numops; i++) { | ||||
* will still function over flood level, but uses lots of | * will still function over flood level, but uses lots of | ||||
* mbufs.) | * mbufs.) | ||||
* If nfsrv_mallocmget_limit() returns True, the system is near | * If nfsrv_mallocmget_limit() returns True, the system is near | ||||
* to its limit for memory that malloc()/mget() can allocate. | * to its limit for memory that malloc()/mget() can allocate. | ||||
*/ | */ | ||||
if (i == 0 && (nd->nd_rp == NULL || | if (i == 0 && (nd->nd_rp == NULL || | ||||
nd->nd_rp->rc_refcnt == 0) && | nd->nd_rp->rc_refcnt == 0) && | ||||
(nfsrv_mallocmget_limit() || | (nfsrv_mallocmget_limit() || | ||||
nfsrc_tcpsavedreplies > nfsrc_floodlevel)) { | NFSD_VNET(nfsrc_tcpsavedreplies) > | ||||
if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) | NFSD_VNET(nfsrc_floodlevel))) { | ||||
if (NFSD_VNET(nfsrc_tcpsavedreplies) > | |||||
NFSD_VNET(nfsrc_floodlevel)) | |||||
printf("nfsd server cache flooded, try " | printf("nfsd server cache flooded, try " | ||||
"increasing vfs.nfsd.tcphighwater\n"); | "increasing vfs.nfsd.tcphighwater\n"); | ||||
nd->nd_repstat = NFSERR_RESOURCE; | nd->nd_repstat = NFSERR_RESOURCE; | ||||
*repp = nfsd_errmap(nd); | *repp = nfsd_errmap(nd); | ||||
if (op == NFSV4OP_SETATTR) { | if (op == NFSV4OP_SETATTR) { | ||||
/* | /* | ||||
* Setattr replies require a bitmap. | * Setattr replies require a bitmap. | ||||
* even for errors like these. | * even for errors like these. | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | case NFSV4OP_PUTPUBFH: | ||||
vrele(vp); | vrele(vp); | ||||
vp = nvp; | vp = nvp; | ||||
cur_fsid = vp->v_mount->mnt_stat.f_fsid; | cur_fsid = vp->v_mount->mnt_stat.f_fsid; | ||||
NFSVOPUNLOCK(vp); | NFSVOPUNLOCK(vp); | ||||
vpnes = nes; | vpnes = nes; | ||||
} | } | ||||
break; | break; | ||||
case NFSV4OP_PUTROOTFH: | case NFSV4OP_PUTROOTFH: | ||||
if (nfs_rootfhset) { | if (NFSD_VNET(nfs_rootfhset)) { | ||||
if ((nd->nd_flag & ND_LASTOP) == 0) { | if ((nd->nd_flag & ND_LASTOP) == 0) { | ||||
/* | /* | ||||
* Pre-parse the next op#. If it is | * Pre-parse the next op#. If it is | ||||
* SaveFH, count it and skip to the | * SaveFH, count it and skip to the | ||||
* next op#, if not the last op#. | * next op#, if not the last op#. | ||||
* nextop is used to determine if | * nextop is used to determine if | ||||
* NFSERR_WRONGSEC can be returned, | * NFSERR_WRONGSEC can be returned, | ||||
* per RFC5661 Sec. 2.6. | * per RFC5661 Sec. 2.6. | ||||
*/ | */ | ||||
do { | do { | ||||
NFSM_DISSECT(tl, uint32_t *, | NFSM_DISSECT(tl, uint32_t *, | ||||
NFSX_UNSIGNED); | NFSX_UNSIGNED); | ||||
nextop = fxdr_unsigned(int, | nextop = fxdr_unsigned(int, | ||||
*tl); | *tl); | ||||
if (nextop == NFSV4OP_SAVEFH && | if (nextop == NFSV4OP_SAVEFH && | ||||
i < numops - 1) | i < numops - 1) | ||||
savefhcnt++; | savefhcnt++; | ||||
} while (nextop == NFSV4OP_SAVEFH && | } while (nextop == NFSV4OP_SAVEFH && | ||||
i < numops - 1); | i < numops - 1); | ||||
} | } | ||||
nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp, | nfsd_fhtovp(nd, &NFSD_VNET(nfs_rootfh), | ||||
&nes, NULL, 0, nextop); | LK_SHARED, &nvp, &nes, NULL, 0, nextop); | ||||
if (!nd->nd_repstat) { | if (!nd->nd_repstat) { | ||||
if (vp) | if (vp) | ||||
vrele(vp); | vrele(vp); | ||||
vp = nvp; | vp = nvp; | ||||
cur_fsid = vp->v_mount->mnt_stat.f_fsid; | cur_fsid = vp->v_mount->mnt_stat.f_fsid; | ||||
NFSVOPUNLOCK(vp); | NFSVOPUNLOCK(vp); | ||||
vpnes = nes; | vpnes = nes; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 312 Lines • Show Last 20 Lines |