aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2014-08-22 18:09:14 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-23 14:18:34 -0400
commit5a9ee0be3371eb77d671a77e26261931c5c3fb31 (patch)
tree6127a9c68edea30b97209bc6eedee1ce5b641c17 /net/tipc/socket.c
parent5b8fa7ce823a59a328e0a7661df2478bfb745de4 (diff)
tipc: use registry when scanning sockets
The functions tipc_port_get_ports() and tipc_port_reinit() scan over all sockets/ports to access each of them. This is done by using a dedicated linked list, 'tipc_socks' where all sockets are members. The list is in turn protected by a spinlock, 'port_list_lock', while each socket is locked by using port_lock at the moment of access. In order to reduce complexity and risk of deadlock, we want to get rid of the linked list and the accompanying spinlock. This is what we do in this commit. Instead of the linked list, we use the port registry to scan across the sockets. We also add usage of bh_lock_sock() inside the scope of port_lock in both functions, as a preparation for the complete removal of port_lock. Finally, we move the functions from port.c to socket.c, and rename them to tipc_sk_sock_show() and tipc_sk_reinit() repectively. Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c118
1 files changed, 107 insertions, 11 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index f2be4c2e20bb..ddc2f8c6fced 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -40,6 +40,7 @@
40#include "node.h" 40#include "node.h"
41#include "link.h" 41#include "link.h"
42#include <linux/export.h> 42#include <linux/export.h>
43#include "config.h"
43 44
44#define SS_LISTENING -1 /* socket is listening */ 45#define SS_LISTENING -1 /* socket is listening */
45#define SS_READY -2 /* socket is connectionless */ 46#define SS_READY -2 /* socket is connectionless */
@@ -63,9 +64,6 @@ static const struct proto_ops msg_ops;
63static struct proto tipc_proto; 64static struct proto tipc_proto;
64static struct proto tipc_proto_kern; 65static struct proto tipc_proto_kern;
65 66
66DEFINE_SPINLOCK(tipc_port_list_lock);
67LIST_HEAD(tipc_socks);
68
69/* 67/*
70 * Revised TIPC socket locking policy: 68 * Revised TIPC socket locking policy:
71 * 69 *
@@ -113,6 +111,17 @@ LIST_HEAD(tipc_socks);
113 111
114#include "socket.h" 112#include "socket.h"
115 113
114/* tipc_sk_lock_next: find & lock next socket in registry from given port number
115*/
116static struct tipc_sock *tipc_sk_lock_next(u32 *ref)
117{
118 struct tipc_port *port = (struct tipc_port *)tipc_ref_lock_next(ref);
119
120 if (!port)
121 return NULL;
122 return tipc_port_to_sock(port);
123}
124
116/** 125/**
117 * advance_rx_queue - discard first buffer in socket receive queue 126 * advance_rx_queue - discard first buffer in socket receive queue
118 * 127 *
@@ -203,16 +212,11 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
203 port->max_pkt = MAX_PKT_DEFAULT; 212 port->max_pkt = MAX_PKT_DEFAULT;
204 port->ref = ref; 213 port->ref = ref;
205 INIT_LIST_HEAD(&port->publications); 214 INIT_LIST_HEAD(&port->publications);
206 INIT_LIST_HEAD(&port->port_list);
207 215
208 /* Guard against race during node address update */
209 spin_lock_bh(&tipc_port_list_lock);
210 msg = &port->phdr; 216 msg = &port->phdr;
211 tipc_msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, 217 tipc_msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG,
212 NAMED_H_SIZE, 0); 218 NAMED_H_SIZE, 0);
213 msg_set_origport(msg, ref); 219 msg_set_origport(msg, ref);
214 list_add_tail(&port->port_list, &tipc_socks);
215 spin_unlock_bh(&tipc_port_list_lock);
216 220
217 /* Finish initializing socket data structures */ 221 /* Finish initializing socket data structures */
218 sock->ops = ops; 222 sock->ops = ops;
@@ -377,9 +381,6 @@ static int tipc_release(struct socket *sock)
377 tipc_link_xmit(buf, dnode, port->ref); 381 tipc_link_xmit(buf, dnode, port->ref);
378 tipc_node_remove_conn(dnode, port->ref); 382 tipc_node_remove_conn(dnode, port->ref);
379 } 383 }
380 spin_lock_bh(&tipc_port_list_lock);
381 list_del(&port->port_list);
382 spin_unlock_bh(&tipc_port_list_lock);
383 k_term_timer(&port->timer); 384 k_term_timer(&port->timer);
384 385
385 /* Discard any remaining (connection-based) messages in receive queue */ 386 /* Discard any remaining (connection-based) messages in receive queue */
@@ -2043,6 +2044,101 @@ static void tipc_sk_timeout(unsigned long ref)
2043 tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); 2044 tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg));
2044} 2045}
2045 2046
2047static int tipc_sk_show(struct tipc_port *port, char *buf,
2048 int len, int full_id)
2049{
2050 struct publication *publ;
2051 int ret;
2052
2053 if (full_id)
2054 ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
2055 tipc_zone(tipc_own_addr),
2056 tipc_cluster(tipc_own_addr),
2057 tipc_node(tipc_own_addr), port->ref);
2058 else
2059 ret = tipc_snprintf(buf, len, "%-10u:", port->ref);
2060
2061 if (port->connected) {
2062 u32 dport = tipc_port_peerport(port);
2063 u32 destnode = tipc_port_peernode(port);
2064
2065 ret += tipc_snprintf(buf + ret, len - ret,
2066 " connected to <%u.%u.%u:%u>",
2067 tipc_zone(destnode),
2068 tipc_cluster(destnode),
2069 tipc_node(destnode), dport);
2070 if (port->conn_type != 0)
2071 ret += tipc_snprintf(buf + ret, len - ret,
2072 " via {%u,%u}", port->conn_type,
2073 port->conn_instance);
2074 } else if (port->published) {
2075 ret += tipc_snprintf(buf + ret, len - ret, " bound to");
2076 list_for_each_entry(publ, &port->publications, pport_list) {
2077 if (publ->lower == publ->upper)
2078 ret += tipc_snprintf(buf + ret, len - ret,
2079 " {%u,%u}", publ->type,
2080 publ->lower);
2081 else
2082 ret += tipc_snprintf(buf + ret, len - ret,
2083 " {%u,%u,%u}", publ->type,
2084 publ->lower, publ->upper);
2085 }
2086 }
2087 ret += tipc_snprintf(buf + ret, len - ret, "\n");
2088 return ret;
2089}
2090
2091struct sk_buff *tipc_sk_socks_show(void)
2092{
2093 struct sk_buff *buf;
2094 struct tlv_desc *rep_tlv;
2095 char *pb;
2096 int pb_len;
2097 struct tipc_sock *tsk;
2098 int str_len = 0;
2099 u32 ref = 0;
2100
2101 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
2102 if (!buf)
2103 return NULL;
2104 rep_tlv = (struct tlv_desc *)buf->data;
2105 pb = TLV_DATA(rep_tlv);
2106 pb_len = ULTRA_STRING_MAX_LEN;
2107
2108 tsk = tipc_sk_lock_next(&ref);
2109 for (; tsk; tsk = tipc_sk_lock_next(&ref)) {
2110 bh_lock_sock(&tsk->sk);
2111 str_len += tipc_sk_show(&tsk->port, pb + str_len,
2112 pb_len - str_len, 0);
2113 bh_unlock_sock(&tsk->sk);
2114 tipc_port_unlock(&tsk->port);
2115 }
2116 str_len += 1; /* for "\0" */
2117 skb_put(buf, TLV_SPACE(str_len));
2118 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
2119
2120 return buf;
2121}
2122
2123/* tipc_sk_reinit: set non-zero address in all existing sockets
2124 * when we go from standalone to network mode.
2125 */
2126void tipc_sk_reinit(void)
2127{
2128 struct tipc_msg *msg;
2129 u32 ref = 0;
2130 struct tipc_sock *tsk = tipc_sk_lock_next(&ref);
2131
2132 for (; tsk; tsk = tipc_sk_lock_next(&ref)) {
2133 bh_lock_sock(&tsk->sk);
2134 msg = &tsk->port.phdr;
2135 msg_set_prevnode(msg, tipc_own_addr);
2136 msg_set_orignode(msg, tipc_own_addr);
2137 bh_unlock_sock(&tsk->sk);
2138 tipc_port_unlock(&tsk->port);
2139 }
2140}
2141
2046/** 2142/**
2047 * tipc_setsockopt - set socket option 2143 * tipc_setsockopt - set socket option
2048 * @sock: socket structure 2144 * @sock: socket structure