diff options
author | Bian Naimeng <biannm@cn.fujitsu.com> | 2009-04-22 06:25:37 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-24 19:17:18 -0400 |
commit | 78155ed75f470710f2aecb3e75e3d97107ba8374 (patch) | |
tree | 1a4b52cf0cd92ce7529036a3efa0eb4ad1bd2744 | |
parent | a9e61e25f9d2e7e43bf17625f5cb56c9e0a89b17 (diff) |
nfsd4: distinguish expired from stale stateids
If we encode the time of client creation into the stateid instead of the
time of server boot, then we can determine whether that stateid is from
a previous instance of the a server, or from a client that has expired,
and return an appropriate error to the client.
Signed-off-by: Bian Naimeng <biannm@cn.fujitsu.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | fs/nfsd/nfs4state.c | 62 |
1 files changed, 49 insertions, 13 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c65a27b76a9d..74e822ec34cb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -206,7 +206,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
206 | dp->dl_recall.cbr_dp = NULL; | 206 | dp->dl_recall.cbr_dp = NULL; |
207 | dp->dl_recall.cbr_ident = cb->cb_ident; | 207 | dp->dl_recall.cbr_ident = cb->cb_ident; |
208 | dp->dl_recall.cbr_trunc = 0; | 208 | dp->dl_recall.cbr_trunc = 0; |
209 | dp->dl_stateid.si_boot = boot_time; | 209 | dp->dl_stateid.si_boot = get_seconds(); |
210 | dp->dl_stateid.si_stateownerid = current_delegid++; | 210 | dp->dl_stateid.si_stateownerid = current_delegid++; |
211 | dp->dl_stateid.si_fileid = 0; | 211 | dp->dl_stateid.si_fileid = 0; |
212 | dp->dl_stateid.si_generation = 0; | 212 | dp->dl_stateid.si_generation = 0; |
@@ -1883,7 +1883,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1883 | stp->st_stateowner = sop; | 1883 | stp->st_stateowner = sop; |
1884 | get_nfs4_file(fp); | 1884 | get_nfs4_file(fp); |
1885 | stp->st_file = fp; | 1885 | stp->st_file = fp; |
1886 | stp->st_stateid.si_boot = boot_time; | 1886 | stp->st_stateid.si_boot = get_seconds(); |
1887 | stp->st_stateid.si_stateownerid = sop->so_id; | 1887 | stp->st_stateid.si_stateownerid = sop->so_id; |
1888 | stp->st_stateid.si_fileid = fp->fi_id; | 1888 | stp->st_stateid.si_fileid = fp->fi_id; |
1889 | stp->st_stateid.si_generation = 0; | 1889 | stp->st_stateid.si_generation = 0; |
@@ -2739,12 +2739,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | |||
2739 | static int | 2739 | static int |
2740 | STALE_STATEID(stateid_t *stateid) | 2740 | STALE_STATEID(stateid_t *stateid) |
2741 | { | 2741 | { |
2742 | if (stateid->si_boot == boot_time) | 2742 | if (time_after((unsigned long)boot_time, |
2743 | return 0; | 2743 | (unsigned long)stateid->si_boot)) { |
2744 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", | 2744 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", |
2745 | stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, | 2745 | stateid->si_boot, stateid->si_stateownerid, |
2746 | stateid->si_generation); | 2746 | stateid->si_fileid, stateid->si_generation); |
2747 | return 1; | 2747 | return 1; |
2748 | } | ||
2749 | return 0; | ||
2750 | } | ||
2751 | |||
2752 | static int | ||
2753 | EXPIRED_STATEID(stateid_t *stateid) | ||
2754 | { | ||
2755 | if (time_before((unsigned long)boot_time, | ||
2756 | ((unsigned long)stateid->si_boot)) && | ||
2757 | time_before((stateid->si_boot + lease_time), get_seconds())) { | ||
2758 | dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n", | ||
2759 | stateid->si_boot, stateid->si_stateownerid, | ||
2760 | stateid->si_fileid, stateid->si_generation); | ||
2761 | return 1; | ||
2762 | } | ||
2763 | return 0; | ||
2764 | } | ||
2765 | |||
2766 | static __be32 | ||
2767 | stateid_error_map(stateid_t *stateid) | ||
2768 | { | ||
2769 | if (STALE_STATEID(stateid)) | ||
2770 | return nfserr_stale_stateid; | ||
2771 | if (EXPIRED_STATEID(stateid)) | ||
2772 | return nfserr_expired; | ||
2773 | |||
2774 | dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n", | ||
2775 | stateid->si_boot, stateid->si_stateownerid, | ||
2776 | stateid->si_fileid, stateid->si_generation); | ||
2777 | return nfserr_bad_stateid; | ||
2748 | } | 2778 | } |
2749 | 2779 | ||
2750 | static inline int | 2780 | static inline int |
@@ -2868,8 +2898,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2868 | status = nfserr_bad_stateid; | 2898 | status = nfserr_bad_stateid; |
2869 | if (is_delegation_stateid(stateid)) { | 2899 | if (is_delegation_stateid(stateid)) { |
2870 | dp = find_delegation_stateid(ino, stateid); | 2900 | dp = find_delegation_stateid(ino, stateid); |
2871 | if (!dp) | 2901 | if (!dp) { |
2902 | status = stateid_error_map(stateid); | ||
2872 | goto out; | 2903 | goto out; |
2904 | } | ||
2873 | status = check_stateid_generation(stateid, &dp->dl_stateid, | 2905 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2874 | flags); | 2906 | flags); |
2875 | if (status) | 2907 | if (status) |
@@ -2882,8 +2914,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2882 | *filpp = dp->dl_vfs_file; | 2914 | *filpp = dp->dl_vfs_file; |
2883 | } else { /* open or lock stateid */ | 2915 | } else { /* open or lock stateid */ |
2884 | stp = find_stateid(stateid, flags); | 2916 | stp = find_stateid(stateid, flags); |
2885 | if (!stp) | 2917 | if (!stp) { |
2918 | status = stateid_error_map(stateid); | ||
2886 | goto out; | 2919 | goto out; |
2920 | } | ||
2887 | if (nfs4_check_fh(current_fh, stp)) | 2921 | if (nfs4_check_fh(current_fh, stp)) |
2888 | goto out; | 2922 | goto out; |
2889 | if (!stp->st_stateowner->so_confirmed) | 2923 | if (!stp->st_stateowner->so_confirmed) |
@@ -2957,7 +2991,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2957 | */ | 2991 | */ |
2958 | sop = search_close_lru(stateid->si_stateownerid, flags); | 2992 | sop = search_close_lru(stateid->si_stateownerid, flags); |
2959 | if (sop == NULL) | 2993 | if (sop == NULL) |
2960 | return nfserr_bad_stateid; | 2994 | return stateid_error_map(stateid); |
2961 | *sopp = sop; | 2995 | *sopp = sop; |
2962 | goto check_replay; | 2996 | goto check_replay; |
2963 | } | 2997 | } |
@@ -3228,8 +3262,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3228 | if (!is_delegation_stateid(stateid)) | 3262 | if (!is_delegation_stateid(stateid)) |
3229 | goto out; | 3263 | goto out; |
3230 | dp = find_delegation_stateid(inode, stateid); | 3264 | dp = find_delegation_stateid(inode, stateid); |
3231 | if (!dp) | 3265 | if (!dp) { |
3266 | status = stateid_error_map(stateid); | ||
3232 | goto out; | 3267 | goto out; |
3268 | } | ||
3233 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3269 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3234 | if (status) | 3270 | if (status) |
3235 | goto out; | 3271 | goto out; |
@@ -3456,7 +3492,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3456 | stp->st_stateowner = sop; | 3492 | stp->st_stateowner = sop; |
3457 | get_nfs4_file(fp); | 3493 | get_nfs4_file(fp); |
3458 | stp->st_file = fp; | 3494 | stp->st_file = fp; |
3459 | stp->st_stateid.si_boot = boot_time; | 3495 | stp->st_stateid.si_boot = get_seconds(); |
3460 | stp->st_stateid.si_stateownerid = sop->so_id; | 3496 | stp->st_stateid.si_stateownerid = sop->so_id; |
3461 | stp->st_stateid.si_fileid = fp->fi_id; | 3497 | stp->st_stateid.si_fileid = fp->fi_id; |
3462 | stp->st_stateid.si_generation = 0; | 3498 | stp->st_stateid.si_generation = 0; |