diff --git a/daemon/lock.c b/daemon/lock.c index f0de2ce..e2592b1 100644 --- a/daemon/lock.c +++ b/daemon/lock.c @@ -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)); diff --git a/daemon/nfs41_compound.c b/daemon/nfs41_compound.c index e76721e..b706132 100644 --- a/daemon/nfs41_compound.c +++ b/daemon/nfs41_compound.c @@ -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]; diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c index 6fcb7da..50919cd 100644 --- a/daemon/nfs41_ops.c +++ b/daemon/nfs41_ops.c @@ -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; diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h index 5054421..b697c32 100644 --- a/daemon/nfs41_ops.h +++ b/daemon/nfs41_ops.h @@ -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( diff --git a/daemon/open.c b/daemon/open.c index 427c5fc..d4c8b07 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -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 */ diff --git a/daemon/setattr.c b/daemon/setattr.c index 82ed115..367e59a 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -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); diff --git a/daemon/util.c b/daemon/util.c index 55377c6..8d20acf 100644 --- a/daemon/util.c +++ b/daemon/util.c @@ -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: diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 6c6e333..bd7d83b 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -2986,7 +2986,8 @@ static NTSTATUS map_close_errors(DWORD status) switch (status) { case NO_ERROR: return STATUS_SUCCESS; case ERROR_NETNAME_DELETED: return STATUS_NETWORK_NAME_DELETED; - case ERROR_NOT_EMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + case ERROR_NOT_EMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + case ERROR_FILE_INVALID: return STATUS_FILE_INVALID; default: print_error("failed to map windows error %d to NTSTATUS; " "defaulting to STATUS_INTERNAL_ERROR\n", status); @@ -4021,7 +4022,7 @@ static NTSTATUS map_readwrite_errors(DWORD status) switch (status) { case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED; case ERROR_HANDLE_EOF: return STATUS_END_OF_FILE; - case ERROR_FILE_INVALID: return STATUS_FILE_CLOSED; + case ERROR_FILE_INVALID: return STATUS_FILE_INVALID; case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER; case ERROR_LOCK_VIOLATION: return STATUS_FILE_LOCK_CONFLICT; case ERROR_NETWORK_ACCESS_DENIED: return STATUS_NETWORK_ACCESS_DENIED; @@ -4194,6 +4195,7 @@ static NTSTATUS map_lock_errors(DWORD status) case ERROR_ATOMIC_LOCKS_NOT_SUPPORTED: return STATUS_UNSUCCESSFUL; case ERROR_OUTOFMEMORY: return STATUS_INSUFFICIENT_RESOURCES; case ERROR_SHARING_VIOLATION: return STATUS_SHARING_VIOLATION; + case ERROR_FILE_INVALID: return STATUS_FILE_INVALID; /* if we return ERROR_INVALID_PARAMETER, Windows translates that to * success!! */ case ERROR_INVALID_PARAMETER: return STATUS_LOCK_NOT_GRANTED;