Commit df79d040dcd7d7e580c50edf40b82e677fe84801

Authored by Jon Maloy
Committed by David S. Miller
1 parent c901d26d4a

tipc: eliminate struct tipc_subscriber

It is unnecessary to keep two structures, struct tipc_conn and struct
tipc_subscriber, with a one-to-one relationship and still with different
life cycles. The fact that the two often run in different contexts, and
still may access each other via direct pointers constitutes an additional
hazard, something we have experienced at several occasions, and still
see happening.

We have identified at least two remaining problems that are easier to
fix if we simplify the topology server data structure somewhat.

- When there is a race between a subscription up/down event and a
  timeout event, it is fully possible that the former might be delivered
  after the latter, leading to confusion for the receiver.

- The function tipc_subcrp_timeout() is executing in interrupt context,
  while the following call chain is at least theoretically possible:
  tipc_subscrp_timeout()
    tipc_subscrp_send_event()
      tipc_conn_sendmsg()
        conn_put()
          tipc_conn_kref_release()
            sock_release(sock)

I.e., we end up calling a function that might try to sleep in
interrupt context. To eliminate this, we need to ensure that the
tipc_conn structure and the socket, as well as the subscription
instances, only are deleted in work queue context, i.e., after the
timeout event really has been sent out.

We now remove this unnecessary complexity, by merging data and
functionality of the subscriber structure into struct tipc_conn
and the associated file server.c. We thereafter add a spinlock and
a new 'inactive' state to the subscription structure. Using those,
both problems described above can be easily solved.

Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 4 changed files with 146 additions and 207 deletions Side-by-side Diff

... ... @@ -2,6 +2,7 @@
2 2 * net/tipc/server.c: TIPC server infrastructure
3 3 *
4 4 * Copyright (c) 2012-2013, Wind River Systems
  5 + * Copyright (c) 2017, Ericsson AB
5 6 * All rights reserved.
6 7 *
7 8 * Redistribution and use in source and binary forms, with or without
8 9  
9 10  
... ... @@ -57,12 +58,13 @@
57 58 * @sock: socket handler associated with connection
58 59 * @flags: indicates connection state
59 60 * @server: pointer to connected server
  61 + * @sub_list: lsit to all pertaing subscriptions
  62 + * @sub_lock: lock protecting the subscription list
  63 + * @outqueue_lock: control access to the outqueue
