diff options
| author | Benjamin Coddington <bcodding@redhat.com> | 2016-11-18 21:11:39 -0500 |
|---|---|---|
| committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2016-11-21 11:58:39 -0500 |
| commit | d75a6a0e3933acbba44e4ad8d8f3c4d4f76b6e03 (patch) | |
| tree | c6d80e481f775da2ed75725b0f0a25afd3537b05 | |
| parent | d41cbfc9a64d11835a5b5b90caa7d6f3a88eb1df (diff) | |
NFSv4.1: Keep a reference on lock states while checking
While walking the list of lock_states, keep a reference on each
nfs4_lock_state to be checked, otherwise the lock state could be removed
while the check performs TEST_STATEID and possible FREE_STATEID.
Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
| -rw-r--r-- | fs/nfs/nfs4proc.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2d1481eb1929..e6dc95e0f97e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -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 | } |
