diff options
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r-- | fs/nfs/nfs4state.c | 104 |
1 files changed, 83 insertions, 21 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 6a7107ae6b72..a53f33b4ac3a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/ratelimit.h> | 49 | #include <linux/ratelimit.h> |
50 | #include <linux/workqueue.h> | 50 | #include <linux/workqueue.h> |
51 | #include <linux/bitops.h> | 51 | #include <linux/bitops.h> |
52 | #include <linux/jiffies.h> | ||
52 | 53 | ||
53 | #include "nfs4_fs.h" | 54 | #include "nfs4_fs.h" |
54 | #include "callback.h" | 55 | #include "callback.h" |
@@ -377,31 +378,24 @@ nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred) | |||
377 | { | 378 | { |
378 | struct rb_node **p = &server->state_owners.rb_node, | 379 | struct rb_node **p = &server->state_owners.rb_node, |
379 | *parent = NULL; | 380 | *parent = NULL; |
380 | struct nfs4_state_owner *sp, *res = NULL; | 381 | struct nfs4_state_owner *sp; |
381 | 382 | ||
382 | while (*p != NULL) { | 383 | while (*p != NULL) { |
383 | parent = *p; | 384 | parent = *p; |
384 | sp = rb_entry(parent, struct nfs4_state_owner, so_server_node); | 385 | sp = rb_entry(parent, struct nfs4_state_owner, so_server_node); |
385 | 386 | ||
386 | if (server < sp->so_server) { | ||
387 | p = &parent->rb_left; | ||
388 | continue; | ||
389 | } | ||
390 | if (server > sp->so_server) { | ||
391 | p = &parent->rb_right; | ||
392 | continue; | ||
393 | } | ||
394 | if (cred < sp->so_cred) | 387 | if (cred < sp->so_cred) |
395 | p = &parent->rb_left; | 388 | p = &parent->rb_left; |
396 | else if (cred > sp->so_cred) | 389 | else if (cred > sp->so_cred) |
397 | p = &parent->rb_right; | 390 | p = &parent->rb_right; |
398 | else { | 391 | else { |
392 | if (!list_empty(&sp->so_lru)) | ||
393 | list_del_init(&sp->so_lru); | ||
399 | atomic_inc(&sp->so_count); | 394 | atomic_inc(&sp->so_count); |
400 | res = sp; | 395 | return sp; |
401 | break; | ||
402 | } | 396 | } |
403 | } | 397 | } |
404 | return res; | 398 | return NULL; |
405 | } | 399 | } |
406 | 400 | ||
407 | static struct nfs4_state_owner * | 401 | static struct nfs4_state_owner * |
@@ -421,6 +415,8 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new) | |||
421 | else if (new->so_cred > sp->so_cred) | 415 | else if (new->so_cred > sp->so_cred) |
422 | p = &parent->rb_right; | 416 | p = &parent->rb_right; |
423 | else { | 417 | else { |
418 | if (!list_empty(&sp->so_lru)) | ||
419 | list_del_init(&sp->so_lru); | ||
424 | atomic_inc(&sp->so_count); | 420 | atomic_inc(&sp->so_count); |
425 | return sp; | 421 | return sp; |
426 | } | 422 | } |
@@ -462,6 +458,7 @@ nfs4_alloc_state_owner(void) | |||
462 | spin_lock_init(&sp->so_sequence.lock); | 458 | spin_lock_init(&sp->so_sequence.lock); |
463 | INIT_LIST_HEAD(&sp->so_sequence.list); | 459 | INIT_LIST_HEAD(&sp->so_sequence.list); |
464 | atomic_set(&sp->so_count, 1); | 460 | atomic_set(&sp->so_count, 1); |
461 | INIT_LIST_HEAD(&sp->so_lru); | ||
465 | return sp; | 462 | return sp; |
466 | } | 463 | } |
467 | 464 | ||
@@ -479,6 +476,38 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |||
479 | } | 476 | } |
480 | } | 477 | } |
481 | 478 | ||
479 | static void nfs4_free_state_owner(struct nfs4_state_owner *sp) | ||
480 | { | ||
481 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | ||
482 | put_rpccred(sp->so_cred); | ||
483 | kfree(sp); | ||
484 | } | ||
485 | |||
486 | static void nfs4_gc_state_owners(struct nfs_server *server) | ||
487 | { | ||
488 | struct nfs_client *clp = server->nfs_client; | ||
489 | struct nfs4_state_owner *sp, *tmp; | ||
490 | unsigned long time_min, time_max; | ||
491 | LIST_HEAD(doomed); | ||
492 | |||
493 | spin_lock(&clp->cl_lock); | ||
494 | time_max = jiffies; | ||
495 | time_min = (long)time_max - (long)clp->cl_lease_time; | ||
496 | list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) { | ||
497 | /* NB: LRU is sorted so that oldest is at the head */ | ||
498 | if (time_in_range(sp->so_expires, time_min, time_max)) | ||
499 | break; | ||
500 | list_move(&sp->so_lru, &doomed); | ||
501 | nfs4_remove_state_owner_locked(sp); | ||
502 | } | ||
503 | spin_unlock(&clp->cl_lock); | ||
504 | |||
505 | list_for_each_entry_safe(sp, tmp, &doomed, so_lru) { | ||
506 | list_del(&sp->so_lru); | ||
507 | nfs4_free_state_owner(sp); | ||
508 | } | ||
509 | } | ||
510 | |||
482 | /** | 511 | /** |
483 | * nfs4_get_state_owner - Look up a state owner given a credential | 512 | * nfs4_get_state_owner - Look up a state owner given a credential |
484 | * @server: nfs_server to search | 513 | * @server: nfs_server to search |
@@ -496,10 +525,10 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, | |||
496 | sp = nfs4_find_state_owner_locked(server, cred); | 525 | sp = nfs4_find_state_owner_locked(server, cred); |
497 | spin_unlock(&clp->cl_lock); | 526 | spin_unlock(&clp->cl_lock); |
498 | if (sp != NULL) | 527 | if (sp != NULL) |
499 | return sp; | 528 | goto out; |
500 | new = nfs4_alloc_state_owner(); | 529 | new = nfs4_alloc_state_owner(); |
501 | if (new == NULL) | 530 | if (new == NULL) |
502 | return NULL; | 531 | goto out; |
503 | new->so_server = server; | 532 | new->so_server = server; |
504 | new->so_cred = cred; | 533 | new->so_cred = cred; |
505 | spin_lock(&clp->cl_lock); | 534 | spin_lock(&clp->cl_lock); |
@@ -511,26 +540,58 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, | |||
511 | rpc_destroy_wait_queue(&new->so_sequence.wait); | 540 | rpc_destroy_wait_queue(&new->so_sequence.wait); |
512 | kfree(new); | 541 | kfree(new); |
513 | } | 542 | } |
543 | out: | ||
544 | nfs4_gc_state_owners(server); | ||
514 | return sp; | 545 | return sp; |
515 | } | 546 | } |
516 | 547 | ||
517 | /** | 548 | /** |
518 | * nfs4_put_state_owner - Release a nfs4_state_owner | 549 | * nfs4_put_state_owner - Release a nfs4_state_owner |
519 | * @sp: state owner data to release | 550 | * @sp: state owner data to release |
520 | * | ||
521 | */ | 551 | */ |
522 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 552 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
523 | { | 553 | { |
524 | struct nfs_client *clp = sp->so_server->nfs_client; | 554 | struct nfs_server *server = sp->so_server; |
525 | struct rpc_cred *cred = sp->so_cred; | 555 | struct nfs_client *clp = server->nfs_client; |
526 | 556 | ||
527 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 557 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) |
528 | return; | 558 | return; |
529 | nfs4_remove_state_owner_locked(sp); | 559 | |
560 | if (!RB_EMPTY_NODE(&sp->so_server_node)) { | ||
561 | sp->so_expires = jiffies; | ||
562 | list_add_tail(&sp->so_lru, &server->state_owners_lru); | ||
563 | spin_unlock(&clp->cl_lock); | ||
564 | } else { | ||
565 | nfs4_remove_state_owner_locked(sp); | ||
566 | spin_unlock(&clp->cl_lock); | ||
567 | nfs4_free_state_owner(sp); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * nfs4_purge_state_owners - Release all cached state owners | ||
573 | * @server: nfs_server with cached state owners to release | ||
574 | * | ||
575 | * Called at umount time. Remaining state owners will be on | ||
576 | * the LRU with ref count of zero. | ||
577 | */ | ||
578 | void nfs4_purge_state_owners(struct nfs_server *server) | ||
579 | { | ||
580 | struct nfs_client *clp = server->nfs_client; | ||
581 | struct nfs4_state_owner *sp, *tmp; | ||
582 | LIST_HEAD(doomed); | ||
583 | |||
584 | spin_lock(&clp->cl_lock); | ||
585 | list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) { | ||
586 | list_move(&sp->so_lru, &doomed); | ||
587 | nfs4_remove_state_owner_locked(sp); | ||
588 | } | ||
530 | spin_unlock(&clp->cl_lock); | 589 | spin_unlock(&clp->cl_lock); |
531 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | 590 | |
532 | put_rpccred(cred); | 591 | list_for_each_entry_safe(sp, tmp, &doomed, so_lru) { |
533 | kfree(sp); | 592 | list_del(&sp->so_lru); |
593 | nfs4_free_state_owner(sp); | ||
594 | } | ||
534 | } | 595 | } |
535 | 596 | ||
536 | static struct nfs4_state * | 597 | static struct nfs4_state * |
@@ -1402,6 +1463,7 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov | |||
1402 | restart: | 1463 | restart: |
1403 | rcu_read_lock(); | 1464 | rcu_read_lock(); |
1404 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 1465 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
1466 | nfs4_purge_state_owners(server); | ||
1405 | spin_lock(&clp->cl_lock); | 1467 | spin_lock(&clp->cl_lock); |
1406 | for (pos = rb_first(&server->state_owners); | 1468 | for (pos = rb_first(&server->state_owners); |
1407 | pos != NULL; | 1469 | pos != NULL; |