Commit fdefaeab authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] Reorganise sock init in rpcsvc to avoid races.

If one of the callback (e.g. data ready) is called
before socket setup is complete, oops may occur.

With this patch, socket is kept SK_BUSY until all is
ready to avoid this.

Also some code is moved around to make it cleaner.
parent 9e73aa9c
...@@ -627,7 +627,7 @@ svc_udp_sendto(struct svc_rqst *rqstp) ...@@ -627,7 +627,7 @@ svc_udp_sendto(struct svc_rqst *rqstp)
return error; return error;
} }
static int static void
svc_udp_init(struct svc_sock *svsk) svc_udp_init(struct svc_sock *svsk)
{ {
svsk->sk_sk->data_ready = svc_udp_data_ready; svsk->sk_sk->data_ready = svc_udp_data_ready;
...@@ -643,9 +643,8 @@ svc_udp_init(struct svc_sock *svsk) ...@@ -643,9 +643,8 @@ svc_udp_init(struct svc_sock *svsk)
3 * svsk->sk_server->sv_bufsz, 3 * svsk->sk_server->sv_bufsz,
3 * svsk->sk_server->sv_bufsz); 3 * svsk->sk_server->sv_bufsz);
set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */
set_bit(SK_CHNGBUF, &svsk->sk_flags); set_bit(SK_CHNGBUF, &svsk->sk_flags);
return 0;
} }
/* /*
...@@ -773,19 +772,14 @@ svc_tcp_accept(struct svc_sock *svsk) ...@@ -773,19 +772,14 @@ svc_tcp_accept(struct svc_sock *svsk)
dprintk("%s: connect from %u.%u.%u.%u:%04x\n", serv->sv_name, dprintk("%s: connect from %u.%u.%u.%u:%04x\n", serv->sv_name,
NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0)))
goto failed;
/* make sure that a write doesn't block forever when /* make sure that a write doesn't block forever when
* low on memory * low on memory
*/ */
newsock->sk->sndtimeo = HZ*30; newsock->sk->sndtimeo = HZ*30;
/* Precharge. Data may have arrived on the socket before we if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0)))
* installed the data_ready callback. goto failed;
*/
set_bit(SK_DATA, &newsvsk->sk_flags);
svc_sock_enqueue(newsvsk);
/* make sure that we don't have too many active connections. /* make sure that we don't have too many active connections.
* If we have, something must be dropped. * If we have, something must be dropped.
...@@ -1006,7 +1000,7 @@ svc_tcp_sendto(struct svc_rqst *rqstp) ...@@ -1006,7 +1000,7 @@ svc_tcp_sendto(struct svc_rqst *rqstp)
return sent; return sent;
} }
static int static void
svc_tcp_init(struct svc_sock *svsk) svc_tcp_init(struct svc_sock *svsk)
{ {
struct sock *sk = svsk->sk_sk; struct sock *sk = svsk->sk_sk;
...@@ -1017,6 +1011,7 @@ svc_tcp_init(struct svc_sock *svsk) ...@@ -1017,6 +1011,7 @@ svc_tcp_init(struct svc_sock *svsk)
if (sk->state == TCP_LISTEN) { if (sk->state == TCP_LISTEN) {
dprintk("setting up TCP socket for listening\n"); dprintk("setting up TCP socket for listening\n");
sk->data_ready = svc_tcp_listen_data_ready; sk->data_ready = svc_tcp_listen_data_ready;
set_bit(SK_CONN, &svsk->sk_flags);
} else { } else {
dprintk("setting up TCP socket for reading\n"); dprintk("setting up TCP socket for reading\n");
sk->state_change = svc_tcp_state_change; sk->state_change = svc_tcp_state_change;
...@@ -1035,9 +1030,8 @@ svc_tcp_init(struct svc_sock *svsk) ...@@ -1035,9 +1030,8 @@ svc_tcp_init(struct svc_sock *svsk)
3 * svsk->sk_server->sv_bufsz); 3 * svsk->sk_server->sv_bufsz);
set_bit(SK_CHNGBUF, &svsk->sk_flags); set_bit(SK_CHNGBUF, &svsk->sk_flags);
set_bit(SK_DATA, &svsk->sk_flags);
} }
return 0;
} }
void void
...@@ -1258,6 +1252,18 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, ...@@ -1258,6 +1252,18 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
memset(svsk, 0, sizeof(*svsk)); memset(svsk, 0, sizeof(*svsk));
inet = sock->sk; inet = sock->sk;
/* Register socket with portmapper */
if (*errp >= 0 && pmap_register)
*errp = svc_register(serv, inet->protocol,
ntohs(inet_sk(inet)->sport));
if (*errp < 0) {
kfree(svsk);
return NULL;
}
set_bit(SK_BUSY, &svsk->sk_flags);
inet->user_data = svsk; inet->user_data = svsk;
svsk->sk_sock = sock; svsk->sk_sock = sock;
svsk->sk_sk = inet; svsk->sk_sk = inet;
...@@ -1271,23 +1277,9 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, ...@@ -1271,23 +1277,9 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
/* Initialize the socket */ /* Initialize the socket */
if (sock->type == SOCK_DGRAM) if (sock->type == SOCK_DGRAM)
*errp = svc_udp_init(svsk); svc_udp_init(svsk);
else else
*errp = svc_tcp_init(svsk); svc_tcp_init(svsk);
if (svsk->sk_sk == NULL)
printk(KERN_WARNING "svsk->sk_sk == NULL after svc_prot_init!\n");
/* Register socket with portmapper */
if (*errp >= 0 && pmap_register)
*errp = svc_register(serv, inet->protocol,
ntohs(inet_sk(inet)->sport));
if (*errp < 0) {
inet->user_data = NULL;
kfree(svsk);
return NULL;
}
spin_lock_bh(&serv->sv_lock); spin_lock_bh(&serv->sv_lock);
if (!pmap_register) { if (!pmap_register) {
...@@ -1302,6 +1294,9 @@ if (svsk->sk_sk == NULL) ...@@ -1302,6 +1294,9 @@ if (svsk->sk_sk == NULL)
dprintk("svc: svc_setup_socket created %p (inet %p)\n", dprintk("svc: svc_setup_socket created %p (inet %p)\n",
svsk, svsk->sk_sk); svsk, svsk->sk_sk);
clear_bit(SK_BUSY, &svsk->sk_flags);
svc_sock_enqueue(svsk);
return svsk; return svsk;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment