aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2012-05-29 13:56:37 -0400
committerJ. Bruce Fields <bfields@redhat.com>2012-06-20 08:59:40 -0400
commit7df302f75ee28a6a87436e93b625ef60d37d098e (patch)
tree11fcb3dd3b30eb6f42167bd7bf671cda7361933d /fs/nfsd
parent2411967305dbfb8930b9b9c11f55f6c1ef7361e1 (diff)
NFSD: TEST_STATEID should not return NFS4ERR_STALE_STATEID
According to RFC 5661, the TEST_STATEID operation is not allowed to return NFS4ERR_STALE_STATEID. In addition, RFC 5661 says: 15.1.16.5. NFS4ERR_STALE_STATEID (Error Code 10023) A stateid generated by an earlier server instance was used. This error is moot in NFSv4.1 because all operations that take a stateid MUST be preceded by the SEQUENCE operation, and the earlier server instance is detected by the session infrastructure that supports SEQUENCE. I triggered NFS4ERR_STALE_STATEID while testing the Linux client's NOGRACE recovery. Bruce suggested an additional test that could be useful to client developers. Lastly, RFC 5661, section 18.48.3 has this: o Special stateids are always considered invalid (they result in the error code NFS4ERR_BAD_STATEID). An explicit check is made for those state IDs to avoid printk noise. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c22
-rw-r--r--fs/nfsd/state.h1
2 files changed, 16 insertions, 7 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8b80a10d4fc5..59b9efc9d69b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -38,6 +38,7 @@
38#include <linux/namei.h> 38#include <linux/namei.h>
39#include <linux/swap.h> 39#include <linux/swap.h>
40#include <linux/pagemap.h> 40#include <linux/pagemap.h>
41#include <linux/ratelimit.h>
41#include <linux/sunrpc/svcauth_gss.h> 42#include <linux/sunrpc/svcauth_gss.h>
42#include <linux/sunrpc/clnt.h> 43#include <linux/sunrpc/clnt.h>
43#include "xdr4.h" 44#include "xdr4.h"
@@ -3338,18 +3339,26 @@ static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_s
3338 return nfserr_old_stateid; 3339 return nfserr_old_stateid;
3339} 3340}
3340 3341
3341__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 3342static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
3342{ 3343{
3343 struct nfs4_stid *s; 3344 struct nfs4_stid *s;
3344 struct nfs4_ol_stateid *ols; 3345 struct nfs4_ol_stateid *ols;
3345 __be32 status; 3346 __be32 status;
3346 3347
3347 if (STALE_STATEID(stateid)) 3348 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
3348 return nfserr_stale_stateid; 3349 return nfserr_bad_stateid;
3349 3350 /* Client debugging aid. */
3351 if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
3352 char addr_str[INET6_ADDRSTRLEN];
3353 rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str,
3354 sizeof(addr_str));
3355 pr_warn_ratelimited("NFSD: client %s testing state ID "
3356 "with incorrect client ID\n", addr_str);
3357 return nfserr_bad_stateid;
3358 }
3350 s = find_stateid(cl, stateid); 3359 s = find_stateid(cl, stateid);
3351 if (!s) 3360 if (!s)
3352 return nfserr_stale_stateid; 3361 return nfserr_bad_stateid;
3353 status = check_stateid_generation(stateid, &s->sc_stateid, 1); 3362 status = check_stateid_generation(stateid, &s->sc_stateid, 1);
3354 if (status) 3363 if (status)
3355 return status; 3364 return status;
@@ -3468,7 +3477,8 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3468 3477
3469 nfs4_lock_state(); 3478 nfs4_lock_state();
3470 list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 3479 list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
3471 stateid->ts_id_status = nfs4_validate_stateid(cl, &stateid->ts_id_stateid); 3480 stateid->ts_id_status =
3481 nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
3472 nfs4_unlock_state(); 3482 nfs4_unlock_state();
3473 3483
3474 return nfs_ok; 3484 return nfs_ok;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 849091e16ea6..495df4e3aa67 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -475,7 +475,6 @@ extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
475extern int nfs4_client_to_reclaim(const char *name); 475extern int nfs4_client_to_reclaim(const char *name);
476extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); 476extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
477extern void release_session_client(struct nfsd4_session *); 477extern void release_session_client(struct nfsd4_session *);
478extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
479extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); 478extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
480 479
481/* nfs4recover operations */ 480/* nfs4recover operations */