Commit 10b9dd56 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-4.9-4' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client bugfixes from Anna Schumaker:
 "Most of these fix regressions or races, but there is one patch for
  stable that Arnd sent me

  Stable bugfix:
   - Hide array-bounds warning

  Bugfixes:
   - Keep a reference on lock states while checking
   - Handle NFS4ERR_OLD_STATEID in nfs4_reclaim_open_state
   - Don't call close if the open stateid has already been cleared
   - Fix CLOSE rases with OPEN
   - Fix a regression in DELEGRETURN"

* tag 'nfs-for-4.9-4' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  NFSv4.x: hide array-bounds warning
  NFSv4.1: Keep a reference on lock states while checking
  NFSv4.1: Handle NFS4ERR_OLD_STATEID in nfs4_reclaim_open_state
  NFSv4: Don't call close if the open stateid has already been cleared
  NFSv4: Fix CLOSE races with OPEN
  NFSv4.1: Fix a regression in DELEGRETURN
parents 4d92c8d0 d55b352b
...@@ -197,7 +197,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, ...@@ -197,7 +197,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
} }
ret = -EPROTONOSUPPORT; ret = -EPROTONOSUPPORT;
if (minorversion == 0) if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
ret = nfs4_callback_up_net(serv, net); ret = nfs4_callback_up_net(serv, net);
else if (xprt->ops->bc_up) else if (xprt->ops->bc_up)
ret = xprt->ops->bc_up(serv, net); ret = xprt->ops->bc_up(serv, net);
......
...@@ -542,6 +542,13 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state) ...@@ -542,6 +542,13 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0; return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0;
} }
static inline bool nfs4_state_match_open_stateid_other(const struct nfs4_state *state,
const nfs4_stateid *stateid)
{
return test_bit(NFS_OPEN_STATE, &state->flags) &&
nfs4_stateid_match_other(&state->open_stateid, stateid);
}
#else #else
#define nfs4_close_state(a, b) do { } while (0) #define nfs4_close_state(a, b) do { } while (0)
......
...@@ -1451,7 +1451,6 @@ static void nfs_resync_open_stateid_locked(struct nfs4_state *state) ...@@ -1451,7 +1451,6 @@ static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
} }
static void nfs_clear_open_stateid_locked(struct nfs4_state *state, static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
nfs4_stateid *arg_stateid,
nfs4_stateid *stateid, fmode_t fmode) nfs4_stateid *stateid, fmode_t fmode)
{ {
clear_bit(NFS_O_RDWR_STATE, &state->flags); clear_bit(NFS_O_RDWR_STATE, &state->flags);
...@@ -1469,10 +1468,9 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state, ...@@ -1469,10 +1468,9 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
} }
if (stateid == NULL) if (stateid == NULL)
return; return;
/* Handle races with OPEN */ /* Handle OPEN+OPEN_DOWNGRADE races */
if (!nfs4_stateid_match_other(arg_stateid, &state->open_stateid) || if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
(nfs4_stateid_match_other(stateid, &state->open_stateid) && !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
!nfs4_stateid_is_newer(stateid, &state->open_stateid))) {
nfs_resync_open_stateid_locked(state); nfs_resync_open_stateid_locked(state);
return; return;
} }
...@@ -1486,7 +1484,9 @@ static void nfs_clear_open_stateid(struct nfs4_state *state, ...@@ -1486,7 +1484,9 @@ static void nfs_clear_open_stateid(struct nfs4_state *state,
nfs4_stateid *stateid, fmode_t fmode) nfs4_stateid *stateid, fmode_t fmode)
{ {
write_seqlock(&state->seqlock); write_seqlock(&state->seqlock);
nfs_clear_open_stateid_locked(state, arg_stateid, stateid, fmode); /* Ignore, if the CLOSE argment doesn't match the current stateid */
if (nfs4_state_match_open_stateid_other(state, arg_stateid))
nfs_clear_open_stateid_locked(state, stateid, fmode);
write_sequnlock(&state->seqlock); write_sequnlock(&state->seqlock);
if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
nfs4_schedule_state_manager(state->owner->so_server->nfs_client); nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
...@@ -2564,15 +2564,23 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state) ...@@ -2564,15 +2564,23 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
static int nfs41_check_expired_locks(struct nfs4_state *state) static int nfs41_check_expired_locks(struct nfs4_state *state)
{ {
int status, ret = NFS_OK; int status, ret = NFS_OK;
struct nfs4_lock_state *lsp; struct nfs4_lock_state *lsp, *prev = NULL;
struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode);
if (!test_bit(LK_STATE_IN_USE, &state->flags)) if (!test_bit(LK_STATE_IN_USE, &state->flags))
goto out; goto out;
spin_lock(&state->state_lock);
list_for_each_entry(lsp, &state->lock_states, ls_locks) { list_for_each_entry(lsp, &state->lock_states, ls_locks) {
if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
struct rpc_cred *cred = lsp->ls_state->owner->so_cred; struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
atomic_inc(&lsp->ls_count);
spin_unlock(&state->state_lock);
nfs4_put_lock_state(prev);
prev = lsp;
status = nfs41_test_and_free_expired_stateid(server, status = nfs41_test_and_free_expired_stateid(server,
&lsp->ls_stateid, &lsp->ls_stateid,
cred); cred);
...@@ -2585,10 +2593,14 @@ static int nfs41_check_expired_locks(struct nfs4_state *state) ...@@ -2585,10 +2593,14 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
set_bit(NFS_LOCK_LOST, &lsp->ls_flags); set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
} else if (status != NFS_OK) { } else if (status != NFS_OK) {
ret = status; ret = status;
break; nfs4_put_lock_state(prev);
goto out;
} }
spin_lock(&state->state_lock);
} }
}; }
spin_unlock(&state->state_lock);
nfs4_put_lock_state(prev);
out: out:
return ret; return ret;
} }
...@@ -3122,7 +3134,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) ...@@ -3122,7 +3134,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
} else if (is_rdwr) } else if (is_rdwr)
calldata->arg.fmode |= FMODE_READ|FMODE_WRITE; calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
if (!nfs4_valid_open_stateid(state)) if (!nfs4_valid_open_stateid(state) ||
test_bit(NFS_OPEN_STATE, &state->flags) == 0)
call_close = 0; call_close = 0;
spin_unlock(&state->owner->so_lock); spin_unlock(&state->owner->so_lock);
...@@ -5569,6 +5582,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) ...@@ -5569,6 +5582,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
switch (task->tk_status) { switch (task->tk_status) {
case 0: case 0:
renew_lease(data->res.server, data->timestamp); renew_lease(data->res.server, data->timestamp);
break;
case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_DELEG_REVOKED: case -NFS4ERR_DELEG_REVOKED:
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
...@@ -5579,8 +5593,6 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) ...@@ -5579,8 +5593,6 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
case -NFS4ERR_OLD_STATEID: case -NFS4ERR_OLD_STATEID:
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
task->tk_status = 0; task->tk_status = 0;
if (data->roc)
pnfs_roc_set_barrier(data->inode, data->roc_barrier);
break; break;
default: default:
if (nfs4_async_handle_error(task, data->res.server, if (nfs4_async_handle_error(task, data->res.server,
...@@ -5590,6 +5602,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) ...@@ -5590,6 +5602,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
} }
} }
data->rpc_status = task->tk_status; data->rpc_status = task->tk_status;
if (data->roc && data->rpc_status == 0)
pnfs_roc_set_barrier(data->inode, data->roc_barrier);
} }
static void nfs4_delegreturn_release(void *calldata) static void nfs4_delegreturn_release(void *calldata)
......
...@@ -1547,6 +1547,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs ...@@ -1547,6 +1547,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
ssleep(1); ssleep(1);
case -NFS4ERR_ADMIN_REVOKED: case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_OLD_STATEID:
case -NFS4ERR_BAD_STATEID: case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_BAD:
case -NFS4ERR_RECLAIM_CONFLICT: case -NFS4ERR_RECLAIM_CONFLICT:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment