diff options
Diffstat (limited to 'fs/nfs/delegation.c')
| -rw-r--r-- | fs/nfs/delegation.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 6dd48a4405b4..2563bebc4c67 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -92,7 +92,7 @@ out: | |||
| 92 | return status; | 92 | return status; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) | 95 | static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) |
| 96 | { | 96 | { |
| 97 | struct nfs_inode *nfsi = NFS_I(inode); | 97 | struct nfs_inode *nfsi = NFS_I(inode); |
| 98 | struct nfs_open_context *ctx; | 98 | struct nfs_open_context *ctx; |
| @@ -116,10 +116,11 @@ again: | |||
| 116 | err = nfs_delegation_claim_locks(ctx, state); | 116 | err = nfs_delegation_claim_locks(ctx, state); |
| 117 | put_nfs_open_context(ctx); | 117 | put_nfs_open_context(ctx); |
| 118 | if (err != 0) | 118 | if (err != 0) |
| 119 | return; | 119 | return err; |
| 120 | goto again; | 120 | goto again; |
| 121 | } | 121 | } |
| 122 | spin_unlock(&inode->i_lock); | 122 | spin_unlock(&inode->i_lock); |
| 123 | return 0; | ||
| 123 | } | 124 | } |
| 124 | 125 | ||
| 125 | /* | 126 | /* |
| @@ -261,30 +262,34 @@ static void nfs_msync_inode(struct inode *inode) | |||
| 261 | /* | 262 | /* |
| 262 | * Basic procedure for returning a delegation to the server | 263 | * Basic procedure for returning a delegation to the server |
| 263 | */ | 264 | */ |
| 264 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) | 265 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) |
| 265 | { | 266 | { |
| 266 | struct nfs_inode *nfsi = NFS_I(inode); | 267 | struct nfs_inode *nfsi = NFS_I(inode); |
| 268 | int err; | ||
| 267 | 269 | ||
| 268 | nfs_msync_inode(inode); | ||
| 269 | /* | 270 | /* |
| 270 | * Guard against new delegated open/lock/unlock calls and against | 271 | * Guard against new delegated open/lock/unlock calls and against |
| 271 | * state recovery | 272 | * state recovery |
| 272 | */ | 273 | */ |
| 273 | down_write(&nfsi->rwsem); | 274 | down_write(&nfsi->rwsem); |
| 274 | nfs_delegation_claim_opens(inode, &delegation->stateid); | 275 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); |
| 275 | up_write(&nfsi->rwsem); | 276 | up_write(&nfsi->rwsem); |
| 276 | nfs_msync_inode(inode); | 277 | if (err) |
| 278 | goto out; | ||
| 277 | 279 | ||
| 278 | return nfs_do_return_delegation(inode, delegation, 1); | 280 | err = nfs_do_return_delegation(inode, delegation, issync); |
| 281 | out: | ||
| 282 | return err; | ||
| 279 | } | 283 | } |
| 280 | 284 | ||
| 281 | /* | 285 | /* |
| 282 | * Return all delegations that have been marked for return | 286 | * Return all delegations that have been marked for return |
| 283 | */ | 287 | */ |
| 284 | void nfs_client_return_marked_delegations(struct nfs_client *clp) | 288 | int nfs_client_return_marked_delegations(struct nfs_client *clp) |
| 285 | { | 289 | { |
| 286 | struct nfs_delegation *delegation; | 290 | struct nfs_delegation *delegation; |
| 287 | struct inode *inode; | 291 | struct inode *inode; |
| 292 | int err = 0; | ||
| 288 | 293 | ||
| 289 | restart: | 294 | restart: |
| 290 | rcu_read_lock(); | 295 | rcu_read_lock(); |
| @@ -298,12 +303,18 @@ restart: | |||
| 298 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 303 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); |
| 299 | spin_unlock(&clp->cl_lock); | 304 | spin_unlock(&clp->cl_lock); |
| 300 | rcu_read_unlock(); | 305 | rcu_read_unlock(); |
| 301 | if (delegation != NULL) | 306 | if (delegation != NULL) { |
| 302 | __nfs_inode_return_delegation(inode, delegation); | 307 | filemap_flush(inode->i_mapping); |
| 308 | err = __nfs_inode_return_delegation(inode, delegation, 0); | ||
| 309 | } | ||
| 303 | iput(inode); | 310 | iput(inode); |
| 304 | goto restart; | 311 | if (!err) |
| 312 | goto restart; | ||
| 313 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | ||
| 314 | return err; | ||
| 305 | } | 315 | } |
| 306 | rcu_read_unlock(); | 316 | rcu_read_unlock(); |
| 317 | return 0; | ||
| 307 | } | 318 | } |
| 308 | 319 | ||
| 309 | /* | 320 | /* |
| @@ -338,8 +349,10 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
| 338 | spin_lock(&clp->cl_lock); | 349 | spin_lock(&clp->cl_lock); |
| 339 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | 350 | delegation = nfs_detach_delegation_locked(nfsi, NULL); |
| 340 | spin_unlock(&clp->cl_lock); | 351 | spin_unlock(&clp->cl_lock); |
| 341 | if (delegation != NULL) | 352 | if (delegation != NULL) { |
| 342 | err = __nfs_inode_return_delegation(inode, delegation); | 353 | nfs_msync_inode(inode); |
| 354 | err = __nfs_inode_return_delegation(inode, delegation, 1); | ||
| 355 | } | ||
| 343 | } | 356 | } |
| 344 | return err; | 357 | return err; |
| 345 | } | 358 | } |
| @@ -368,33 +381,47 @@ void nfs_super_return_all_delegations(struct super_block *sb) | |||
| 368 | spin_unlock(&delegation->lock); | 381 | spin_unlock(&delegation->lock); |
| 369 | } | 382 | } |
| 370 | rcu_read_unlock(); | 383 | rcu_read_unlock(); |
| 371 | nfs_client_return_marked_delegations(clp); | 384 | if (nfs_client_return_marked_delegations(clp) != 0) |
| 385 | nfs4_schedule_state_manager(clp); | ||
| 372 | } | 386 | } |
| 373 | 387 | ||
| 374 | static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) | 388 | static |
| 389 | void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp, fmode_t flags) | ||
| 375 | { | 390 | { |
| 376 | struct nfs_delegation *delegation; | 391 | struct nfs_delegation *delegation; |
| 377 | 392 | ||
| 378 | rcu_read_lock(); | 393 | rcu_read_lock(); |
| 379 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 394 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
| 380 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | 395 | if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE)) |
| 381 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | 396 | continue; |
| 397 | if (delegation->type & flags) | ||
| 398 | nfs_mark_return_delegation(clp, delegation); | ||
| 382 | } | 399 | } |
| 383 | rcu_read_unlock(); | 400 | rcu_read_unlock(); |
| 384 | } | 401 | } |
| 385 | 402 | ||
| 403 | static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) | ||
| 404 | { | ||
| 405 | nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); | ||
| 406 | } | ||
| 407 | |||
| 386 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) | 408 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) |
| 387 | { | 409 | { |
| 388 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) | 410 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) |
| 389 | nfs4_schedule_state_manager(clp); | 411 | nfs4_schedule_state_manager(clp); |
| 390 | } | 412 | } |
| 391 | 413 | ||
| 392 | void nfs_expire_all_delegations(struct nfs_client *clp) | 414 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags) |
| 393 | { | 415 | { |
| 394 | nfs_client_mark_return_all_delegations(clp); | 416 | nfs_client_mark_return_all_delegation_types(clp, flags); |
| 395 | nfs_delegation_run_state_manager(clp); | 417 | nfs_delegation_run_state_manager(clp); |
| 396 | } | 418 | } |
| 397 | 419 | ||
| 420 | void nfs_expire_all_delegations(struct nfs_client *clp) | ||
| 421 | { | ||
| 422 | nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); | ||
| 423 | } | ||
| 424 | |||
| 398 | /* | 425 | /* |
| 399 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. | 426 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. |
| 400 | */ | 427 | */ |
| @@ -413,8 +440,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) { | 440 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
| 414 | if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) | 441 | if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) |
| 415 | continue; | 442 | continue; |
| 416 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | 443 | nfs_mark_return_delegation(clp, delegation); |
| 417 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | ||
| 418 | } | 444 | } |
| 419 | rcu_read_unlock(); | 445 | rcu_read_unlock(); |
| 420 | } | 446 | } |
| @@ -428,18 +454,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) | |||
| 428 | /* | 454 | /* |
| 429 | * Asynchronous delegation recall! | 455 | * Asynchronous delegation recall! |
| 430 | */ | 456 | */ |
| 431 | 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)) | ||
| 432 | { | 460 | { |
| 433 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 461 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
| 434 | struct nfs_delegation *delegation; | 462 | struct nfs_delegation *delegation; |
| 435 | 463 | ||
| 436 | rcu_read_lock(); | 464 | rcu_read_lock(); |
| 437 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 465 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
| 438 | if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, | 466 | |
| 439 | sizeof(delegation->stateid.data)) != 0) { | 467 | if (!validate_stateid(delegation, stateid)) { |
| 440 | rcu_read_unlock(); | 468 | rcu_read_unlock(); |
| 441 | return -ENOENT; | 469 | return -ENOENT; |
| 442 | } | 470 | } |
| 471 | |||
| 443 | nfs_mark_return_delegation(clp, delegation); | 472 | nfs_mark_return_delegation(clp, delegation); |
| 444 | rcu_read_unlock(); | 473 | rcu_read_unlock(); |
| 445 | nfs_delegation_run_state_manager(clp); | 474 | nfs_delegation_run_state_manager(clp); |
