aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4state.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r--fs/nfs/nfs4state.c104
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
407static struct nfs4_state_owner * 401static 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
479static 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
486static 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 }
543out:
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 */
522void nfs4_put_state_owner(struct nfs4_state_owner *sp) 552void 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 */
578void 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
536static struct nfs4_state * 597static struct nfs4_state *
@@ -1402,6 +1463,7 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
1402restart: 1463restart:
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;