Skip to content

Commit 10b9dd5

Browse files
committed
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
2 parents 4d92c8d + d55b352 commit 10b9dd5

4 files changed

Lines changed: 35 additions & 13 deletions

File tree

fs/nfs/callback.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
197197
}
198198

199199
ret = -EPROTONOSUPPORT;
200-
if (minorversion == 0)
200+
if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
201201
ret = nfs4_callback_up_net(serv, net);
202202
else if (xprt->ops->bc_up)
203203
ret = xprt->ops->bc_up(serv, net);

fs/nfs/nfs4_fs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,13 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
542542
return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0;
543543
}
544544

545+
static inline bool nfs4_state_match_open_stateid_other(const struct nfs4_state *state,
546+
const nfs4_stateid *stateid)
547+
{
548+
return test_bit(NFS_OPEN_STATE, &state->flags) &&
549+
nfs4_stateid_match_other(&state->open_stateid, stateid);
550+
}
551+
545552
#else
546553

547554
#define nfs4_close_state(a, b) do { } while (0)

fs/nfs/nfs4proc.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,6 @@ static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
14511451
}
14521452

14531453
static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
1454-
nfs4_stateid *arg_stateid,
14551454
nfs4_stateid *stateid, fmode_t fmode)
14561455
{
14571456
clear_bit(NFS_O_RDWR_STATE, &state->flags);
@@ -1469,10 +1468,9 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
14691468
}
14701469
if (stateid == NULL)
14711470
return;
1472-
/* Handle races with OPEN */
1473-
if (!nfs4_stateid_match_other(arg_stateid, &state->open_stateid) ||
1474-
(nfs4_stateid_match_other(stateid, &state->open_stateid) &&
1475-
!nfs4_stateid_is_newer(stateid, &state->open_stateid))) {
1471+
/* Handle OPEN+OPEN_DOWNGRADE races */
1472+
if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
1473+
!nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
14761474
nfs_resync_open_stateid_locked(state);
14771475
return;
14781476
}
@@ -1486,7 +1484,9 @@ static void nfs_clear_open_stateid(struct nfs4_state *state,
14861484
nfs4_stateid *stateid, fmode_t fmode)
14871485
{
14881486
write_seqlock(&state->seqlock);
1489-
nfs_clear_open_stateid_locked(state, arg_stateid, stateid, fmode);
1487+
/* Ignore, if the CLOSE argment doesn't match the current stateid */
1488+
if (nfs4_state_match_open_stateid_other(state, arg_stateid))
1489+
nfs_clear_open_stateid_locked(state, stateid, fmode);
14901490
write_sequnlock(&state->seqlock);
14911491
if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
14921492
nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
@@ -2564,15 +2564,23 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
25642564
static int nfs41_check_expired_locks(struct nfs4_state *state)
25652565
{
25662566
int status, ret = NFS_OK;
2567-
struct nfs4_lock_state *lsp;
2567+
struct nfs4_lock_state *lsp, *prev = NULL;
25682568
struct nfs_server *server = NFS_SERVER(state->inode);
25692569

25702570
if (!test_bit(LK_STATE_IN_USE, &state->flags))
25712571
goto out;
2572+
2573+
spin_lock(&state->state_lock);
25722574
list_for_each_entry(lsp, &state->lock_states, ls_locks) {
25732575
if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
25742576
struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
25752577

2578+
atomic_inc(&lsp->ls_count);
2579+
spin_unlock(&state->state_lock);
2580+
2581+
nfs4_put_lock_state(prev);
2582+
prev = lsp;
2583+
25762584
status = nfs41_test_and_free_expired_stateid(server,
25772585
&lsp->ls_stateid,
25782586
cred);
@@ -2585,10 +2593,14 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
25852593
set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
25862594
} else if (status != NFS_OK) {
25872595
ret = status;
2588-
break;
2596+
nfs4_put_lock_state(prev);
2597+
goto out;
25892598
}
2599+
spin_lock(&state->state_lock);
25902600
}
2591-
};
2601+
}
2602+
spin_unlock(&state->state_lock);
2603+
nfs4_put_lock_state(prev);
25922604
out:
25932605
return ret;
25942606
}
@@ -3122,7 +3134,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
31223134
} else if (is_rdwr)
31233135
calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
31243136

3125-
if (!nfs4_valid_open_stateid(state))
3137+
if (!nfs4_valid_open_stateid(state) ||
3138+
test_bit(NFS_OPEN_STATE, &state->flags) == 0)
31263139
call_close = 0;
31273140
spin_unlock(&state->owner->so_lock);
31283141

@@ -5569,6 +5582,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
55695582
switch (task->tk_status) {
55705583
case 0:
55715584
renew_lease(data->res.server, data->timestamp);
5585+
break;
55725586
case -NFS4ERR_ADMIN_REVOKED:
55735587
case -NFS4ERR_DELEG_REVOKED:
55745588
case -NFS4ERR_EXPIRED:
@@ -5579,8 +5593,6 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
55795593
case -NFS4ERR_OLD_STATEID:
55805594
case -NFS4ERR_STALE_STATEID:
55815595
task->tk_status = 0;
5582-
if (data->roc)
5583-
pnfs_roc_set_barrier(data->inode, data->roc_barrier);
55845596
break;
55855597
default:
55865598
if (nfs4_async_handle_error(task, data->res.server,
@@ -5590,6 +5602,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
55905602
}
55915603
}
55925604
data->rpc_status = task->tk_status;
5605+
if (data->roc && data->rpc_status == 0)
5606+
pnfs_roc_set_barrier(data->inode, data->roc_barrier);
55935607
}
55945608

55955609
static void nfs4_delegreturn_release(void *calldata)

fs/nfs/nfs4state.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,7 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
15471547
ssleep(1);
15481548
case -NFS4ERR_ADMIN_REVOKED:
15491549
case -NFS4ERR_STALE_STATEID:
1550+
case -NFS4ERR_OLD_STATEID:
15501551
case -NFS4ERR_BAD_STATEID:
15511552
case -NFS4ERR_RECLAIM_BAD:
15521553
case -NFS4ERR_RECLAIM_CONFLICT:

0 commit comments

Comments
 (0)