60 64 * @rwork: receive work item
61   - * @usr_data: user-specified field
62 65 * @rx_action: what to do when connection socket is active
63 66 * @outqueue: pointer to first outbound message in queue
64 67 * @outqueue_lock: control access to the outqueue
65   - * @outqueue: list of connection objects for its server
66 68 * @swork: send work item
67 69 */
68 70 struct tipc_conn {
69 71  
... ... @@ -71,9 +73,10 @@
71 73 struct socket *sock;
72 74 unsigned long flags;
73 75 struct tipc_server *server;
  76 + struct list_head sub_list;
  77 + spinlock_t sub_lock; /* for subscription list */
74 78 struct work_struct rwork;
75 79 int (*rx_action) (struct tipc_conn *con);
76   - void *usr_data;
77 80 struct list_head outqueue;
78 81 spinlock_t outqueue_lock;
79 82 struct work_struct swork;
... ... @@ -81,6 +84,7 @@
81 84  
82 85 /* An entry waiting to be sent */
83 86 struct outqueue_entry {
  87 + u32 evt;
84 88 struct list_head list;
85 89 struct kvec iov;
86 90 };
87 91  
88 92  
89 93  
... ... @@ -89,18 +93,33 @@
89 93 static void tipc_send_work(struct work_struct *work);
90 94 static void tipc_clean_outqueues(struct tipc_conn *con);
91 95  
  96 +static bool connected(struct tipc_conn *con)
  97 +{
  98 + return con && test_bit(CF_CONNECTED, &con->flags);
  99 +}
  100 +
  101 +/**
  102 + * htohl - convert value to endianness used by destination
  103 + * @in: value to convert
  104 + * @swap: non-zero if endianness must be reversed
  105 + *
  106 + * Returns converted value
  107 + */
  108 +static u32 htohl(u32 in, int swap)
  109 +{
  110 + return swap ? swab32(in) : in;
  111 +}
  112 +
92 113 static void tipc_conn_kref_release(struct kref *kref)
93 114 {
94 115 struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
95 116 struct tipc_server *s = con->server;
96 117 struct socket *sock = con->sock;
97   - struct sock *sk;
98 118  
99 119 if (sock) {
100   - sk = sock->sk;
101 120 if (test_bit(CF_SERVER, &con->flags)) {
102 121 __module_get(sock->ops->owner);
103   - __module_get(sk->sk_prot_creator->owner);
  122 + __module_get(sock->sk->sk_prot_creator->owner);
104 123 }
105 124 sock_release(sock);
106 125 con->sock = NULL;
... ... @@ -129,11 +148,8 @@
129 148  
130 149 spin_lock_bh(&s->idr_lock);
131 150 con = idr_find(&s->conn_idr, conid);
132   - if (con) {
133   - if (!test_bit(CF_CONNECTED, &con->flags) ||
134   - !kref_get_unless_zero(&con->kref))
135   - con = NULL;
136   - }
  151 + if (!connected(con) || !kref_get_unless_zero(&con->kref))
  152 + con = NULL;
137 153 spin_unlock_bh(&s->idr_lock);
138 154 return con;
139 155 }
... ... @@ -144,7 +160,7 @@
144 160  
145 161 read_lock_bh(&sk->sk_callback_lock);
146 162 con = sock2con(sk);
147   - if (con && test_bit(CF_CONNECTED, &con->flags)) {
  163 + if (connected(con)) {
148 164 conn_get(con);
149 165 if (!queue_work(con->server->rcv_wq, &con->rwork))
150 166 conn_put(con);
... ... @@ -158,7 +174,7 @@
158 174  
159 175 read_lock_bh(&sk->sk_callback_lock);
160 176 con = sock2con(sk);
161   - if (con && test_bit(CF_CONNECTED, &con->flags)) {
  177 + if (connected(con)) {
162 178 conn_get(con);
163 179 if (!queue_work(con->server->send_wq, &con->swork))
164 180 conn_put(con);
... ... @@ -181,6 +197,24 @@
181 197 write_unlock_bh(&sk->sk_callback_lock);
182 198 }
183 199  
  200 +/* tipc_con_delete_sub - delete a specific or all subscriptions
  201 + * for a given subscriber
  202 + */
  203 +static void tipc_con_delete_sub(struct tipc_conn *con, struct tipc_subscr *s)
  204 +{
  205 + struct list_head *sub_list = &con->sub_list;
  206 + struct tipc_subscription *sub, *tmp;
  207 +
  208 + spin_lock_bh(&con->sub_lock);
  209 + list_for_each_entry_safe(sub, tmp, sub_list, subscrp_list) {
  210 + if (!s || !memcmp(s, &sub->evt.s, sizeof(*s)))
  211 + tipc_sub_delete(sub);
  212 + else if (s)
  213 + break;
  214 + }
  215 + spin_unlock_bh(&con->sub_lock);
  216 +}
  217 +
184 218 static void tipc_close_conn(struct tipc_conn *con)
185 219 {
186 220 struct sock *sk = con->sock->sk;
187 221  
... ... @@ -188,10 +222,11 @@
188 222  
189 223 write_lock_bh(&sk->sk_callback_lock);
190 224 disconnect = test_and_clear_bit(CF_CONNECTED, &con->flags);
  225 +
191 226 if (disconnect) {
192 227 sk->sk_user_data = NULL;
193 228 if (con->conid)
194   - tipc_subscrb_delete(con->usr_data);
  229 + tipc_con_delete_sub(con, NULL);
195 230 }
196 231 write_unlock_bh(&sk->sk_callback_lock);
197 232  
198 233  
... ... @@ -215,7 +250,9 @@
215 250  
216 251 kref_init(&con->kref);
217 252 INIT_LIST_HEAD(&con->outqueue);
  253 + INIT_LIST_HEAD(&con->sub_list);
218 254 spin_lock_init(&con->outqueue_lock);
  255 + spin_lock_init(&con->sub_lock);
219 256 INIT_WORK(&con->swork, tipc_send_work);
220 257 INIT_WORK(&con->rwork, tipc_recv_work);
221 258  
... ... @@ -236,6 +273,35 @@
236 273 return con;
237 274 }
238 275  
  276 +int tipc_con_rcv_sub(struct net *net, int conid, struct tipc_conn *con,
  277 + void *buf, size_t len)
  278 +{
  279 + struct tipc_subscr *s = (struct tipc_subscr *)buf;
  280 + struct tipc_subscription *sub;
  281 + bool status;
  282 + int swap;
  283 +
  284 + /* Determine subscriber's endianness */
  285 + swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE |
  286 + TIPC_SUB_CANCEL));
  287 +
  288 + /* Detect & process a subscription cancellation request */
  289 + if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
  290 + s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
  291 + tipc_con_delete_sub(con, s);
  292 + return 0;
  293 + }
  294 + status = !(s->filter & htohl(TIPC_SUB_NO_STATUS, swap));
  295 + sub = tipc_subscrp_subscribe(net, s, conid, swap, status);
  296 + if (!sub)
  297 + return -1;
  298 +
  299 + spin_lock_bh(&con->sub_lock);
  300 + list_add(&sub->subscrp_list, &con->sub_list);
  301 + spin_unlock_bh(&con->sub_lock);
  302 + return 0;
  303 +}
  304 +
239 305 static int tipc_receive_from_sock(struct tipc_conn *con)
240 306 {
241 307 struct tipc_server *s = con->server;
... ... @@ -262,9 +328,7 @@
262 328 }
263 329  
264 330 read_lock_bh(&sk->sk_callback_lock);
265   - if (test_bit(CF_CONNECTED, &con->flags))
266   - ret = tipc_subscrb_rcv(sock_net(con->sock->sk), con->conid,
267   - con->usr_data, buf, ret);
  331 + ret = tipc_con_rcv_sub(s->net, con->conid, con, buf, ret);
268 332 read_unlock_bh(&sk->sk_callback_lock);
269 333 kmem_cache_free(s->rcvbuf_cache, buf);
270 334 if (ret < 0)
... ... @@ -302,15 +366,6 @@
302 366 newcon->rx_action = tipc_receive_from_sock;
303 367 tipc_register_callbacks(newsock, newcon);
304 368  
305   - /* Notify that new connection is incoming */
306   - newcon->usr_data = tipc_subscrb_create(newcon->conid);
307   -
308   - if (!newcon->usr_data) {
309   - sock_release(newsock);
310   - conn_put(newcon);
311   - return -ENOMEM;
312   - }
313   -
314 369 /* Wake up receive process in case of 'SYN+' message */
315 370 newsock->sk->sk_data_ready(newsock->sk);
316 371 return ret;
... ... @@ -427,7 +482,7 @@
427 482 }
428 483  
429 484 int tipc_conn_sendmsg(struct tipc_server *s, int conid,
430   - void *data, size_t len)
  485 + u32 evt, void *data, size_t len)
431 486 {
432 487 struct outqueue_entry *e;
433 488 struct tipc_conn *con;
... ... @@ -436,7 +491,7 @@
436 491 if (!con)
437 492 return -EINVAL;
438 493  
439   - if (!test_bit(CF_CONNECTED, &con->flags)) {
  494 + if (!connected(con)) {
440 495 conn_put(con);
441 496 return 0;
442 497 }
... ... @@ -446,7 +501,7 @@
446 501 conn_put(con);
447 502 return -ENOMEM;
448 503 }
449   -
  504 + e->evt = evt;
450 505 spin_lock_bh(&con->outqueue_lock);
451 506 list_add_tail(&e->list, &con->outqueue);
452 507 spin_unlock_bh(&con->outqueue_lock);
453 508  
454 509  
... ... @@ -470,10 +525,9 @@
470 525 bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
471 526 u32 upper, u32 filter, int *conid)
472 527 {
473   - struct tipc_subscriber *scbr;
474 528 struct tipc_subscr sub;
475   - struct tipc_server *s;
476 529 struct tipc_conn *con;
  530 + int rc;
477 531  
478 532 sub.seq.type = type;
479 533 sub.seq.lower = lower;
480 534  
481 535  
482 536  
... ... @@ -487,32 +541,23 @@
487 541 return false;
488 542  
489 543 *conid = con->conid;
490   - s = con->server;
491   - scbr = tipc_subscrb_create(*conid);
492   - if (!scbr) {
493   - conn_put(con);
494   - return false;
495   - }
496   -
497   - con->usr_data = scbr;
498 544 con->sock = NULL;
499   - tipc_subscrb_rcv(net, *conid, scbr, &sub, sizeof(sub));
500   - return true;
  545 + rc = tipc_con_rcv_sub(net, *conid, con, &sub, sizeof(sub));
  546 + if (rc < 0)
  547 + tipc_close_conn(con);
  548 + return !rc;
501 549 }
502 550  
503 551 void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
504 552 {
505 553 struct tipc_conn *con;
506   - struct tipc_server *srv;
507 554  
508 555 con = tipc_conn_lookup(tipc_topsrv(net), conid);
509 556 if (!con)
510 557 return;
511 558  
512 559 test_and_clear_bit(CF_CONNECTED, &con->flags);
513   - srv = con->server;
514   - if (con->conid)
515   - tipc_subscrb_delete(con->usr_data);
  560 + tipc_con_delete_sub(con, NULL);
516 561 conn_put(con);
517 562 conn_put(con);
518 563 }
... ... @@ -537,7 +582,8 @@
537 582  
538 583 static void tipc_send_to_sock(struct tipc_conn *con)
539 584 {
540   - struct tipc_server *s = con->server;
  585 + struct list_head *queue = &con->outqueue;
  586 + struct tipc_server *srv = con->server;
541 587 struct outqueue_entry *e;
542 588 struct tipc_event *evt;
543 589 struct msghdr msg;
544 590  
545 591  
546 592  
... ... @@ -545,16 +591,20 @@
545 591 int ret;
546 592  
547 593 spin_lock_bh(&con->outqueue_lock);
548   - while (test_bit(CF_CONNECTED, &con->flags)) {
549   - e = list_entry(con->outqueue.next, struct outqueue_entry, list);
550   - if ((struct list_head *) e == &con->outqueue)
551   - break;
552 594  
  595 + while (!list_empty(queue)) {
  596 + e = list_first_entry(queue, struct outqueue_entry, list);
  597 +
553 598 spin_unlock_bh(&con->outqueue_lock);
554 599  
  600 + if (e->evt == TIPC_SUBSCR_TIMEOUT) {
  601 + evt = (struct tipc_event *)e->iov.iov_base;
  602 + tipc_con_delete_sub(con, &evt->s);
  603 + }
  604 + memset(&msg, 0, sizeof(msg));
  605 + msg.msg_flags = MSG_DONTWAIT;
  606 +
555 607 if (con->sock) {
556   - memset(&msg, 0, sizeof(msg));
557   - msg.msg_flags = MSG_DONTWAIT;
558 608 ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
559 609 e->iov.iov_len);
560 610 if (ret == -EWOULDBLOCK || ret == 0) {
... ... @@ -565,7 +615,7 @@
565 615 }
566 616 } else {
567 617 evt = e->iov.iov_base;
568   - tipc_send_kern_top_evt(s->net, evt);
  618 + tipc_send_kern_top_evt(srv->net, evt);
569 619 }
570 620  
571 621 /* Don't starve users filling buffers */
... ... @@ -573,7 +623,6 @@
573 623 cond_resched();
574 624 count = 0;
575 625 }
576   -
577 626 spin_lock_bh(&con->outqueue_lock);
578 627 list_del(&e->list);
579 628 tipc_free_entry(e);
... ... @@ -591,7 +640,7 @@
591 640 struct tipc_conn *con = container_of(work, struct tipc_conn, rwork);
592 641 int count = 0;
593 642  
594   - while (test_bit(CF_CONNECTED, &con->flags)) {
  643 + while (connected(con)) {
595 644 if (con->rx_action(con))
596 645 break;
597 646  
... ... @@ -608,7 +657,7 @@
608 657 {
609 658 struct tipc_conn *con = container_of(work, struct tipc_conn, swork);
610 659  
611   - if (test_bit(CF_CONNECTED, &con->flags))
  660 + if (connected(con))
612 661 tipc_send_to_sock(con);
613 662  
614 663 conn_put(con);
... ... @@ -77,7 +77,7 @@
77 77 };
78 78  
79 79 int tipc_conn_sendmsg(struct tipc_server *s, int conid,
80   - void *data, size_t len);
  80 + u32 evt, void *data, size_t len);
81 81  
82 82 bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
83 83 u32 upper, u32 filter, int *conid);
1 1 /*
2 2 * net/tipc/subscr.c: TIPC network topology service
3 3 *
4   - * Copyright (c) 2000-2006, Ericsson AB
  4 + * Copyright (c) 2000-2017, Ericsson AB
5 5 * Copyright (c) 2005-2007, 2010-2013, Wind River Systems
6 6 * All rights reserved.
7 7 *
... ... @@ -39,22 +39,6 @@
39 39 #include "subscr.h"
40 40  
41 41 /**
42   - * struct tipc_subscriber - TIPC network topology subscriber
43   - * @kref: reference counter to tipc_subscription object
44   - * @conid: connection identifier to server connecting to subscriber
45   - * @lock: control access to subscriber
46   - * @subscrp_list: list of subscription objects for this subscriber
47   - */
48   -struct tipc_subscriber {
49   - struct kref kref;
50   - int conid;
51   - spinlock_t lock;
52   - struct list_head subscrp_list;
53   -};
54   -
55   -static void tipc_subscrb_put(struct tipc_subscriber *subscriber);
56   -
57   -/**
58 42 * htohl - convert value to endianness used by destination
59 43 * @in: value to convert
60 44 * @swap: non-zero if endianness must be reversed
61 45  
... ... @@ -71,9 +55,10 @@
71 55 u32 event, u32 port_ref, u32 node)
72 56 {
73 57 struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
74   - struct tipc_subscriber *subscriber = sub->subscriber;
75 58 struct kvec msg_sect;
76 59  
  60 + if (sub->inactive)
  61 + return;
77 62 msg_sect.iov_base = (void *)&sub->evt;
78 63 msg_sect.iov_len = sizeof(struct tipc_event);
79 64 sub->evt.event = htohl(event, sub->swap);
... ... @@ -81,7 +66,7 @@
81 66 sub->evt.found_upper = htohl(found_upper, sub->swap);
82 67 sub->evt.port.ref = htohl(port_ref, sub->swap);
83 68 sub->evt.port.node = htohl(node, sub->swap);
84   - tipc_conn_sendmsg(tn->topsrv, subscriber->conid,
  69 + tipc_conn_sendmsg(tn->topsrv, sub->conid, event,
85 70 msg_sect.iov_base, msg_sect.iov_len);
86 71 }
87 72  
88 73  
89 74  
90 75  
91 76  
92 77  
93 78  
... ... @@ -132,54 +117,33 @@
132 117 return;
133 118 if (filter & TIPC_SUB_NODE_SCOPE && scope != TIPC_NODE_SCOPE)
134 119 return;
135   -
136   - tipc_subscrp_send_event(sub, found_lower, found_upper, event, port_ref,
137   - node);
  120 + spin_lock(&sub->lock);
  121 + tipc_subscrp_send_event(sub, found_lower, found_upper,
  122 + event, port_ref, node);
  123 + spin_unlock(&sub->lock);
138 124 }
139 125  
140 126 static void tipc_subscrp_timeout(struct timer_list *t)
141 127 {
142 128 struct tipc_subscription *sub = from_timer(sub, t, timer);
143   - struct tipc_subscriber *subscriber = sub->subscriber;
  129 + struct tipc_subscr *s = &sub->evt.s;
144 130  
145   - spin_lock_bh(&subscriber->lock);
146   - tipc_nametbl_unsubscribe(sub);
147   - list_del(&sub->subscrp_list);
148   - spin_unlock_bh(&subscriber->lock);
149   -
150   - /* Notify subscriber of timeout */
151   - tipc_subscrp_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
  131 + spin_lock(&sub->lock);
  132 + tipc_subscrp_send_event(sub, s->seq.lower, s->seq.upper,
152 133 TIPC_SUBSCR_TIMEOUT, 0, 0);
153   -
154   - tipc_subscrp_put(sub);
  134 + sub->inactive = true;
  135 + spin_unlock(&sub->lock);
155 136 }
156 137  
157   -static void tipc_subscrb_kref_release(struct kref *kref)
158   -{
159   - kfree(container_of(kref,struct tipc_subscriber, kref));
160   -}
161   -
162   -static void tipc_subscrb_put(struct tipc_subscriber *subscriber)
163   -{
164   - kref_put(&subscriber->kref, tipc_subscrb_kref_release);
165   -}
166   -
167   -static void tipc_subscrb_get(struct tipc_subscriber *subscriber)
168   -{
169   - kref_get(&subscriber->kref);
170   -}
171   -
172 138 static void tipc_subscrp_kref_release(struct kref *kref)
173 139 {
174 140 struct tipc_subscription *sub = container_of(kref,
175 141 struct tipc_subscription,
176 142 kref);
177 143 struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
178   - struct tipc_subscriber *subscriber = sub->subscriber;
179 144  
180 145 atomic_dec(&tn->subscription_count);
181 146 kfree(sub);
182   - tipc_subscrb_put(subscriber);
183 147 }
184 148  
185 149 void tipc_subscrp_put(struct tipc_subscription *subscription)
186 150  
... ... @@ -192,68 +156,9 @@
192 156 kref_get(&subscription->kref);
193 157 }
194 158  
195   -/* tipc_subscrb_subscrp_delete - delete a specific subscription or all
196   - * subscriptions for a given subscriber.
197   - */
198   -static void tipc_subscrb_subscrp_delete(struct tipc_subscriber *subscriber,
199   - struct tipc_subscr *s)
200   -{
201   - struct list_head *subscription_list = &subscriber->subscrp_list;
202   - struct tipc_subscription *sub, *temp;
203   - u32 timeout;
204   -
205   - spin_lock_bh(&subscriber->lock);
206   - list_for_each_entry_safe(sub, temp, subscription_list, subscrp_list) {
207   - if (s && memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr)))
208   - continue;
209   -
210   - timeout = htohl(sub->evt.s.timeout, sub->swap);
211   - if (timeout == TIPC_WAIT_FOREVER || del_timer(&sub->timer)) {
212   - tipc_nametbl_unsubscribe(sub);
213   - list_del(&sub->subscrp_list);
214   - tipc_subscrp_put(sub);
215   - }
216   -
217   - if (s)
218   - break;
219   - }
220   - spin_unlock_bh(&subscriber->lock);
221   -}
222   -
223   -struct tipc_subscriber *tipc_subscrb_create(int conid)
224   -{
225   - struct tipc_subscriber *subscriber;
226   -
227   - subscriber = kzalloc(sizeof(*subscriber), GFP_ATOMIC);
228   - if (!subscriber) {
229   - pr_warn("Subscriber rejected, no memory\n");
230   - return NULL;
231   - }
232   - INIT_LIST_HEAD(&subscriber->subscrp_list);
233   - kref_init(&subscriber->kref);
234   - subscriber->conid = conid;
235   - spin_lock_init(&subscriber->lock);
236   -
237   - return subscriber;
238   -}
239   -
240   -void tipc_subscrb_delete(struct tipc_subscriber *subscriber)
241   -{
242   - tipc_subscrb_subscrp_delete(subscriber, NULL);
243   - tipc_subscrb_put(subscriber);
244   -}
245   -
246   -static void tipc_subscrp_cancel(struct tipc_subscr *s,
247   - struct tipc_subscriber *subscriber)
248   -{
249   - tipc_subscrb_get(subscriber);
250   - tipc_subscrb_subscrp_delete(subscriber, s);
251   - tipc_subscrb_put(subscriber);
252   -}
253   -
254 159 static struct tipc_subscription *tipc_subscrp_create(struct net *net,
255 160 struct tipc_subscr *s,
256   - int swap)
  161 + int conid, bool swap)
