namecache: limit the number of delegations

to prevent delegations from claiming all available slots in the attribute cache, nfs41_name_cache_insert() now returns ERROR_TOO_MANY_OPEN_FILES when the number of delegated entries reaches 50% of the cache capacity.  see comment 'delegations and cache feedback' in name_cache.c for details

when nfs41_open() sees this error from nfs41_name_cache_insert(), it calls new function nfs41_client_delegation_return_lru() to return the least-recently-used delegation and, if successful, loops back to nfs41_name_cache_insert().  nfs41_client_delegation_return_lru() returns NFS4ERR_BADHANDLE if all delegations are currently in use (associated with an existing open), in which case nfs41_open() returns the newly-granted delegation

Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
Casey Bodley 2011-08-19 12:04:30 -04:00 committed by unknown
parent a0d4403a99
commit 7b07dcebb8
4 changed files with 145 additions and 27 deletions

View file

@ -301,7 +301,6 @@ out:
return status;
}
/* open delegation */
int nfs41_delegation_granted(
IN nfs41_session *session,
@ -320,8 +319,10 @@ int nfs41_delegation_granted(
delegation->type != OPEN_DELEGATE_WRITE)
goto out;
if (delegation->recalled)
if (delegation->recalled) {
status = NFS4ERR_DELEG_REVOKED;
goto out_return;
}
/* allocate the delegation state */
status = delegation_create(parent, file, delegation, &state);
@ -398,8 +399,13 @@ static int delegation_find(
EnterCriticalSection(&client->state.lock);
entry = list_search(&client->state.delegations, value, cmp);
if (entry) {
/* return a reference to the delegation */
*deleg_out = deleg_entry(entry);
nfs41_delegation_ref(*deleg_out);
/* move to the 'most recently used' end of the list */
list_remove(entry);
list_add_tail(&client->state.delegations, entry);
status = NFS4_OK;
}
LeaveCriticalSection(&client->state.lock);
@ -718,6 +724,7 @@ out_deleg:
goto out;
}
void nfs41_client_delegation_free(
IN nfs41_client *client)
{
@ -790,3 +797,40 @@ int nfs41_client_delegation_recovery(
out:
return status;
}
int nfs41_client_delegation_return_lru(
IN nfs41_client *client)
{
struct list_entry *entry;
nfs41_delegation_state *state = NULL;
int status = NFS4ERR_BADHANDLE;
/* starting from the least recently opened, find a delegation
* that's not 'in use' and return it */
EnterCriticalSection(&client->state.lock);
list_for_each(entry, &client->state.delegations) {
state = deleg_entry(entry);
/* skip if it's currently in use for an open; note that ref_count
* can't go from 1 to 2 without holding client->state.lock */
if (state->ref_count > 1)
continue;
AcquireSRWLockExclusive(&state->lock);
if (state->status == DELEGATION_GRANTED) {
/* start returning the delegation */
state->status = DELEGATION_RETURNING;
status = NFS4ERR_DELEG_REVOKED;
}
ReleaseSRWLockExclusive(&state->lock);
if (status == NFS4ERR_DELEG_REVOKED)
break;
}
LeaveCriticalSection(&client->state.lock);
if (status == NFS4ERR_DELEG_REVOKED)
status = delegation_return(client, state, FALSE, TRUE);
return status;
}