aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-05 19:56:44 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-06 10:32:43 -0500
commita1d0b5eebc4fd6e0edb02688b35f17f67f42aea5 (patch)
tree80d13543ee4f1928e0436919a19de40be2a3b12b
parentfa68a1ba1de349f0d1fcc54171b95236efe24148 (diff)
NFS: Properly handle the case where the delegation is revoked
If we know that the delegation stateid is bad or revoked, we need to remove that delegation as soon as possible, and then mark all the stateids that relied on that delegation for recovery. We cannot use the delegation as part of the recovery process. Also note that NFSv4.1 uses a different error code (NFS4ERR_DELEG_REVOKED) to indicate that the delegation was revoked. Finally, ensure that setlk() and setattr() can both recover safely from a revoked delegation. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: stable@vger.kernel.org
-rw-r--r--fs/nfs/delegation.c11
-rw-r--r--fs/nfs/delegation.h1
-rw-r--r--fs/nfs/nfs4_fs.h2
-rw-r--r--fs/nfs/nfs4proc.c18
-rw-r--r--fs/nfs/nfs4state.c29
5 files changed, 57 insertions, 4 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 7f2654069806..ac889af8ccf5 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -466,6 +466,17 @@ static void nfs_delegation_run_state_manager(struct nfs_client *clp)
466 nfs4_schedule_state_manager(clp); 466 nfs4_schedule_state_manager(clp);
467} 467}
468 468
469void nfs_remove_bad_delegation(struct inode *inode)
470{
471 struct nfs_delegation *delegation;
472
473 delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode));
474 if (delegation) {
475 nfs_inode_find_state_and_recover(inode, &delegation->stateid);
476 nfs_free_delegation(delegation);
477 }
478}
479
469/** 480/**
470 * nfs_expire_all_delegation_types 481 * nfs_expire_all_delegation_types
471 * @clp: client to process 482 * @clp: client to process
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index d9322e490c56..691a79609184 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -45,6 +45,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
45void nfs_handle_cb_pathdown(struct nfs_client *clp); 45void nfs_handle_cb_pathdown(struct nfs_client *clp);
46int nfs_client_return_marked_delegations(struct nfs_client *clp); 46int nfs_client_return_marked_delegations(struct nfs_client *clp);
47int nfs_delegations_present(struct nfs_client *clp); 47int nfs_delegations_present(struct nfs_client *clp);
48void nfs_remove_bad_delegation(struct inode *inode);
48 49
49void nfs_delegation_mark_reclaim(struct nfs_client *clp); 50void nfs_delegation_mark_reclaim(struct nfs_client *clp);
50void nfs_delegation_reap_unclaimed(struct nfs_client *clp); 51void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 19079ec8252c..7ddad3fa4074 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -317,6 +317,8 @@ extern void nfs4_put_open_state(struct nfs4_state *);
317extern void nfs4_close_state(struct nfs4_state *, fmode_t); 317extern void nfs4_close_state(struct nfs4_state *, fmode_t);
318extern void nfs4_close_sync(struct nfs4_state *, fmode_t); 318extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
319extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); 319extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
320extern void nfs_inode_find_state_and_recover(struct inode *inode,
321 const nfs4_stateid *stateid);
320extern void nfs4_schedule_lease_recovery(struct nfs_client *); 322extern void nfs4_schedule_lease_recovery(struct nfs_client *);
321extern void nfs4_schedule_state_manager(struct nfs_client *); 323extern void nfs4_schedule_state_manager(struct nfs_client *);
322extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp); 324extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ea7adfc868c2..f31fcea1af7e 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -268,8 +268,11 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
268 switch(errorcode) { 268 switch(errorcode) {
269 case 0: 269 case 0:
270 return 0; 270 return 0;
271 case -NFS4ERR_DELEG_REVOKED:
271 case -NFS4ERR_ADMIN_REVOKED: 272 case -NFS4ERR_ADMIN_REVOKED:
272 case -NFS4ERR_BAD_STATEID: 273 case -NFS4ERR_BAD_STATEID:
274 if (state != NULL)
275 nfs_remove_bad_delegation(state->inode);
273 case -NFS4ERR_OPENMODE: 276 case -NFS4ERR_OPENMODE:
274 if (state == NULL) 277 if (state == NULL)
275 break; 278 break;
@@ -1331,8 +1334,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
1331 * The show must go on: exit, but mark the 1334 * The show must go on: exit, but mark the
1332 * stateid as needing recovery. 1335 * stateid as needing recovery.
1333 */ 1336 */
1337 case -NFS4ERR_DELEG_REVOKED:
1334 case -NFS4ERR_ADMIN_REVOKED: 1338 case -NFS4ERR_ADMIN_REVOKED:
1335 case -NFS4ERR_BAD_STATEID: 1339 case -NFS4ERR_BAD_STATEID:
1340 nfs_inode_find_state_and_recover(state->inode,
1341 stateid);
1336 nfs4_schedule_stateid_recovery(server, state); 1342 nfs4_schedule_stateid_recovery(server, state);
1337 case -EKEYEXPIRED: 1343 case -EKEYEXPIRED:
1338 /* 1344 /*
@@ -1931,7 +1937,9 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
1931 struct nfs4_state *state) 1937 struct nfs4_state *state)
1932{ 1938{
1933 struct nfs_server *server = NFS_SERVER(inode); 1939 struct nfs_server *server = NFS_SERVER(inode);
1934 struct nfs4_exception exception = { }; 1940 struct nfs4_exception exception = {
1941 .state = state,
1942 };
1935 int err; 1943 int err;
1936 do { 1944 do {
1937 err = nfs4_handle_exception(server, 1945 err = nfs4_handle_exception(server,
@@ -3760,8 +3768,11 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
3760 if (task->tk_status >= 0) 3768 if (task->tk_status >= 0)
3761 return 0; 3769 return 0;
3762 switch(task->tk_status) { 3770 switch(task->tk_status) {
3771 case -NFS4ERR_DELEG_REVOKED:
3763 case -NFS4ERR_ADMIN_REVOKED: 3772 case -NFS4ERR_ADMIN_REVOKED:
3764 case -NFS4ERR_BAD_STATEID: 3773 case -NFS4ERR_BAD_STATEID:
3774 if (state != NULL)
3775 nfs_remove_bad_delegation(state->inode);
3765 case -NFS4ERR_OPENMODE: 3776 case -NFS4ERR_OPENMODE:
3766 if (state == NULL) 3777 if (state == NULL)
3767 break; 3778 break;
@@ -4604,7 +4615,9 @@ out:
4604 4615
4605static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) 4616static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
4606{ 4617{
4607 struct nfs4_exception exception = { }; 4618 struct nfs4_exception exception = {
4619 .state = state,
4620 };
4608 int err; 4621 int err;
4609 4622
4610 do { 4623 do {
@@ -4697,6 +4710,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
4697 * The show must go on: exit, but mark the 4710 * The show must go on: exit, but mark the
4698 * stateid as needing recovery. 4711 * stateid as needing recovery.
4699 */ 4712 */
4713 case -NFS4ERR_DELEG_REVOKED:
4700 case -NFS4ERR_ADMIN_REVOKED: 4714 case -NFS4ERR_ADMIN_REVOKED:
4701 case -NFS4ERR_BAD_STATEID: 4715 case -NFS4ERR_BAD_STATEID:
4702 case -NFS4ERR_OPENMODE: 4716 case -NFS4ERR_OPENMODE:
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 2f760604246f..d60e7ad2690e 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1106,12 +1106,37 @@ void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4
1106{ 1106{
1107 struct nfs_client *clp = server->nfs_client; 1107 struct nfs_client *clp = server->nfs_client;
1108 1108
1109 if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags))
1110 nfs_async_inode_return_delegation(state->inode, &state->stateid);
1111 nfs4_state_mark_reclaim_nograce(clp, state); 1109 nfs4_state_mark_reclaim_nograce(clp, state);
1112 nfs4_schedule_state_manager(clp); 1110 nfs4_schedule_state_manager(clp);
1113} 1111}
1114 1112
1113void nfs_inode_find_state_and_recover(struct inode *inode,
1114 const nfs4_stateid *stateid)
1115{
1116 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
1117 struct nfs_inode *nfsi = NFS_I(inode);
1118 struct nfs_open_context *ctx;
1119 struct nfs4_state *state;
1120 bool found = false;
1121
1122 spin_lock(&inode->i_lock);
1123 list_for_each_entry(ctx, &nfsi->open_files, list) {
1124 state = ctx->state;
1125 if (state == NULL)
1126 continue;
1127 if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
1128 continue;
1129 if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
1130 continue;
1131 nfs4_state_mark_reclaim_nograce(clp, state);
1132 found = true;
1133 }
1134 spin_unlock(&inode->i_lock);
1135 if (found)
1136 nfs4_schedule_state_manager(clp);
1137}
1138
1139
1115static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) 1140static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
1116{ 1141{
1117 struct inode *inode = state->inode; 1142 struct inode *inode = state->inode;