NFSv4: Fail I/O if the state recovery fails irrevocably
If state recovery fails with an ESTALE or a ENOENT, then we shouldn't keep retrying. Instead, mark the stateid as being invalid and fail the I/O with an EIO error. For other operations such as POSIX and BSD file locking, truncate etc, fail with an EBADF to indicate that this file descriptor is no longer valid. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
@@ -295,7 +295,9 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
|
||||
}
|
||||
if (state == NULL)
|
||||
break;
|
||||
nfs4_schedule_stateid_recovery(server, state);
|
||||
ret = nfs4_schedule_stateid_recovery(server, state);
|
||||
if (ret < 0)
|
||||
break;
|
||||
goto wait_on_recovery;
|
||||
case -NFS4ERR_DELEG_REVOKED:
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
@@ -303,11 +305,16 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
|
||||
if (state == NULL)
|
||||
break;
|
||||
nfs_remove_bad_delegation(state->inode);
|
||||
nfs4_schedule_stateid_recovery(server, state);
|
||||
ret = nfs4_schedule_stateid_recovery(server, state);
|
||||
if (ret < 0)
|
||||
break;
|
||||
goto wait_on_recovery;
|
||||
case -NFS4ERR_EXPIRED:
|
||||
if (state != NULL)
|
||||
nfs4_schedule_stateid_recovery(server, state);
|
||||
if (state != NULL) {
|
||||
ret = nfs4_schedule_stateid_recovery(server, state);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
nfs4_schedule_lease_recovery(clp);
|
||||
@@ -2053,7 +2060,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
||||
|
||||
nfs_fattr_init(fattr);
|
||||
|
||||
if (state != NULL) {
|
||||
if (state != NULL && nfs4_valid_open_stateid(state)) {
|
||||
struct nfs_lockowner lockowner = {
|
||||
.l_owner = current->files,
|
||||
.l_pid = current->tgid,
|
||||
@@ -2201,6 +2208,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
||||
calldata->arg.fmode &= ~FMODE_WRITE;
|
||||
}
|
||||
}
|
||||
if (!nfs4_valid_open_stateid(state))
|
||||
call_close = 0;
|
||||
spin_unlock(&state->owner->so_lock);
|
||||
|
||||
if (!call_close) {
|
||||
@@ -3980,11 +3989,14 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
|
||||
case -NFS4ERR_OPENMODE:
|
||||
if (state == NULL)
|
||||
break;
|
||||
nfs4_schedule_stateid_recovery(server, state);
|
||||
if (nfs4_schedule_stateid_recovery(server, state) < 0)
|
||||
goto stateid_invalid;
|
||||
goto wait_on_recovery;
|
||||
case -NFS4ERR_EXPIRED:
|
||||
if (state != NULL)
|
||||
nfs4_schedule_stateid_recovery(server, state);
|
||||
if (state != NULL) {
|
||||
if (nfs4_schedule_stateid_recovery(server, state) < 0)
|
||||
goto stateid_invalid;
|
||||
}
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
nfs4_schedule_lease_recovery(clp);
|
||||
@@ -4016,6 +4028,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
|
||||
}
|
||||
task->tk_status = nfs4_map_errors(task->tk_status);
|
||||
return 0;
|
||||
stateid_invalid:
|
||||
task->tk_status = -EIO;
|
||||
return 0;
|
||||
wait_on_recovery:
|
||||
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
|
||||
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
|
||||
@@ -4632,12 +4647,18 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
|
||||
data->res.open_seqid = data->arg.open_seqid;
|
||||
} else
|
||||
data->arg.new_lock_owner = 0;
|
||||
if (!nfs4_valid_open_stateid(state)) {
|
||||
data->rpc_status = -EBADF;
|
||||
task->tk_action = NULL;
|
||||
goto out_release_open_seqid;
|
||||
}
|
||||
data->timestamp = jiffies;
|
||||
if (nfs4_setup_sequence(data->server,
|
||||
&data->arg.seq_args,
|
||||
&data->res.seq_res,
|
||||
task) == 0)
|
||||
return;
|
||||
out_release_open_seqid:
|
||||
nfs_release_seqid(data->arg.open_seqid);
|
||||
out_release_lock_seqid:
|
||||
nfs_release_seqid(data->arg.lock_seqid);
|
||||
|
Reference in New Issue
Block a user