Commit eb409460b1abec0e2a1f9c9d07019f4157a6d6bc

Authored by Lijun Chen
Committed by David S. Miller
1 parent fc144deec6

[TIPC]: Added subscription cancellation capability

This patch allows a TIPC application to cancel an existing
topology service subscription by re-requesting the subscription
with the TIPC_SUB_CANCEL filter bit set.  (All other bits of
the cancel request must match the original subscription request.)

Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Per Liden <per.liden@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 85 additions and 15 deletions Side-by-side Diff

include/linux/tipc.h
... ... @@ -129,6 +129,7 @@
129 129  
130 130 #define TIPC_SUB_PORTS 0x01 /* filter for port availability */
131 131 #define TIPC_SUB_SERVICE 0x02 /* filter for service availability */
  132 +#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */
132 133 #if 0
133 134 /* The following filter options are not currently implemented */
134 135 #define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */
... ... @@ -155,7 +155,7 @@
155 155 sub->seq.upper, found_lower, found_upper);
156 156 if (!tipc_subscr_overlap(sub, found_lower, found_upper))
157 157 return;
158   - if (!must && (sub->filter != TIPC_SUB_PORTS))
  158 + if (!must && !(sub->filter & TIPC_SUB_PORTS))
159 159 return;
160 160 subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
161 161 }
... ... @@ -176,6 +176,13 @@
176 176 if (subscriber == NULL)
177 177 return;
178 178  
  179 + /* Validate timeout (in case subscription is being cancelled) */
  180 +
  181 + if (sub->timeout == TIPC_WAIT_FOREVER) {
  182 + tipc_ref_unlock(subscriber_ref);
  183 + return;
  184 + }
  185 +
179 186 /* Unlink subscription from name table */
180 187  
181 188 tipc_nametbl_unsubscribe(sub);
... ... @@ -199,6 +206,20 @@
199 206 }
200 207  
201 208 /**
  209 + * subscr_del - delete a subscription within a subscription list
  210 + *
  211 + * Called with subscriber locked.
  212 + */
  213 +
  214 +static void subscr_del(struct subscription *sub)
  215 +{
  216 + tipc_nametbl_unsubscribe(sub);
  217 + list_del(&sub->subscription_list);
  218 + kfree(sub);
  219 + atomic_dec(&topsrv.subscription_count);
  220 +}
  221 +
  222 +/**
202 223 * subscr_terminate - terminate communication with a subscriber
203 224 *
204 225 * Called with subscriber locked. Routine must temporarily release this lock
205 226  
... ... @@ -227,12 +248,9 @@
227 248 k_cancel_timer(&sub->timer);
228 249 k_term_timer(&sub->timer);
229 250 }
230   - tipc_nametbl_unsubscribe(sub);
231   - list_del(&sub->subscription_list);
232   - dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
  251 + dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n",
233 252 sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
234   - kfree(sub);
235   - atomic_dec(&topsrv.subscription_count);
  253 + subscr_del(sub);
236 254 }
237 255  
238 256 /* Sever connection to subscriber */
... ... @@ -253,6 +271,49 @@
253 271 }
254 272  
255 273 /**
  274 + * subscr_cancel - handle subscription cancellation request
  275 + *
  276 + * Called with subscriber locked. Routine must temporarily release this lock
  277 + * to enable the subscription timeout routine to finish without deadlocking;
  278 + * the lock is then reclaimed to allow caller to release it upon return.
  279 + *
  280 + * Note that fields of 's' use subscriber's endianness!
  281 + */
  282 +
  283 +static void subscr_cancel(struct tipc_subscr *s,
  284 + struct subscriber *subscriber)
  285 +{
  286 + struct subscription *sub;
  287 + struct subscription *sub_temp;
  288 + int found = 0;
  289 +
  290 + /* Find first matching subscription, exit if not found */
  291 +
  292 + list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
  293 + subscription_list) {
  294 + if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
  295 + found = 1;
  296 + break;
  297 + }
  298 + }
  299 + if (!found)
  300 + return;
  301 +
  302 + /* Cancel subscription timer (if used), then delete subscription */
  303 +
  304 + if (sub->timeout != TIPC_WAIT_FOREVER) {
  305 + sub->timeout = TIPC_WAIT_FOREVER;
  306 + spin_unlock_bh(subscriber->lock);
  307 + k_cancel_timer(&sub->timer);
  308 + k_term_timer(&sub->timer);
  309 + spin_lock_bh(subscriber->lock);
  310 + }
  311 + dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
  312 + sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
  313 + subscr_del(sub);
  314 +}
  315 +
  316 +/**
256 317 * subscr_subscribe - create subscription for subscriber
257 318 *
258 319 * Called with subscriber locked
... ... @@ -263,6 +324,21 @@
263 324 {
264 325 struct subscription *sub;
265 326  
  327 + /* Determine/update subscriber's endianness */
  328 +
  329 + if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
  330 + subscriber->swap = 0;
  331 + else
  332 + subscriber->swap = 1;
  333 +
  334 + /* Detect & process a subscription cancellation request */
  335 +
  336 + if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
  337 + s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
  338 + subscr_cancel(s, subscriber);
  339 + return;
  340 + }
  341 +
266 342 /* Refuse subscription if global limit exceeded */
267 343  
268 344 if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
... ... @@ -281,13 +357,6 @@
281 357 return;
282 358 }
283 359  
284   - /* Determine/update subscriber's endianness */
285   -
286   - if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
287   - subscriber->swap = 0;
288   - else
289   - subscriber->swap = 1;
290   -
291 360 /* Initialize subscription object */
292 361  
293 362 memset(sub, 0, sizeof(*sub));
... ... @@ -296,8 +365,8 @@
296 365 sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
297 366 sub->timeout = htohl(s->timeout, subscriber->swap);
298 367 sub->filter = htohl(s->filter, subscriber->swap);
299   - if ((((sub->filter != TIPC_SUB_PORTS)
300   - && (sub->filter != TIPC_SUB_SERVICE)))
  368 + if ((!(sub->filter & TIPC_SUB_PORTS)
  369 + == !(sub->filter & TIPC_SUB_SERVICE))
301 370 || (sub->seq.lower > sub->seq.upper)) {
302 371 warn("Subscription rejected, illegal request\n");
303 372 kfree(sub);