aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2016-09-22 13:39:03 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2016-09-27 14:34:12 -0400
commitc5896fc8622d57b31e1e98545d67d7089019e478 (patch)
tree6c6b12e912a69eaba8c7a7103adde22158b44292 /fs/nfs
parentf7a62adad01cdb2b64c5a17cdd440736b99a5829 (diff)
NFSv4.1: Ensure we always run TEST/FREE_STATEID on locks
Right now, we're only running TEST/FREE_STATEID on the locks if the open stateid recovery succeeds. The protocol requires us to always do so. The fix would be to move the call to TEST/FREE_STATEID and do it before we attempt open recovery. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Tested-by: Oleg Drokin <green@linuxhacker.ru> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c92
1 files changed, 52 insertions, 40 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 02eab9113273..b5290fd99209 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2486,6 +2486,45 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
2486} 2486}
2487 2487
2488/** 2488/**
2489 * nfs41_check_expired_locks - possibly free a lock stateid
2490 *
2491 * @state: NFSv4 state for an inode
2492 *
2493 * Returns NFS_OK if recovery for this stateid is now finished.
2494 * Otherwise a negative NFS4ERR value is returned.
2495 */
2496static int nfs41_check_expired_locks(struct nfs4_state *state)
2497{
2498 int status, ret = NFS_OK;
2499 struct nfs4_lock_state *lsp;
2500 struct nfs_server *server = NFS_SERVER(state->inode);
2501
2502 if (!test_bit(LK_STATE_IN_USE, &state->flags))
2503 goto out;
2504 list_for_each_entry(lsp, &state->lock_states, ls_locks) {
2505 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
2506 struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
2507
2508 status = nfs41_test_and_free_expired_stateid(server,
2509 &lsp->ls_stateid,
2510 cred);
2511 trace_nfs4_test_lock_stateid(state, lsp, status);
2512 if (status == -NFS4ERR_EXPIRED ||
2513 status == -NFS4ERR_BAD_STATEID) {
2514 clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
2515 if (!recover_lost_locks)
2516 set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
2517 } else if (status != NFS_OK) {
2518 ret = status;
2519 break;
2520 }
2521 }
2522 };
2523out:
2524 return ret;
2525}
2526
2527/**
2489 * nfs41_check_open_stateid - possibly free an open stateid 2528 * nfs41_check_open_stateid - possibly free an open stateid
2490 * 2529 *
2491 * @state: NFSv4 state for an inode 2530 * @state: NFSv4 state for an inode
@@ -2522,6 +2561,9 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
2522 int status; 2561 int status;
2523 2562
2524 nfs41_check_delegation_stateid(state); 2563 nfs41_check_delegation_stateid(state);
2564 status = nfs41_check_expired_locks(state);
2565 if (status != NFS_OK)
2566 return status;
2525 status = nfs41_check_open_stateid(state); 2567 status = nfs41_check_open_stateid(state);
2526 if (status != NFS_OK) 2568 if (status != NFS_OK)
2527 status = nfs4_open_expired(sp, state); 2569 status = nfs4_open_expired(sp, state);
@@ -6106,49 +6148,19 @@ out:
6106} 6148}
6107 6149
6108#if defined(CONFIG_NFS_V4_1) 6150#if defined(CONFIG_NFS_V4_1)
6109/**
6110 * nfs41_check_expired_locks - possibly free a lock stateid
6111 *
6112 * @state: NFSv4 state for an inode
6113 *
6114 * Returns NFS_OK if recovery for this stateid is now finished.
6115 * Otherwise a negative NFS4ERR value is returned.
6116 */
6117static int nfs41_check_expired_locks(struct nfs4_state *state)
6118{
6119 int status, ret = NFS_OK;
6120 struct nfs4_lock_state *lsp;
6121 struct nfs_server *server = NFS_SERVER(state->inode);
6122
6123 list_for_each_entry(lsp, &state->lock_states, ls_locks) {
6124 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
6125 struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
6126
6127 status = nfs41_test_and_free_expired_stateid(server,
6128 &lsp->ls_stateid,
6129 cred);
6130 trace_nfs4_test_lock_stateid(state, lsp, status);
6131 if (status == -NFS4ERR_EXPIRED ||
6132 status == -NFS4ERR_BAD_STATEID)
6133 clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
6134 else if (status != NFS_OK) {
6135 ret = status;
6136 break;
6137 }
6138 }
6139 };
6140
6141 return ret;
6142}
6143
6144static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request) 6151static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
6145{ 6152{
6146 int status = NFS_OK; 6153 struct nfs4_lock_state *lsp;
6154 int status;
6147 6155
6148 if (test_bit(LK_STATE_IN_USE, &state->flags)) 6156 status = nfs4_set_lock_state(state, request);
6149 status = nfs41_check_expired_locks(state); 6157 if (status != 0)
6150 if (status != NFS_OK) 6158 return status;
6151 status = nfs4_lock_expired(state, request); 6159 lsp = request->fl_u.nfs4_fl.owner;
6160 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) ||
6161 test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
6162 return 0;
6163 status = nfs4_lock_expired(state, request);
6152 return status; 6164 return status;
6153} 6165}
6154#endif 6166#endif