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 /fs | |
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>
Diffstat (limited to 'fs')
-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 | } |