recovery: avoid delegation_return_lru() on delegation recovery

the namecache/delegation feedback code in nfs41_ops.c:open_update_cache() is interfering with delegation recovery.  if its call to nfs41_name_cache_insert() fails with ERROR_TOO_MANY_OPEN_FILES, the delegation is returned instead of being recovered.  this shouldn't happen during recovery, because we're replacing a delegation rather than adding a new one

nfs41_open() now remembers whether we already had a delegation.  if we did, open_update_cache() will pass OPEN_DELEGATE_NONE to nfs41_name_cache_insert() to prevent it from returning ERROR_TOO_MANY_OPEN_FILES.  if we didn't already have a delegation, the nfs41_delegreturn() needs to be called with the same try_recovery flag from nfs41_open()

Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
Casey Bodley 2011-11-04 13:50:01 -04:00 committed by unknown
parent f988c89bf4
commit 68252b6522
2 changed files with 28 additions and 26 deletions

View file

@ -306,7 +306,8 @@ out:
static void open_delegation_return(
IN nfs41_session *session,
IN nfs41_path_fh *file,
IN open_delegation4 *delegation)
IN open_delegation4 *delegation,
IN bool_t try_recovery)
{
stateid_arg stateid;
int status;
@ -321,7 +322,7 @@ static void open_delegation_return(
stateid.type = STATEID_DELEG_FILE;
memcpy(&stateid.stateid, &delegation->stateid, sizeof(stateid4));
status = nfs41_delegreturn(session, file, &stateid, TRUE);
status = nfs41_delegreturn(session, file, &stateid, try_recovery);
/* clear the delegation type returned by nfs41_open() */
delegation->type = OPEN_DELEGATE_NONE;
@ -331,12 +332,16 @@ static void open_update_cache(
IN nfs41_session *session,
IN nfs41_path_fh *parent,
IN nfs41_path_fh *file,
IN bool_t try_recovery,
IN open_delegation4 *delegation,
IN bool_t already_delegated,
IN change_info4 *changeinfo,
IN nfs41_getattr_res *dir_attrs,
IN nfs41_getattr_res *file_attrs)
{
struct nfs41_name_cache *cache = session_name_cache(session);
enum open_delegation_type4 delegation_type =
already_delegated ? OPEN_DELEGATE_NONE : delegation->type;
uint32_t status;
/* update the attributes of the parent directory */
@ -350,7 +355,7 @@ static void open_update_cache(
retry_cache_insert:
AcquireSRWLockShared(&file->path->lock);
status = nfs41_name_cache_insert(cache, file->path->path, &file->name,
&file->fh, file_attrs->info, changeinfo, delegation->type);
&file->fh, file_attrs->info, changeinfo, delegation_type);
ReleaseSRWLockShared(&file->path->lock);
if (status == ERROR_TOO_MANY_OPEN_FILES) {
@ -364,7 +369,7 @@ retry_cache_insert:
if (status && delegation->type != OPEN_DELEGATE_NONE) {
/* if we can't make room in the cache, return this
* delegation immediately to free resources on the server */
open_delegation_return(session, file, delegation);
open_delegation_return(session, file, delegation, try_recovery);
goto retry_cache_insert;
}
}
@ -403,6 +408,8 @@ int nfs41_open(
nfs41_restorefh_res restorefh_res;
nfs41_file_info tmp_info, dir_info;
bool_t current_fh_is_dir;
bool_t already_delegated = delegation->type == OPEN_DELEGATE_READ
|| delegation->type == OPEN_DELEGATE_WRITE;
/* depending on the claim type, OPEN expects CURRENT_FH set
* to either the parent directory, or to the file itself */
@ -522,8 +529,8 @@ int nfs41_open(
nfs41_superblock_space_changed(file->fh.superblock);
/* update the name/attr cache with the results */
open_update_cache(session, parent, file, delegation,
&open_res.resok4.cinfo, &pgetattr_res, &getattr_res);
open_update_cache(session, parent, file, try_recovery, delegation,
already_delegated, &open_res.resok4.cinfo, &pgetattr_res, &getattr_res);
out:
return status;
}

View file

@ -78,14 +78,13 @@ static int recover_open_grace(
IN state_owner4 *owner,
IN uint32_t access,
IN uint32_t deny,
IN enum open_delegation_type4 delegate_type,
OUT stateid4 *stateid,
OUT open_delegation4 *delegation)
{
/* reclaim the open stateid with CLAIM_PREVIOUS */
open_claim4 claim;
claim.claim = CLAIM_PREVIOUS;
claim.u.prev.delegate_type = delegate_type;
claim.u.prev.delegate_type = delegation->type;
return nfs41_open(session, parent, file, owner, &claim, access, deny,
OPEN4_NOCREATE, 0, 0, FALSE, stateid, delegation, NULL);
@ -98,14 +97,13 @@ static int recover_open_no_grace(
IN state_owner4 *owner,
IN uint32_t access,
IN uint32_t deny,
IN enum open_delegation_type4 delegate_type,
OUT stateid4 *stateid,
OUT open_delegation4 *delegation)
{
open_claim4 claim;
int status;
if (delegate_type != OPEN_DELEGATE_NONE) {
if (delegation->type != OPEN_DELEGATE_NONE) {
/* attempt out-of-grace recovery with CLAIM_DELEGATE_PREV */
claim.claim = CLAIM_DELEGATE_PREV;
claim.u.deleg_prev.filename = &file->name;
@ -125,9 +123,9 @@ static int recover_open_no_grace(
claim.u.null.filename = &file->name;
/* ask nicely for the delegation we had */
if (delegate_type == OPEN_DELEGATE_READ)
if (delegation->type == OPEN_DELEGATE_READ)
access |= OPEN4_SHARE_ACCESS_WANT_READ_DELEG;
else if (delegate_type == OPEN_DELEGATE_WRITE)
else if (delegation->type == OPEN_DELEGATE_WRITE)
access |= OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG;
status = nfs41_open(session, parent, file, owner,
@ -144,7 +142,6 @@ static int recover_open(
{
open_delegation4 delegation = { 0 };
stateid4 stateid = { 0 };
enum open_delegation_type4 delegate_type = OPEN_DELEGATE_NONE;
int status = NFS4ERR_BADHANDLE;
/* check for an associated delegation */
@ -154,7 +151,7 @@ static int recover_open(
if (deleg->revoked) {
/* reclaim the delegation along with the open */
AcquireSRWLockShared(&deleg->lock);
delegate_type = deleg->state.type;
delegation.type = deleg->state.type;
ReleaseSRWLockShared(&deleg->lock);
} else if (deleg->state.recalled) {
/* we'll need an open stateid regardless */
@ -173,7 +170,7 @@ static int recover_open(
if (*grace)
status = recover_open_grace(session, &open->parent, &open->file,
&open->owner, open->share_access, open->share_deny,
delegate_type, &stateid, &delegation);
&stateid, &delegation);
else
status = NFS4ERR_NO_GRACE;
@ -181,7 +178,7 @@ static int recover_open(
*grace = FALSE;
status = recover_open_no_grace(session, &open->parent, &open->file,
&open->owner, open->share_access, open->share_deny,
delegate_type, &stateid, &delegation);
&stateid, &delegation);
}
if (status)
goto out;
@ -276,15 +273,14 @@ static int recover_delegation_want(
{
deleg_claim4 claim;
open_delegation4 delegation = { 0 };
enum open_delegation_type4 delegate_type;
uint32_t want_flags = 0;
int status = NFS4_OK;
AcquireSRWLockShared(&deleg->lock);
delegate_type = deleg->state.type;
delegation.type = deleg->state.type;
ReleaseSRWLockShared(&deleg->lock);
if (delegate_type == OPEN_DELEGATE_READ)
if (delegation.type == OPEN_DELEGATE_READ)
want_flags |= OPEN4_SHARE_ACCESS_WANT_READ_DELEG;
else
want_flags |= OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG;
@ -292,7 +288,7 @@ static int recover_delegation_want(
if (*grace) {
/* recover the delegation with WANT_DELEGATION/CLAIM_PREVIOUS */
claim.claim = CLAIM_PREVIOUS;
claim.prev_delegate_type = delegate_type;
claim.prev_delegate_type = delegation.type;
status = nfs41_want_delegation(session, &deleg->file, &claim,
want_flags, FALSE, &delegation);
@ -336,13 +332,12 @@ static int recover_delegation_open(
stateid_arg stateid;
uint32_t access = OPEN4_SHARE_ACCESS_READ;
uint32_t deny = OPEN4_SHARE_DENY_NONE;
enum open_delegation_type4 delegate_type = OPEN_DELEGATE_NONE;
int status = NFS4_OK;
/* choose the desired access mode based on delegation type */
AcquireSRWLockShared(&deleg->lock);
delegate_type = deleg->state.type;
if (delegate_type == OPEN_DELEGATE_WRITE)
delegation.type = deleg->state.type;
if (delegation.type == OPEN_DELEGATE_WRITE)
access |= OPEN4_SHARE_ACCESS_WRITE | OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG;
else
access |= OPEN4_SHARE_ACCESS_WANT_READ_DELEG;
@ -356,14 +351,14 @@ static int recover_delegation_open(
if (*grace)
status = recover_open_grace(session, &deleg->parent, &deleg->file,
&owner, access, deny, delegate_type, &stateid.stateid, &delegation);
&owner, access, deny, &stateid.stateid, &delegation);
else
status = NFS4ERR_NO_GRACE;
if (status == NFS4ERR_NO_GRACE) {
*grace = FALSE;
status = recover_open_no_grace(session, &deleg->parent, &deleg->file,
&owner, access, deny, delegate_type, &stateid.stateid, &delegation);
&owner, access, deny, &stateid.stateid, &delegation);
}
if (status)
goto out;