aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/delegation.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /fs/nfs/delegation.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'fs/nfs/delegation.c')
-rw-r--r--fs/nfs/delegation.c164
1 files changed, 105 insertions, 59 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 6dd48a4405b4..ea61d26e7871 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -10,6 +10,7 @@
10#include <linux/kthread.h> 10#include <linux/kthread.h>
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/sched.h> 12#include <linux/sched.h>
13#include <linux/slab.h>
13#include <linux/smp_lock.h> 14#include <linux/smp_lock.h>
14#include <linux/spinlock.h> 15#include <linux/spinlock.h>
15 16
@@ -23,6 +24,8 @@
23 24
24static void nfs_do_free_delegation(struct nfs_delegation *delegation) 25static void nfs_do_free_delegation(struct nfs_delegation *delegation)
25{ 26{
27 if (delegation->cred)
28 put_rpccred(delegation->cred);
26 kfree(delegation); 29 kfree(delegation);
27} 30}
28 31
@@ -35,13 +38,7 @@ static void nfs_free_delegation_callback(struct rcu_head *head)
35 38
36static void nfs_free_delegation(struct nfs_delegation *delegation) 39static void nfs_free_delegation(struct nfs_delegation *delegation)
37{ 40{
38 struct rpc_cred *cred;
39
40 cred = rcu_dereference(delegation->cred);
41 rcu_assign_pointer(delegation->cred, NULL);
42 call_rcu(&delegation->rcu, nfs_free_delegation_callback); 41 call_rcu(&delegation->rcu, nfs_free_delegation_callback);
43 if (cred)
44 put_rpccred(cred);
45} 42}
46 43
47void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) 44void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
@@ -92,7 +89,7 @@ out:
92 return status; 89 return status;
93} 90}
94 91
95static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) 92static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
96{ 93{
97 struct nfs_inode *nfsi = NFS_I(inode); 94 struct nfs_inode *nfsi = NFS_I(inode);
98 struct nfs_open_context *ctx; 95 struct nfs_open_context *ctx;
@@ -116,10 +113,11 @@ again:
116 err = nfs_delegation_claim_locks(ctx, state); 113 err = nfs_delegation_claim_locks(ctx, state);
117 put_nfs_open_context(ctx); 114 put_nfs_open_context(ctx);
118 if (err != 0) 115 if (err != 0)
119 return; 116 return err;
120 goto again; 117 goto again;
121 } 118 }
122 spin_unlock(&inode->i_lock); 119 spin_unlock(&inode->i_lock);
120 return 0;
123} 121}
124 122
125/* 123/*
@@ -127,21 +125,35 @@ again:
127 */ 125 */
128void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) 126void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
129{ 127{
130 struct nfs_delegation *delegation = NFS_I(inode)->delegation; 128 struct nfs_delegation *delegation;
131 struct rpc_cred *oldcred; 129 struct rpc_cred *oldcred = NULL;
132 130
133 if (delegation == NULL) 131 rcu_read_lock();
134 return; 132 delegation = rcu_dereference(NFS_I(inode)->delegation);
135 memcpy(delegation->stateid.data, res->delegation.data, 133 if (delegation != NULL) {
136 sizeof(delegation->stateid.data)); 134 spin_lock(&delegation->lock);
137 delegation->type = res->delegation_type; 135 if (delegation->inode != NULL) {
138 delegation->maxsize = res->maxsize; 136 memcpy(delegation->stateid.data, res->delegation.data,
139 oldcred = delegation->cred; 137 sizeof(delegation->stateid.data));
140 delegation->cred = get_rpccred(cred); 138 delegation->type = res->delegation_type;
141 clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); 139 delegation->maxsize = res->maxsize;
142 NFS_I(inode)->delegation_state = delegation->type; 140 oldcred = delegation->cred;
143 smp_wmb(); 141 delegation->cred = get_rpccred(cred);
144 put_rpccred(oldcred); 142 clear_bit(NFS_DELEGATION_NEED_RECLAIM,
143 &delegation->flags);
144 NFS_I(inode)->delegation_state = delegation->type;
145 spin_unlock(&delegation->lock);
146 put_rpccred(oldcred);
147 rcu_read_unlock();
148 } else {
149 /* We appear to have raced with a delegation return. */
150 spin_unlock(&delegation->lock);
151 rcu_read_unlock();
152 nfs_inode_set_delegation(inode, cred, res);
153 }
154 } else {
155 rcu_read_unlock();
156 }
145} 157}
146 158
147static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) 159static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
@@ -164,9 +176,13 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation
164 return inode; 176 return inode;
165} 177}
166 178
167static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) 179static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi,
180 const nfs4_stateid *stateid,
181 struct nfs_client *clp)
168{ 182{
169 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); 183 struct nfs_delegation *delegation =
184 rcu_dereference_protected(nfsi->delegation,
185 lockdep_is_held(&clp->cl_lock));
170 186
171 if (delegation == NULL) 187 if (delegation == NULL)
172 goto nomatch; 188 goto nomatch;
@@ -193,7 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
193{ 209{
194 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; 210 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
195 struct nfs_inode *nfsi = NFS_I(inode); 211 struct nfs_inode *nfsi = NFS_I(inode);
196 struct nfs_delegation *delegation; 212 struct nfs_delegation *delegation, *old_delegation;
197 struct nfs_delegation *freeme = NULL; 213 struct nfs_delegation *freeme = NULL;
198 int status = 0; 214 int status = 0;
199 215
@@ -211,10 +227,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
211 spin_lock_init(&delegation->lock); 227 spin_lock_init(&delegation->lock);
212 228
213 spin_lock(&clp->cl_lock); 229 spin_lock(&clp->cl_lock);
214 if (rcu_dereference(nfsi->delegation) != NULL) { 230 old_delegation = rcu_dereference_protected(nfsi->delegation,
215 if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, 231 lockdep_is_held(&clp->cl_lock));
216 sizeof(delegation->stateid)) == 0 && 232 if (old_delegation != NULL) {
217 delegation->type == nfsi->delegation->type) { 233 if (memcmp(&delegation->stateid, &old_delegation->stateid,
234 sizeof(old_delegation->stateid)) == 0 &&
235 delegation->type == old_delegation->type) {
218 goto out; 236 goto out;
219 } 237 }
220 /* 238 /*
@@ -224,12 +242,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
224 dfprintk(FILE, "%s: server %s handed out " 242 dfprintk(FILE, "%s: server %s handed out "
225 "a duplicate delegation!\n", 243 "a duplicate delegation!\n",
226 __func__, clp->cl_hostname); 244 __func__, clp->cl_hostname);
227 if (delegation->type <= nfsi->delegation->type) { 245 if (delegation->type <= old_delegation->type) {
228 freeme = delegation; 246 freeme = delegation;
229 delegation = NULL; 247 delegation = NULL;
230 goto out; 248 goto out;
231 } 249 }
232 freeme = nfs_detach_delegation_locked(nfsi, NULL); 250 freeme = nfs_detach_delegation_locked(nfsi, NULL, clp);
233 } 251 }
234 list_add_rcu(&delegation->super_list, &clp->cl_delegations); 252 list_add_rcu(&delegation->super_list, &clp->cl_delegations);
235 nfsi->delegation_state = delegation->type; 253 nfsi->delegation_state = delegation->type;
@@ -261,30 +279,34 @@ static void nfs_msync_inode(struct inode *inode)
261/* 279/*
262 * Basic procedure for returning a delegation to the server 280 * Basic procedure for returning a delegation to the server
263 */ 281 */
264static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) 282static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
265{ 283{
266 struct nfs_inode *nfsi = NFS_I(inode); 284 struct nfs_inode *nfsi = NFS_I(inode);
285 int err;
267 286
268 nfs_msync_inode(inode);
269 /* 287 /*
270 * Guard against new delegated open/lock/unlock calls and against 288 * Guard against new delegated open/lock/unlock calls and against
271 * state recovery 289 * state recovery
272 */ 290 */
273 down_write(&nfsi->rwsem); 291 down_write(&nfsi->rwsem);
274 nfs_delegation_claim_opens(inode, &delegation->stateid); 292 err = nfs_delegation_claim_opens(inode, &delegation->stateid);
275 up_write(&nfsi->rwsem); 293 up_write(&nfsi->rwsem);
276 nfs_msync_inode(inode); 294 if (err)
295 goto out;
277 296
278 return nfs_do_return_delegation(inode, delegation, 1); 297 err = nfs_do_return_delegation(inode, delegation, issync);
298out:
299 return err;
279} 300}
280 301
281/* 302/*
282 * Return all delegations that have been marked for return 303 * Return all delegations that have been marked for return
283 */ 304 */
284void nfs_client_return_marked_delegations(struct nfs_client *clp) 305int nfs_client_return_marked_delegations(struct nfs_client *clp)
285{ 306{
286 struct nfs_delegation *delegation; 307 struct nfs_delegation *delegation;
287 struct inode *inode; 308 struct inode *inode;
309 int err = 0;
288 310
289restart: 311restart:
290 rcu_read_lock(); 312 rcu_read_lock();
@@ -295,15 +317,21 @@ restart:
295 if (inode == NULL) 317 if (inode == NULL)
296 continue; 318 continue;
297 spin_lock(&clp->cl_lock); 319 spin_lock(&clp->cl_lock);
298 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); 320 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp);
299 spin_unlock(&clp->cl_lock); 321 spin_unlock(&clp->cl_lock);
300 rcu_read_unlock(); 322 rcu_read_unlock();
301 if (delegation != NULL) 323 if (delegation != NULL) {
302 __nfs_inode_return_delegation(inode, delegation); 324 filemap_flush(inode->i_mapping);
325 err = __nfs_inode_return_delegation(inode, delegation, 0);
326 }
303 iput(inode); 327 iput(inode);
304 goto restart; 328 if (!err)
329 goto restart;
330 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
331 return err;
305 } 332 }
306 rcu_read_unlock(); 333 rcu_read_unlock();
334 return 0;
307} 335}
308 336
309/* 337/*
@@ -318,9 +346,9 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode)
318 struct nfs_inode *nfsi = NFS_I(inode); 346 struct nfs_inode *nfsi = NFS_I(inode);
319 struct nfs_delegation *delegation; 347 struct nfs_delegation *delegation;
320 348
321 if (rcu_dereference(nfsi->delegation) != NULL) { 349 if (rcu_access_pointer(nfsi->delegation) != NULL) {
322 spin_lock(&clp->cl_lock); 350 spin_lock(&clp->cl_lock);
323 delegation = nfs_detach_delegation_locked(nfsi, NULL); 351 delegation = nfs_detach_delegation_locked(nfsi, NULL, clp);
324 spin_unlock(&clp->cl_lock); 352 spin_unlock(&clp->cl_lock);
325 if (delegation != NULL) 353 if (delegation != NULL)
326 nfs_do_return_delegation(inode, delegation, 0); 354 nfs_do_return_delegation(inode, delegation, 0);
@@ -334,12 +362,14 @@ int nfs_inode_return_delegation(struct inode *inode)
334 struct nfs_delegation *delegation; 362 struct nfs_delegation *delegation;
335 int err = 0; 363 int err = 0;
336 364
337 if (rcu_dereference(nfsi->delegation) != NULL) { 365 if (rcu_access_pointer(nfsi->delegation) != NULL) {
338 spin_lock(&clp->cl_lock); 366 spin_lock(&clp->cl_lock);
339 delegation = nfs_detach_delegation_locked(nfsi, NULL); 367 delegation = nfs_detach_delegation_locked(nfsi, NULL, clp);
340 spin_unlock(&clp->cl_lock); 368 spin_unlock(&clp->cl_lock);
341 if (delegation != NULL) 369 if (delegation != NULL) {
342 err = __nfs_inode_return_delegation(inode, delegation); 370 nfs_msync_inode(inode);
371 err = __nfs_inode_return_delegation(inode, delegation, 1);
372 }
343 } 373 }
344 return err; 374 return err;
345} 375}
@@ -368,33 +398,47 @@ void nfs_super_return_all_delegations(struct super_block *sb)
368 spin_unlock(&delegation->lock); 398 spin_unlock(&delegation->lock);
369 } 399 }
370 rcu_read_unlock(); 400 rcu_read_unlock();
371 nfs_client_return_marked_delegations(clp); 401 if (nfs_client_return_marked_delegations(clp) != 0)
402 nfs4_schedule_state_manager(clp);
372} 403}
373 404
374static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) 405static
406void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp, fmode_t flags)
375{ 407{
376 struct nfs_delegation *delegation; 408 struct nfs_delegation *delegation;
377 409
378 rcu_read_lock(); 410 rcu_read_lock();
379 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { 411 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
380 set_bit(NFS_DELEGATION_RETURN, &delegation->flags); 412 if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
381 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); 413 continue;
414 if (delegation->type & flags)
415 nfs_mark_return_delegation(clp, delegation);
382 } 416 }
383 rcu_read_unlock(); 417 rcu_read_unlock();
384} 418}
385 419
420static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
421{
422 nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
423}
424
386static void nfs_delegation_run_state_manager(struct nfs_client *clp) 425static void nfs_delegation_run_state_manager(struct nfs_client *clp)
387{ 426{
388 if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) 427 if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
389 nfs4_schedule_state_manager(clp); 428 nfs4_schedule_state_manager(clp);
390} 429}
391 430
392void nfs_expire_all_delegations(struct nfs_client *clp) 431void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
393{ 432{
394 nfs_client_mark_return_all_delegations(clp); 433 nfs_client_mark_return_all_delegation_types(clp, flags);
395 nfs_delegation_run_state_manager(clp); 434 nfs_delegation_run_state_manager(clp);
396} 435}
397 436
437void nfs_expire_all_delegations(struct nfs_client *clp)
438{
439 nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
440}
441
398/* 442/*
399 * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. 443 * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
400 */ 444 */
@@ -413,8 +457,7 @@ static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *c
413 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { 457 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
414 if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) 458 if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
415 continue; 459 continue;
416 set_bit(NFS_DELEGATION_RETURN, &delegation->flags); 460 nfs_mark_return_delegation(clp, delegation);
417 set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
418 } 461 }
419 rcu_read_unlock(); 462 rcu_read_unlock();
420} 463}
@@ -428,18 +471,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
428/* 471/*
429 * Asynchronous delegation recall! 472 * Asynchronous delegation recall!
430 */ 473 */
431int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) 474int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
475 int (*validate_stateid)(struct nfs_delegation *delegation,
476 const nfs4_stateid *stateid))
432{ 477{
433 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; 478 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
434 struct nfs_delegation *delegation; 479 struct nfs_delegation *delegation;
435 480
436 rcu_read_lock(); 481 rcu_read_lock();
437 delegation = rcu_dereference(NFS_I(inode)->delegation); 482 delegation = rcu_dereference(NFS_I(inode)->delegation);
438 if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, 483
439 sizeof(delegation->stateid.data)) != 0) { 484 if (!validate_stateid(delegation, stateid)) {
440 rcu_read_unlock(); 485 rcu_read_unlock();
441 return -ENOENT; 486 return -ENOENT;
442 } 487 }
488
443 nfs_mark_return_delegation(clp, delegation); 489 nfs_mark_return_delegation(clp, delegation);
444 rcu_read_unlock(); 490 rcu_read_unlock();
445 nfs_delegation_run_state_manager(clp); 491 nfs_delegation_run_state_manager(clp);
@@ -496,7 +542,7 @@ restart:
496 if (inode == NULL) 542 if (inode == NULL)
497 continue; 543 continue;
498 spin_lock(&clp->cl_lock); 544 spin_lock(&clp->cl_lock);
499 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); 545 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp);
500 spin_unlock(&clp->cl_lock); 546 spin_unlock(&clp->cl_lock);
501 rcu_read_unlock(); 547 rcu_read_unlock();
502 if (delegation != NULL) 548 if (delegation != NULL)