aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/delegation.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/delegation.c')
-rw-r--r--fs/nfs/delegation.c147
1 files changed, 104 insertions, 43 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 81c5eec3cf38..2542cdaa1116 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -55,7 +55,8 @@ int nfs4_have_delegation(struct inode *inode, fmode_t flags)
55 flags &= FMODE_READ|FMODE_WRITE; 55 flags &= FMODE_READ|FMODE_WRITE;
56 rcu_read_lock(); 56 rcu_read_lock();
57 delegation = rcu_dereference(NFS_I(inode)->delegation); 57 delegation = rcu_dereference(NFS_I(inode)->delegation);
58 if (delegation != NULL && (delegation->type & flags) == flags) { 58 if (delegation != NULL && (delegation->type & flags) == flags &&
59 !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
59 nfs_mark_delegation_referenced(delegation); 60 nfs_mark_delegation_referenced(delegation);
60 ret = 1; 61 ret = 1;
61 } 62 }
@@ -94,7 +95,9 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s
94{ 95{
95 struct nfs_inode *nfsi = NFS_I(inode); 96 struct nfs_inode *nfsi = NFS_I(inode);
96 struct nfs_open_context *ctx; 97 struct nfs_open_context *ctx;
98 struct nfs4_state_owner *sp;
97 struct nfs4_state *state; 99 struct nfs4_state *state;
100 unsigned int seq;
98 int err; 101 int err;
99 102
100again: 103again:
@@ -109,9 +112,13 @@ again:
109 continue; 112 continue;
110 get_nfs_open_context(ctx); 113 get_nfs_open_context(ctx);
111 spin_unlock(&inode->i_lock); 114 spin_unlock(&inode->i_lock);
115 sp = state->owner;
116 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
112 err = nfs4_open_delegation_recall(ctx, state, stateid); 117 err = nfs4_open_delegation_recall(ctx, state, stateid);
113 if (err >= 0) 118 if (!err)
114 err = nfs_delegation_claim_locks(ctx, state); 119 err = nfs_delegation_claim_locks(ctx, state);
120 if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
121 err = -EAGAIN;
115 put_nfs_open_context(ctx); 122 put_nfs_open_context(ctx);
116 if (err != 0) 123 if (err != 0)
117 return err; 124 return err;
@@ -182,39 +189,91 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation
182} 189}
183 190
184static struct nfs_delegation * 191static struct nfs_delegation *
192nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
193{
194 struct nfs_delegation *ret = NULL;
195 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
196
197 if (delegation == NULL)
198 goto out;
199 spin_lock(&delegation->lock);
200 if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
201 ret = delegation;
202 spin_unlock(&delegation->lock);
203out:
204 return ret;
205}
206
207static struct nfs_delegation *
208nfs_start_delegation_return(struct nfs_inode *nfsi)
209{
210 struct nfs_delegation *delegation;
211
212 rcu_read_lock();
213 delegation = nfs_start_delegation_return_locked(nfsi);
214 rcu_read_unlock();
215 return delegation;
216}
217
218static void
219nfs_abort_delegation_return(struct nfs_delegation *delegation,
220 struct nfs_client *clp)
221{
222
223 spin_lock(&delegation->lock);
224 clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
225 set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
226 spin_unlock(&delegation->lock);
227 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
228}
229
230static struct nfs_delegation *
185nfs_detach_delegation_locked(struct nfs_inode *nfsi, 231nfs_detach_delegation_locked(struct nfs_inode *nfsi,
186 struct nfs_server *server) 232 struct nfs_delegation *delegation,
233 struct nfs_client *clp)
187{ 234{
188 struct nfs_delegation *delegation = 235 struct nfs_delegation *deleg_cur =
189 rcu_dereference_protected(nfsi->delegation, 236 rcu_dereference_protected(nfsi->delegation,
190 lockdep_is_held(&server->nfs_client->cl_lock)); 237 lockdep_is_held(&clp->cl_lock));
191 238
192 if (delegation == NULL) 239 if (deleg_cur == NULL || delegation != deleg_cur)
193 goto nomatch; 240 return NULL;
194 241
195 spin_lock(&delegation->lock); 242 spin_lock(&delegation->lock);
243 set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
196 list_del_rcu(&delegation->super_list); 244 list_del_rcu(&delegation->super_list);
197 delegation->inode = NULL; 245 delegation->inode = NULL;
198 nfsi->delegation_state = 0; 246 nfsi->delegation_state = 0;
199 rcu_assign_pointer(nfsi->delegation, NULL); 247 rcu_assign_pointer(nfsi->delegation, NULL);
200 spin_unlock(&delegation->lock); 248 spin_unlock(&delegation->lock);
201 return delegation; 249 return delegation;
202nomatch:
203 return NULL;
204} 250}
205 251
206static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi, 252static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
207 struct nfs_server *server) 253 struct nfs_delegation *delegation,
254 struct nfs_server *server)
208{ 255{
209 struct nfs_client *clp = server->nfs_client; 256 struct nfs_client *clp = server->nfs_client;
210 struct nfs_delegation *delegation;
211 257
212 spin_lock(&clp->cl_lock); 258 spin_lock(&clp->cl_lock);
213 delegation = nfs_detach_delegation_locked(nfsi, server); 259 delegation = nfs_detach_delegation_locked(nfsi, delegation, clp);
214 spin_unlock(&clp->cl_lock); 260 spin_unlock(&clp->cl_lock);
215 return delegation; 261 return delegation;
216} 262}
217 263
264static struct nfs_delegation *
265nfs_inode_detach_delegation(struct inode *inode)
266{
267 struct nfs_inode *nfsi = NFS_I(inode);
268 struct nfs_server *server = NFS_SERVER(inode);
269 struct nfs_delegation *delegation;
270
271 delegation = nfs_start_delegation_return(nfsi);
272 if (delegation == NULL)
273 return NULL;
274 return nfs_detach_delegation(nfsi, delegation, server);
275}
276
218/** 277/**
219 * nfs_inode_set_delegation - set up a delegation on an inode 278 * nfs_inode_set_delegation - set up a delegation on an inode
220 * @inode: inode to which delegation applies 279 * @inode: inode to which delegation applies
@@ -268,7 +327,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
268 delegation = NULL; 327 delegation = NULL;
269 goto out; 328 goto out;
270 } 329 }
271 freeme = nfs_detach_delegation_locked(nfsi, server); 330 freeme = nfs_detach_delegation_locked(nfsi,
331 old_delegation, clp);
332 if (freeme == NULL)
333 goto out;
272 } 334 }
273 list_add_rcu(&delegation->super_list, &server->delegations); 335 list_add_rcu(&delegation->super_list, &server->delegations);
274 nfsi->delegation_state = delegation->type; 336 nfsi->delegation_state = delegation->type;
@@ -292,19 +354,29 @@ out:
292/* 354/*
293 * Basic procedure for returning a delegation to the server 355 * Basic procedure for returning a delegation to the server
294 */ 356 */
295static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) 357static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
296{ 358{
359 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
297 struct nfs_inode *nfsi = NFS_I(inode); 360 struct nfs_inode *nfsi = NFS_I(inode);
298 int err; 361 int err;
299 362
300 /* 363 if (delegation == NULL)
301 * Guard against new delegated open/lock/unlock calls and against 364 return 0;
302 * state recovery 365 do {
303 */ 366 err = nfs_delegation_claim_opens(inode, &delegation->stateid);
304 down_write(&nfsi->rwsem); 367 if (!issync || err != -EAGAIN)
305 err = nfs_delegation_claim_opens(inode, &delegation->stateid); 368 break;
306 up_write(&nfsi->rwsem); 369 /*
307 if (err) 370 * Guard against state recovery
371 */
372 err = nfs4_wait_clnt_recover(clp);
373 } while (err == 0);
374
375 if (err) {
376 nfs_abort_delegation_return(delegation, clp);
377 goto out;
378 }
379 if (!nfs_detach_delegation(nfsi, delegation, NFS_SERVER(inode)))
308 goto out; 380 goto out;
309 381
310 err = nfs_do_return_delegation(inode, delegation, issync); 382 err = nfs_do_return_delegation(inode, delegation, issync);
@@ -340,13 +412,10 @@ restart:
340 inode = nfs_delegation_grab_inode(delegation); 412 inode = nfs_delegation_grab_inode(delegation);
341 if (inode == NULL) 413 if (inode == NULL)
342 continue; 414 continue;
343 delegation = nfs_detach_delegation(NFS_I(inode), 415 delegation = nfs_start_delegation_return_locked(NFS_I(inode));
344 server);
345 rcu_read_unlock(); 416 rcu_read_unlock();
346 417
347 if (delegation != NULL) 418 err = nfs_end_delegation_return(inode, delegation, 0);
348 err = __nfs_inode_return_delegation(inode,
349 delegation, 0);
350 iput(inode); 419 iput(inode);
351 if (!err) 420 if (!err)
352 goto restart; 421 goto restart;
@@ -367,15 +436,11 @@ restart:
367 */ 436 */
368void nfs_inode_return_delegation_noreclaim(struct inode *inode) 437void nfs_inode_return_delegation_noreclaim(struct inode *inode)
369{ 438{
370 struct nfs_server *server = NFS_SERVER(inode);
371 struct nfs_inode *nfsi = NFS_I(inode);
372 struct nfs_delegation *delegation; 439 struct nfs_delegation *delegation;
373 440
374 if (rcu_access_pointer(nfsi->delegation) != NULL) { 441 delegation = nfs_inode_detach_delegation(inode);
375 delegation = nfs_detach_delegation(nfsi, server); 442 if (delegation != NULL)
376 if (delegation != NULL) 443 nfs_do_return_delegation(inode, delegation, 0);
377 nfs_do_return_delegation(inode, delegation, 0);
378 }
379} 444}
380 445
381/** 446/**
@@ -390,18 +455,14 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode)
390 */ 455 */
391int nfs4_inode_return_delegation(struct inode *inode) 456int nfs4_inode_return_delegation(struct inode *inode)
392{ 457{
393 struct nfs_server *server = NFS_SERVER(inode);
394 struct nfs_inode *nfsi = NFS_I(inode); 458 struct nfs_inode *nfsi = NFS_I(inode);
395 struct nfs_delegation *delegation; 459 struct nfs_delegation *delegation;
396 int err = 0; 460 int err = 0;
397 461
398 nfs_wb_all(inode); 462 nfs_wb_all(inode);
399 if (rcu_access_pointer(nfsi->delegation) != NULL) { 463 delegation = nfs_start_delegation_return(nfsi);
400 delegation = nfs_detach_delegation(nfsi, server); 464 if (delegation != NULL)
401 if (delegation != NULL) { 465 err = nfs_end_delegation_return(inode, delegation, 1);
402 err = __nfs_inode_return_delegation(inode, delegation, 1);
403 }
404 }
405 return err; 466 return err;
406} 467}
407 468
@@ -471,7 +532,7 @@ void nfs_remove_bad_delegation(struct inode *inode)
471{ 532{
472 struct nfs_delegation *delegation; 533 struct nfs_delegation *delegation;
473 534
474 delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode)); 535 delegation = nfs_inode_detach_delegation(inode);
475 if (delegation) { 536 if (delegation) {
476 nfs_inode_find_state_and_recover(inode, &delegation->stateid); 537 nfs_inode_find_state_and_recover(inode, &delegation->stateid);
477 nfs_free_delegation(delegation); 538 nfs_free_delegation(delegation);
@@ -649,7 +710,7 @@ restart:
649 if (inode == NULL) 710 if (inode == NULL)
650 continue; 711 continue;
651 delegation = nfs_detach_delegation(NFS_I(inode), 712 delegation = nfs_detach_delegation(NFS_I(inode),
652 server); 713 delegation, server);
653 rcu_read_unlock(); 714 rcu_read_unlock();
654 715
655 if (delegation != NULL) 716 if (delegation != NULL)