Commit eb409460b1abec0e2a1f9c9d07019f4157a6d6bc
Committed by
David S. Miller
1 parent
fc144deec6
Exists in
master
and in
20 other branches
[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 */ |
net/tipc/subscr.c
... | ... | @@ -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); |