aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
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
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')
-rw-r--r--net/tipc/config.c4
-rw-r--r--net/tipc/net.c2
-rw-r--r--net/tipc/port.c87
-rw-r--r--net/tipc/port.h5
-rw-r--r--net/tipc/ref.c20
-rw-r--r--net/tipc/ref.h1
-rw-r--r--net/tipc/socket.c118
-rw-r--r--net/tipc/socket.h3
8 files changed, 133 insertions, 107 deletions
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 2b42403ad33a..876f4c6a2631 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -35,7 +35,7 @@
35 */ 35 */
36 36
37#include "core.h" 37#include "core.h"
38#include "port.h" 38#include "socket.h"
39#include "name_table.h" 39#include "name_table.h"
40#include "config.h" 40#include "config.h"
41#include "server.h" 41#include "server.h"
@@ -266,7 +266,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
266 rep_tlv_buf = tipc_media_get_names(); 266 rep_tlv_buf = tipc_media_get_names();
267 break; 267 break;
268 case TIPC_CMD_SHOW_PORTS: 268 case TIPC_CMD_SHOW_PORTS:
269 rep_tlv_buf = tipc_port_get_ports(); 269 rep_tlv_buf = tipc_sk_socks_show();
270 break; 270 break;
271 case TIPC_CMD_SHOW_STATS: 271 case TIPC_CMD_SHOW_STATS:
272 rep_tlv_buf = tipc_show_stats(); 272 rep_tlv_buf = tipc_show_stats();
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 7fcc94998fea..421dd89152ac 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -111,7 +111,7 @@ int tipc_net_start(u32 addr)
111 111
112 tipc_own_addr = addr; 112 tipc_own_addr = addr;
113 tipc_named_reinit(); 113 tipc_named_reinit();
114 tipc_port_reinit(); 114 tipc_sk_reinit();
115 res = tipc_bclink_init(); 115 res = tipc_bclink_init();
116 if (res) 116 if (res)
117 return res; 117 return res;
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 1efa2982d2d2..cea3730fe026 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -63,93 +63,6 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
63 (!peernode && (orignode == tipc_own_addr)); 63 (!peernode && (orignode == tipc_own_addr));
64} 64}
65 65
66static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id)
67{
68 struct publication *publ;
69 int ret;
70
71 if (full_id)
72 ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
73 tipc_zone(tipc_own_addr),
74 tipc_cluster(tipc_own_addr),
75 tipc_node(tipc_own_addr), p_ptr->ref);
76 else
77 ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref);
78
79 if (p_ptr->connected) {
80 u32 dport = tipc_port_peerport(p_ptr);
81 u32 destnode = tipc_port_peernode(p_ptr);
82
83 ret += tipc_snprintf(buf + ret, len - ret,
84 " connected to <%u.%u.%u:%u>",
85 tipc_zone(destnode),
86 tipc_cluster(destnode),
87 tipc_node(destnode), dport);
88 if (p_ptr->conn_type != 0)
89 ret += tipc_snprintf(buf + ret, len - ret,
90 " via {%u,%u}", p_ptr->conn_type,
91 p_ptr->conn_instance);
92 } else if (p_ptr->published) {
93 ret += tipc_snprintf(buf + ret, len - ret, " bound to");
94 list_for_each_entry(publ, &p_ptr->publications, pport_list) {
95 if (publ->lower == publ->upper)
96 ret += tipc_snprintf(buf + ret, len - ret,
97 " {%u,%u}", publ->type,
98 publ->lower);
99 else
100 ret += tipc_snprintf(buf + ret, len - ret,
101 " {%u,%u,%u}", publ->type,
102 publ->lower, publ->upper);
103 }
104 }
105 ret += tipc_snprintf(buf + ret, len - ret, "\n");
106 return ret;
107}
108
109struct sk_buff *tipc_port_get_ports(void)
110{
111 struct sk_buff *buf;
112 struct tlv_desc *rep_tlv;
113 char *pb;
114 int pb_len;
115 struct tipc_port *p_ptr;
116 int str_len = 0;
117
118 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
119 if (!buf)
120 return NULL;
121 rep_tlv = (struct tlv_desc *)buf->data;
122 pb = TLV_DATA(rep_tlv);
123 pb_len = ULTRA_STRING_MAX_LEN;
124
125 spin_lock_bh(&tipc_port_list_lock);
126 list_for_each_entry(p_ptr, &tipc_socks, port_list) {
127 spin_lock_bh(p_ptr->lock);
128 str_len += port_print(p_ptr, pb, pb_len, 0);
129 spin_unlock_bh(p_ptr->lock);
130 }
131 spin_unlock_bh(&tipc_port_list_lock);
132 str_len += 1; /* for "\0" */
133 skb_put(buf, TLV_SPACE(str_len));
134 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
135
136 return buf;
137}
138
139void tipc_port_reinit(void)
140{
141 struct tipc_port *p_ptr;
142 struct tipc_msg *msg;
143
144 spin_lock_bh(&tipc_port_list_lock);
145 list_for_each_entry(p_ptr, &tipc_socks, port_list) {
146 msg = &p_ptr->phdr;
147 msg_set_prevnode(msg, tipc_own_addr);
148 msg_set_orignode(msg, tipc_own_addr);
149 }
150 spin_unlock_bh(&tipc_port_list_lock);
151}
152
153int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, 66int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
154 struct tipc_name_seq const *seq) 67 struct tipc_name_seq const *seq)
155{ 68{
diff --git a/net/tipc/port.h b/net/tipc/port.h
index 4c6cfdd36351..4a3c54e5d69c 100644
--- a/net/tipc/port.h
+++ b/net/tipc/port.h
@@ -73,7 +73,6 @@ struct tipc_port {
73 u32 max_pkt; 73 u32 max_pkt;
74 u32 ref; 74 u32 ref;
75 struct tipc_msg phdr; 75 struct tipc_msg phdr;
76 struct list_head port_list;
77 struct list_head publications; 76 struct list_head publications;
78 u32 pub_count; 77 u32 pub_count;
79 u32 probing_state; 78 u32 probing_state;
@@ -81,9 +80,6 @@ struct tipc_port {
81 struct timer_list timer; 80 struct timer_list timer;
82}; 81};
83 82
84extern struct list_head tipc_socks;
85extern spinlock_t tipc_port_list_lock;
86
87/* 83/*
88 * TIPC port manipulation routines 84 * TIPC port manipulation routines
89 */ 85 */
@@ -100,7 +96,6 @@ int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
100 96
101int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); 97int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg);
102 98
103struct sk_buff *tipc_port_get_ports(void);
104void tipc_port_reinit(void); 99void tipc_port_reinit(void);
105 100
106/** 101/**
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 3d4ecd754eee..7fc2740846e3 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -264,3 +264,23 @@ void *tipc_ref_lock(u32 ref)
264 } 264 }
265 return NULL; 265 return NULL;
266} 266}
267
268/* tipc_ref_lock_next - lock & return next object after referenced one
269*/
270void *tipc_ref_lock_next(u32 *ref)
271{
272 struct reference *entry;
273 uint index = *ref & tipc_ref_table.index_mask;
274
275 while (++index < tipc_ref_table.capacity) {
276 entry = &tipc_ref_table.entries[index];
277 if (!entry->object)
278 continue;
279 spin_lock_bh(&entry->lock);
280 *ref = entry->ref;
281 if (entry->object)
282 return entry->object;
283 spin_unlock_bh(&entry->lock);
284 }
285 return NULL;
286}
diff --git a/net/tipc/ref.h b/net/tipc/ref.h
index d01aa1df63b8..e236fa520a1d 100644
--- a/net/tipc/ref.h
+++ b/net/tipc/ref.h
@@ -44,5 +44,6 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock);
44void tipc_ref_discard(u32 ref); 44void tipc_ref_discard(u32 ref);
45 45
46void *tipc_ref_lock(u32 ref); 46void *tipc_ref_lock(u32 ref);
47void *tipc_ref_lock_next(u32 *ref);
47 48
48#endif 49#endif
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
diff --git a/net/tipc/socket.h b/net/tipc/socket.h
index 1405633362f5..5d515be604a9 100644
--- a/net/tipc/socket.h
+++ b/net/tipc/socket.h
@@ -79,7 +79,8 @@ static inline int tipc_sk_conn_cong(struct tipc_sock *tsk)
79} 79}
80 80
81int tipc_sk_rcv(struct sk_buff *buf); 81int tipc_sk_rcv(struct sk_buff *buf);
82 82struct sk_buff *tipc_sk_socks_show(void);
83void tipc_sk_mcast_rcv(struct sk_buff *buf); 83void tipc_sk_mcast_rcv(struct sk_buff *buf);
84void tipc_sk_reinit(void);
84 85
85#endif 86#endif