|
@@ -370,11 +370,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
|
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
|
case -NFS4ERR_BAD_STATEID:
|
|
|
- if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) {
|
|
|
- nfs_remove_bad_delegation(inode);
|
|
|
- exception->retry = 1;
|
|
|
- break;
|
|
|
- }
|
|
|
if (state == NULL)
|
|
|
break;
|
|
|
ret = nfs4_schedule_stateid_recovery(server, state);
|
|
@@ -1654,7 +1649,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
|
|
|
nfs_inode_find_state_and_recover(state->inode,
|
|
|
stateid);
|
|
|
nfs4_schedule_stateid_recovery(server, state);
|
|
|
- return 0;
|
|
|
+ return -EAGAIN;
|
|
|
case -NFS4ERR_DELAY:
|
|
|
case -NFS4ERR_GRACE:
|
|
|
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
@@ -2109,46 +2104,60 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state)
|
|
|
+{
|
|
|
+ nfs_remove_bad_delegation(state->inode);
|
|
|
+ write_seqlock(&state->seqlock);
|
|
|
+ nfs4_stateid_copy(&state->stateid, &state->open_stateid);
|
|
|
+ write_sequnlock(&state->seqlock);
|
|
|
+ clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
|
+}
|
|
|
+
|
|
|
+static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
|
|
|
+{
|
|
|
+ if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
|
|
|
+ nfs_finish_clear_delegation_stateid(state);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
|
|
+{
|
|
|
+ /* NFSv4.0 doesn't allow for delegation recovery on open expire */
|
|
|
+ nfs40_clear_delegation_stateid(state);
|
|
|
+ return nfs4_open_expired(sp, state);
|
|
|
+}
|
|
|
+
|
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
|
-static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
|
|
|
+static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(state->inode);
|
|
|
- nfs4_stateid *stateid = &state->stateid;
|
|
|
+ nfs4_stateid stateid;
|
|
|
struct nfs_delegation *delegation;
|
|
|
- struct rpc_cred *cred = NULL;
|
|
|
- int status = -NFS4ERR_BAD_STATEID;
|
|
|
-
|
|
|
- /* If a state reset has been done, test_stateid is unneeded */
|
|
|
- if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
|
|
- return;
|
|
|
+ struct rpc_cred *cred;
|
|
|
+ int status;
|
|
|
|
|
|
/* Get the delegation credential for use by test/free_stateid */
|
|
|
rcu_read_lock();
|
|
|
delegation = rcu_dereference(NFS_I(state->inode)->delegation);
|
|
|
- if (delegation != NULL &&
|
|
|
- nfs4_stateid_match(&delegation->stateid, stateid)) {
|
|
|
- cred = get_rpccred(delegation->cred);
|
|
|
- rcu_read_unlock();
|
|
|
- status = nfs41_test_stateid(server, stateid, cred);
|
|
|
- trace_nfs4_test_delegation_stateid(state, NULL, status);
|
|
|
- } else
|
|
|
+ if (delegation == NULL) {
|
|
|
rcu_read_unlock();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ nfs4_stateid_copy(&stateid, &delegation->stateid);
|
|
|
+ cred = get_rpccred(delegation->cred);
|
|
|
+ rcu_read_unlock();
|
|
|
+ status = nfs41_test_stateid(server, &stateid, cred);
|
|
|
+ trace_nfs4_test_delegation_stateid(state, NULL, status);
|
|
|
|
|
|
if (status != NFS_OK) {
|
|
|
/* Free the stateid unless the server explicitly
|
|
|
* informs us the stateid is unrecognized. */
|
|
|
if (status != -NFS4ERR_BAD_STATEID)
|
|
|
- nfs41_free_stateid(server, stateid, cred);
|
|
|
- nfs_remove_bad_delegation(state->inode);
|
|
|
-
|
|
|
- write_seqlock(&state->seqlock);
|
|
|
- nfs4_stateid_copy(&state->stateid, &state->open_stateid);
|
|
|
- write_sequnlock(&state->seqlock);
|
|
|
- clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
|
+ nfs41_free_stateid(server, &stateid, cred);
|
|
|
+ nfs_finish_clear_delegation_stateid(state);
|
|
|
}
|
|
|
|
|
|
- if (cred != NULL)
|
|
|
- put_rpccred(cred);
|
|
|
+ put_rpccred(cred);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -2192,7 +2201,7 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
|
|
|
{
|
|
|
int status;
|
|
|
|
|
|
- nfs41_clear_delegation_stateid(state);
|
|
|
+ nfs41_check_delegation_stateid(state);
|
|
|
status = nfs41_check_open_stateid(state);
|
|
|
if (status != NFS_OK)
|
|
|
status = nfs4_open_expired(sp, state);
|
|
@@ -2231,19 +2240,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|
|
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
|
|
|
|
|
|
ret = _nfs4_proc_open(opendata);
|
|
|
- if (ret != 0) {
|
|
|
- if (ret == -ENOENT) {
|
|
|
- dentry = opendata->dentry;
|
|
|
- if (dentry->d_inode)
|
|
|
- d_delete(dentry);
|
|
|
- else if (d_unhashed(dentry))
|
|
|
- d_add(dentry, NULL);
|
|
|
-
|
|
|
- nfs_set_verifier(dentry,
|
|
|
- nfs_save_change_attribute(opendata->dir->d_inode));
|
|
|
- }
|
|
|
+ if (ret != 0)
|
|
|
goto out;
|
|
|
- }
|
|
|
|
|
|
state = nfs4_opendata_to_nfs4_state(opendata);
|
|
|
ret = PTR_ERR(state);
|
|
@@ -4841,9 +4839,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
|
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
|
case -NFS4ERR_BAD_STATEID:
|
|
|
- if (state == NULL)
|
|
|
- break;
|
|
|
- nfs_remove_bad_delegation(state->inode);
|
|
|
case -NFS4ERR_OPENMODE:
|
|
|
if (state == NULL)
|
|
|
break;
|
|
@@ -8341,7 +8336,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
|
|
|
static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
|
|
|
.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
|
|
|
.state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
|
|
|
- .recover_open = nfs4_open_expired,
|
|
|
+ .recover_open = nfs40_open_expired,
|
|
|
.recover_lock = nfs4_lock_expired,
|
|
|
.establish_clid = nfs4_init_clientid,
|
|
|
};
|
|
@@ -8408,8 +8403,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
|
|
|
| NFS_CAP_CHANGE_ATTR
|
|
|
| NFS_CAP_POSIX_LOCK
|
|
|
| NFS_CAP_STATEID_NFSV41
|
|
|
- | NFS_CAP_ATOMIC_OPEN_V1
|
|
|
- | NFS_CAP_SEEK,
|
|
|
+ | NFS_CAP_ATOMIC_OPEN_V1,
|
|
|
.init_client = nfs41_init_client,
|
|
|
.shutdown_client = nfs41_shutdown_client,
|
|
|
.match_stateid = nfs41_match_stateid,
|
|
@@ -8431,7 +8425,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
|
|
|
| NFS_CAP_CHANGE_ATTR
|
|
|
| NFS_CAP_POSIX_LOCK
|
|
|
| NFS_CAP_STATEID_NFSV41
|
|
|
- | NFS_CAP_ATOMIC_OPEN_V1,
|
|
|
+ | NFS_CAP_ATOMIC_OPEN_V1
|
|
|
+ | NFS_CAP_SEEK,
|
|
|
.init_client = nfs41_init_client,
|
|
|
.shutdown_client = nfs41_shutdown_client,
|
|
|
.match_stateid = nfs41_match_stateid,
|