257 162 {
258 163 struct tipc_net *tn = net_generic(net, tipc_net_id);
259 164 struct tipc_subscription *sub;
... ... @@ -275,6 +180,8 @@
275 180  
276 181 /* Initialize subscription object */
277 182 sub->net = net;
  183 + sub->conid = conid;
  184 + sub->inactive = false;
278 185 if (((filter & TIPC_SUB_PORTS) && (filter & TIPC_SUB_SERVICE)) ||
279 186 (htohl(s->seq.lower, swap) > htohl(s->seq.upper, swap))) {
280 187 pr_warn("Subscription rejected, illegal request\n");
281 188  
282 189  
283 190  
284 191  
285 192  
286 193  
287 194  
288 195  
289 196  
... ... @@ -284,59 +191,39 @@
284 191  
285 192 sub->swap = swap;
286 193 memcpy(&sub->evt.s, s, sizeof(*s));
  194 + spin_lock_init(&sub->lock);
287 195 atomic_inc(&tn->subscription_count);
288 196 kref_init(&sub->kref);
289 197 return sub;
290 198 }
291 199  
292   -static int tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s,
293   - struct tipc_subscriber *subscriber, int swap,
294   - bool status)
  200 +struct tipc_subscription *tipc_subscrp_subscribe(struct net *net,
  201 + struct tipc_subscr *s,
  202 + int conid, bool swap,
  203 + bool status)
