aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-04-01 16:37:12 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-08 09:55:32 -0400
commit9411b1d4c7df26dca6bc6261b5dc87a5b4c81e5c (patch)
tree43fe6d0f9e83740f0b2e7b4691b3fb374c03fd17 /fs
parent41d22663cb6a4108091c050cba3c470a3e175dd9 (diff)
nfsd4: cleanup handling of nfsv4.0 closed stateid's
Closed stateid's are kept around a little while to handle close replays in the 4.0 case. So we stash them in the last-used stateid in the oo_last_closed_stateid field of the open owner. We can free that in encode_seqid_op_tail once the seqid on the open owner is next incremented. But we don't want to do that on the close itself; so we set NFS4_OO_PURGE_CLOSE flag set on the open owner, skip freeing it the first time through encode_seqid_op_tail, then when we see that flag set next time we free it. This is unnecessarily baroque. Instead, just move the logic that increments the seqid out of the xdr code and into the operation code itself. The justification given for the current placement is that we need to wait till the last minute to be sure we know whether the status is a sequence-id-mutating error or not, but examination of the code shows that can't actually happen. Reported-by: Yanchuan Nian <ycnian@gmail.com> Tested-by: Yanchuan Nian <ycnian@gmail.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4proc.c3
-rw-r--r--fs/nfsd/nfs4state.c57
-rw-r--r--fs/nfsd/nfs4xdr.c34
-rw-r--r--fs/nfsd/state.h4
-rw-r--r--fs/nfsd/xdr4.h1
5 files changed, 43 insertions, 56 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index a9b707b23858..609e1e211330 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -415,7 +415,8 @@ out:
415 nfsd4_cleanup_open_state(open, status); 415 nfsd4_cleanup_open_state(open, status);
416 if (open->op_openowner) 416 if (open->op_openowner)
417 cstate->replay_owner = &open->op_openowner->oo_owner; 417 cstate->replay_owner = &open->op_openowner->oo_owner;
418 else 418 nfsd4_bump_seqid(cstate, status);
419 if (!cstate->replay_owner)
419 nfs4_unlock_state(); 420 nfs4_unlock_state();
420 return status; 421 return status;
421} 422}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 795b24d82d18..bcd2339ae8c1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -720,6 +720,28 @@ dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
720} 720}
721#endif 721#endif
722 722
723/*
724 * Bump the seqid on cstate->replay_owner, and clear replay_owner if it
725 * won't be used for replay.
726 */
727void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
728{
729 struct nfs4_stateowner *so = cstate->replay_owner;
730
731 if (nfserr == nfserr_replay_me)
732 return;
733
734 if (!seqid_mutating_err(ntohl(nfserr))) {
735 cstate->replay_owner = NULL;
736 return;
737 }
738 if (!so)
739 return;
740 if (so->so_is_open_owner)
741 release_last_closed_stateid(openowner(so));
742 so->so_seqid++;
743 return;
744}
723 745
724static void 746static void
725gen_sessionid(struct nfsd4_session *ses) 747gen_sessionid(struct nfsd4_session *ses)
@@ -3702,6 +3724,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3702 nfsd4_client_record_create(oo->oo_owner.so_client); 3724 nfsd4_client_record_create(oo->oo_owner.so_client);
3703 status = nfs_ok; 3725 status = nfs_ok;
3704out: 3726out:
3727 nfsd4_bump_seqid(cstate, status);
3705 if (!cstate->replay_owner) 3728 if (!cstate->replay_owner)
3706 nfs4_unlock_state(); 3729 nfs4_unlock_state();
3707 return status; 3730 return status;
@@ -3785,31 +3808,12 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
3785 memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 3808 memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
3786 status = nfs_ok; 3809 status = nfs_ok;
3787out: 3810out:
3811 nfsd4_bump_seqid(cstate, status);
3788 if (!cstate->replay_owner) 3812 if (!cstate->replay_owner)
3789 nfs4_unlock_state(); 3813 nfs4_unlock_state();
3790 return status; 3814 return status;
3791} 3815}
3792 3816
3793void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so)
3794{
3795 struct nfs4_openowner *oo;
3796 struct nfs4_ol_stateid *s;
3797
3798 if (!so->so_is_open_owner)
3799 return;
3800 oo = openowner(so);
3801 s = oo->oo_last_closed_stid;
3802 if (!s)
3803 return;
3804 if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) {
3805 /* Release the last_closed_stid on the next seqid bump: */
3806 oo->oo_flags |= NFS4_OO_PURGE_CLOSE;
3807 return;
3808 }
3809 oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE;
3810 release_last_closed_stateid(oo);
3811}
3812
3813static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 3817static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
3814{ 3818{
3815 unhash_open_stateid(s); 3819 unhash_open_stateid(s);
@@ -3838,17 +3842,20 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3838 &close->cl_stateid, 3842 &close->cl_stateid,
3839 NFS4_OPEN_STID|NFS4_CLOSED_STID, 3843 NFS4_OPEN_STID|NFS4_CLOSED_STID,
3840 &stp, nn); 3844 &stp, nn);
3845 nfsd4_bump_seqid(cstate, status);
3841 if (status) 3846 if (status)
3842 goto out; 3847 goto out;
3843 oo = openowner(stp->st_stateowner); 3848 oo = openowner(stp->st_stateowner);
3844 status = nfs_ok;
3845 update_stateid(&stp->st_stid.sc_stateid); 3849 update_stateid(&stp->st_stid.sc_stateid);
3846 memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 3850 memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
3847 3851
3848 nfsd4_close_open_stateid(stp); 3852 nfsd4_close_open_stateid(stp);
3849 release_last_closed_stateid(oo); 3853
3850 oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE; 3854 if (cstate->minorversion) {
3851 oo->oo_last_closed_stid = stp; 3855 unhash_stid(&stp->st_stid);
3856 free_generic_stateid(stp);
3857 } else
3858 oo->oo_last_closed_stid = stp;
3852 3859
3853 if (list_empty(&oo->oo_owner.so_stateids)) { 3860 if (list_empty(&oo->oo_owner.so_stateids)) {
3854 if (cstate->minorversion) { 3861 if (cstate->minorversion) {
@@ -4270,6 +4277,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4270out: 4277out:
4271 if (status && new_state) 4278 if (status && new_state)
4272 release_lockowner(lock_sop); 4279 release_lockowner(lock_sop);
4280 nfsd4_bump_seqid(cstate, status);
4273 if (!cstate->replay_owner) 4281 if (!cstate->replay_owner)
4274 nfs4_unlock_state(); 4282 nfs4_unlock_state();
4275 if (file_lock) 4283 if (file_lock)
@@ -4439,6 +4447,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4439 memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); 4447 memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
4440 4448
4441out: 4449out:
4450 nfsd4_bump_seqid(cstate, status);
4442 if (!cstate->replay_owner) 4451 if (!cstate->replay_owner)
4443 nfs4_unlock_state(); 4452 nfs4_unlock_state();
4444 if (file_lock) 4453 if (file_lock)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 700de0192834..a5e8a6424843 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1701,28 +1701,6 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c)
1701 \ 1701 \
1702 save = resp->p; 1702 save = resp->p;
1703 1703
1704/*
1705 * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
1706 * is where sequence id's are incremented, and the replay cache is filled.
1707 * Note that we increment sequence id's here, at the last moment, so we're sure
1708 * we know whether the error to be returned is a sequence id mutating error.
1709 */
1710
1711static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, __be32 nfserr)
1712{
1713 struct nfs4_stateowner *stateowner = resp->cstate.replay_owner;
1714
1715 if (seqid_mutating_err(ntohl(nfserr)) && stateowner) {
1716 stateowner->so_seqid++;
1717 stateowner->so_replay.rp_status = nfserr;
1718 stateowner->so_replay.rp_buflen =
1719 (char *)resp->p - (char *)save;
1720 memcpy(stateowner->so_replay.rp_buf, save,
1721 stateowner->so_replay.rp_buflen);
1722 nfsd4_purge_closed_stateid(stateowner);
1723 }
1724}
1725
1726/* Encode as an array of strings the string given with components 1704/* Encode as an array of strings the string given with components
1727 * separated @sep, escaped with esc_enter and esc_exit. 1705 * separated @sep, escaped with esc_enter and esc_exit.
1728 */ 1706 */
@@ -2667,7 +2645,6 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
2667 if (!nfserr) 2645 if (!nfserr)
2668 nfsd4_encode_stateid(resp, &close->cl_stateid); 2646 nfsd4_encode_stateid(resp, &close->cl_stateid);
2669 2647
2670 encode_seqid_op_tail(resp, save, nfserr);
2671 return nfserr; 2648 return nfserr;
2672} 2649}
2673 2650
@@ -2770,7 +2747,6 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
2770 else if (nfserr == nfserr_denied) 2747 else if (nfserr == nfserr_denied)
2771 nfsd4_encode_lock_denied(resp, &lock->lk_denied); 2748 nfsd4_encode_lock_denied(resp, &lock->lk_denied);
2772 2749
2773 encode_seqid_op_tail(resp, save, nfserr);
2774 return nfserr; 2750 return nfserr;
2775} 2751}
2776 2752
@@ -2790,7 +2766,6 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
2790 if (!nfserr) 2766 if (!nfserr)
2791 nfsd4_encode_stateid(resp, &locku->lu_stateid); 2767 nfsd4_encode_stateid(resp, &locku->lu_stateid);
2792 2768
2793 encode_seqid_op_tail(resp, save, nfserr);
2794 return nfserr; 2769 return nfserr;
2795} 2770}
2796 2771
@@ -2885,7 +2860,6 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
2885 } 2860 }
2886 /* XXX save filehandle here */ 2861 /* XXX save filehandle here */
2887out: 2862out:
2888 encode_seqid_op_tail(resp, save, nfserr);
2889 return nfserr; 2863 return nfserr;
2890} 2864}
2891 2865
@@ -2897,7 +2871,6 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
2897 if (!nfserr) 2871 if (!nfserr)
2898 nfsd4_encode_stateid(resp, &oc->oc_resp_stateid); 2872 nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);
2899 2873
2900 encode_seqid_op_tail(resp, save, nfserr);
2901 return nfserr; 2874 return nfserr;
2902} 2875}
2903 2876
@@ -2909,7 +2882,6 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struc
2909 if (!nfserr) 2882 if (!nfserr)
2910 nfsd4_encode_stateid(resp, &od->od_stateid); 2883 nfsd4_encode_stateid(resp, &od->od_stateid);
2911 2884
2912 encode_seqid_op_tail(resp, save, nfserr);
2913 return nfserr; 2885 return nfserr;
2914} 2886}
2915 2887
@@ -3567,6 +3539,7 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
3567void 3539void
3568nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) 3540nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
3569{ 3541{
3542 struct nfs4_stateowner *so = resp->cstate.replay_owner;
3570 __be32 *statp; 3543 __be32 *statp;
3571 __be32 *p; 3544 __be32 *p;
3572 3545
@@ -3583,6 +3556,11 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
3583 /* nfsd4_check_drc_limit guarantees enough room for error status */ 3556 /* nfsd4_check_drc_limit guarantees enough room for error status */
3584 if (!op->status) 3557 if (!op->status)
3585 op->status = nfsd4_check_resp_size(resp, 0); 3558 op->status = nfsd4_check_resp_size(resp, 0);
3559 if (so) {
3560 so->so_replay.rp_status = op->status;
3561 so->so_replay.rp_buflen = (char *)resp->p - (char *)(statp+1);
3562 memcpy(so->so_replay.rp_buf, statp+1, so->so_replay.rp_buflen);
3563 }
3586status: 3564status:
3587 /* 3565 /*
3588 * Note: We write the status directly, instead of using WRITE32(), 3566 * Note: We write the status directly, instead of using WRITE32(),
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 7674bc806200..13ec4853e9af 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -355,7 +355,6 @@ struct nfs4_openowner {
355 struct nfs4_ol_stateid *oo_last_closed_stid; 355 struct nfs4_ol_stateid *oo_last_closed_stid;
356 time_t oo_time; /* time of placement on so_close_lru */ 356 time_t oo_time; /* time of placement on so_close_lru */
357#define NFS4_OO_CONFIRMED 1 357#define NFS4_OO_CONFIRMED 1
358#define NFS4_OO_PURGE_CLOSE 2
359#define NFS4_OO_NEW 4 358#define NFS4_OO_NEW 4
360 unsigned char oo_flags; 359 unsigned char oo_flags;
361}; 360};
@@ -363,7 +362,7 @@ struct nfs4_openowner {
363struct nfs4_lockowner { 362struct nfs4_lockowner {
364 struct nfs4_stateowner lo_owner; /* must be first element */ 363 struct nfs4_stateowner lo_owner; /* must be first element */
365 struct list_head lo_owner_ino_hash; /* hash by owner,file */ 364 struct list_head lo_owner_ino_hash; /* hash by owner,file */
366 struct list_head lo_perstateid; /* for lockowners only */ 365 struct list_head lo_perstateid;
367 struct list_head lo_list; /* for temporary uses */ 366 struct list_head lo_list; /* for temporary uses */
368}; 367};
369 368
@@ -477,7 +476,6 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
477 struct nfsd_net *nn); 476 struct nfsd_net *nn);
478extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn); 477extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn);
479extern void put_client_renew(struct nfs4_client *clp); 478extern void put_client_renew(struct nfs4_client *clp);
480extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
481 479
482/* nfs4recover operations */ 480/* nfs4recover operations */
483extern int nfsd4_client_tracking_init(struct net *net); 481extern int nfsd4_client_tracking_init(struct net *net);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 40e05e6d2518..3b271d2092b6 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -623,6 +623,7 @@ extern __be32 nfsd4_test_stateid(struct svc_rqst *rqstp,
623 struct nfsd4_compound_state *, struct nfsd4_test_stateid *test_stateid); 623 struct nfsd4_compound_state *, struct nfsd4_test_stateid *test_stateid);
624extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp, 624extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
625 struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid); 625 struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
626extern void nfsd4_bump_seqid(struct nfsd4_compound_state *, __be32 nfserr);
626#endif 627#endif
627 628
628/* 629/*