diff options
author | NeilBrown <neilb@suse.de> | 2007-02-07 11:10:26 +1100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-02-23 16:24:27 -0800 |
commit | a805446f1f5152d55fe31043b364ad3e79c63b0a (patch) | |
tree | 13bf0f6803a6a3eb201fa65262e63d3e80b5fc03 /net/sunrpc/svc.c | |
parent | 76d21f587d66f8508f6448c7253e46ff1881bec9 (diff) |
knfsd: Fix a race in closing NFSd connections.
If you lose this race, it can iput a socket inode twice and you
get a BUG in fs/inode.c
When I added the option for user-space to close a socket,
I added some cruft to svc_delete_socket so that I could call
that function when closing a socket per user-space request.
This was the wrong thing to do. I should have just set SK_CLOSE
and let normal mechanisms do the work.
Not only wrong, but buggy. The locking is all wrong and it openned
up a race where-by a socket could be closed twice.
So this patch:
Introduces svc_close_socket which sets SK_CLOSE then either leave
the close up to a thread, or calls svc_delete_socket if it can
get SK_BUSY.
Adds a bias to sk_busy which is removed when SK_DEAD is set,
This avoid races around shutting down the socket.
Changes several 'spin_lock' to 'spin_lock_bh' where the _bh
was missing.
Bugzilla-url: http://bugzilla.kernel.org/show_bug.cgi?id=7916
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'net/sunrpc/svc.c')
-rw-r--r-- | net/sunrpc/svc.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index f8179755bd5f..9359b84cc8d6 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -387,7 +387,7 @@ svc_destroy(struct svc_serv *serv) svsk = list_entry(serv->sv_tempsocks.next, struct svc_sock, sk_list); - svc_delete_socket(svsk); + svc_close_socket(svsk); } if (serv->sv_shutdown) serv->sv_shutdown(serv); @@ -396,7 +396,7 @@ svc_destroy(struct svc_serv *serv) svsk = list_entry(serv->sv_permsocks.next, struct svc_sock, sk_list); - svc_delete_socket(svsk); + svc_close_socket(svsk); } cache_clean_deferred(serv); |