295 204 {
296 205 struct tipc_subscription *sub = NULL;
297 206 u32 timeout;
298 207  
299   - sub = tipc_subscrp_create(net, s, swap);
  208 + sub = tipc_subscrp_create(net, s, conid, swap);
300 209 if (!sub)
301   - return -1;
  210 + return NULL;
302 211  
303   - spin_lock_bh(&subscriber->lock);
304   - list_add(&sub->subscrp_list, &subscriber->subscrp_list);
305   - sub->subscriber = subscriber;
306 212 tipc_nametbl_subscribe(sub, status);
307   - tipc_subscrb_get(subscriber);
308   - spin_unlock_bh(&subscriber->lock);
309   -
310 213 timer_setup(&sub->timer, tipc_subscrp_timeout, 0);
311 214 timeout = htohl(sub->evt.s.timeout, swap);
312   -
313 215 if (timeout != TIPC_WAIT_FOREVER)
314 216 mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
315   - return 0;
  217 + return sub;
316 218 }
317 219  
318   -/* Handle one request to create a new subscription for the subscriber
319   - */
320   -int tipc_subscrb_rcv(struct net *net, int conid, void *usr_data,
321   - void *buf, size_t len)
  220 +void tipc_sub_delete(struct tipc_subscription *sub)
322 221 {
323   - struct tipc_subscriber *subscriber = usr_data;
324   - struct tipc_subscr *s = (struct tipc_subscr *)buf;
325   - bool status;
326   - int swap;
327   -
328   - /* Determine subscriber's endianness */
329   - swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE |
330   - TIPC_SUB_CANCEL));
331   -
332   - /* Detect & process a subscription cancellation request */
333   - if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
334   - s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
335   - tipc_subscrp_cancel(s, subscriber);
336   - return 0;
337   - }
338   - status = !(s->filter & htohl(TIPC_SUB_NO_STATUS, swap));
339   - return tipc_subscrp_subscribe(net, s, subscriber, swap, status);
  222 + tipc_nametbl_unsubscribe(sub);
  223 + if (sub->evt.s.timeout != TIPC_WAIT_FOREVER)
  224 + del_timer_sync(&sub->timer);
  225 + list_del(&sub->subscrp_list);
  226 + tipc_subscrp_put(sub);
