diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-05 14:55:18 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:40 -0400 |
commit | 901630278469c0d7610554227f39ed2d02d0d270 (patch) | |
tree | b530f50e5838943826a215d402b1de770d970bde | |
parent | 2ced46c27058710a6d731d6eca77f1dd14ccde75 (diff) |
NFSv4: Support recalling delegations by stateid
There appear to be some rogue servers out there that issue multiple
delegations with different stateids for the same file. Ensure that when we
return delegations, we do so on a per-stateid basis rather than a per-file
basis.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/delegation.c | 80 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 10 |
2 files changed, 51 insertions, 39 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 9f17b91205cf..cee2ba42b68d 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -57,7 +57,7 @@ out_err: | |||
57 | return status; | 57 | return status; |
58 | } | 58 | } |
59 | 59 | ||
60 | static void nfs_delegation_claim_opens(struct inode *inode) | 60 | static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) |
61 | { | 61 | { |
62 | struct nfs_inode *nfsi = NFS_I(inode); | 62 | struct nfs_inode *nfsi = NFS_I(inode); |
63 | struct nfs_open_context *ctx; | 63 | struct nfs_open_context *ctx; |
@@ -72,6 +72,8 @@ again: | |||
72 | continue; | 72 | continue; |
73 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 73 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
74 | continue; | 74 | continue; |
75 | if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0) | ||
76 | continue; | ||
75 | get_nfs_open_context(ctx); | 77 | get_nfs_open_context(ctx); |
76 | spin_unlock(&inode->i_lock); | 78 | spin_unlock(&inode->i_lock); |
77 | err = nfs4_open_delegation_recall(ctx, state); | 79 | err = nfs4_open_delegation_recall(ctx, state); |
@@ -170,33 +172,55 @@ static void nfs_msync_inode(struct inode *inode) | |||
170 | /* | 172 | /* |
171 | * Basic procedure for returning a delegation to the server | 173 | * Basic procedure for returning a delegation to the server |
172 | */ | 174 | */ |
173 | int __nfs_inode_return_delegation(struct inode *inode) | 175 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) |
174 | { | 176 | { |
175 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 177 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
176 | struct nfs_inode *nfsi = NFS_I(inode); | 178 | struct nfs_inode *nfsi = NFS_I(inode); |
177 | struct nfs_delegation *delegation; | ||
178 | int res = 0; | ||
179 | 179 | ||
180 | nfs_msync_inode(inode); | 180 | nfs_msync_inode(inode); |
181 | down_read(&clp->cl_sem); | 181 | down_read(&clp->cl_sem); |
182 | /* Guard against new delegated open calls */ | 182 | /* Guard against new delegated open calls */ |
183 | down_write(&nfsi->rwsem); | 183 | down_write(&nfsi->rwsem); |
184 | spin_lock(&clp->cl_lock); | 184 | nfs_delegation_claim_opens(inode, &delegation->stateid); |
185 | delegation = nfsi->delegation; | ||
186 | if (delegation != NULL) { | ||
187 | list_del_init(&delegation->super_list); | ||
188 | nfsi->delegation = NULL; | ||
189 | nfsi->delegation_state = 0; | ||
190 | } | ||
191 | spin_unlock(&clp->cl_lock); | ||
192 | nfs_delegation_claim_opens(inode); | ||
193 | up_write(&nfsi->rwsem); | 185 | up_write(&nfsi->rwsem); |
194 | up_read(&clp->cl_sem); | 186 | up_read(&clp->cl_sem); |
195 | nfs_msync_inode(inode); | 187 | nfs_msync_inode(inode); |
196 | 188 | ||
197 | if (delegation != NULL) | 189 | return nfs_do_return_delegation(inode, delegation); |
198 | res = nfs_do_return_delegation(inode, delegation); | 190 | } |
199 | return res; | 191 | |
192 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | ||
193 | { | ||
194 | struct nfs_delegation *delegation = nfsi->delegation; | ||
195 | |||
196 | if (delegation == NULL) | ||
197 | goto nomatch; | ||
198 | if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | ||
199 | sizeof(delegation->stateid.data)) != 0) | ||
200 | goto nomatch; | ||
201 | list_del_init(&delegation->super_list); | ||
202 | nfsi->delegation = NULL; | ||
203 | nfsi->delegation_state = 0; | ||
204 | return delegation; | ||
205 | nomatch: | ||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | int nfs_inode_return_delegation(struct inode *inode) | ||
210 | { | ||
211 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | ||
212 | struct nfs_inode *nfsi = NFS_I(inode); | ||
213 | struct nfs_delegation *delegation; | ||
214 | int err = 0; | ||
215 | |||
216 | if (nfsi->delegation_state != 0) { | ||
217 | spin_lock(&clp->cl_lock); | ||
218 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | ||
219 | spin_unlock(&clp->cl_lock); | ||
220 | if (delegation != NULL) | ||
221 | err = __nfs_inode_return_delegation(inode, delegation); | ||
222 | } | ||
223 | return err; | ||
200 | } | 224 | } |
201 | 225 | ||
202 | /* | 226 | /* |
@@ -218,8 +242,9 @@ restart: | |||
218 | inode = igrab(delegation->inode); | 242 | inode = igrab(delegation->inode); |
219 | if (inode == NULL) | 243 | if (inode == NULL) |
220 | continue; | 244 | continue; |
245 | nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
221 | spin_unlock(&clp->cl_lock); | 246 | spin_unlock(&clp->cl_lock); |
222 | nfs_inode_return_delegation(inode); | 247 | __nfs_inode_return_delegation(inode, delegation); |
223 | iput(inode); | 248 | iput(inode); |
224 | goto restart; | 249 | goto restart; |
225 | } | 250 | } |
@@ -243,8 +268,9 @@ restart: | |||
243 | inode = igrab(delegation->inode); | 268 | inode = igrab(delegation->inode); |
244 | if (inode == NULL) | 269 | if (inode == NULL) |
245 | continue; | 270 | continue; |
271 | nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
246 | spin_unlock(&clp->cl_lock); | 272 | spin_unlock(&clp->cl_lock); |
247 | nfs_inode_return_delegation(inode); | 273 | __nfs_inode_return_delegation(inode, delegation); |
248 | iput(inode); | 274 | iput(inode); |
249 | goto restart; | 275 | goto restart; |
250 | } | 276 | } |
@@ -285,8 +311,9 @@ restart: | |||
285 | inode = igrab(delegation->inode); | 311 | inode = igrab(delegation->inode); |
286 | if (inode == NULL) | 312 | if (inode == NULL) |
287 | continue; | 313 | continue; |
314 | nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
288 | spin_unlock(&clp->cl_lock); | 315 | spin_unlock(&clp->cl_lock); |
289 | nfs_inode_return_delegation(inode); | 316 | __nfs_inode_return_delegation(inode, delegation); |
290 | iput(inode); | 317 | iput(inode); |
291 | goto restart; | 318 | goto restart; |
292 | } | 319 | } |
@@ -316,21 +343,14 @@ static int recall_thread(void *data) | |||
316 | down_read(&clp->cl_sem); | 343 | down_read(&clp->cl_sem); |
317 | down_write(&nfsi->rwsem); | 344 | down_write(&nfsi->rwsem); |
318 | spin_lock(&clp->cl_lock); | 345 | spin_lock(&clp->cl_lock); |
319 | delegation = nfsi->delegation; | 346 | delegation = nfs_detach_delegation_locked(nfsi, args->stateid); |
320 | if (delegation != NULL && memcmp(delegation->stateid.data, | 347 | if (delegation != NULL) |
321 | args->stateid->data, | ||
322 | sizeof(delegation->stateid.data)) == 0) { | ||
323 | list_del_init(&delegation->super_list); | ||
324 | nfsi->delegation = NULL; | ||
325 | nfsi->delegation_state = 0; | ||
326 | args->result = 0; | 348 | args->result = 0; |
327 | } else { | 349 | else |
328 | delegation = NULL; | ||
329 | args->result = -ENOENT; | 350 | args->result = -ENOENT; |
330 | } | ||
331 | spin_unlock(&clp->cl_lock); | 351 | spin_unlock(&clp->cl_lock); |
332 | complete(&args->started); | 352 | complete(&args->started); |
333 | nfs_delegation_claim_opens(inode); | 353 | nfs_delegation_claim_opens(inode, args->stateid); |
334 | up_write(&nfsi->rwsem); | 354 | up_write(&nfsi->rwsem); |
335 | up_read(&clp->cl_sem); | 355 | up_read(&clp->cl_sem); |
336 | nfs_msync_inode(inode); | 356 | nfs_msync_inode(inode); |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index f6e42fb21afb..7b22f1742445 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -26,7 +26,7 @@ struct nfs_delegation { | |||
26 | 26 | ||
27 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 27 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
28 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 28 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
29 | int __nfs_inode_return_delegation(struct inode *inode); | 29 | int nfs_inode_return_delegation(struct inode *inode); |
30 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 30 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
31 | 31 | ||
32 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 32 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
@@ -52,14 +52,6 @@ static inline int nfs_have_delegation(struct inode *inode, int flags) | |||
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
55 | static inline int nfs_inode_return_delegation(struct inode *inode) | ||
56 | { | ||
57 | int err = 0; | ||
58 | |||
59 | if (NFS_I(inode)->delegation != NULL) | ||
60 | err = __nfs_inode_return_delegation(inode); | ||
61 | return err; | ||
62 | } | ||
63 | #else | 55 | #else |
64 | static inline int nfs_have_delegation(struct inode *inode, int flags) | 56 | static inline int nfs_have_delegation(struct inode *inode, int flags) |
65 | { | 57 | { |