Commit 409e1456 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 9e9cb622 2892505e
...@@ -376,7 +376,6 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr, ...@@ -376,7 +376,6 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
struct tipc_cfg_msg_hdr *req_hdr; struct tipc_cfg_msg_hdr *req_hdr;
struct tipc_cfg_msg_hdr *rep_hdr; struct tipc_cfg_msg_hdr *rep_hdr;
struct sk_buff *rep_buf; struct sk_buff *rep_buf;
int ret;
/* Validate configuration message header (ignore invalid message) */ /* Validate configuration message header (ignore invalid message) */
req_hdr = (struct tipc_cfg_msg_hdr *)buf; 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,12 +397,8 @@ static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
rep_hdr->tcm_len = htonl(rep_buf->len); rep_hdr->tcm_len = htonl(rep_buf->len);
rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data, rep_buf->len);
rep_buf->len);
if (ret < 0)
pr_err("Sending cfg reply message failed, no memory\n");
kfree_skb(rep_buf); kfree_skb(rep_buf);
} }
} }
......
...@@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument) ...@@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument)
spin_lock_bh(&qitem_lock); spin_lock_bh(&qitem_lock);
if (!handler_enabled) { if (!handler_enabled) {
pr_err("Signal request ignored by handler\n");
spin_unlock_bh(&qitem_lock); spin_unlock_bh(&qitem_lock);
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
......
...@@ -941,17 +941,48 @@ int tipc_nametbl_init(void) ...@@ -941,17 +941,48 @@ int tipc_nametbl_init(void)
return 0; return 0;
} }
/**
* tipc_purge_publications - remove all publications for a given type
*
* tipc_nametbl_lock must be held when calling this function
*/
static void tipc_purge_publications(struct name_seq *seq)
{
struct publication *publ, *safe;
struct sub_seq *sseq;
struct name_info *info;
if (!seq->sseqs) {
nameseq_delete_empty(seq);
return;
}
sseq = seq->sseqs;
info = sseq->info;
list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
publ->ref, publ->key);
}
}
void tipc_nametbl_stop(void) void tipc_nametbl_stop(void)
{ {
u32 i; u32 i;
struct name_seq *seq;
struct hlist_head *seq_head;
struct hlist_node *safe;
/* Verify name table is empty, then release it */ /* Verify name table is empty and purge any lingering
* publications, then release the name table
*/
write_lock_bh(&tipc_nametbl_lock); write_lock_bh(&tipc_nametbl_lock);
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
if (hlist_empty(&table.types[i])) if (hlist_empty(&table.types[i]))
continue; continue;
pr_err("nametbl_stop(): orphaned hash chain detected\n"); seq_head = &table.types[i];
break; hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) {
tipc_purge_publications(seq);
}
continue;
} }
kfree(table.types); kfree(table.types);
table.types = NULL; table.types = NULL;
......
...@@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con); ...@@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con);
static void tipc_conn_kref_release(struct kref *kref) static void tipc_conn_kref_release(struct kref *kref)
{ {
struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
struct tipc_server *s = con->server;
if (con->sock) { if (con->sock) {
tipc_sock_release_local(con->sock); tipc_sock_release_local(con->sock);
...@@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref) ...@@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref)
} }
tipc_clean_outqueues(con); tipc_clean_outqueues(con);
if (con->conid)
s->tipc_conn_shutdown(con->conid, con->usr_data);
kfree(con); kfree(con);
} }
...@@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con) ...@@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con)
struct tipc_server *s = con->server; struct tipc_server *s = con->server;
if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
if (con->conid)
s->tipc_conn_shutdown(con->conid, con->usr_data);
spin_lock_bh(&s->idr_lock); spin_lock_bh(&s->idr_lock);
idr_remove(&s->conn_idr, con->conid); idr_remove(&s->conn_idr, con->conid);
s->idr_in_use--; s->idr_in_use--;
...@@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid, ...@@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid,
list_add_tail(&e->list, &con->outqueue); list_add_tail(&e->list, &con->outqueue);
spin_unlock_bh(&con->outqueue_lock); spin_unlock_bh(&con->outqueue_lock);
if (test_bit(CF_CONNECTED, &con->flags)) if (test_bit(CF_CONNECTED, &con->flags)) {
if (!queue_work(s->send_wq, &con->swork)) if (!queue_work(s->send_wq, &con->swork))
conn_put(con); conn_put(con);
} else {
conn_put(con);
}
return 0; return 0;
} }
......
...@@ -997,7 +997,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo) ...@@ -997,7 +997,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo)
for (;;) { for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
if (skb_queue_empty(&sk->sk_receive_queue)) { if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
if (sock->state == SS_DISCONNECTING) { if (sock->state == SS_DISCONNECTING) {
err = -ENOTCONN; err = -ENOTCONN;
break; break;
...@@ -1623,7 +1623,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo) ...@@ -1623,7 +1623,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
for (;;) { for (;;) {
prepare_to_wait_exclusive(sk_sleep(sk), &wait, prepare_to_wait_exclusive(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE); TASK_INTERRUPTIBLE);
if (skb_queue_empty(&sk->sk_receive_queue)) { if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
release_sock(sk); release_sock(sk);
timeo = schedule_timeout(timeo); timeo = schedule_timeout(timeo);
lock_sock(sk); lock_sock(sk);
......
...@@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower, ...@@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
{ {
struct tipc_subscriber *subscriber = sub->subscriber; struct tipc_subscriber *subscriber = sub->subscriber;
struct kvec msg_sect; struct kvec msg_sect;
int ret;
msg_sect.iov_base = (void *)&sub->evt; msg_sect.iov_base = (void *)&sub->evt;
msg_sect.iov_len = sizeof(struct tipc_event); msg_sect.iov_len = sizeof(struct tipc_event);
sub->evt.event = htohl(event, sub->swap); sub->evt.event = htohl(event, sub->swap);
sub->evt.found_lower = htohl(found_lower, sub->swap); sub->evt.found_lower = htohl(found_lower, sub->swap);
sub->evt.found_upper = htohl(found_upper, sub->swap); sub->evt.found_upper = htohl(found_upper, sub->swap);
sub->evt.port.ref = htohl(port_ref, sub->swap); sub->evt.port.ref = htohl(port_ref, sub->swap);
sub->evt.port.node = htohl(node, sub->swap); sub->evt.port.node = htohl(node, sub->swap);
ret = tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base,
msg_sect.iov_base, msg_sect.iov_len); msg_sect.iov_len);
if (ret < 0)
pr_err("Sending subscription event failed, no memory\n");
} }
/** /**
...@@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub) ...@@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub)
/* The spin lock per subscriber is used to protect its members */ /* The spin lock per subscriber is used to protect its members */
spin_lock_bh(&subscriber->lock); spin_lock_bh(&subscriber->lock);
/* Validate if the connection related to the subscriber is
* closed (in case subscriber is terminating)
*/
if (subscriber->conid == 0) {
spin_unlock_bh(&subscriber->lock);
return;
}
/* Validate timeout (in case subscription is being cancelled) */ /* Validate timeout (in case subscription is being cancelled) */
if (sub->timeout == TIPC_WAIT_FOREVER) { if (sub->timeout == TIPC_WAIT_FOREVER) {
spin_unlock_bh(&subscriber->lock); spin_unlock_bh(&subscriber->lock);
...@@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber) ...@@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber)
spin_lock_bh(&subscriber->lock); spin_lock_bh(&subscriber->lock);
/* Invalidate subscriber reference */
subscriber->conid = 0;
/* Destroy any existing subscriptions for subscriber */ /* Destroy any existing subscriptions for subscriber */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list, list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
subscription_list) { subscription_list) {
......
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