340 227 }
341 228  
342 229 int tipc_topsrv_start(struct net *net)
... ... @@ -43,7 +43,7 @@
43 43 #define TIPC_MAX_PUBLICATIONS 65535
44 44  
45 45 struct tipc_subscription;
46   -struct tipc_subscriber;
  46 +struct tipc_conn;
47 47  
48 48 /**
49 49 * struct tipc_subscription - TIPC network topology subscription object
50 50  
51 51  
52 52  
... ... @@ -58,19 +58,22 @@
58 58 */
59 59 struct tipc_subscription {
60 60 struct kref kref;
61   - struct tipc_subscriber *subscriber;
62 61 struct net *net;
63 62 struct timer_list timer;
64 63 struct list_head nameseq_list;
65 64 struct list_head subscrp_list;
66   - int swap;
67 65 struct tipc_event evt;
  66 + int conid;
  67 + bool swap;
  68 + bool inactive;
  69 + spinlock_t lock; /* serialize up/down and timer events */
68 70 };
69 71  
70   -struct tipc_subscriber *tipc_subscrb_create(int conid);
71   -void tipc_subscrb_delete(struct tipc_subscriber *subscriber);
72   -int tipc_subscrb_rcv(struct net *net, int conid, void *usr_data,
73   - void *buf, size_t len);
  72 +struct tipc_subscription *tipc_subscrp_subscribe(struct net *net,
  73 + struct tipc_subscr *s,
  74 + int conid, bool swap,
  75 + bool status);
  76 +void tipc_sub_delete(struct tipc_subscription *sub);
74 77 int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
75 78 u32 found_upper);
76 79 void tipc_subscrp_report_overlap(struct tipc_subscription *sub,