aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-10-20 02:29:13 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-20 13:26:44 -0400
commit1a047060a99f274a7c52cfea8159e4142a14b8a7 (patch)
tree5f9754ea24794b1346dc257b3a8702fa958785e8 /net
parente05d722e4555cd54677b4c8431d9e81fd047ef7a (diff)
[PATCH] knfsd: fix race that can disable NFS server
This patch is suitable for just about any 2.6 kernel. It should go in 2.6.19 and 2.6.18.2 and possible even the .17 and .16 stable series. This is a long standing bug that seems to have only recently become apparent, presumably due to increasing use of NFS over TCP - many distros seem to be making it the default. The SK_CONN bit gets set when a listening socket may be ready for an accept, just as SK_DATA is set when data may be available. It is entirely possible for svc_tcp_accept to be called with neither of these set. It doesn't happen often but there is a small race in svc_sock_enqueue as SK_CONN and SK_DATA are tested outside the spin_lock. They could be cleared immediately after the test and before the lock is gained. This normally shouldn't be a problem. The sockets are non-blocking so trying to read() or accept() when ther is nothing to do is not a problem. However: svc_tcp_recvfrom makes the decision "Should I accept() or should I read()" based on whether SK_CONN is set or not. This usually works but is not safe. The decision should be based on whether it is a TCP_LISTEN socket or a TCP_CONNECTED socket. Signed-off-by: Neil Brown <neilb@suse.de> Cc: Adrian Bunk <bunk@stusta.de> Cc: <stable@kernel.org> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/svcsock.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 61e307cca13d..96521f16342b 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -973,7 +973,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
973 return 0; 973 return 0;
974 } 974 }
975 975
976 if (test_bit(SK_CONN, &svsk->sk_flags)) { 976 if (svsk->sk_sk->sk_state == TCP_LISTEN) {
977 svc_tcp_accept(svsk); 977 svc_tcp_accept(svsk);
978 svc_sock_received(svsk); 978 svc_sock_received(svsk);
979 return 0; 979 return 0;