aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAntonio Quartulli <antonio@open-mesh.com>2013-07-30 16:16:24 -0400
committerAntonio Quartulli <antonio@meshcoding.com>2013-10-19 11:31:56 -0400
commita70a9aa990bdf24039cb4167993bcc5a0f9cbb18 (patch)
tree0e2cbae6d327c6a2a0904f0ba95dcbde914a3d47 /net
parente75de4fa41d810113cf81f658a56e3972c7c12b4 (diff)
batman-adv: lock around TT operations to avoid sending inconsistent data
A TT response may be prepared and sent while the local or global translation table is getting updated. The worst case is when one of the tables is accessed after its content has been recently updated but the metadata (TTVN/CRC) has not yet. In this case the reader will get a table content which does not match the TTVN/CRC. This will lead to an inconsistent state and so to a TT recovery. To avoid entering this situation, put a lock around those TT operations recomputing the metadata and around the TT Response creation (the latter is the only reader that accesses the metadata together with the table). Signed-off-by: Antonio Quartulli <antonio@open-mesh.com> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Diffstat (limited to 'net')
-rw-r--r--net/batman-adv/main.c1
-rw-r--r--net/batman-adv/originator.c1
-rw-r--r--net/batman-adv/translation-table.c23
-rw-r--r--net/batman-adv/types.h13
4 files changed, 34 insertions, 4 deletions
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 22075511c448..3159a148c1ac 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -110,6 +110,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
110 spin_lock_init(&bat_priv->tt.req_list_lock); 110 spin_lock_init(&bat_priv->tt.req_list_lock);
111 spin_lock_init(&bat_priv->tt.roam_list_lock); 111 spin_lock_init(&bat_priv->tt.roam_list_lock);
112 spin_lock_init(&bat_priv->tt.last_changeset_lock); 112 spin_lock_init(&bat_priv->tt.last_changeset_lock);
113 spin_lock_init(&bat_priv->tt.commit_lock);
113 spin_lock_init(&bat_priv->gw.list_lock); 114 spin_lock_init(&bat_priv->gw.list_lock);
114 spin_lock_init(&bat_priv->tvlv.container_list_lock); 115 spin_lock_init(&bat_priv->tvlv.container_list_lock);
115 spin_lock_init(&bat_priv->tvlv.handler_list_lock); 116 spin_lock_init(&bat_priv->tvlv.handler_list_lock);
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index a591dc5c321e..867778e8184d 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -239,6 +239,7 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
239 spin_lock_init(&orig_node->bcast_seqno_lock); 239 spin_lock_init(&orig_node->bcast_seqno_lock);
240 spin_lock_init(&orig_node->neigh_list_lock); 240 spin_lock_init(&orig_node->neigh_list_lock);
241 spin_lock_init(&orig_node->tt_buff_lock); 241 spin_lock_init(&orig_node->tt_buff_lock);
242 spin_lock_init(&orig_node->tt_lock);
242 243
243 batadv_nc_init_orig(orig_node); 244 batadv_nc_init_orig(orig_node);
244 245
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 58794c4cea91..00f4faa69c07 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -2019,6 +2019,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
2019 req_src, tt_data->ttvn, 2019 req_src, tt_data->ttvn,
2020 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); 2020 (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
2021 2021
2022 spin_lock_bh(&bat_priv->tt.commit_lock);
2022 2023
2023 my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); 2024 my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
2024 req_ttvn = tt_data->ttvn; 2025 req_ttvn = tt_data->ttvn;
@@ -2091,6 +2092,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
2091unlock: 2092unlock:
2092 spin_unlock_bh(&bat_priv->tt.last_changeset_lock); 2093 spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
2093out: 2094out:
2095 spin_unlock_bh(&bat_priv->tt.commit_lock);
2094 if (orig_node) 2096 if (orig_node)
2095 batadv_orig_node_free_ref(orig_node); 2097 batadv_orig_node_free_ref(orig_node);
2096 if (primary_if) 2098 if (primary_if)
@@ -2259,6 +2261,8 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
2259 if (!orig_node) 2261 if (!orig_node)
2260 goto out; 2262 goto out;
2261 2263
2264 spin_lock_bh(&orig_node->tt_lock);
2265
2262 if (tt_data->flags & BATADV_TT_FULL_TABLE) { 2266 if (tt_data->flags & BATADV_TT_FULL_TABLE) {
2263 batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries); 2267 batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries);
2264 } else { 2268 } else {
@@ -2267,6 +2271,11 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
2267 tt_data->ttvn, tt_change); 2271 tt_data->ttvn, tt_change);
2268 } 2272 }
2269 2273
2274 /* Recalculate the CRC for this orig_node and store it */
2275 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
2276
2277 spin_unlock_bh(&orig_node->tt_lock);
2278
2270 /* Delete the tt_req_node from pending tt_requests list */ 2279 /* Delete the tt_req_node from pending tt_requests list */
2271 spin_lock_bh(&bat_priv->tt.req_list_lock); 2280 spin_lock_bh(&bat_priv->tt.req_list_lock);
2272 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { 2281 list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
@@ -2276,9 +2285,6 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
2276 kfree(node); 2285 kfree(node);
2277 } 2286 }
2278 spin_unlock_bh(&bat_priv->tt.req_list_lock); 2287 spin_unlock_bh(&bat_priv->tt.req_list_lock);
2279
2280 /* Recalculate the CRC for this orig_node and store it */
2281 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
2282out: 2288out:
2283 if (orig_node) 2289 if (orig_node)
2284 batadv_orig_node_free_ref(orig_node); 2290 batadv_orig_node_free_ref(orig_node);
@@ -2532,10 +2538,12 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
2532{ 2538{
2533 uint16_t changed_num = 0; 2539 uint16_t changed_num = 0;
2534 2540
2541 spin_lock_bh(&bat_priv->tt.commit_lock);
2542
2535 if (atomic_read(&bat_priv->tt.local_changes) < 1) { 2543 if (atomic_read(&bat_priv->tt.local_changes) < 1) {
2536 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) 2544 if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
2537 batadv_tt_tvlv_container_update(bat_priv); 2545 batadv_tt_tvlv_container_update(bat_priv);
2538 return; 2546 goto out;
2539 } 2547 }
2540 2548
2541 changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash, 2549 changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash,
@@ -2555,6 +2563,9 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
2555 /* reset the sending counter */ 2563 /* reset the sending counter */
2556 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); 2564 atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
2557 batadv_tt_tvlv_container_update(bat_priv); 2565 batadv_tt_tvlv_container_update(bat_priv);
2566
2567out:
2568 spin_unlock_bh(&bat_priv->tt.commit_lock);
2558} 2569}
2559 2570
2560bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, 2571bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
@@ -2631,6 +2642,8 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
2631 goto request_table; 2642 goto request_table;
2632 } 2643 }
2633 2644
2645 spin_lock_bh(&orig_node->tt_lock);
2646
2634 tt_change = (struct batadv_tvlv_tt_change *)tt_buff; 2647 tt_change = (struct batadv_tvlv_tt_change *)tt_buff;
2635 batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, 2648 batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
2636 ttvn, tt_change); 2649 ttvn, tt_change);
@@ -2641,6 +2654,8 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
2641 */ 2654 */
2642 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); 2655 orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
2643 2656
2657 spin_unlock_bh(&orig_node->tt_lock);
2658
2644 /* The ttvn alone is not enough to guarantee consistency 2659 /* The ttvn alone is not enough to guarantee consistency
2645 * because a single value could represent different states 2660 * because a single value could represent different states
2646 * (due to the wrap around). Thus a node has to check whether 2661 * (due to the wrap around). Thus a node has to check whether
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 04a0da6011b7..bd95d612260c 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -128,6 +128,10 @@ struct batadv_frag_list_entry {
128 * @tt_size: number of global TT entries announced by the orig node 128 * @tt_size: number of global TT entries announced by the orig node
129 * @tt_initialised: bool keeping track of whether or not this node have received 129 * @tt_initialised: bool keeping track of whether or not this node have received
130 * any translation table information from the orig node yet 130 * any translation table information from the orig node yet
131 * @tt_lock: prevents from updating the table while reading it. Table update is
132 * made up by two operations (data structure update and metdata -CRC/TTVN-
133 * recalculation) and they have to be executed atomically in order to avoid
134 * another thread to read the table/metadata between those.
131 * @last_real_seqno: last and best known sequence number 135 * @last_real_seqno: last and best known sequence number
132 * @last_ttl: ttl of last received packet 136 * @last_ttl: ttl of last received packet
133 * @bcast_bits: bitfield containing the info which payload broadcast originated 137 * @bcast_bits: bitfield containing the info which payload broadcast originated
@@ -171,6 +175,8 @@ struct batadv_orig_node {
171 spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ 175 spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */
172 atomic_t tt_size; 176 atomic_t tt_size;
173 bool tt_initialised; 177 bool tt_initialised;
178 /* prevents from changing the table while reading it */
179 spinlock_t tt_lock;
174 uint32_t last_real_seqno; 180 uint32_t last_real_seqno;
175 uint8_t last_ttl; 181 uint8_t last_ttl;
176 DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); 182 DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
@@ -388,6 +394,11 @@ enum batadv_counters {
388 * @last_changeset: last tt changeset this host has generated 394 * @last_changeset: last tt changeset this host has generated
389 * @last_changeset_len: length of last tt changeset this host has generated 395 * @last_changeset_len: length of last tt changeset this host has generated
390 * @last_changeset_lock: lock protecting last_changeset & last_changeset_len 396 * @last_changeset_lock: lock protecting last_changeset & last_changeset_len
397 * @commit_lock: prevents from executing a local TT commit while reading the
398 * local table. The local TT commit is made up by two operations (data
399 * structure update and metdata -CRC/TTVN- recalculation) and they have to be
400 * executed atomically in order to avoid another thread to read the
401 * table/metadata between those.
391 * @work: work queue callback item for translation table purging 402 * @work: work queue callback item for translation table purging
392 */ 403 */
393struct batadv_priv_tt { 404struct batadv_priv_tt {
@@ -408,6 +419,8 @@ struct batadv_priv_tt {
408 int16_t last_changeset_len; 419 int16_t last_changeset_len;
409 /* protects last_changeset & last_changeset_len */ 420 /* protects last_changeset & last_changeset_len */
410 spinlock_t last_changeset_lock; 421 spinlock_t last_changeset_lock;
422 /* prevents from executing a commit while reading the table */
423 spinlock_t commit_lock;
411 struct delayed_work work; 424 struct delayed_work work;
412}; 425};
413 426