summaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2013-06-17 10:54:39 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-17 18:53:00 -0400
commitc5fa7b3cf3cb22e4ac60485fc2dc187fe012910f (patch)
tree9cc84cfb44bd0962132f9506adec55fe8fb433d4 /net/tipc/socket.c
parent5d21cb70db0122507cd18f58b4a9112583c1e075 (diff)
tipc: introduce new TIPC server infrastructure
TIPC has two internal servers, one providing a subscription service for topology events, and another providing the configuration interface. These servers have previously been running in BH context, accessing the TIPC-port (aka native) API directly. Apart from these servers, even the TIPC socket implementation is partially built on this API. As this API may simultaneously be called via different paths and in different contexts, a complex and costly lock policiy is required in order to protect TIPC internal resources. To eliminate the need for this complex lock policiy, we introduce a new, generic service API that uses kernel sockets for message passing instead of the native API. Once the toplogy and configuration servers are converted to use this new service, all code pertaining to the native API can be removed. This entails a significant reduction in code amount and complexity, and opens up for a complete rework of the locking policy in TIPC. The new service also solves another problem: As the current topology server works in BH context, it cannot easily be blocked when sending of events fails due to congestion. In such cases events may have to be silently dropped, something that is unacceptable. Therefore, the new service keeps a dedicated outbound queue receiving messages from BH context. Once messages are inserted into this queue, we will immediately schedule a work from a special workqueue. This way, messages/events from the topology server are in reality sent in process context, and the server can block if necessary. Analogously, there is a new workqueue for receiving messages. Once a notification about an arriving message is received in BH context, we schedule a work from the receive workqueue to do the job of receiving the message in process context. As both sending and receive messages are now finished in processes, subscribed events cannot be dropped any more. As of this commit, this new server infrastructure is built, but not actually yet called by the existing TIPC code, but since the conversion changes required in order to use it are significant, the addition is kept here as a separate commit. Signed-off-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c99
1 files changed, 92 insertions, 7 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index d5fa708f037d..bd8e2cdeceef 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2,7 +2,7 @@
2 * net/tipc/socket.c: TIPC socket API 2 * net/tipc/socket.c: TIPC socket API
3 * 3 *
4 * Copyright (c) 2001-2007, 2012 Ericsson AB 4 * Copyright (c) 2001-2007, 2012 Ericsson AB
5 * Copyright (c) 2004-2008, 2010-2012, Wind River Systems 5 * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
@@ -63,12 +63,15 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
63static void wakeupdispatch(struct tipc_port *tport); 63static void wakeupdispatch(struct tipc_port *tport);
64static void tipc_data_ready(struct sock *sk, int len); 64static void tipc_data_ready(struct sock *sk, int len);
65static void tipc_write_space(struct sock *sk); 65static void tipc_write_space(struct sock *sk);
66static int release(struct socket *sock);
67static int accept(struct socket *sock, struct socket *new_sock, int flags);
66 68
67static const struct proto_ops packet_ops; 69static const struct proto_ops packet_ops;
68static const struct proto_ops stream_ops; 70static const struct proto_ops stream_ops;
69static const struct proto_ops msg_ops; 71static const struct proto_ops msg_ops;
70 72
71static struct proto tipc_proto; 73static struct proto tipc_proto;
74static struct proto tipc_proto_kern;
72 75
73static int sockets_enabled; 76static int sockets_enabled;
74 77
@@ -141,7 +144,7 @@ static void reject_rx_queue(struct sock *sk)
141} 144}
142 145
143/** 146/**
144 * tipc_create - create a TIPC socket 147 * tipc_sk_create - create a TIPC socket
145 * @net: network namespace (must be default network) 148 * @net: network namespace (must be default network)
146 * @sock: pre-allocated socket structure 149 * @sock: pre-allocated socket structure
147 * @protocol: protocol indicator (must be 0) 150 * @protocol: protocol indicator (must be 0)
@@ -152,8 +155,8 @@ static void reject_rx_queue(struct sock *sk)
152 * 155 *
153 * Returns 0 on success, errno otherwise 156 * Returns 0 on success, errno otherwise
154 */ 157 */
155static int tipc_create(struct net *net, struct socket *sock, int protocol, 158static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
156 int kern) 159 int kern)
157{ 160{
158 const struct proto_ops *ops; 161 const struct proto_ops *ops;
159 socket_state state; 162 socket_state state;
@@ -183,7 +186,11 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
183 } 186 }
184 187
185 /* Allocate socket's protocol area */ 188 /* Allocate socket's protocol area */
186 sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); 189 if (!kern)
190 sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto);
191 else
192 sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto_kern);
193
187 if (sk == NULL) 194 if (sk == NULL)
188 return -ENOMEM; 195 return -ENOMEM;
189 196
@@ -219,6 +226,78 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol,
219} 226}
220 227
221/** 228/**
229 * tipc_sock_create_local - create TIPC socket from inside TIPC module
230 * @type: socket type - SOCK_RDM or SOCK_SEQPACKET
231 *
232 * We cannot use sock_creat_kern here because it bumps module user count.
233 * Since socket owner and creator is the same module we must make sure
234 * that module count remains zero for module local sockets, otherwise
235 * we cannot do rmmod.
236 *
237 * Returns 0 on success, errno otherwise
238 */
239int tipc_sock_create_local(int type, struct socket **res)
240{
241 int rc;
242 struct sock *sk;
243
244 rc = sock_create_lite(AF_TIPC, type, 0, res);
245 if (rc < 0) {
246 pr_err("Failed to create kernel socket\n");
247 return rc;
248 }
249 tipc_sk_create(&init_net, *res, 0, 1);
250
251 sk = (*res)->sk;
252
253 return 0;
254}
255
256/**
257 * tipc_sock_release_local - release socket created by tipc_sock_create_local
258 * @sock: the socket to be released.
259 *
260 * Module reference count is not incremented when such sockets are created,
261 * so we must keep it from being decremented when they are released.
262 */
263void tipc_sock_release_local(struct socket *sock)
264{
265 release(sock);
266 sock->ops = NULL;
267 sock_release(sock);
268}
269
270/**
271 * tipc_sock_accept_local - accept a connection on a socket created
272 * with tipc_sock_create_local. Use this function to avoid that
273 * module reference count is inadvertently incremented.
274 *
275 * @sock: the accepting socket
276 * @newsock: reference to the new socket to be created
277 * @flags: socket flags
278 */
279
280int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
281 int flags)
282{
283 struct sock *sk = sock->sk;
284 int ret;
285
286 ret = sock_create_lite(sk->sk_family, sk->sk_type,
287 sk->sk_protocol, newsock);
288 if (ret < 0)
289 return ret;
290
291 ret = accept(sock, *newsock, flags);
292 if (ret < 0) {
293 sock_release(*newsock);
294 return ret;
295 }
296 (*newsock)->ops = sock->ops;
297 return ret;
298}
299
300/**
222 * release - destroy a TIPC socket 301 * release - destroy a TIPC socket
223 * @sock: socket to destroy 302 * @sock: socket to destroy
224 * 303 *
@@ -1529,7 +1608,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
1529 1608
1530 buf = skb_peek(&sk->sk_receive_queue); 1609 buf = skb_peek(&sk->sk_receive_queue);
1531 1610
1532 res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); 1611 res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1);
1533 if (res) 1612 if (res)
1534 goto exit; 1613 goto exit;
1535 1614
@@ -1839,7 +1918,7 @@ static const struct proto_ops stream_ops = {
1839static const struct net_proto_family tipc_family_ops = { 1918static const struct net_proto_family tipc_family_ops = {
1840 .owner = THIS_MODULE, 1919 .owner = THIS_MODULE,
1841 .family = AF_TIPC, 1920 .family = AF_TIPC,
1842 .create = tipc_create 1921 .create = tipc_sk_create
1843}; 1922};
1844 1923
1845static struct proto tipc_proto = { 1924static struct proto tipc_proto = {
@@ -1849,6 +1928,12 @@ static struct proto tipc_proto = {
1849 .sysctl_rmem = sysctl_tipc_rmem 1928 .sysctl_rmem = sysctl_tipc_rmem
1850}; 1929};
1851 1930
1931static struct proto tipc_proto_kern = {
1932 .name = "TIPC",
1933 .obj_size = sizeof(struct tipc_sock),
1934 .sysctl_rmem = sysctl_tipc_rmem
1935};
1936
1852/** 1937/**
1853 * tipc_socket_init - initialize TIPC socket interface 1938 * tipc_socket_init - initialize TIPC socket interface
1854 * 1939 *