diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-21 12:31:05 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-21 12:31:05 -0400 |
commit | c77365c963cf8703ecf1004cd3b298068a3e1b76 (patch) | |
tree | 449a02a25c425148a52c5bec073787902ad86fed | |
parent | 95b72eb0bdef6476b7e73061f0382adf46c5495a (diff) |
NFSv4: Ensure that we don't drop a state owner more than once
Retest the RB_EMPTY_NODE() condition under the spin lock
to ensure that we don't call rb_erase() more than once on the
same state owner.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4state.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 3b07f094f3a9..b300fb840b21 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -435,13 +435,17 @@ nfs4_alloc_state_owner(struct nfs_server *server, | |||
435 | static void | 435 | static void |
436 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | 436 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) |
437 | { | 437 | { |
438 | if (!RB_EMPTY_NODE(&sp->so_server_node)) { | 438 | struct rb_node *rb_node = &sp->so_server_node; |
439 | |||
440 | if (!RB_EMPTY_NODE(rb_node)) { | ||
439 | struct nfs_server *server = sp->so_server; | 441 | struct nfs_server *server = sp->so_server; |
440 | struct nfs_client *clp = server->nfs_client; | 442 | struct nfs_client *clp = server->nfs_client; |
441 | 443 | ||
442 | spin_lock(&clp->cl_lock); | 444 | spin_lock(&clp->cl_lock); |
443 | rb_erase(&sp->so_server_node, &server->state_owners); | 445 | if (!RB_EMPTY_NODE(rb_node)) { |
444 | RB_CLEAR_NODE(&sp->so_server_node); | 446 | rb_erase(rb_node, &server->state_owners); |
447 | RB_CLEAR_NODE(rb_node); | ||
448 | } | ||
445 | spin_unlock(&clp->cl_lock); | 449 | spin_unlock(&clp->cl_lock); |
446 | } | 450 | } |
447 | } | 451 | } |