diff options
author | Andy Adamson <andros@netapp.com> | 2009-04-03 01:28:45 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-03 20:41:19 -0400 |
commit | 6668958fac1d05f55420de702f3678d46c1e93a5 (patch) | |
tree | 2ee7fe01bb6720ecb1147c5c7f7e3d0289fc71bb /fs | |
parent | dd453dfd70538cadc02cb47ff8d8cfd0cb8cf435 (diff) |
nfsd41: stateid handling
When sessions are used, stateful operation sequenceid and stateid handling
are not used. When sessions are used, on the first open set the seqid to 1,
mark state confirmed and skip seqid processing.
When sessionas are used the stateid generation number is ignored when it is zero
whereas without sessions bad_stateid or stale stateid is returned.
Add flags to propagate session use to all stateful ops and down to
check_stateid_generation.
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Andy Adamson <andros@netapp.com>
[nfsd4_has_session should return a boolean, not u32]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: pass nfsd4_compoundres * to nfsd4_process_open1]
[nfsd41: calculate HAS_SESSION in nfs4_preprocess_stateid_op]
[nfsd41: calculate HAS_SESSION in nfs4_preprocess_seqid_op]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 47 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 2 |
3 files changed, 44 insertions, 10 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e6a0f314fdbe..aeb4888bdfad 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -168,6 +168,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
168 | struct nfsd4_open *open) | 168 | struct nfsd4_open *open) |
169 | { | 169 | { |
170 | __be32 status; | 170 | __be32 status; |
171 | struct nfsd4_compoundres *resp; | ||
172 | |||
171 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", | 173 | dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", |
172 | (int)open->op_fname.len, open->op_fname.data, | 174 | (int)open->op_fname.len, open->op_fname.data, |
173 | open->op_stateowner); | 175 | open->op_stateowner); |
@@ -179,7 +181,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
179 | nfs4_lock_state(); | 181 | nfs4_lock_state(); |
180 | 182 | ||
181 | /* check seqid for replay. set nfs4_owner */ | 183 | /* check seqid for replay. set nfs4_owner */ |
182 | status = nfsd4_process_open1(open); | 184 | resp = rqstp->rq_resp; |
185 | status = nfsd4_process_open1(&resp->cstate, open); | ||
183 | if (status == nfserr_replay_me) { | 186 | if (status == nfserr_replay_me) { |
184 | struct nfs4_replay *rp = &open->op_stateowner->so_replay; | 187 | struct nfs4_replay *rp = &open->op_stateowner->so_replay; |
185 | fh_put(&cstate->current_fh); | 188 | fh_put(&cstate->current_fh); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f49f305096ec..bbaf3c9bfe5a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -2183,7 +2183,8 @@ static struct lock_manager_operations nfsd_lease_mng_ops = { | |||
2183 | 2183 | ||
2184 | 2184 | ||
2185 | __be32 | 2185 | __be32 |
2186 | nfsd4_process_open1(struct nfsd4_open *open) | 2186 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, |
2187 | struct nfsd4_open *open) | ||
2187 | { | 2188 | { |
2188 | clientid_t *clientid = &open->op_clientid; | 2189 | clientid_t *clientid = &open->op_clientid; |
2189 | struct nfs4_client *clp = NULL; | 2190 | struct nfs4_client *clp = NULL; |
@@ -2206,6 +2207,9 @@ nfsd4_process_open1(struct nfsd4_open *open) | |||
2206 | return nfserr_expired; | 2207 | return nfserr_expired; |
2207 | goto renew; | 2208 | goto renew; |
2208 | } | 2209 | } |
2210 | /* When sessions are used, skip open sequenceid processing */ | ||
2211 | if (nfsd4_has_session(cstate)) | ||
2212 | goto renew; | ||
2209 | if (!sop->so_confirmed) { | 2213 | if (!sop->so_confirmed) { |
2210 | /* Replace unconfirmed owners without checking for replay. */ | 2214 | /* Replace unconfirmed owners without checking for replay. */ |
2211 | clp = sop->so_client; | 2215 | clp = sop->so_client; |
@@ -2483,6 +2487,7 @@ out: | |||
2483 | __be32 | 2487 | __be32 |
2484 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 2488 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
2485 | { | 2489 | { |
2490 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
2486 | struct nfs4_file *fp = NULL; | 2491 | struct nfs4_file *fp = NULL; |
2487 | struct inode *ino = current_fh->fh_dentry->d_inode; | 2492 | struct inode *ino = current_fh->fh_dentry->d_inode; |
2488 | struct nfs4_stateid *stp = NULL; | 2493 | struct nfs4_stateid *stp = NULL; |
@@ -2541,9 +2546,14 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2541 | release_open_stateid(stp); | 2546 | release_open_stateid(stp); |
2542 | goto out; | 2547 | goto out; |
2543 | } | 2548 | } |
2549 | if (nfsd4_has_session(&resp->cstate)) | ||
2550 | update_stateid(&stp->st_stateid); | ||
2544 | } | 2551 | } |
2545 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2552 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); |
2546 | 2553 | ||
2554 | if (nfsd4_has_session(&resp->cstate)) | ||
2555 | open->op_stateowner->so_confirmed = 1; | ||
2556 | |||
2547 | /* | 2557 | /* |
2548 | * Attempt to hand out a delegation. No error return, because the | 2558 | * Attempt to hand out a delegation. No error return, because the |
2549 | * OPEN succeeds even if we fail. | 2559 | * OPEN succeeds even if we fail. |
@@ -2564,7 +2574,8 @@ out: | |||
2564 | * To finish the open response, we just need to set the rflags. | 2574 | * To finish the open response, we just need to set the rflags. |
2565 | */ | 2575 | */ |
2566 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; | 2576 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; |
2567 | if (!open->op_stateowner->so_confirmed) | 2577 | if (!open->op_stateowner->so_confirmed && |
2578 | !nfsd4_has_session(&resp->cstate)) | ||
2568 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; | 2579 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; |
2569 | 2580 | ||
2570 | return status; | 2581 | return status; |
@@ -2781,8 +2792,15 @@ grace_disallows_io(struct inode *inode) | |||
2781 | return locks_in_grace() && mandatory_lock(inode); | 2792 | return locks_in_grace() && mandatory_lock(inode); |
2782 | } | 2793 | } |
2783 | 2794 | ||
2784 | static int check_stateid_generation(stateid_t *in, stateid_t *ref) | 2795 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, int flags) |
2785 | { | 2796 | { |
2797 | /* | ||
2798 | * When sessions are used the stateid generation number is ignored | ||
2799 | * when it is zero. | ||
2800 | */ | ||
2801 | if ((flags & HAS_SESSION) && in->si_generation == 0) | ||
2802 | goto out; | ||
2803 | |||
2786 | /* If the client sends us a stateid from the future, it's buggy: */ | 2804 | /* If the client sends us a stateid from the future, it's buggy: */ |
2787 | if (in->si_generation > ref->si_generation) | 2805 | if (in->si_generation > ref->si_generation) |
2788 | return nfserr_bad_stateid; | 2806 | return nfserr_bad_stateid; |
@@ -2798,6 +2816,7 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref) | |||
2798 | */ | 2816 | */ |
2799 | if (in->si_generation < ref->si_generation) | 2817 | if (in->si_generation < ref->si_generation) |
2800 | return nfserr_old_stateid; | 2818 | return nfserr_old_stateid; |
2819 | out: | ||
2801 | return nfs_ok; | 2820 | return nfs_ok; |
2802 | } | 2821 | } |
2803 | 2822 | ||
@@ -2825,6 +2844,9 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2825 | if (grace_disallows_io(ino)) | 2844 | if (grace_disallows_io(ino)) |
2826 | return nfserr_grace; | 2845 | return nfserr_grace; |
2827 | 2846 | ||
2847 | if (nfsd4_has_session(cstate)) | ||
2848 | flags |= HAS_SESSION; | ||
2849 | |||
2828 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 2850 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
2829 | return check_special_stateids(current_fh, stateid, flags); | 2851 | return check_special_stateids(current_fh, stateid, flags); |
2830 | 2852 | ||
@@ -2837,7 +2859,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2837 | dp = find_delegation_stateid(ino, stateid); | 2859 | dp = find_delegation_stateid(ino, stateid); |
2838 | if (!dp) | 2860 | if (!dp) |
2839 | goto out; | 2861 | goto out; |
2840 | status = check_stateid_generation(stateid, &dp->dl_stateid); | 2862 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2863 | flags); | ||
2841 | if (status) | 2864 | if (status) |
2842 | goto out; | 2865 | goto out; |
2843 | status = nfs4_check_delegmode(dp, flags); | 2866 | status = nfs4_check_delegmode(dp, flags); |
@@ -2854,7 +2877,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2854 | goto out; | 2877 | goto out; |
2855 | if (!stp->st_stateowner->so_confirmed) | 2878 | if (!stp->st_stateowner->so_confirmed) |
2856 | goto out; | 2879 | goto out; |
2857 | status = check_stateid_generation(stateid, &stp->st_stateid); | 2880 | status = check_stateid_generation(stateid, &stp->st_stateid, |
2881 | flags); | ||
2858 | if (status) | 2882 | if (status) |
2859 | goto out; | 2883 | goto out; |
2860 | status = nfs4_check_openmode(stp, flags); | 2884 | status = nfs4_check_openmode(stp, flags); |
@@ -2905,6 +2929,10 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2905 | 2929 | ||
2906 | if (STALE_STATEID(stateid)) | 2930 | if (STALE_STATEID(stateid)) |
2907 | return nfserr_stale_stateid; | 2931 | return nfserr_stale_stateid; |
2932 | |||
2933 | if (nfsd4_has_session(cstate)) | ||
2934 | flags |= HAS_SESSION; | ||
2935 | |||
2908 | /* | 2936 | /* |
2909 | * We return BAD_STATEID if filehandle doesn't match stateid, | 2937 | * We return BAD_STATEID if filehandle doesn't match stateid, |
2910 | * the confirmed flag is incorrecly set, or the generation | 2938 | * the confirmed flag is incorrecly set, or the generation |
@@ -2961,7 +2989,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2961 | * For the moment, we ignore the possibility of | 2989 | * For the moment, we ignore the possibility of |
2962 | * generation number wraparound. | 2990 | * generation number wraparound. |
2963 | */ | 2991 | */ |
2964 | if (seqid != sop->so_seqid) | 2992 | if (!(flags & HAS_SESSION) && seqid != sop->so_seqid) |
2965 | goto check_replay; | 2993 | goto check_replay; |
2966 | 2994 | ||
2967 | if (sop->so_confirmed && flags & CONFIRM) { | 2995 | if (sop->so_confirmed && flags & CONFIRM) { |
@@ -2974,7 +3002,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2974 | " confirmed yet!\n"); | 3002 | " confirmed yet!\n"); |
2975 | return nfserr_bad_stateid; | 3003 | return nfserr_bad_stateid; |
2976 | } | 3004 | } |
2977 | status = check_stateid_generation(stateid, &stp->st_stateid); | 3005 | status = check_stateid_generation(stateid, &stp->st_stateid, flags); |
2978 | if (status) | 3006 | if (status) |
2979 | return status; | 3007 | return status; |
2980 | renew_client(sop->so_client); | 3008 | renew_client(sop->so_client); |
@@ -3169,11 +3197,14 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3169 | stateid_t *stateid = &dr->dr_stateid; | 3197 | stateid_t *stateid = &dr->dr_stateid; |
3170 | struct inode *inode; | 3198 | struct inode *inode; |
3171 | __be32 status; | 3199 | __be32 status; |
3200 | int flags = 0; | ||
3172 | 3201 | ||
3173 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 3202 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
3174 | return status; | 3203 | return status; |
3175 | inode = cstate->current_fh.fh_dentry->d_inode; | 3204 | inode = cstate->current_fh.fh_dentry->d_inode; |
3176 | 3205 | ||
3206 | if (nfsd4_has_session(cstate)) | ||
3207 | flags |= HAS_SESSION; | ||
3177 | nfs4_lock_state(); | 3208 | nfs4_lock_state(); |
3178 | status = nfserr_bad_stateid; | 3209 | status = nfserr_bad_stateid; |
3179 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3210 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
@@ -3187,7 +3218,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3187 | dp = find_delegation_stateid(inode, stateid); | 3218 | dp = find_delegation_stateid(inode, stateid); |
3188 | if (!dp) | 3219 | if (!dp) |
3189 | goto out; | 3220 | goto out; |
3190 | status = check_stateid_generation(stateid, &dp->dl_stateid); | 3221 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3191 | if (status) | 3222 | if (status) |
3192 | goto out; | 3223 | goto out; |
3193 | renew_client(dp->dl_client); | 3224 | renew_client(dp->dl_client); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c6a726d04efd..dd81ac1a1c6c 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -3194,7 +3194,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3194 | iov = &rqstp->rq_res.head[0]; | 3194 | iov = &rqstp->rq_res.head[0]; |
3195 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; | 3195 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; |
3196 | BUG_ON(iov->iov_len > PAGE_SIZE); | 3196 | BUG_ON(iov->iov_len > PAGE_SIZE); |
3197 | if (resp->cstate.slot != NULL) { | 3197 | if (nfsd4_has_session(&resp->cstate)) { |
3198 | if (resp->cstate.status == nfserr_replay_cache && | 3198 | if (resp->cstate.status == nfserr_replay_cache && |
3199 | !nfsd4_not_cached(resp)) { | 3199 | !nfsd4_not_cached(resp)) { |
3200 | iov->iov_len = resp->cstate.iovlen; | 3200 | iov->iov_len = resp->cstate.iovlen; |