diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/server.c | 44 | ||||
-rw-r--r-- | net/tipc/socket.c | 83 | ||||
-rw-r--r-- | net/tipc/socket.h | 4 |
3 files changed, 39 insertions, 92 deletions
diff --git a/net/tipc/server.c b/net/tipc/server.c index eadd4ed45905..a57c8407cbf3 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c | |||
@@ -37,11 +37,13 @@ | |||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "socket.h" | 38 | #include "socket.h" |
39 | #include <net/sock.h> | 39 | #include <net/sock.h> |
40 | #include <linux/module.h> | ||
40 | 41 | ||
41 | /* Number of messages to send before rescheduling */ | 42 | /* Number of messages to send before rescheduling */ |
42 | #define MAX_SEND_MSG_COUNT 25 | 43 | #define MAX_SEND_MSG_COUNT 25 |
43 | #define MAX_RECV_MSG_COUNT 25 | 44 | #define MAX_RECV_MSG_COUNT 25 |
44 | #define CF_CONNECTED 1 | 45 | #define CF_CONNECTED 1 |
46 | #define CF_SERVER 2 | ||
45 | 47 | ||
46 | #define sock2con(x) ((struct tipc_conn *)(x)->sk_user_data) | 48 | #define sock2con(x) ((struct tipc_conn *)(x)->sk_user_data) |
47 | 49 | ||
@@ -88,9 +90,16 @@ static void tipc_clean_outqueues(struct tipc_conn *con); | |||
88 | static void tipc_conn_kref_release(struct kref *kref) | 90 | static void tipc_conn_kref_release(struct kref *kref) |
89 | { | 91 | { |
90 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); | 92 | struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); |
93 | struct socket *sock = con->sock; | ||
94 | struct sock *sk; | ||
91 | 95 | ||
92 | if (con->sock) { | 96 | if (sock) { |
93 | tipc_sock_release_local(con->sock); | 97 | sk = sock->sk; |
98 | if (test_bit(CF_SERVER, &con->flags)) { | ||
99 | __module_get(sock->ops->owner); | ||
100 | __module_get(sk->sk_prot_creator->owner); | ||
101 | } | ||
102 | sk_release_kernel(sk); | ||
94 | con->sock = NULL; | 103 | con->sock = NULL; |
95 | } | 104 | } |
96 | 105 | ||
@@ -281,7 +290,7 @@ static int tipc_accept_from_sock(struct tipc_conn *con) | |||
281 | struct tipc_conn *newcon; | 290 | struct tipc_conn *newcon; |
282 | int ret; | 291 | int ret; |
283 | 292 | ||
284 | ret = tipc_sock_accept_local(sock, &newsock, O_NONBLOCK); | 293 | ret = kernel_accept(sock, &newsock, O_NONBLOCK); |
285 | if (ret < 0) | 294 | if (ret < 0) |
286 | return ret; | 295 | return ret; |
287 | 296 | ||
@@ -309,9 +318,12 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con) | |||
309 | struct socket *sock = NULL; | 318 | struct socket *sock = NULL; |
310 | int ret; | 319 | int ret; |
311 | 320 | ||
312 | ret = tipc_sock_create_local(s->net, s->type, &sock); | 321 | ret = sock_create_kern(AF_TIPC, SOCK_SEQPACKET, 0, &sock); |
313 | if (ret < 0) | 322 | if (ret < 0) |
314 | return NULL; | 323 | return NULL; |
324 | |||
325 | sk_change_net(sock->sk, s->net); | ||
326 | |||
315 | ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE, | 327 | ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE, |
316 | (char *)&s->imp, sizeof(s->imp)); | 328 | (char *)&s->imp, sizeof(s->imp)); |
317 | if (ret < 0) | 329 | if (ret < 0) |
@@ -337,11 +349,31 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con) | |||
337 | pr_err("Unknown socket type %d\n", s->type); | 349 | pr_err("Unknown socket type %d\n", s->type); |
338 | goto create_err; | 350 | goto create_err; |
339 | } | 351 | } |
352 | |||
353 | /* As server's listening socket owner and creator is the same module, | ||
354 | * we have to decrease TIPC module reference count to guarantee that | ||
355 | * it remains zero after the server socket is created, otherwise, | ||
356 | * executing "rmmod" command is unable to make TIPC module deleted | ||
357 | * after TIPC module is inserted successfully. | ||
358 | * | ||
359 | * However, the reference count is ever increased twice in | ||
360 | * sock_create_kern(): one is to increase the reference count of owner | ||
361 | * of TIPC socket's proto_ops struct; another is to increment the | ||
362 | * reference count of owner of TIPC proto struct. Therefore, we must | ||
363 | * decrement the module reference count twice to ensure that it keeps | ||
364 | * zero after server's listening socket is created. Of course, we | ||
365 | * must bump the module reference count twice as well before the socket | ||
366 | * is closed. | ||
367 | */ | ||
368 | module_put(sock->ops->owner); | ||
369 | module_put(sock->sk->sk_prot_creator->owner); | ||
370 | set_bit(CF_SERVER, &con->flags); | ||
371 | |||
340 | return sock; | 372 | return sock; |
341 | 373 | ||
342 | create_err: | 374 | create_err: |
343 | sock_release(sock); | 375 | kernel_sock_shutdown(sock, SHUT_RDWR); |
344 | con->sock = NULL; | 376 | sk_release_kernel(sock->sk); |
345 | return NULL; | 377 | return NULL; |
346 | } | 378 | } |
347 | 379 | ||
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 934947f038b6..813847d25a49 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -121,9 +121,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz); | |||
121 | static const struct proto_ops packet_ops; | 121 | static const struct proto_ops packet_ops; |
122 | static const struct proto_ops stream_ops; | 122 | static const struct proto_ops stream_ops; |
123 | static const struct proto_ops msg_ops; | 123 | static const struct proto_ops msg_ops; |
124 | |||
125 | static struct proto tipc_proto; | 124 | static struct proto tipc_proto; |
126 | static struct proto tipc_proto_kern; | ||
127 | 125 | ||
128 | static const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = { | 126 | static const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = { |
129 | [TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC }, | 127 | [TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC }, |
@@ -341,11 +339,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, | |||
341 | } | 339 | } |
342 | 340 | ||
343 | /* Allocate socket's protocol area */ | 341 | /* Allocate socket's protocol area */ |
344 | if (!kern) | 342 | sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); |
345 | sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); | ||
346 | else | ||
347 | sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto_kern); | ||
348 | |||
349 | if (sk == NULL) | 343 | if (sk == NULL) |
350 | return -ENOMEM; | 344 | return -ENOMEM; |
351 | 345 | ||
@@ -383,75 +377,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock, | |||
383 | return 0; | 377 | return 0; |
384 | } | 378 | } |
385 | 379 | ||
386 | /** | ||
387 | * tipc_sock_create_local - create TIPC socket from inside TIPC module | ||
388 | * @type: socket type - SOCK_RDM or SOCK_SEQPACKET | ||
389 | * | ||
390 | * We cannot use sock_creat_kern here because it bumps module user count. | ||
391 | * Since socket owner and creator is the same module we must make sure | ||
392 | * that module count remains zero for module local sockets, otherwise | ||
393 | * we cannot do rmmod. | ||
394 | * | ||
395 | * Returns 0 on success, errno otherwise | ||
396 | */ | ||
397 | int tipc_sock_create_local(struct net *net, int type, struct socket **res) | ||
398 | { | ||
399 | int rc; | ||
400 | |||
401 | rc = sock_create_lite(AF_TIPC, type, 0, res); | ||
402 | if (rc < 0) { | ||
403 | pr_err("Failed to create kernel socket\n"); | ||
404 | return rc; | ||
405 | } | ||
406 | tipc_sk_create(net, *res, 0, 1); | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | /** | ||
412 | * tipc_sock_release_local - release socket created by tipc_sock_create_local | ||
413 | * @sock: the socket to be released. | ||
414 | * | ||
415 | * Module reference count is not incremented when such sockets are created, | ||
416 | * so we must keep it from being decremented when they are released. | ||
417 | */ | ||
418 | void tipc_sock_release_local(struct socket *sock) | ||
419 | { | ||
420 | tipc_release(sock); | ||
421 | sock->ops = NULL; | ||
422 | sock_release(sock); | ||
423 | } | ||
424 | |||
425 | /** | ||
426 | * tipc_sock_accept_local - accept a connection on a socket created | ||
427 | * with tipc_sock_create_local. Use this function to avoid that | ||
428 | * module reference count is inadvertently incremented. | ||
429 | * | ||
430 | * @sock: the accepting socket | ||
431 | * @newsock: reference to the new socket to be created | ||
432 | * @flags: socket flags | ||
433 | */ | ||
434 | |||
435 | int tipc_sock_accept_local(struct socket *sock, struct socket **newsock, | ||
436 | int flags) | ||
437 | { | ||
438 | struct sock *sk = sock->sk; | ||
439 | int ret; | ||
440 | |||
441 | ret = sock_create_lite(sk->sk_family, sk->sk_type, | ||
442 | sk->sk_protocol, newsock); | ||
443 | if (ret < 0) | ||
444 | return ret; | ||
445 | |||
446 | ret = tipc_accept(sock, *newsock, flags); | ||
447 | if (ret < 0) { | ||
448 | sock_release(*newsock); | ||
449 | return ret; | ||
450 | } | ||
451 | (*newsock)->ops = sock->ops; | ||
452 | return ret; | ||
453 | } | ||
454 | |||
455 | static void tipc_sk_callback(struct rcu_head *head) | 380 | static void tipc_sk_callback(struct rcu_head *head) |
456 | { | 381 | { |
457 | struct tipc_sock *tsk = container_of(head, struct tipc_sock, rcu); | 382 | struct tipc_sock *tsk = container_of(head, struct tipc_sock, rcu); |
@@ -2608,12 +2533,6 @@ static struct proto tipc_proto = { | |||
2608 | .sysctl_rmem = sysctl_tipc_rmem | 2533 | .sysctl_rmem = sysctl_tipc_rmem |
2609 | }; | 2534 | }; |
2610 | 2535 | ||
2611 | static struct proto tipc_proto_kern = { | ||
2612 | .name = "TIPC", | ||
2613 | .obj_size = sizeof(struct tipc_sock), | ||
2614 | .sysctl_rmem = sysctl_tipc_rmem | ||
2615 | }; | ||
2616 | |||
2617 | /** | 2536 | /** |
2618 | * tipc_socket_init - initialize TIPC socket interface | 2537 | * tipc_socket_init - initialize TIPC socket interface |
2619 | * | 2538 | * |
diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 238f1b7bd9bd..bf6551389522 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h | |||
@@ -44,10 +44,6 @@ | |||
44 | SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE)) | 44 | SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE)) |
45 | int tipc_socket_init(void); | 45 | int tipc_socket_init(void); |
46 | void tipc_socket_stop(void); | 46 | void tipc_socket_stop(void); |
47 | int tipc_sock_create_local(struct net *net, int type, struct socket **res); | ||
48 | void tipc_sock_release_local(struct socket *sock); | ||
49 | int tipc_sock_accept_local(struct socket *sock, struct socket **newsock, | ||
50 | int flags); | ||
51 | int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq); | 47 | int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq); |
52 | void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, | 48 | void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, |
53 | struct sk_buff_head *inputq); | 49 | struct sk_buff_head *inputq); |