aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorAlexandros Batsakis <batsakis@netapp.com>2009-12-05 13:48:55 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-12-05 13:48:55 -0500
commit2597641deae82c9a95e255518da189ab557da0af (patch)
tree0b2dc7c46f2a0398ecefd6bb63a657710cf921fa /fs/nfs
parent0629e370dd5819efa5cf8d418a8e6729efe388ef (diff)
nfs41: v2 fix cb_recall bug
in NFSv4.1 the seqid part of a stateid in CB_RECALL must be 0 Signed-off-by: Alexandros Batsakis <batsakis@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/callback.h5
-rw-r--r--fs/nfs/callback_proc.c37
-rw-r--r--fs/nfs/delegation.c9
-rw-r--r--fs/nfs/delegation.h4
4 files changed, 48 insertions, 7 deletions
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index 0ca830984c4b..d4036be0b589 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -106,6 +106,8 @@ struct cb_sequenceres {
106extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, 106extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
107 struct cb_sequenceres *res); 107 struct cb_sequenceres *res);
108 108
109extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation,
110 const nfs4_stateid *stateid);
109 111
110#define RCA4_TYPE_MASK_RDATA_DLG 0 112#define RCA4_TYPE_MASK_RDATA_DLG 0
111#define RCA4_TYPE_MASK_WDATA_DLG 1 113#define RCA4_TYPE_MASK_WDATA_DLG 1
@@ -125,8 +127,9 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
125#ifdef CONFIG_NFS_V4 127#ifdef CONFIG_NFS_V4
126extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); 128extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
127extern void nfs_callback_down(int minorversion); 129extern void nfs_callback_down(int minorversion);
130extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation,
131 const nfs4_stateid *stateid);
128#endif /* CONFIG_NFS_V4 */ 132#endif /* CONFIG_NFS_V4 */
129
130/* 133/*
131 * nfs41: Callbacks are expected to not cause substantial latency, 134 * nfs41: Callbacks are expected to not cause substantial latency,
132 * so we limit their concurrency to 1 by setting up the maximum number 135 * so we limit their concurrency to 1 by setting up the maximum number
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 61b85306bb25..defa9b4c470e 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -61,6 +61,16 @@ out:
61 return res->status; 61 return res->status;
62} 62}
63 63
64static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *)
65{
66#if defined(CONFIG_NFS_V4_1)
67 if (clp->cl_minorversion > 0)
68 return nfs41_validate_delegation_stateid;
69#endif
70 return nfs4_validate_delegation_stateid;
71}
72
73
64__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) 74__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
65{ 75{
66 struct nfs_client *clp; 76 struct nfs_client *clp;
@@ -81,7 +91,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
81 inode = nfs_delegation_find_inode(clp, &args->fh); 91 inode = nfs_delegation_find_inode(clp, &args->fh);
82 if (inode != NULL) { 92 if (inode != NULL) {
83 /* Set up a helper thread to actually return the delegation */ 93 /* Set up a helper thread to actually return the delegation */
84 switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { 94 switch (nfs_async_inode_return_delegation(inode, &args->stateid,
95 nfs_validate_delegation_stateid(clp))) {
85 case 0: 96 case 0:
86 res = 0; 97 res = 0;
87 break; 98 break;
@@ -102,8 +113,31 @@ out:
102 return res; 113 return res;
103} 114}
104 115
116int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
117{
118 if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
119 sizeof(delegation->stateid.data)) != 0)
120 return 0;
121 return 1;
122}
123
105#if defined(CONFIG_NFS_V4_1) 124#if defined(CONFIG_NFS_V4_1)
106 125
126int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
127{
128 if (delegation == NULL)
129 return 0;
130
131 /* seqid is 4-bytes long */
132 if (((u32 *) &stateid->data)[0] != 0)
133 return 0;
134 if (memcmp(&delegation->stateid.data[4], &stateid->data[4],
135 sizeof(stateid->data)-4))
136 return 0;
137
138 return 1;
139}
140
107/* 141/*
108 * Validate the sequenceID sent by the server. 142 * Validate the sequenceID sent by the server.
109 * Return success if the sequenceID is one more than what we last saw on 143 * Return success if the sequenceID is one more than what we last saw on
@@ -255,5 +289,4 @@ out:
255 dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); 289 dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
256 return status; 290 return status;
257} 291}
258
259#endif /* CONFIG_NFS_V4_1 */ 292#endif /* CONFIG_NFS_V4_1 */
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index f4758ec42138..2563bebc4c67 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -454,18 +454,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
454/* 454/*
455 * Asynchronous delegation recall! 455 * Asynchronous delegation recall!
456 */ 456 */
457int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) 457int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
458 int (*validate_stateid)(struct nfs_delegation *delegation,
459 const nfs4_stateid *stateid))
458{ 460{
459 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; 461 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
460 struct nfs_delegation *delegation; 462 struct nfs_delegation *delegation;
461 463
462 rcu_read_lock(); 464 rcu_read_lock();
463 delegation = rcu_dereference(NFS_I(inode)->delegation); 465 delegation = rcu_dereference(NFS_I(inode)->delegation);
464 if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, 466
465 sizeof(delegation->stateid.data)) != 0) { 467 if (!validate_stateid(delegation, stateid)) {
466 rcu_read_unlock(); 468 rcu_read_unlock();
467 return -ENOENT; 469 return -ENOENT;
468 } 470 }
471
469 nfs_mark_return_delegation(clp, delegation); 472 nfs_mark_return_delegation(clp, delegation);
470 rcu_read_unlock(); 473 rcu_read_unlock();
471 nfs_delegation_run_state_manager(clp); 474 nfs_delegation_run_state_manager(clp);
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index f6d0731a8cf5..944b627ec6e1 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -34,7 +34,9 @@ enum {
34int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 34int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
35void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 35void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
36int nfs_inode_return_delegation(struct inode *inode); 36int nfs_inode_return_delegation(struct inode *inode);
37int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); 37int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
38 int (*validate_stateid)(struct nfs_delegation *delegation,
39 const nfs4_stateid *stateid));
38void nfs_inode_return_delegation_noreclaim(struct inode *inode); 40void nfs_inode_return_delegation_noreclaim(struct inode *inode);
39 41
40struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); 42struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);