aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-04-09 17:02:51 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-16 10:59:30 -0400
commit3bd64a5ba1719c2bb6cba4493dfd3e23a7653e54 (patch)
treec968f3f51d6082d3c7f0a03ec3d9fdaa031e6593 /fs/nfsd
parent23340032e64d70ce76817a88e8193c8040b095cf (diff)
nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED
A 4.1 server must notify a client that has had any state revoked using the SEQ4_STATUS_RECALLABLE_STATE_REVOKED flag. The client can figure out exactly which state is the problem using CHECK_STATEID and then free it using FREE_STATEID. The status flag will be unset once all such revoked stateids are freed. Our server's only recallable state is delegations. So we keep with each 4.1 client a list of delegations that have timed out and been recalled, but haven't yet been freed by FREE_STATEID. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c55
-rw-r--r--fs/nfsd/state.h3
2 files changed, 50 insertions, 8 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index add9721ab059..3b84700d1bd7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -445,7 +445,6 @@ static void unhash_stid(struct nfs4_stid *s)
445static void 445static void
446unhash_delegation(struct nfs4_delegation *dp) 446unhash_delegation(struct nfs4_delegation *dp)
447{ 447{
448 unhash_stid(&dp->dl_stid);
449 list_del_init(&dp->dl_perclnt); 448 list_del_init(&dp->dl_perclnt);
450 spin_lock(&recall_lock); 449 spin_lock(&recall_lock);
451 list_del_init(&dp->dl_perfile); 450 list_del_init(&dp->dl_perfile);
@@ -454,10 +453,37 @@ unhash_delegation(struct nfs4_delegation *dp)
454 nfs4_put_deleg_lease(dp->dl_file); 453 nfs4_put_deleg_lease(dp->dl_file);
455 put_nfs4_file(dp->dl_file); 454 put_nfs4_file(dp->dl_file);
456 dp->dl_file = NULL; 455 dp->dl_file = NULL;
456}
457
458
459
460static void destroy_revoked_delegation(struct nfs4_delegation *dp)
461{
462 list_del_init(&dp->dl_recall_lru);
457 remove_stid(&dp->dl_stid); 463 remove_stid(&dp->dl_stid);
458 nfs4_put_delegation(dp); 464 nfs4_put_delegation(dp);
459} 465}
460 466
467static void destroy_delegation(struct nfs4_delegation *dp)
468{
469 unhash_delegation(dp);
470 remove_stid(&dp->dl_stid);
471 nfs4_put_delegation(dp);
472}
473
474static void revoke_delegation(struct nfs4_delegation *dp)
475{
476 struct nfs4_client *clp = dp->dl_stid.sc_client;
477
478 if (clp->cl_minorversion == 0)
479 destroy_delegation(dp);
480 else {
481 unhash_delegation(dp);
482 dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
483 list_add(&dp->dl_recall_lru, &clp->cl_revoked);
484 }
485}
486
461/* 487/*
462 * SETCLIENTID state 488 * SETCLIENTID state
463 */ 489 */
@@ -1114,7 +1140,7 @@ destroy_client(struct nfs4_client *clp)
1114 spin_unlock(&recall_lock); 1140 spin_unlock(&recall_lock);
1115 while (!list_empty(&reaplist)) { 1141 while (!list_empty(&reaplist)) {
1116 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 1142 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
1117 unhash_delegation(dp); 1143 destroy_delegation(dp);
1118 } 1144 }
1119 while (!list_empty(&clp->cl_openowners)) { 1145 while (!list_empty(&clp->cl_openowners)) {
1120 oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 1146 oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
@@ -1310,6 +1336,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
1310 INIT_LIST_HEAD(&clp->cl_delegations); 1336 INIT_LIST_HEAD(&clp->cl_delegations);
1311 INIT_LIST_HEAD(&clp->cl_lru); 1337 INIT_LIST_HEAD(&clp->cl_lru);
1312 INIT_LIST_HEAD(&clp->cl_callbacks); 1338 INIT_LIST_HEAD(&clp->cl_callbacks);
1339 INIT_LIST_HEAD(&clp->cl_revoked);
1313 spin_lock_init(&clp->cl_lock); 1340 spin_lock_init(&clp->cl_lock);
1314 nfsd4_init_callback(&clp->cl_cb_null); 1341 nfsd4_init_callback(&clp->cl_cb_null);
1315 clp->cl_time = get_seconds(); 1342 clp->cl_time = get_seconds();
@@ -2171,6 +2198,8 @@ out:
2171 default: 2198 default:
2172 seq->status_flags = 0; 2199 seq->status_flags = 0;
2173 } 2200 }
2201 if (!list_empty(&clp->cl_revoked))
2202 seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
2174out_no_session: 2203out_no_session:
2175 kfree(conn); 2204 kfree(conn);
2176 spin_unlock(&nn->client_lock); 2205 spin_unlock(&nn->client_lock);
@@ -3297,7 +3326,7 @@ nfs4_laundromat(struct nfsd_net *nn)
3297 spin_unlock(&recall_lock); 3326 spin_unlock(&recall_lock);
3298 list_for_each_safe(pos, next, &reaplist) { 3327 list_for_each_safe(pos, next, &reaplist) {
3299 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 3328 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
3300 unhash_delegation(dp); 3329 revoke_delegation(dp);
3301 } 3330 }
3302 test_val = nn->nfsd4_lease; 3331 test_val = nn->nfsd4_lease;
3303 list_for_each_safe(pos, next, &nn->close_lru) { 3332 list_for_each_safe(pos, next, &nn->close_lru) {
@@ -3459,6 +3488,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
3459 switch (s->sc_type) { 3488 switch (s->sc_type) {
3460 case NFS4_DELEG_STID: 3489 case NFS4_DELEG_STID:
3461 return nfs_ok; 3490 return nfs_ok;
3491 case NFS4_REVOKED_DELEG_STID:
3492 return nfserr_deleg_revoked;
3462 case NFS4_OPEN_STID: 3493 case NFS4_OPEN_STID:
3463 case NFS4_LOCK_STID: 3494 case NFS4_LOCK_STID:
3464 ols = openlockstateid(s); 3495 ols = openlockstateid(s);
@@ -3602,6 +3633,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3602{ 3633{
3603 stateid_t *stateid = &free_stateid->fr_stateid; 3634 stateid_t *stateid = &free_stateid->fr_stateid;
3604 struct nfs4_stid *s; 3635 struct nfs4_stid *s;
3636 struct nfs4_delegation *dp;
3605 struct nfs4_client *cl = cstate->session->se_client; 3637 struct nfs4_client *cl = cstate->session->se_client;
3606 __be32 ret = nfserr_bad_stateid; 3638 __be32 ret = nfserr_bad_stateid;
3607 3639
@@ -3623,6 +3655,11 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3623 else 3655 else
3624 ret = nfserr_locks_held; 3656 ret = nfserr_locks_held;
3625 break; 3657 break;
3658 case NFS4_REVOKED_DELEG_STID:
3659 dp = delegstateid(s);
3660 destroy_revoked_delegation(dp);
3661 ret = nfs_ok;
3662 break;
3626 default: 3663 default:
3627 ret = nfserr_bad_stateid; 3664 ret = nfserr_bad_stateid;
3628 } 3665 }
@@ -3647,10 +3684,12 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
3647 status = nfsd4_check_seqid(cstate, sop, seqid); 3684 status = nfsd4_check_seqid(cstate, sop, seqid);
3648 if (status) 3685 if (status)
3649 return status; 3686 return status;
3650 if (stp->st_stid.sc_type == NFS4_CLOSED_STID) 3687 if (stp->st_stid.sc_type == NFS4_CLOSED_STID
3688 || stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
3651 /* 3689 /*
3652 * "Closed" stateid's exist *only* to return 3690 * "Closed" stateid's exist *only* to return
3653 * nfserr_replay_me from the previous step. 3691 * nfserr_replay_me from the previous step, and
3692 * revoked delegations are kept only for free_stateid.
3654 */ 3693 */
3655 return nfserr_bad_stateid; 3694 return nfserr_bad_stateid;
3656 status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 3695 status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
@@ -3913,7 +3952,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3913 if (status) 3952 if (status)
3914 goto out; 3953 goto out;
3915 3954
3916 unhash_delegation(dp); 3955 destroy_delegation(dp);
3917out: 3956out:
3918 nfs4_unlock_state(); 3957 nfs4_unlock_state();
3919 3958
@@ -4763,7 +4802,7 @@ u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
4763 spin_unlock(&recall_lock); 4802 spin_unlock(&recall_lock);
4764 4803
4765 list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) 4804 list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
4766 unhash_delegation(dp); 4805 revoke_delegation(dp);
4767 4806
4768 return count; 4807 return count;
4769} 4808}
@@ -5018,7 +5057,7 @@ nfs4_state_shutdown_net(struct net *net)
5018 spin_unlock(&recall_lock); 5057 spin_unlock(&recall_lock);
5019 list_for_each_safe(pos, next, &reaplist) { 5058 list_for_each_safe(pos, next, &reaplist) {
5020 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 5059 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
5021 unhash_delegation(dp); 5060 destroy_delegation(dp);
5022 } 5061 }
5023 5062
5024 nfsd4_client_tracking_exit(net); 5063 nfsd4_client_tracking_exit(net);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 13ec4853e9af..274e2a114e05 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -79,6 +79,8 @@ struct nfs4_stid {
79#define NFS4_DELEG_STID 4 79#define NFS4_DELEG_STID 4
80/* For an open stateid kept around *only* to process close replays: */ 80/* For an open stateid kept around *only* to process close replays: */
81#define NFS4_CLOSED_STID 8 81#define NFS4_CLOSED_STID 8
82/* For a deleg stateid kept around only to process free_stateid's: */
83#define NFS4_REVOKED_DELEG_STID 16
82 unsigned char sc_type; 84 unsigned char sc_type;
83 stateid_t sc_stateid; 85 stateid_t sc_stateid;
84 struct nfs4_client *sc_client; 86 struct nfs4_client *sc_client;
@@ -238,6 +240,7 @@ struct nfs4_client {
238 struct list_head cl_openowners; 240 struct list_head cl_openowners;
239 struct idr cl_stateids; /* stateid lookup */ 241 struct idr cl_stateids; /* stateid lookup */
240 struct list_head cl_delegations; 242 struct list_head cl_delegations;
243 struct list_head cl_revoked; /* unacknowledged, revoked 4.1 state */
241 struct list_head cl_lru; /* tail queue */ 244 struct list_head cl_lru; /* tail queue */
242 struct xdr_netobj cl_name; /* id generated by client */ 245 struct xdr_netobj cl_name; /* id generated by client */
243 nfs4_verifier cl_verifier; /* generated by client */ 246 nfs4_verifier cl_verifier; /* generated by client */