diff options
author | David S. Miller <davem@davemloft.net> | 2014-03-06 14:46:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-06 14:46:38 -0500 |
commit | 409e145643d66d5307fbd4ec1a0addfef95ef1c3 (patch) | |
tree | 399fe3c584aaf3a9c71d770e5ae00d55e50e0841 | |
parent | 9e9cb6221aa7cb04765484fe87cc2d1b92edce64 (diff) | |
parent | 2892505ea170094f982516bb38105eac45f274b1 (diff) |
Merge branch 'tipc'
Eric Hugne says:
====================
tipc: refcount and memory leak fixes
v3: Remove error logging from data path completely. Rebased on top of
latest net merge.
v2: Drop specific -ENOMEM logging in patch #1 (tipc: allow connection
shutdown callback to be invoked in advance) And add a general error
message if an internal server tries to send a message on a
closed/nonexisting connection.
In addition to the fix for refcount leak and memory leak during
module removal, we also fix a problem where the topology server
listening socket where unexpectedly closed. We also eliminate an
unnecessary context switch during accept()/recvmsg() for nonblocking
sockets.
It might be good to include this patchset in stable aswell. After the
v3 rebase on latest merge from net all patches apply cleanly on that
tree.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/tipc/config.c | 9 | ||||
-rw-r--r-- | net/tipc/handler.c | 1 | ||||
-rw-r--r-- | net/tipc/name_table.c | 37 | ||||
-rw-r--r-- | net/tipc/server.c | 14 | ||||
-rw-r--r-- | net/tipc/socket.c | 4 | ||||
-rw-r--r-- | net/tipc/subscr.c | 19 |
6 files changed, 47 insertions, 37 deletions
diff --git a/net/tipc/config.c b/net/tipc/config.c index e74eef2e7490..e6d721692ae0 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c | |||
@@ -376,7 +376,6 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr, | |||
376 | struct tipc_cfg_msg_hdr *req_hdr; | 376 | struct tipc_cfg_msg_hdr *req_hdr; |
377 | struct tipc_cfg_msg_hdr *rep_hdr; | 377 | struct tipc_cfg_msg_hdr *rep_hdr; |
378 | struct sk_buff *rep_buf; | 378 | struct sk_buff *rep_buf; |
379 | int ret; | ||
380 | 379 | ||
381 | /* Validate configuration message header (ignore invalid message) */ | 380 | /* Validate configuration message header (ignore invalid message) */ |
382 | req_hdr = (struct tipc_cfg_msg_hdr *)buf; | 381 | req_hdr = (struct tipc_cfg_msg_hdr *)buf; |
@@ -398,12 +397,8 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr, | |||
398 | memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); | 397 | memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); |
399 | rep_hdr->tcm_len = htonl(rep_buf->len); | 398 | rep_hdr->tcm_len = htonl(rep_buf->len); |
400 | rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); | 399 | rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); |
401 | 400 | tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data, | |
402 | ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data, | 401 | rep_buf->len); |
403 | rep_buf->len); | ||
404 | if (ret < 0) | ||
405 | pr_err("Sending cfg reply message failed, no memory\n"); | ||
406 | |||
407 | kfree_skb(rep_buf); | 402 | kfree_skb(rep_buf); |
408 | } | 403 | } |
409 | } | 404 | } |
diff --git a/net/tipc/handler.c b/net/tipc/handler.c index e4bc8a296744..1fabf160501f 100644 --- a/net/tipc/handler.c +++ b/net/tipc/handler.c | |||
@@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument) | |||
58 | 58 | ||
59 | spin_lock_bh(&qitem_lock); | 59 | spin_lock_bh(&qitem_lock); |
60 | if (!handler_enabled) { | 60 | if (!handler_enabled) { |
61 | pr_err("Signal request ignored by handler\n"); | ||
62 | spin_unlock_bh(&qitem_lock); | 61 | spin_unlock_bh(&qitem_lock); |
63 | return -ENOPROTOOPT; | 62 | return -ENOPROTOOPT; |
64 | } | 63 | } |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 48302be175ce..042e8e3cabc0 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c | |||
@@ -941,17 +941,48 @@ int tipc_nametbl_init(void) | |||
941 | return 0; | 941 | return 0; |
942 | } | 942 | } |
943 | 943 | ||
944 | /** | ||
945 | * tipc_purge_publications - remove all publications for a given type | ||
946 | * | ||
947 | * tipc_nametbl_lock must be held when calling this function | ||
948 | */ | ||
949 | static void tipc_purge_publications(struct name_seq *seq) | ||
950 | { | ||
951 | struct publication *publ, *safe; | ||
952 | struct sub_seq *sseq; | ||
953 | struct name_info *info; | ||
954 | |||
955 | if (!seq->sseqs) { | ||
956 | nameseq_delete_empty(seq); | ||
957 | return; | ||
958 | } | ||
959 | sseq = seq->sseqs; | ||
960 | info = sseq->info; | ||
961 | list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) { | ||
962 | tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node, | ||
963 | publ->ref, publ->key); | ||
964 | } | ||
965 | } | ||
966 | |||
944 | void tipc_nametbl_stop(void) | 967 | void tipc_nametbl_stop(void) |
945 | { | 968 | { |
946 | u32 i; | 969 | u32 i; |
970 | struct name_seq *seq; | ||
971 | struct hlist_head *seq_head; | ||
972 | struct hlist_node *safe; | ||
947 | 973 | ||
948 | /* Verify name table is empty, then release it */ | 974 | /* Verify name table is empty and purge any lingering |
975 | * publications, then release the name table | ||
976 | */ | ||
949 | write_lock_bh(&tipc_nametbl_lock); | 977 | write_lock_bh(&tipc_nametbl_lock); |
950 | for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { | 978 | for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { |
951 | if (hlist_empty(&table.types[i])) | 979 | if (hlist_empty(&table.types[i])) |
952 | continue; | 980 | continue; |
953 | pr_err("nametbl_stop(): orphaned hash chain detected\n"); | 981 | seq_head = &table.types[i]; |
954 | break; | 982 | hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) { |
983 | tipc_purge_publications(seq); | ||
984 | } | ||
985 | continue; | ||
955 | } | 986 | } |
956 | kfree(table.types); | 987 | kfree(table.types); |
957 | table.types = NULL; | 988 | table.types = NULL; |
diff --git a/net/tipc/server.c b/net/tipc/server.c index 373979789a73..646a930eefbf 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c | |||
@@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con); | |||
87 | static void tipc_conn_kref_release(struct kref *kref) | 87 | static void tipc_conn_kref_release(struct kref *kref) |
88 | { | 88 | { |
89 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); | 89 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); |
90 | struct tipc_server *s = con->server; | ||
91 | 90 | ||
92 | if (con->sock) { | 91 | if (con->sock) { |
93 | tipc_sock_release_local(con->sock); | 92 | tipc_sock_release_local(con->sock); |
@@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref) | |||
95 | } | 94 | } |
96 | 95 | ||
97 | tipc_clean_outqueues(con); | 96 | tipc_clean_outqueues(con); |
98 | |||
99 | if (con->conid) | ||
100 | s->tipc_conn_shutdown(con->conid, con->usr_data); | ||
101 | |||
102 | kfree(con); | 97 | kfree(con); |
103 | } | 98 | } |
104 | 99 | ||
@@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con) | |||
181 | struct tipc_server *s = con->server; | 176 | struct tipc_server *s = con->server; |
182 | 177 | ||
183 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { | 178 | if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { |
179 | if (con->conid) | ||
180 | s->tipc_conn_shutdown(con->conid, con->usr_data); | ||
181 | |||
184 | spin_lock_bh(&s->idr_lock); | 182 | spin_lock_bh(&s->idr_lock); |
185 | idr_remove(&s->conn_idr, con->conid); | 183 | idr_remove(&s->conn_idr, con->conid); |
186 | s->idr_in_use--; | 184 | s->idr_in_use--; |
@@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid, | |||
429 | list_add_tail(&e->list, &con->outqueue); | 427 | list_add_tail(&e->list, &con->outqueue); |
430 | spin_unlock_bh(&con->outqueue_lock); | 428 | spin_unlock_bh(&con->outqueue_lock); |
431 | 429 | ||
432 | if (test_bit(CF_CONNECTED, &con->flags)) | 430 | if (test_bit(CF_CONNECTED, &con->flags)) { |
433 | if (!queue_work(s->send_wq, &con->swork)) | 431 | if (!queue_work(s->send_wq, &con->swork)) |
434 | conn_put(con); | 432 | conn_put(con); |
435 | 433 | } else { | |
434 | conn_put(con); | ||
435 | } | ||
436 | return 0; | 436 | return 0; |
437 | } | 437 | } |
438 | 438 | ||
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index a4cf274455aa..0ed0eaa62f29 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -997,7 +997,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo) | |||
997 | 997 | ||
998 | for (;;) { | 998 | for (;;) { |
999 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 999 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
1000 | if (skb_queue_empty(&sk->sk_receive_queue)) { | 1000 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { |
1001 | if (sock->state == SS_DISCONNECTING) { | 1001 | if (sock->state == SS_DISCONNECTING) { |
1002 | err = -ENOTCONN; | 1002 | err = -ENOTCONN; |
1003 | break; | 1003 | break; |
@@ -1623,7 +1623,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo) | |||
1623 | for (;;) { | 1623 | for (;;) { |
1624 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, | 1624 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, |
1625 | TASK_INTERRUPTIBLE); | 1625 | TASK_INTERRUPTIBLE); |
1626 | if (skb_queue_empty(&sk->sk_receive_queue)) { | 1626 | if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { |
1627 | release_sock(sk); | 1627 | release_sock(sk); |
1628 | timeo = schedule_timeout(timeo); | 1628 | timeo = schedule_timeout(timeo); |
1629 | lock_sock(sk); | 1629 | lock_sock(sk); |
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 7cb0bd5b1176..11c9ae00837d 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c | |||
@@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower, | |||
96 | { | 96 | { |
97 | struct tipc_subscriber *subscriber = sub->subscriber; | 97 | struct tipc_subscriber *subscriber = sub->subscriber; |
98 | struct kvec msg_sect; | 98 | struct kvec msg_sect; |
99 | int ret; | ||
100 | 99 | ||
101 | msg_sect.iov_base = (void *)&sub->evt; | 100 | msg_sect.iov_base = (void *)&sub->evt; |
102 | msg_sect.iov_len = sizeof(struct tipc_event); | 101 | msg_sect.iov_len = sizeof(struct tipc_event); |
103 | |||
104 | sub->evt.event = htohl(event, sub->swap); | 102 | sub->evt.event = htohl(event, sub->swap); |
105 | sub->evt.found_lower = htohl(found_lower, sub->swap); | 103 | sub->evt.found_lower = htohl(found_lower, sub->swap); |
106 | sub->evt.found_upper = htohl(found_upper, sub->swap); | 104 | sub->evt.found_upper = htohl(found_upper, sub->swap); |
107 | sub->evt.port.ref = htohl(port_ref, sub->swap); | 105 | sub->evt.port.ref = htohl(port_ref, sub->swap); |
108 | sub->evt.port.node = htohl(node, sub->swap); | 106 | sub->evt.port.node = htohl(node, sub->swap); |
109 | ret = tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, | 107 | tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base, |
110 | msg_sect.iov_base, msg_sect.iov_len); | 108 | msg_sect.iov_len); |
111 | if (ret < 0) | ||
112 | pr_err("Sending subscription event failed, no memory\n"); | ||
113 | } | 109 | } |
114 | 110 | ||
115 | /** | 111 | /** |
@@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub) | |||
153 | /* The spin lock per subscriber is used to protect its members */ | 149 | /* The spin lock per subscriber is used to protect its members */ |
154 | spin_lock_bh(&subscriber->lock); | 150 | spin_lock_bh(&subscriber->lock); |
155 | 151 | ||
156 | /* Validate if the connection related to the subscriber is | ||
157 | * closed (in case subscriber is terminating) | ||
158 | */ | ||
159 | if (subscriber->conid == 0) { | ||
160 | spin_unlock_bh(&subscriber->lock); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | /* Validate timeout (in case subscription is being cancelled) */ | 152 | /* Validate timeout (in case subscription is being cancelled) */ |
165 | if (sub->timeout == TIPC_WAIT_FOREVER) { | 153 | if (sub->timeout == TIPC_WAIT_FOREVER) { |
166 | spin_unlock_bh(&subscriber->lock); | 154 | spin_unlock_bh(&subscriber->lock); |
@@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber) | |||
215 | 203 | ||
216 | spin_lock_bh(&subscriber->lock); | 204 | spin_lock_bh(&subscriber->lock); |
217 | 205 | ||
218 | /* Invalidate subscriber reference */ | ||
219 | subscriber->conid = 0; | ||
220 | |||
221 | /* Destroy any existing subscriptions for subscriber */ | 206 | /* Destroy any existing subscriptions for subscriber */ |
222 | list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, | 207 | list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, |
223 | subscription_list) { | 208 | subscription_list) { |