aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-05 14:55:18 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:40 -0400
commit901630278469c0d7610554227f39ed2d02d0d270 (patch)
treeb530f50e5838943826a215d402b1de770d970bde /fs/nfs
parent2ced46c27058710a6d731d6eca77f1dd14ccde75 (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>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/delegation.c80
-rw-r--r--fs/nfs/delegation.h10
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
60static void nfs_delegation_claim_opens(struct inode *inode) 60static 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 */
173int __nfs_inode_return_delegation(struct inode *inode) 175static 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
192static 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;
205nomatch:
206 return NULL;
207}
208
209int 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
27int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 27int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
28void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 28void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
29int __nfs_inode_return_delegation(struct inode *inode); 29int nfs_inode_return_delegation(struct inode *inode);
30int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); 30int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
31 31
32struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); 32struct 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
55static 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
64static inline int nfs_have_delegation(struct inode *inode, int flags) 56static inline int nfs_have_delegation(struct inode *inode, int flags)
65{ 57{