Changeset View
Changeset View
Standalone View
Standalone View
fs/nfsserver/nfs_nfsdstate.c
Context not available. | |||||
NFSV4ROOTLOCKMUTEX; | NFSV4ROOTLOCKMUTEX; | ||||
NFSSTATESPINLOCK; | NFSSTATESPINLOCK; | ||||
SYSCTL_DECL(_vfs_nfsd); | |||||
int nfsrv_statehashsize = NFSSTATEHASHSIZE; | |||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, statehashsize, CTLFLAG_RDTUN, | |||||
&nfsrv_statehashsize, 0, | |||||
"Size of state hash table set via loader.conf"); | |||||
int nfsrv_clienthashsize = NFSCLIENTHASHSIZE; | |||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, clienthashsize, CTLFLAG_RDTUN, | |||||
&nfsrv_clienthashsize, 0, | |||||
"Size of client hash table set via loader.conf"); | |||||
int nfsrv_lockhashsize = NFSLOCKHASHSIZE; | |||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, fhhashsize, CTLFLAG_RDTUN, | |||||
&nfsrv_lockhashsize, 0, | |||||
"Size of file handle hash table set via loader.conf"); | |||||
int nfsrv_sessionhashsize = NFSSESSIONHASHSIZE; | |||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, sessionhashsize, CTLFLAG_RDTUN, | |||||
&nfsrv_sessionhashsize, 0, | |||||
"Size of session hash table set via loader.conf"); | |||||
static int nfsrv_v4statelimit = NFSRV_V4STATELIMIT; | |||||
SYSCTL_INT(_vfs_nfsd, OID_AUTO, v4statelimit, CTLFLAG_RWTUN, | |||||
&nfsrv_v4statelimit, 0, | |||||
"High water limit for NFSv4 opens+locks+delegations"); | |||||
/* | /* | ||||
* Hash lists for nfs V4. | * Hash lists for nfs V4. | ||||
* (Some would put them in the .h file, but I don't like declaring storage | |||||
* in a .h) | |||||
*/ | */ | ||||
struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE]; | struct nfsclienthashhead *nfsclienthash; | ||||
struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE]; | struct nfslockhashhead *nfslockhash; | ||||
struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE]; | struct nfssessionhash *nfssessionhash; | ||||
#endif /* !APPLEKEXT */ | #endif /* !APPLEKEXT */ | ||||
static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0; | static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0; | ||||
Context not available. | |||||
/* | /* | ||||
* Check for state resource limit exceeded. | * Check for state resource limit exceeded. | ||||
*/ | */ | ||||
if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { | if (nfsrv_openpluslock > nfsrv_v4statelimit) { | ||||
error = NFSERR_RESOURCE; | error = NFSERR_RESOURCE; | ||||
goto out; | goto out; | ||||
} | } | ||||
Context not available. | |||||
* Search for a match in the client list. | * Search for a match in the client list. | ||||
*/ | */ | ||||
gotit = i = 0; | gotit = i = 0; | ||||
while (i < NFSCLIENTHASHSIZE && !gotit) { | while (i < nfsrv_clienthashsize && !gotit) { | ||||
LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { | LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { | ||||
if (new_clp->lc_idlen == clp->lc_idlen && | if (new_clp->lc_idlen == clp->lc_idlen && | ||||
!NFSBCMP(new_clp->lc_id, clp->lc_id, clp->lc_idlen)) { | !NFSBCMP(new_clp->lc_id, clp->lc_id, clp->lc_idlen)) { | ||||
Context not available. | |||||
/* | /* | ||||
* Get rid of the old one. | * Get rid of the old one. | ||||
*/ | */ | ||||
if (i != NFSCLIENTHASHSIZE) { | if (i != nfsrv_clienthashsize) { | ||||
LIST_REMOVE(clp, lc_hash); | LIST_REMOVE(clp, lc_hash); | ||||
nfsrv_cleanclient(clp, p); | nfsrv_cleanclient(clp, p); | ||||
nfsrv_freedeleglist(&clp->lc_deleg); | nfsrv_freedeleglist(&clp->lc_deleg); | ||||
Context not available. | |||||
LIST_INIT(&new_clp->lc_deleg); | LIST_INIT(&new_clp->lc_deleg); | ||||
LIST_INIT(&new_clp->lc_olddeleg); | LIST_INIT(&new_clp->lc_olddeleg); | ||||
LIST_INIT(&new_clp->lc_session); | LIST_INIT(&new_clp->lc_session); | ||||
for (i = 0; i < NFSSTATEHASHSIZE; i++) | for (i = 0; i < nfsrv_statehashsize; i++) | ||||
LIST_INIT(&new_clp->lc_stateid[i]); | LIST_INIT(&new_clp->lc_stateid[i]); | ||||
LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, | LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, | ||||
lc_hash); | lc_hash); | ||||
Context not available. | |||||
ls_list); | ls_list); | ||||
LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) | LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) | ||||
tstp->ls_clp = new_clp; | tstp->ls_clp = new_clp; | ||||
for (i = 0; i < NFSSTATEHASHSIZE; i++) { | for (i = 0; i < nfsrv_statehashsize; i++) { | ||||
LIST_NEWHEAD(&new_clp->lc_stateid[i], | LIST_NEWHEAD(&new_clp->lc_stateid[i], | ||||
&clp->lc_stateid[i], ls_hash); | &clp->lc_stateid[i], ls_hash); | ||||
LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) | LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) | ||||
Context not available. | |||||
LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list); | LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list); | ||||
LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) | LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) | ||||
tstp->ls_clp = new_clp; | tstp->ls_clp = new_clp; | ||||
for (i = 0; i < NFSSTATEHASHSIZE; i++) { | for (i = 0; i < nfsrv_statehashsize; i++) { | ||||
LIST_NEWHEAD(&new_clp->lc_stateid[i], | LIST_NEWHEAD(&new_clp->lc_stateid[i], | ||||
&clp->lc_stateid[i], ls_hash); | &clp->lc_stateid[i], ls_hash); | ||||
LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) | LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash) | ||||
Context not available. | |||||
if (!error && (opflags & CLOPS_RENEWOP)) { | if (!error && (opflags & CLOPS_RENEWOP)) { | ||||
if (nfsrv_notsamecredname(nd, clp)) { | if (nfsrv_notsamecredname(nd, clp)) { | ||||
doneok = 0; | doneok = 0; | ||||
for (i = 0; i < NFSSTATEHASHSIZE && doneok == 0; i++) { | for (i = 0; i < nfsrv_statehashsize && doneok == 0; i++) { | ||||
LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { | LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { | ||||
if ((stp->ls_flags & NFSLCK_OPEN) && | if ((stp->ls_flags & NFSLCK_OPEN) && | ||||
stp->ls_uid == nd->nd_cred->cr_uid) { | stp->ls_uid == nd->nd_cred->cr_uid) { | ||||
Context not available. | |||||
} | } | ||||
/* Scan for state on the clientid. */ | /* Scan for state on the clientid. */ | ||||
for (i = 0; i < NFSSTATEHASHSIZE; i++) | for (i = 0; i < nfsrv_statehashsize; i++) | ||||
if (!LIST_EMPTY(&clp->lc_stateid[i])) { | if (!LIST_EMPTY(&clp->lc_stateid[i])) { | ||||
NFSLOCKV4ROOTMUTEX(); | NFSLOCKV4ROOTMUTEX(); | ||||
nfsv4_unlock(&nfsv4rootfs_lock, 1); | nfsv4_unlock(&nfsv4rootfs_lock, 1); | ||||
Context not available. | |||||
* Search for a match in the client list. | * Search for a match in the client list. | ||||
*/ | */ | ||||
gotit = i = 0; | gotit = i = 0; | ||||
while (i < NFSCLIENTHASHSIZE && !gotit) { | while (i < nfsrv_clienthashsize && !gotit) { | ||||
LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { | LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { | ||||
if (revokep->nclid_idlen == clp->lc_idlen && | if (revokep->nclid_idlen == clp->lc_idlen && | ||||
!NFSBCMP(revokep->nclid_id, clp->lc_id, clp->lc_idlen)) { | !NFSBCMP(revokep->nclid_id, clp->lc_id, clp->lc_idlen)) { | ||||
Context not available. | |||||
/* | /* | ||||
* Rattle through the client lists until done. | * Rattle through the client lists until done. | ||||
*/ | */ | ||||
while (i < NFSCLIENTHASHSIZE && cnt < maxcnt) { | while (i < nfsrv_clienthashsize && cnt < maxcnt) { | ||||
clp = LIST_FIRST(&nfsclienthash[i]); | clp = LIST_FIRST(&nfsclienthash[i]); | ||||
while (clp != LIST_END(&nfsclienthash[i]) && cnt < maxcnt) { | while (clp != LIST_END(&nfsclienthash[i]) && cnt < maxcnt) { | ||||
nfsrv_dumpaclient(clp, &dumpp[cnt]); | nfsrv_dumpaclient(clp, &dumpp[cnt]); | ||||
Context not available. | |||||
/* | /* | ||||
* For each client... | * For each client... | ||||
*/ | */ | ||||
for (i = 0; i < NFSCLIENTHASHSIZE; i++) { | for (i = 0; i < nfsrv_clienthashsize; i++) { | ||||
clp = LIST_FIRST(&nfsclienthash[i]); | clp = LIST_FIRST(&nfsclienthash[i]); | ||||
while (clp != LIST_END(&nfsclienthash[i])) { | while (clp != LIST_END(&nfsclienthash[i])) { | ||||
nclp = LIST_NEXT(clp, lc_hash); | nclp = LIST_NEXT(clp, lc_hash); | ||||
Context not available. | |||||
nfsrv_clients > nfsrv_clienthighwater)) || | nfsrv_clients > nfsrv_clienthighwater)) || | ||||
(clp->lc_expiry + NFSRV_MOULDYLEASE) < NFSD_MONOSEC || | (clp->lc_expiry + NFSRV_MOULDYLEASE) < NFSD_MONOSEC || | ||||
(clp->lc_expiry < NFSD_MONOSEC && | (clp->lc_expiry < NFSD_MONOSEC && | ||||
(nfsrv_openpluslock * 10 / 9) > NFSRV_V4STATELIMIT)) { | (nfsrv_openpluslock * 10 / 9) > nfsrv_v4statelimit)) { | ||||
/* | /* | ||||
* Lease has expired several nfsrv_lease times ago: | * Lease has expired several nfsrv_lease times ago: | ||||
* PLUS | * PLUS | ||||
Context not available. | |||||
stp->ls_noopens++; | stp->ls_noopens++; | ||||
if (stp->ls_noopens > NFSNOOPEN || | if (stp->ls_noopens > NFSNOOPEN || | ||||
(nfsrv_openpluslock * 2) > | (nfsrv_openpluslock * 2) > | ||||
NFSRV_V4STATELIMIT) | nfsrv_v4statelimit) | ||||
nfsrv_stablefirst.nsf_flags |= | nfsrv_stablefirst.nsf_flags |= | ||||
NFSNSF_NOOPENS; | NFSNSF_NOOPENS; | ||||
} else { | } else { | ||||
Context not available. | |||||
* Check for state resource limit exceeded. | * Check for state resource limit exceeded. | ||||
*/ | */ | ||||
if ((new_stp->ls_flags & NFSLCK_LOCK) && | if ((new_stp->ls_flags & NFSLCK_LOCK) && | ||||
nfsrv_openpluslock > NFSRV_V4STATELIMIT) { | nfsrv_openpluslock > nfsrv_v4statelimit) { | ||||
error = NFSERR_RESOURCE; | error = NFSERR_RESOURCE; | ||||
goto out; | goto out; | ||||
} | } | ||||
Context not available. | |||||
* returns NFSERR_RESOURCE and the limit is just a rather | * returns NFSERR_RESOURCE and the limit is just a rather | ||||
* arbitrary high water mark, so no harm is done. | * arbitrary high water mark, so no harm is done. | ||||
*/ | */ | ||||
if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { | if (nfsrv_openpluslock > nfsrv_v4statelimit) { | ||||
error = NFSERR_RESOURCE; | error = NFSERR_RESOURCE; | ||||
goto out; | goto out; | ||||
} | } | ||||
Context not available. | |||||
*/ | */ | ||||
min_index = 0; | min_index = 0; | ||||
max_index = 0xffffffff; | max_index = 0xffffffff; | ||||
for (i = 0; i < NFSSTATEHASHSIZE; i++) { | for (i = 0; i < nfsrv_statehashsize; i++) { | ||||
LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { | LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { | ||||
if (stp->ls_stateid.other[2] > 0x80000000) { | if (stp->ls_stateid.other[2] > 0x80000000) { | ||||
if (stp->ls_stateid.other[2] < max_index) | if (stp->ls_stateid.other[2] < max_index) | ||||
Context not available. | |||||
* cleanest way to code the loop.) | * cleanest way to code the loop.) | ||||
*/ | */ | ||||
tryagain: | tryagain: | ||||
for (i = 0; i < NFSSTATEHASHSIZE; i++) { | for (i = 0; i < nfsrv_statehashsize; i++) { | ||||
LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { | LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { | ||||
if (stp->ls_stateid.other[2] == canuse) { | if (stp->ls_stateid.other[2] == canuse) { | ||||
canuse++; | canuse++; | ||||
Context not available. | |||||
/* | /* | ||||
* For each client... | * For each client... | ||||
*/ | */ | ||||
for (i = 0; i < NFSCLIENTHASHSIZE; i++) { | for (i = 0; i < nfsrv_clienthashsize; i++) { | ||||
LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { | LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { | ||||
LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) { | LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) { | ||||
if (LIST_EMPTY(&stp->ls_open) && | if (LIST_EMPTY(&stp->ls_open) && | ||||
(stp->ls_noopens > NFSNOOPEN || | (stp->ls_noopens > NFSNOOPEN || | ||||
(nfsrv_openpluslock * 2) > | (nfsrv_openpluslock * 2) > | ||||
NFSRV_V4STATELIMIT)) | nfsrv_v4statelimit)) | ||||
nfsrv_freeopenowner(stp, 0, p); | nfsrv_freeopenowner(stp, 0, p); | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
/* | /* | ||||
* For each client, clean out the state and then free the structure. | * For each client, clean out the state and then free the structure. | ||||
*/ | */ | ||||
for (i = 0; i < NFSCLIENTHASHSIZE; i++) { | for (i = 0; i < nfsrv_clienthashsize; i++) { | ||||
LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { | LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { | ||||
nfsrv_cleanclient(clp, p); | nfsrv_cleanclient(clp, p); | ||||
nfsrv_freedeleglist(&clp->lc_deleg); | nfsrv_freedeleglist(&clp->lc_deleg); | ||||
Context not available. | |||||
/* | /* | ||||
* Also, free up any remaining lock file structures. | * Also, free up any remaining lock file structures. | ||||
*/ | */ | ||||
for (i = 0; i < NFSLOCKHASHSIZE; i++) { | for (i = 0; i < nfsrv_lockhashsize; i++) { | ||||
LIST_FOREACH_SAFE(lfp, &nfslockhash[i], lf_hash, nlfp) { | LIST_FOREACH_SAFE(lfp, &nfslockhash[i], lf_hash, nlfp) { | ||||
printf("nfsd unload: fnd a lock file struct\n"); | printf("nfsd unload: fnd a lock file struct\n"); | ||||
nfsrv_freenfslockfile(lfp); | nfsrv_freenfslockfile(lfp); | ||||
Context not available. |