diff options
Diffstat (limited to 'net/tipc/subscr.c')
-rw-r--r-- | net/tipc/subscr.c | 124 |
1 files changed, 70 insertions, 54 deletions
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 0dd02244e21d..9d94e65d0894 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c | |||
@@ -54,6 +54,8 @@ struct tipc_subscriber { | |||
54 | 54 | ||
55 | static void tipc_subscrp_delete(struct tipc_subscription *sub); | 55 | static void tipc_subscrp_delete(struct tipc_subscription *sub); |
56 | static void tipc_subscrb_put(struct tipc_subscriber *subscriber); | 56 | static void tipc_subscrb_put(struct tipc_subscriber *subscriber); |
57 | static void tipc_subscrp_put(struct tipc_subscription *subscription); | ||
58 | static void tipc_subscrp_get(struct tipc_subscription *subscription); | ||
57 | 59 | ||
58 | /** | 60 | /** |
59 | * htohl - convert value to endianness used by destination | 61 | * htohl - convert value to endianness used by destination |
@@ -123,6 +125,7 @@ void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower, | |||
123 | { | 125 | { |
124 | struct tipc_name_seq seq; | 126 | struct tipc_name_seq seq; |
125 | 127 | ||
128 | tipc_subscrp_get(sub); | ||
126 | tipc_subscrp_convert_seq(&sub->evt.s.seq, sub->swap, &seq); | 129 | tipc_subscrp_convert_seq(&sub->evt.s.seq, sub->swap, &seq); |
127 | if (!tipc_subscrp_check_overlap(&seq, found_lower, found_upper)) | 130 | if (!tipc_subscrp_check_overlap(&seq, found_lower, found_upper)) |
128 | return; | 131 | return; |
@@ -132,30 +135,23 @@ void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower, | |||
132 | 135 | ||
133 | tipc_subscrp_send_event(sub, found_lower, found_upper, event, port_ref, | 136 | tipc_subscrp_send_event(sub, found_lower, found_upper, event, port_ref, |
134 | node); | 137 | node); |
138 | tipc_subscrp_put(sub); | ||
135 | } | 139 | } |
136 | 140 | ||
137 | static void tipc_subscrp_timeout(unsigned long data) | 141 | static void tipc_subscrp_timeout(unsigned long data) |
138 | { | 142 | { |
139 | struct tipc_subscription *sub = (struct tipc_subscription *)data; | 143 | struct tipc_subscription *sub = (struct tipc_subscription *)data; |
140 | struct tipc_subscriber *subscriber = sub->subscriber; | ||
141 | 144 | ||
142 | /* Notify subscriber of timeout */ | 145 | /* Notify subscriber of timeout */ |
143 | tipc_subscrp_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper, | 146 | tipc_subscrp_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper, |
144 | TIPC_SUBSCR_TIMEOUT, 0, 0); | 147 | TIPC_SUBSCR_TIMEOUT, 0, 0); |
145 | 148 | ||
146 | spin_lock_bh(&subscriber->lock); | 149 | tipc_subscrp_put(sub); |
147 | tipc_subscrp_delete(sub); | ||
148 | spin_unlock_bh(&subscriber->lock); | ||
149 | |||
150 | tipc_subscrb_put(subscriber); | ||
151 | } | 150 | } |
152 | 151 | ||
153 | static void tipc_subscrb_kref_release(struct kref *kref) | 152 | static void tipc_subscrb_kref_release(struct kref *kref) |
154 | { | 153 | { |
155 | struct tipc_subscriber *subcriber = container_of(kref, | 154 | kfree(container_of(kref,struct tipc_subscriber, kref)); |
156 | struct tipc_subscriber, kref); | ||
157 | |||
158 | kfree(subcriber); | ||
159 | } | 155 | } |
160 | 156 | ||
161 | static void tipc_subscrb_put(struct tipc_subscriber *subscriber) | 157 | static void tipc_subscrb_put(struct tipc_subscriber *subscriber) |
@@ -168,6 +164,59 @@ static void tipc_subscrb_get(struct tipc_subscriber *subscriber) | |||
168 | kref_get(&subscriber->kref); | 164 | kref_get(&subscriber->kref); |
169 | } | 165 | } |
170 | 166 | ||
167 | static void tipc_subscrp_kref_release(struct kref *kref) | ||
168 | { | ||
169 | struct tipc_subscription *sub = container_of(kref, | ||
170 | struct tipc_subscription, | ||
171 | kref); | ||
172 | struct tipc_net *tn = net_generic(sub->net, tipc_net_id); | ||
173 | struct tipc_subscriber *subscriber = sub->subscriber; | ||
174 | |||
175 | spin_lock_bh(&subscriber->lock); | ||
176 | tipc_nametbl_unsubscribe(sub); | ||
177 | list_del(&sub->subscrp_list); | ||
178 | atomic_dec(&tn->subscription_count); | ||
179 | spin_unlock_bh(&subscriber->lock); | ||
180 | kfree(sub); | ||
181 | tipc_subscrb_put(subscriber); | ||
182 | } | ||
183 | |||
184 | static void tipc_subscrp_put(struct tipc_subscription *subscription) | ||
185 | { | ||
186 | kref_put(&subscription->kref, tipc_subscrp_kref_release); | ||
187 | } | ||
188 | |||
189 | static void tipc_subscrp_get(struct tipc_subscription *subscription) | ||
190 | { | ||
191 | kref_get(&subscription->kref); | ||
192 | } | ||
193 | |||
194 | /* tipc_subscrb_subscrp_delete - delete a specific subscription or all | ||
195 | * subscriptions for a given subscriber. | ||
196 | */ | ||
197 | static void tipc_subscrb_subscrp_delete(struct tipc_subscriber *subscriber, | ||
198 | struct tipc_subscr *s) | ||
199 | { | ||
200 | struct list_head *subscription_list = &subscriber->subscrp_list; | ||
201 | struct tipc_subscription *sub, *temp; | ||
202 | |||
203 | spin_lock_bh(&subscriber->lock); | ||
204 | list_for_each_entry_safe(sub, temp, subscription_list, subscrp_list) { | ||
205 | if (s && memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) | ||
206 | continue; | ||
207 | |||
208 | tipc_subscrp_get(sub); | ||
209 | spin_unlock_bh(&subscriber->lock); | ||
210 | tipc_subscrp_delete(sub); | ||
211 | tipc_subscrp_put(sub); | ||
212 | spin_lock_bh(&subscriber->lock); | ||
213 | |||
214 | if (s) | ||
215 | break; | ||
216 | } | ||
217 | spin_unlock_bh(&subscriber->lock); | ||
218 | } | ||
219 | |||
171 | static struct tipc_subscriber *tipc_subscrb_create(int conid) | 220 | static struct tipc_subscriber *tipc_subscrb_create(int conid) |
172 | { | 221 | { |
173 | struct tipc_subscriber *subscriber; | 222 | struct tipc_subscriber *subscriber; |
@@ -177,8 +226,8 @@ static struct tipc_subscriber *tipc_subscrb_create(int conid) | |||
177 | pr_warn("Subscriber rejected, no memory\n"); | 226 | pr_warn("Subscriber rejected, no memory\n"); |
178 | return NULL; | 227 | return NULL; |
179 | } | 228 | } |
180 | kref_init(&subscriber->kref); | ||
181 | INIT_LIST_HEAD(&subscriber->subscrp_list); | 229 | INIT_LIST_HEAD(&subscriber->subscrp_list); |
230 | kref_init(&subscriber->kref); | ||
182 | subscriber->conid = conid; | 231 | subscriber->conid = conid; |
183 | spin_lock_init(&subscriber->lock); | 232 | spin_lock_init(&subscriber->lock); |
184 | 233 | ||
@@ -187,55 +236,22 @@ static struct tipc_subscriber *tipc_subscrb_create(int conid) | |||
187 | 236 | ||
188 | static void tipc_subscrb_delete(struct tipc_subscriber *subscriber) | 237 | static void tipc_subscrb_delete(struct tipc_subscriber *subscriber) |
189 | { | 238 | { |
190 | struct tipc_subscription *sub, *temp; | 239 | tipc_subscrb_subscrp_delete(subscriber, NULL); |
191 | u32 timeout; | ||
192 | |||
193 | spin_lock_bh(&subscriber->lock); | ||
194 | /* Destroy any existing subscriptions for subscriber */ | ||
195 | list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list, | ||
196 | subscrp_list) { | ||
197 | timeout = htohl(sub->evt.s.timeout, sub->swap); | ||
198 | if ((timeout == TIPC_WAIT_FOREVER) || del_timer(&sub->timer)) { | ||
199 | tipc_subscrp_delete(sub); | ||
200 | tipc_subscrb_put(subscriber); | ||
201 | } | ||
202 | } | ||
203 | spin_unlock_bh(&subscriber->lock); | ||
204 | |||
205 | tipc_subscrb_put(subscriber); | 240 | tipc_subscrb_put(subscriber); |
206 | } | 241 | } |
207 | 242 | ||
208 | static void tipc_subscrp_delete(struct tipc_subscription *sub) | 243 | static void tipc_subscrp_delete(struct tipc_subscription *sub) |
209 | { | 244 | { |
210 | struct tipc_net *tn = net_generic(sub->net, tipc_net_id); | 245 | u32 timeout = htohl(sub->evt.s.timeout, sub->swap); |
211 | 246 | ||
212 | tipc_nametbl_unsubscribe(sub); | 247 | if (timeout == TIPC_WAIT_FOREVER || del_timer(&sub->timer)) |
213 | list_del(&sub->subscrp_list); | 248 | tipc_subscrp_put(sub); |
214 | kfree(sub); | ||
215 | atomic_dec(&tn->subscription_count); | ||
216 | } | 249 | } |
217 | 250 | ||
218 | static void tipc_subscrp_cancel(struct tipc_subscr *s, | 251 | static void tipc_subscrp_cancel(struct tipc_subscr *s, |
219 | struct tipc_subscriber *subscriber) | 252 | struct tipc_subscriber *subscriber) |
220 | { | 253 | { |
221 | struct tipc_subscription *sub, *temp; | 254 | tipc_subscrb_subscrp_delete(subscriber, s); |
222 | u32 timeout; | ||
223 | |||
224 | spin_lock_bh(&subscriber->lock); | ||
225 | /* Find first matching subscription, exit if not found */ | ||
226 | list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list, | ||
227 | subscrp_list) { | ||
228 | if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) { | ||
229 | timeout = htohl(sub->evt.s.timeout, sub->swap); | ||
230 | if ((timeout == TIPC_WAIT_FOREVER) || | ||
231 | del_timer(&sub->timer)) { | ||
232 | tipc_subscrp_delete(sub); | ||
233 | tipc_subscrb_put(subscriber); | ||
234 | } | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | spin_unlock_bh(&subscriber->lock); | ||
239 | } | 255 | } |
240 | 256 | ||
241 | static struct tipc_subscription *tipc_subscrp_create(struct net *net, | 257 | static struct tipc_subscription *tipc_subscrp_create(struct net *net, |
@@ -272,6 +288,7 @@ static struct tipc_subscription *tipc_subscrp_create(struct net *net, | |||
272 | sub->swap = swap; | 288 | sub->swap = swap; |
273 | memcpy(&sub->evt.s, s, sizeof(*s)); | 289 | memcpy(&sub->evt.s, s, sizeof(*s)); |
274 | atomic_inc(&tn->subscription_count); | 290 | atomic_inc(&tn->subscription_count); |
291 | kref_init(&sub->kref); | ||
275 | return sub; | 292 | return sub; |
276 | } | 293 | } |
277 | 294 | ||
@@ -288,17 +305,16 @@ static void tipc_subscrp_subscribe(struct net *net, struct tipc_subscr *s, | |||
288 | 305 | ||
289 | spin_lock_bh(&subscriber->lock); | 306 | spin_lock_bh(&subscriber->lock); |
290 | list_add(&sub->subscrp_list, &subscriber->subscrp_list); | 307 | list_add(&sub->subscrp_list, &subscriber->subscrp_list); |
291 | tipc_subscrb_get(subscriber); | ||
292 | sub->subscriber = subscriber; | 308 | sub->subscriber = subscriber; |
293 | tipc_nametbl_subscribe(sub); | 309 | tipc_nametbl_subscribe(sub); |
310 | tipc_subscrb_get(subscriber); | ||
294 | spin_unlock_bh(&subscriber->lock); | 311 | spin_unlock_bh(&subscriber->lock); |
295 | 312 | ||
313 | setup_timer(&sub->timer, tipc_subscrp_timeout, (unsigned long)sub); | ||
296 | timeout = htohl(sub->evt.s.timeout, swap); | 314 | timeout = htohl(sub->evt.s.timeout, swap); |
297 | if (timeout == TIPC_WAIT_FOREVER) | ||
298 | return; | ||
299 | 315 | ||
300 | setup_timer(&sub->timer, tipc_subscrp_timeout, (unsigned long)sub); | 316 | if (timeout != TIPC_WAIT_FOREVER) |
301 | mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout)); | 317 | mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout)); |
302 | } | 318 | } |
303 | 319 | ||
304 | /* Handle one termination request for the subscriber */ | 320 | /* Handle one termination request for the subscriber */ |