diff options
author | Alexandros Batsakis <batsakis@netapp.com> | 2009-12-05 13:48:55 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-12-05 13:48:55 -0500 |
commit | 2597641deae82c9a95e255518da189ab557da0af (patch) | |
tree | 0b2dc7c46f2a0398ecefd6bb63a657710cf921fa /fs | |
parent | 0629e370dd5819efa5cf8d418a8e6729efe388ef (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')
-rw-r--r-- | fs/nfs/callback.h | 5 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 37 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 9 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 4 |
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 { | |||
106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | 106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, |
107 | struct cb_sequenceres *res); | 107 | struct cb_sequenceres *res); |
108 | 108 | ||
109 | extern 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 |
126 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); | 128 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
127 | extern void nfs_callback_down(int minorversion); | 129 | extern void nfs_callback_down(int minorversion); |
130 | extern 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 | ||
64 | static 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 | ||
116 | int 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 | ||
126 | int 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 | */ |
457 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) | 457 | int 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 { | |||
34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
36 | int nfs_inode_return_delegation(struct inode *inode); | 36 | int nfs_inode_return_delegation(struct inode *inode); |
37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 37 | int 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)); | ||
38 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | 40 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); |
39 | 41 | ||
40 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 42 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |