diff options
author | Ying Xue <ying.xue@windriver.com> | 2014-01-07 17:02:43 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-07 18:44:25 -0500 |
commit | f9a2c80b8b7366748a1c3975df07f4a34aa80538 (patch) | |
tree | 9c3c627d0feeedd82eb8cad56e90657a3fe0f3a0 /net/tipc/discover.c | |
parent | b9d4c33935bb5673fa9f721ecf85e5029c847f08 (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.c | 11 |
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 | */ |
275 | void tipc_disc_add_dest(struct tipc_link_req *req) | 277 | void 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 | */ |
284 | void tipc_disc_remove_dest(struct tipc_link_req *req) | 288 | void 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); |
327 | exit: | 333 | exit: |
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; |