diff options
Diffstat (limited to 'net/tipc/server.c')
-rw-r--r-- | net/tipc/server.c | 48 |
1 files changed, 21 insertions, 27 deletions
diff --git a/net/tipc/server.c b/net/tipc/server.c index 215849ce453d..3cd6402e812c 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c | |||
@@ -86,12 +86,12 @@ struct outqueue_entry { | |||
86 | static void tipc_recv_work(struct work_struct *work); | 86 | static void tipc_recv_work(struct work_struct *work); |
87 | static void tipc_send_work(struct work_struct *work); | 87 | static void tipc_send_work(struct work_struct *work); |
88 | static void tipc_clean_outqueues(struct tipc_conn *con); | 88 | static void tipc_clean_outqueues(struct tipc_conn *con); |
89 | static void tipc_sock_release(struct tipc_conn *con); | ||
90 | 89 | ||
91 | static void tipc_conn_kref_release(struct kref *kref) | 90 | static void tipc_conn_kref_release(struct kref *kref) |
92 | { | 91 | { |
93 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); | 92 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); |
94 | struct sockaddr_tipc *saddr = con->server->saddr; | 93 | struct tipc_server *s = con->server; |
94 | struct sockaddr_tipc *saddr = s->saddr; | ||
95 | struct socket *sock = con->sock; | 95 | struct socket *sock = con->sock; |
96 | struct sock *sk; | 96 | struct sock *sk; |
97 | 97 | ||
@@ -103,9 +103,13 @@ static void tipc_conn_kref_release(struct kref *kref) | |||
103 | } | 103 | } |
104 | saddr->scope = -TIPC_NODE_SCOPE; | 104 | saddr->scope = -TIPC_NODE_SCOPE; |
105 | kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr)); | 105 | kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr)); |
106 | tipc_sock_release(con); | ||
107 | sock_release(sock); | 106 | sock_release(sock); |
108 | con->sock = NULL; | 107 | con->sock = NULL; |
108 | |||
109 | spin_lock_bh(&s->idr_lock); | ||
110 | idr_remove(&s->conn_idr, con->conid); | ||
111 | s->idr_in_use--; | ||
112 | spin_unlock_bh(&s->idr_lock); | ||
109 | } | 113 | } |
110 | 114 | ||
111 | tipc_clean_outqueues(con); | 115 | tipc_clean_outqueues(con); |
@@ -128,8 +132,10 @@ static struct tipc_conn *tipc_conn_lookup(struct tipc_server *s, int conid) | |||
128 | 132 | ||
129 | spin_lock_bh(&s->idr_lock); | 133 | spin_lock_bh(&s->idr_lock); |
130 | con = idr_find(&s->conn_idr, conid); | 134 | con = idr_find(&s->conn_idr, conid); |
131 | if (con) | 135 | if (con && test_bit(CF_CONNECTED, &con->flags)) |
132 | conn_get(con); | 136 | conn_get(con); |
137 | else | ||
138 | con = NULL; | ||
133 | spin_unlock_bh(&s->idr_lock); | 139 | spin_unlock_bh(&s->idr_lock); |
134 | return con; | 140 | return con; |
135 | } | 141 | } |
@@ -186,26 +192,15 @@ static void tipc_unregister_callbacks(struct tipc_conn *con) | |||
186 | write_unlock_bh(&sk->sk_callback_lock); | 192 | write_unlock_bh(&sk->sk_callback_lock); |
187 | } | 193 | } |
188 | 194 | ||
189 | static void tipc_sock_release(struct tipc_conn *con) | ||
190 | { | ||
191 | struct tipc_server *s = con->server; | ||
192 | |||
193 | if (con->conid) | ||
194 | s->tipc_conn_release(con->conid, con->usr_data); | ||
195 | |||
196 | tipc_unregister_callbacks(con); | ||
197 | } | ||
198 | |||
199 | static void tipc_close_conn(struct tipc_conn *con) | 195 | static void tipc_close_conn(struct tipc_conn *con) |
200 | { | 196 | { |
201 | struct tipc_server *s = con->server; | 197 | struct tipc_server *s = con->server; |
202 | 198 | ||
203 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { | 199 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { |
200 | tipc_unregister_callbacks(con); | ||
204 | 201 | ||
205 | spin_lock_bh(&s->idr_lock); | 202 | if (con->conid) |
206 | idr_remove(&s->conn_idr, con->conid); | 203 | s->tipc_conn_release(con->conid, con->usr_data); |
207 | s->idr_in_use--; | ||
208 | spin_unlock_bh(&s->idr_lock); | ||
209 | 204 | ||
210 | /* We shouldn't flush pending works as we may be in the | 205 | /* We shouldn't flush pending works as we may be in the |
211 | * thread. In fact the races with pending rx/tx work structs | 206 | * thread. In fact the races with pending rx/tx work structs |
@@ -458,6 +453,11 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid, | |||
458 | if (!con) | 453 | if (!con) |
459 | return -EINVAL; | 454 | return -EINVAL; |
460 | 455 | ||
456 | if (!test_bit(CF_CONNECTED, &con->flags)) { | ||
457 | conn_put(con); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | e = tipc_alloc_entry(data, len); | 461 | e = tipc_alloc_entry(data, len); |
462 | if (!e) { | 462 | if (!e) { |
463 | conn_put(con); | 463 | conn_put(con); |
@@ -471,12 +471,8 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid, | |||
471 | list_add_tail(&e->list, &con->outqueue); | 471 | list_add_tail(&e->list, &con->outqueue); |
472 | spin_unlock_bh(&con->outqueue_lock); | 472 | spin_unlock_bh(&con->outqueue_lock); |
473 | 473 | ||
474 | if (test_bit(CF_CONNECTED, &con->flags)) { | 474 | if (!queue_work(s->send_wq, &con->swork)) |
475 | if (!queue_work(s->send_wq, &con->swork)) | ||
476 | conn_put(con); | ||
477 | } else { | ||
478 | conn_put(con); | 475 | conn_put(con); |
479 | } | ||
480 | return 0; | 476 | return 0; |
481 | } | 477 | } |
482 | 478 | ||
@@ -500,7 +496,7 @@ static void tipc_send_to_sock(struct tipc_conn *con) | |||
500 | int ret; | 496 | int ret; |
501 | 497 | ||
502 | spin_lock_bh(&con->outqueue_lock); | 498 | spin_lock_bh(&con->outqueue_lock); |
503 | while (1) { | 499 | while (test_bit(CF_CONNECTED, &con->flags)) { |
504 | e = list_entry(con->outqueue.next, struct outqueue_entry, | 500 | e = list_entry(con->outqueue.next, struct outqueue_entry, |
505 | list); | 501 | list); |
506 | if ((struct list_head *) e == &con->outqueue) | 502 | if ((struct list_head *) e == &con->outqueue) |
@@ -623,14 +619,12 @@ int tipc_server_start(struct tipc_server *s) | |||
623 | void tipc_server_stop(struct tipc_server *s) | 619 | void tipc_server_stop(struct tipc_server *s) |
624 | { | 620 | { |
625 | struct tipc_conn *con; | 621 | struct tipc_conn *con; |
626 | int total = 0; | ||
627 | int id; | 622 | int id; |
628 | 623 | ||
629 | spin_lock_bh(&s->idr_lock); | 624 | spin_lock_bh(&s->idr_lock); |
630 | for (id = 0; total < s->idr_in_use; id++) { | 625 | for (id = 0; s->idr_in_use; id++) { |
631 | con = idr_find(&s->conn_idr, id); | 626 | con = idr_find(&s->conn_idr, id); |
632 | if (con) { | 627 | if (con) { |
633 | total++; | ||
634 | spin_unlock_bh(&s->idr_lock); | 628 | spin_unlock_bh(&s->idr_lock); |
635 | tipc_close_conn(con); | 629 | tipc_close_conn(con); |
636 | spin_lock_bh(&s->idr_lock); | 630 | spin_lock_bh(&s->idr_lock); |