aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/discover.c
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2014-01-07 17:02:43 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-07 18:44:25 -0500
commitf9a2c80b8b7366748a1c3975df07f4a34aa80538 (patch)
tree9c3c627d0feeedd82eb8cad56e90657a3fe0f3a0 /net/tipc/discover.c
parentb9d4c33935bb5673fa9f721ecf85e5029c847f08 (diff)
tipc: introduce new spinlock to protect struct link_req
Currently, only 'bearer_lock' is used to protect struct link_req in the function disc_timeout(). This is unsafe, since the member fields 'num_nodes' and 'timer_intv' might be accessed by below three different threads simultaneously, none of them grabbing bearer_lock in the critical region: link_activate() tipc_bearer_add_dest() tipc_disc_add_dest() req->num_nodes++; tipc_link_reset() tipc_bearer_remove_dest() tipc_disc_remove_dest() req->num_nodes-- disc_update() read req->num_nodes write req->timer_intv disc_timeout() read req->num_nodes read/write req->timer_intv Without lock protection, the only symptom of a race is that discovery messages occasionally may not be sent out. This is not fatal, since such messages are best-effort anyway. On the other hand, since discovery messages are not time critical, adding a protecting lock brings no serious overhead either. So we add a new, dedicated spinlock in order to guarantee absolute data consistency in link_req objects. This also helps reduce the overall role of the bearer_lock, which we want to remove completely in a later commit series. Signed-off-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Paul Gortmaker <paul.gortmaker@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/discover.c')
-rw-r--r--net/tipc/discover.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index bc849f1efa16..412ff41b8611 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -50,6 +50,7 @@
50 * @dest: destination address for request messages 50 * @dest: destination address for request messages
51 * @domain: network domain to which links can be established 51 * @domain: network domain to which links can be established
52 * @num_nodes: number of nodes currently discovered (i.e. with an active link) 52 * @num_nodes: number of nodes currently discovered (i.e. with an active link)
53 * @lock: spinlock for controlling access to requests
53 * @buf: request message to be (repeatedly) sent 54 * @buf: request message to be (repeatedly) sent
54 * @timer: timer governing period between requests 55 * @timer: timer governing period between requests
55 * @timer_intv: current interval between requests (in ms) 56 * @timer_intv: current interval between requests (in ms)
@@ -59,6 +60,7 @@ struct tipc_link_req {
59 struct tipc_media_addr dest; 60 struct tipc_media_addr dest;
60 u32 domain; 61 u32 domain;
61 int num_nodes; 62 int num_nodes;
63 spinlock_t lock;
62 struct sk_buff *buf; 64 struct sk_buff *buf;
63 struct timer_list timer; 65 struct timer_list timer;
64 unsigned int timer_intv; 66 unsigned int timer_intv;
@@ -274,7 +276,9 @@ static void disc_update(struct tipc_link_req *req)
274 */ 276 */
275void tipc_disc_add_dest(struct tipc_link_req *req) 277void tipc_disc_add_dest(struct tipc_link_req *req)
276{ 278{
279 spin_lock_bh(&req->lock);
277 req->num_nodes++; 280 req->num_nodes++;
281 spin_unlock_bh(&req->lock);
278} 282}
279 283
280/** 284/**
@@ -283,8 +287,10 @@ void tipc_disc_add_dest(struct tipc_link_req *req)
283 */ 287 */
284void tipc_disc_remove_dest(struct tipc_link_req *req) 288void tipc_disc_remove_dest(struct tipc_link_req *req)
285{ 289{
290 spin_lock_bh(&req->lock);
286 req->num_nodes--; 291 req->num_nodes--;
287 disc_update(req); 292 disc_update(req);
293 spin_unlock_bh(&req->lock);
288} 294}
289 295
290/** 296/**
@@ -297,7 +303,7 @@ static void disc_timeout(struct tipc_link_req *req)
297{ 303{
298 int max_delay; 304 int max_delay;
299 305
300 spin_lock_bh(&req->bearer->lock); 306 spin_lock_bh(&req->lock);
301 307
302 /* Stop searching if only desired node has been found */ 308 /* Stop searching if only desired node has been found */
303 if (tipc_node(req->domain) && req->num_nodes) { 309 if (tipc_node(req->domain) && req->num_nodes) {
@@ -325,7 +331,7 @@ static void disc_timeout(struct tipc_link_req *req)
325 331
326 k_start_timer(&req->timer, req->timer_intv); 332 k_start_timer(&req->timer, req->timer_intv);
327exit: 333exit:
328 spin_unlock_bh(&req->bearer->lock); 334 spin_unlock_bh(&req->lock);
329} 335}
330 336
331/** 337/**
@@ -356,6 +362,7 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest,
356 req->domain = dest_domain; 362 req->domain = dest_domain;
357 req->num_nodes = 0; 363 req->num_nodes = 0;
358 req->timer_intv = TIPC_LINK_REQ_INIT; 364 req->timer_intv = TIPC_LINK_REQ_INIT;
365 spin_lock_init(&req->lock);
359 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req); 366 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
360 k_start_timer(&req->timer, req->timer_intv); 367 k_start_timer(&req->timer, req->timer_intv);
361 b_ptr->link_req = req; 368 b_ptr->link_req = req;