aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-11-23 17:43:40 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-11-23 17:43:40 -0500
commit10b9dd56860e93f11cd352e8c75a33357b80b70b (patch)
treec19fa487f183ca6b035be66cf9a4f512129e29f3 /fs
parent4d92c8d036a7f1c9671eb672e7623925f5274737 (diff)
parentd55b352b01bc78fbc3d1bb650140668b87e58bf9 (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.c2
-rw-r--r--fs/nfs/nfs4_fs.h7
-rw-r--r--fs/nfs/nfs4proc.c38
-rw-r--r--fs/nfs/nfs4state.c1
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
545static 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
1453static void nfs_clear_open_stateid_locked(struct nfs4_state *state, 1453static 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)
2564static int nfs41_check_expired_locks(struct nfs4_state *state) 2564static 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);
2592out: 2604out:
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
5595static void nfs4_delegreturn_release(void *calldata) 5609static 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: