recovery: use normal OPEN/LOCK on ERR_NO_GRACE
if we see NFS4ERR_NO_GRACE from recovery operations, it means we lost our state due to a lease expiration rather than a server reboot. in this case, it's possible that conflicting locks were granted to other clients, so we have to try normal OPEN/LOCK operations to recover our state. because they're sent during recovery, nfs41_open() and nfs41_lock() take a new 'bool_t try_recovery' argument so we can avoid recursion if these operations fail due to conflicting locks, we have no choice but to return errors to the application. using a stateid that was revoked due to lease expiration results in NFS4ERR_EXPIRED, and we map this error to ERROR_FILE_INVALID: The volume for a file has been externally altered so that the opened file is no longer valid. Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
parent
222c1bf020
commit
0a309c4350
8 changed files with 46 additions and 17 deletions
|
|
@ -163,7 +163,7 @@ static int handle_lock(nfs41_upcall *upcall)
|
|||
nfs41_lock_stateid_arg(state, &stateid);
|
||||
|
||||
status = nfs41_lock(state->session, &state->file, &state->owner,
|
||||
type, args->offset, args->length, 0, &stateid);
|
||||
type, args->offset, args->length, FALSE, TRUE, &stateid);
|
||||
if (status) {
|
||||
dprintf(LKLVL, "nfs41_lock failed with %s\n",
|
||||
nfs_error_string(status));
|
||||
|
|
|
|||
|
|
@ -135,13 +135,24 @@ static int recover_open(
|
|||
/* reclaim the open stateid */
|
||||
status = nfs41_open_reclaim(session, &open->parent, &open->file,
|
||||
&open->owner, open->share_access, open->share_deny, &stateid.stateid);
|
||||
|
||||
if (status == NFS4_OK) {
|
||||
/* update the open stateid on success */
|
||||
memcpy(&open->stateid, &stateid.stateid, sizeof(stateid4));
|
||||
|
||||
} else if (status == NFS4ERR_NO_GRACE) {
|
||||
dprintf(1, "not in grace period, retrying a normal open\n");
|
||||
status = nfs41_open(session, open->share_access,
|
||||
open->share_deny, OPEN4_NOCREATE, 0, FALSE, open, NULL);
|
||||
|
||||
/* update the stateid arg with the new open->stateid */
|
||||
memcpy(&stateid.stateid, &open->stateid, sizeof(stateid4));
|
||||
}
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
AcquireSRWLockExclusive(&open->lock);
|
||||
|
||||
/* update the open stateid */
|
||||
memcpy(&open->stateid, &stateid.stateid, sizeof(stateid4));
|
||||
stateid.type = STATEID_OPEN;
|
||||
stateid.open = open;
|
||||
|
||||
|
|
@ -149,7 +160,12 @@ static int recover_open(
|
|||
list_for_each(entry, &open->locks.list) {
|
||||
lock = list_container(entry, nfs41_lock_state, open_entry);
|
||||
status = nfs41_lock(session, &open->file, &open->owner,
|
||||
lock->type, lock->offset, lock->length, TRUE, &stateid);
|
||||
lock->type, lock->offset, lock->length, TRUE, FALSE, &stateid);
|
||||
if (status == NFS4ERR_NO_GRACE) {
|
||||
dprintf(1, "not in grace period, retrying a normal lock\n");
|
||||
status = nfs41_lock(session, &open->file, &open->owner,
|
||||
lock->type, lock->offset, lock->length, FALSE, FALSE, &stateid);
|
||||
}
|
||||
if (status == NFS4ERR_BADSESSION)
|
||||
break;
|
||||
}
|
||||
|
|
@ -306,12 +322,15 @@ restart_recovery:
|
|||
recovery_finish(session->client);
|
||||
goto do_retry;
|
||||
|
||||
case NFS4ERR_STALE_STATEID:
|
||||
case NFS4ERR_EXPIRED: /* revoked by lease expiration */
|
||||
case NFS4ERR_STALE_STATEID: /* server reboot */
|
||||
if (compound->args.argarray[0].op == OP_SEQUENCE) {
|
||||
nfs41_sequence_args *seq = (nfs41_sequence_args*)
|
||||
compound->args.argarray[0].arg;
|
||||
nfs41_session_free_slot(session, seq->sa_slotid);
|
||||
}
|
||||
if (!try_recovery)
|
||||
goto out;
|
||||
{
|
||||
nfs_argop4 *argop = &compound->args.argarray[
|
||||
compound->res.resarray_count-1];
|
||||
|
|
|
|||
|
|
@ -295,8 +295,9 @@ int nfs41_open(
|
|||
IN uint32_t deny,
|
||||
IN uint32_t create,
|
||||
IN uint32_t mode,
|
||||
IN bool_t try_recovery,
|
||||
IN OUT nfs41_open_state *state,
|
||||
OUT nfs41_file_info *info)
|
||||
OUT OPTIONAL nfs41_file_info *info)
|
||||
{
|
||||
int status;
|
||||
nfs41_compound compound;
|
||||
|
|
@ -314,7 +315,10 @@ int nfs41_open(
|
|||
nfs41_getattr_res getattr_res, pgetattr_res;
|
||||
nfs41_savefh_res savefh_res;
|
||||
nfs41_restorefh_res restorefh_res;
|
||||
nfs41_file_info dir_info;
|
||||
nfs41_file_info tmp_info, dir_info;
|
||||
|
||||
if (info == NULL)
|
||||
info = &tmp_info;
|
||||
|
||||
init_getattr_request(&attr_request);
|
||||
attr_request.arr[0] |= FATTR4_WORD0_FSID | FATTR4_WORD0_FILEID;
|
||||
|
|
@ -367,7 +371,7 @@ int nfs41_open(
|
|||
pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT;
|
||||
pgetattr_res.info = &dir_info;
|
||||
|
||||
status = compound_encode_send_decode(session, &compound, TRUE);
|
||||
status = compound_encode_send_decode(session, &compound, try_recovery);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
|
|
@ -867,6 +871,7 @@ int nfs41_lock(
|
|||
IN uint64_t offset,
|
||||
IN uint64_t length,
|
||||
IN bool_t reclaim,
|
||||
IN bool_t try_recovery,
|
||||
IN OUT stateid_arg *stateid)
|
||||
{
|
||||
int status;
|
||||
|
|
@ -910,7 +915,7 @@ int nfs41_lock(
|
|||
lock_res.u.resok4.lock_stateid = &stateid->stateid;
|
||||
lock_res.u.denied.owner.owner_len = NFS4_OPAQUE_LIMIT;
|
||||
|
||||
status = compound_encode_send_decode(session, &compound, !reclaim);
|
||||
status = compound_encode_send_decode(session, &compound, try_recovery);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -915,8 +915,9 @@ int nfs41_open(
|
|||
IN uint32_t deny,
|
||||
IN uint32_t create,
|
||||
IN uint32_t mode,
|
||||
IN bool_t try_recovery,
|
||||
IN OUT nfs41_open_state *state,
|
||||
OUT nfs41_file_info *info);
|
||||
OUT OPTIONAL nfs41_file_info *info);
|
||||
|
||||
int nfs41_open_reclaim(
|
||||
IN nfs41_session *session,
|
||||
|
|
@ -976,6 +977,7 @@ int nfs41_lock(
|
|||
IN uint64_t offset,
|
||||
IN uint64_t length,
|
||||
IN bool_t reclaim,
|
||||
IN bool_t try_recovery,
|
||||
IN OUT stateid_arg *stateid);
|
||||
|
||||
int nfs41_unlock(
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ static int handle_open(nfs41_upcall *upcall)
|
|||
args->created = status == NFS4_OK ? TRUE : FALSE;
|
||||
} else {
|
||||
status = nfs41_open(state->session, state->share_access,
|
||||
state->share_deny, create, args->mode, state, &info);
|
||||
state->share_deny, create, args->mode, TRUE, state, &info);
|
||||
|
||||
if (status == NFS4_OK) {
|
||||
/* add to the client's list of state for recovery */
|
||||
|
|
|
|||
|
|
@ -440,14 +440,14 @@ static int handle_setattr(nfs41_upcall *upcall)
|
|||
case FileEndOfFileInformation:
|
||||
if (!state->do_close) {
|
||||
// get a stateid
|
||||
uint32_t allow = 0, deny = 0;
|
||||
StringCchPrintfA((LPSTR)state->owner.owner, NFS4_OPAQUE_LIMIT,
|
||||
"%u", args->open_owner_id);
|
||||
state->owner.owner_len = (uint32_t)strlen(
|
||||
(const char*)state->owner.owner);
|
||||
map_access_2_allowdeny(args->access_mask, args->access_mode, &allow, &deny);
|
||||
status = nfs41_open(state->session, allow, deny,
|
||||
OPEN4_NOCREATE, 0, state, NULL);
|
||||
map_access_2_allowdeny(args->access_mask, args->access_mode,
|
||||
&state->share_access, &state->share_deny);
|
||||
status = nfs41_open(state->session, state->share_access,
|
||||
state->share_deny, OPEN4_NOCREATE, 0, TRUE, state, NULL);
|
||||
if (status) {
|
||||
dprintf(1, "nfs41_open() failed with %s\n", nfs_error_string(status));
|
||||
status = nfs_to_windows_error(status, ERROR_FILE_NOT_FOUND);
|
||||
|
|
|
|||
|
|
@ -316,6 +316,7 @@ int nfs_to_windows_error(int status, int default_error)
|
|||
case NFS4ERR_SYMLINK:
|
||||
case NFS4ERR_WRONG_TYPE: return ERROR_INVALID_PARAMETER;
|
||||
|
||||
case NFS4ERR_EXPIRED:
|
||||
case NFS4ERR_NOFILEHANDLE:
|
||||
case NFS4ERR_OLD_STATEID:
|
||||
case NFS4ERR_BAD_STATEID:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue