diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-23 17:43:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-23 17:43:40 -0500 |
commit | 10b9dd56860e93f11cd352e8c75a33357b80b70b (patch) | |
tree | c19fa487f183ca6b035be66cf9a4f512129e29f3 /fs | |
parent | 4d92c8d036a7f1c9671eb672e7623925f5274737 (diff) | |
parent | d55b352b01bc78fbc3d1bb650140668b87e58bf9 (diff) |
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
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/callback.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 7 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 38 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 1 |
4 files changed, 35 insertions, 13 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 532d8e242d4d..484bebc20bca 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -197,7 +197,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, | |||
197 | } | 197 | } |
198 | 198 | ||
199 | ret = -EPROTONOSUPPORT; | 199 | ret = -EPROTONOSUPPORT; |
200 | if (minorversion == 0) | 200 | if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0) |
201 | ret = nfs4_callback_up_net(serv, net); | 201 | ret = nfs4_callback_up_net(serv, net); |
202 | else if (xprt->ops->bc_up) | 202 | else if (xprt->ops->bc_up) |
203 | ret = xprt->ops->bc_up(serv, net); | 203 | ret = xprt->ops->bc_up(serv, net); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 9b3a82abab07..1452177c822d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -542,6 +542,13 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state) | |||
542 | return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0; | 542 | return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0; |
543 | } | 543 | } |
544 | 544 | ||
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 | |||
545 | #else | 552 | #else |
546 | 553 | ||
547 | #define nfs4_close_state(a, b) do { } while (0) | 554 | #define nfs4_close_state(a, b) do { } while (0) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7897826d7c51..241da19b7da4 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1451,7 +1451,6 @@ static void nfs_resync_open_stateid_locked(struct nfs4_state *state) | |||
1451 | } | 1451 | } |
1452 | 1452 | ||
1453 | static void nfs_clear_open_stateid_locked(struct nfs4_state *state, | 1453 | static void nfs_clear_open_stateid_locked(struct nfs4_state *state, |
1454 | nfs4_stateid *arg_stateid, | ||
1455 | nfs4_stateid *stateid, fmode_t fmode) | 1454 | nfs4_stateid *stateid, fmode_t fmode) |
1456 | { | 1455 | { |
1457 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1456 | clear_bit(NFS_O_RDWR_STATE, &state->flags); |
@@ -1469,10 +1468,9 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state, | |||
1469 | } | 1468 | } |
1470 | if (stateid == NULL) | 1469 | if (stateid == NULL) |
1471 | return; | 1470 | return; |
1472 | /* Handle races with OPEN */ | 1471 | /* Handle OPEN+OPEN_DOWNGRADE races */ |
1473 | if (!nfs4_stateid_match_other(arg_stateid, &state->open_stateid) || | 1472 | if (nfs4_stateid_match_other(stateid, &state->open_stateid) && |
1474 | (nfs4_stateid_match_other(stateid, &state->open_stateid) && | 1473 | !nfs4_stateid_is_newer(stateid, &state->open_stateid)) { |
1475 | !nfs4_stateid_is_newer(stateid, &state->open_stateid))) { | ||
1476 | nfs_resync_open_stateid_locked(state); | 1474 | nfs_resync_open_stateid_locked(state); |
1477 | return; | 1475 | return; |
1478 | } | 1476 | } |
@@ -1486,7 +1484,9 @@ static void nfs_clear_open_stateid(struct nfs4_state *state, | |||
1486 | nfs4_stateid *stateid, fmode_t fmode) | 1484 | nfs4_stateid *stateid, fmode_t fmode) |
1487 | { | 1485 | { |
1488 | write_seqlock(&state->seqlock); | 1486 | 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); | ||
1490 | write_sequnlock(&state->seqlock); | 1490 | write_sequnlock(&state->seqlock); |
1491 | if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) | 1491 | if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) |
1492 | nfs4_schedule_state_manager(state->owner->so_server->nfs_client); | 1492 | 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 | static int nfs41_check_expired_locks(struct nfs4_state *state) | 2564 | static int nfs41_check_expired_locks(struct nfs4_state *state) |
2565 | { | 2565 | { |
2566 | int status, ret = NFS_OK; | 2566 | int status, ret = NFS_OK; |
2567 | struct nfs4_lock_state *lsp; | 2567 | struct nfs4_lock_state *lsp, *prev = NULL; |
2568 | struct nfs_server *server = NFS_SERVER(state->inode); | 2568 | struct nfs_server *server = NFS_SERVER(state->inode); |
2569 | 2569 | ||
2570 | if (!test_bit(LK_STATE_IN_USE, &state->flags)) | 2570 | if (!test_bit(LK_STATE_IN_USE, &state->flags)) |
2571 | goto out; | 2571 | goto out; |
2572 | |||
2573 | spin_lock(&state->state_lock); | ||
2572 | list_for_each_entry(lsp, &state->lock_states, ls_locks) { | 2574 | list_for_each_entry(lsp, &state->lock_states, ls_locks) { |
2573 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { | 2575 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { |
2574 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; | 2576 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; |
2575 | 2577 | ||
2578 | atomic_inc(&lsp->ls_count); | ||
2579 | spin_unlock(&state->state_lock); | ||
2580 | |||
2581 | nfs4_put_lock_state(prev); | ||
2582 | prev = lsp; | ||
2583 | |||
2576 | status = nfs41_test_and_free_expired_stateid(server, | 2584 | status = nfs41_test_and_free_expired_stateid(server, |
2577 | &lsp->ls_stateid, | 2585 | &lsp->ls_stateid, |
2578 | cred); | 2586 | cred); |
@@ -2585,10 +2593,14 @@ static int nfs41_check_expired_locks(struct nfs4_state *state) | |||
2585 | set_bit(NFS_LOCK_LOST, &lsp->ls_flags); | 2593 | set_bit(NFS_LOCK_LOST, &lsp->ls_flags); |
2586 | } else if (status != NFS_OK) { | 2594 | } else if (status != NFS_OK) { |
2587 | ret = status; | 2595 | ret = status; |
2588 | break; | 2596 | nfs4_put_lock_state(prev); |
2597 | goto out; | ||
2589 | } | 2598 | } |
2599 | spin_lock(&state->state_lock); | ||
2590 | } | 2600 | } |
2591 | }; | 2601 | } |
2602 | spin_unlock(&state->state_lock); | ||
2603 | nfs4_put_lock_state(prev); | ||
2592 | out: | 2604 | out: |
2593 | return ret; | 2605 | return ret; |
2594 | } | 2606 | } |
@@ -3122,7 +3134,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
3122 | } else if (is_rdwr) | 3134 | } else if (is_rdwr) |
3123 | calldata->arg.fmode |= FMODE_READ|FMODE_WRITE; | 3135 | calldata->arg.fmode |= FMODE_READ|FMODE_WRITE; |
3124 | 3136 | ||
3125 | if (!nfs4_valid_open_stateid(state)) | 3137 | if (!nfs4_valid_open_stateid(state) || |
3138 | test_bit(NFS_OPEN_STATE, &state->flags) == 0) | ||
3126 | call_close = 0; | 3139 | call_close = 0; |
3127 | spin_unlock(&state->owner->so_lock); | 3140 | spin_unlock(&state->owner->so_lock); |
3128 | 3141 | ||
@@ -5569,6 +5582,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
5569 | switch (task->tk_status) { | 5582 | switch (task->tk_status) { |
5570 | case 0: | 5583 | case 0: |
5571 | renew_lease(data->res.server, data->timestamp); | 5584 | renew_lease(data->res.server, data->timestamp); |
5585 | break; | ||
5572 | case -NFS4ERR_ADMIN_REVOKED: | 5586 | case -NFS4ERR_ADMIN_REVOKED: |
5573 | case -NFS4ERR_DELEG_REVOKED: | 5587 | case -NFS4ERR_DELEG_REVOKED: |
5574 | case -NFS4ERR_EXPIRED: | 5588 | case -NFS4ERR_EXPIRED: |
@@ -5579,8 +5593,6 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
5579 | case -NFS4ERR_OLD_STATEID: | 5593 | case -NFS4ERR_OLD_STATEID: |
5580 | case -NFS4ERR_STALE_STATEID: | 5594 | case -NFS4ERR_STALE_STATEID: |
5581 | task->tk_status = 0; | 5595 | task->tk_status = 0; |
5582 | if (data->roc) | ||
5583 | pnfs_roc_set_barrier(data->inode, data->roc_barrier); | ||
5584 | break; | 5596 | break; |
5585 | default: | 5597 | default: |
5586 | if (nfs4_async_handle_error(task, data->res.server, | 5598 | 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 | } | 5602 | } |
5591 | } | 5603 | } |
5592 | data->rpc_status = task->tk_status; | 5604 | data->rpc_status = task->tk_status; |
5605 | if (data->roc && data->rpc_status == 0) | ||
5606 | pnfs_roc_set_barrier(data->inode, data->roc_barrier); | ||
5593 | } | 5607 | } |
5594 | 5608 | ||
5595 | static void nfs4_delegreturn_release(void *calldata) | 5609 | static void nfs4_delegreturn_release(void *calldata) |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5f4281ec5f72..0959c9661662 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1547,6 +1547,7 @@ restart: | |||
1547 | ssleep(1); | 1547 | ssleep(1); |
1548 | case -NFS4ERR_ADMIN_REVOKED: | 1548 | case -NFS4ERR_ADMIN_REVOKED: |
1549 | case -NFS4ERR_STALE_STATEID: | 1549 | case -NFS4ERR_STALE_STATEID: |
1550 | case -NFS4ERR_OLD_STATEID: | ||
1550 | case -NFS4ERR_BAD_STATEID: | 1551 | case -NFS4ERR_BAD_STATEID: |
1551 | case -NFS4ERR_RECLAIM_BAD: | 1552 | case -NFS4ERR_RECLAIM_BAD: |
1552 | case -NFS4ERR_RECLAIM_CONFLICT: | 1553 | case -NFS4ERR_RECLAIM_CONFLICT: |