diff options
author | NeilBrown <neilb@suse.de> | 2007-02-08 17:20:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-09 12:25:47 -0500 |
commit | aaf68cfbf2241d24d46583423f6bff5c47e088b3 (patch) | |
tree | 65ca14b85d28b12da097d7d187cebfef88b5ba3a /net/sunrpc/svc.c | |
parent | 387bb17374c5fa057462d00d4ba941d49f45de4d (diff) |
[PATCH] 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>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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 4c1611211119..c1f878131ac6 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -386,7 +386,7 @@ svc_destroy(struct svc_serv *serv) | |||
386 | svsk = list_entry(serv->sv_tempsocks.next, | 386 | svsk = list_entry(serv->sv_tempsocks.next, |
387 | struct svc_sock, | 387 | struct svc_sock, |
388 | sk_list); | 388 | sk_list); |
389 | svc_delete_socket(svsk); | 389 | svc_close_socket(svsk); |
390 | } | 390 | } |
391 | if (serv->sv_shutdown) | 391 | if (serv->sv_shutdown) |
392 | serv->sv_shutdown(serv); | 392 | serv->sv_shutdown(serv); |
@@ -395,7 +395,7 @@ svc_destroy(struct svc_serv *serv) | |||
395 | svsk = list_entry(serv->sv_permsocks.next, | 395 | svsk = list_entry(serv->sv_permsocks.next, |
396 | struct svc_sock, | 396 | struct svc_sock, |
397 | sk_list); | 397 | sk_list); |
398 | svc_delete_socket(svsk); | 398 | svc_close_socket(svsk); |
399 | } | 399 | } |
400 | 400 | ||
401 | cache_clean_deferred(serv); | 401 | cache_clean_deferred(serv); |