|
12 | 12 | #include <linux/byteorder/generic.h> |
13 | 13 | #include <linux/cache.h> |
14 | 14 | #include <linux/compiler.h> |
| 15 | +#include <linux/completion.h> |
15 | 16 | #include <linux/container_of.h> |
16 | 17 | #include <linux/err.h> |
17 | 18 | #include <linux/etherdevice.h> |
@@ -365,23 +366,38 @@ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars) |
365 | 366 | } |
366 | 367 |
|
367 | 368 | /** |
368 | | - * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer |
369 | | - * @bat_priv: the bat priv with all the soft interface information |
370 | | - * @tp_vars: the private data of the current TP meter session to cleanup |
| 369 | + * batadv_tp_list_detach() - remove tp session from mesh session list once |
| 370 | + * @tp_vars: the private data of the current TP meter session |
371 | 371 | */ |
372 | | -static void batadv_tp_sender_cleanup(struct batadv_priv *bat_priv, |
373 | | - struct batadv_tp_vars *tp_vars) |
| 372 | +static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars) |
374 | 373 | { |
375 | | - cancel_delayed_work(&tp_vars->finish_work); |
| 374 | + bool detached = false; |
376 | 375 |
|
377 | 376 | spin_lock_bh(&tp_vars->bat_priv->tp_list_lock); |
378 | | - hlist_del_rcu(&tp_vars->list); |
| 377 | + if (!hlist_unhashed(&tp_vars->list)) { |
| 378 | + hlist_del_init_rcu(&tp_vars->list); |
| 379 | + detached = true; |
| 380 | + } |
379 | 381 | spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock); |
380 | 382 |
|
| 383 | + if (!detached) |
| 384 | + return; |
| 385 | + |
| 386 | + atomic_dec(&tp_vars->bat_priv->tp_num); |
| 387 | + |
381 | 388 | /* drop list reference */ |
382 | 389 | batadv_tp_vars_put(tp_vars); |
| 390 | +} |
383 | 391 |
|
384 | | - atomic_dec(&tp_vars->bat_priv->tp_num); |
| 392 | +/** |
| 393 | + * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer |
| 394 | + * @tp_vars: the private data of the current TP meter session to cleanup |
| 395 | + */ |
| 396 | +static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars) |
| 397 | +{ |
| 398 | + cancel_delayed_work_sync(&tp_vars->finish_work); |
| 399 | + |
| 400 | + batadv_tp_list_detach(tp_vars); |
385 | 401 |
|
386 | 402 | /* kill the timer and remove its reference */ |
387 | 403 | del_timer_sync(&tp_vars->timer); |
@@ -886,7 +902,8 @@ static int batadv_tp_send(void *arg) |
886 | 902 | batadv_orig_node_put(orig_node); |
887 | 903 |
|
888 | 904 | batadv_tp_sender_end(bat_priv, tp_vars); |
889 | | - batadv_tp_sender_cleanup(bat_priv, tp_vars); |
| 905 | + batadv_tp_sender_cleanup(tp_vars); |
| 906 | + complete(&tp_vars->finished); |
890 | 907 |
|
891 | 908 | batadv_tp_vars_put(tp_vars); |
892 | 909 |
|
@@ -918,7 +935,8 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars) |
918 | 935 | batadv_tp_vars_put(tp_vars); |
919 | 936 |
|
920 | 937 | /* cleanup of failed tp meter variables */ |
921 | | - batadv_tp_sender_cleanup(bat_priv, tp_vars); |
| 938 | + batadv_tp_sender_cleanup(tp_vars); |
| 939 | + complete(&tp_vars->finished); |
922 | 940 | return; |
923 | 941 | } |
924 | 942 |
|
@@ -1024,6 +1042,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, |
1024 | 1042 | tp_vars->start_time = jiffies; |
1025 | 1043 |
|
1026 | 1044 | init_waitqueue_head(&tp_vars->more_bytes); |
| 1045 | + init_completion(&tp_vars->finished); |
1027 | 1046 |
|
1028 | 1047 | spin_lock_init(&tp_vars->unacked_lock); |
1029 | 1048 | INIT_LIST_HEAD(&tp_vars->unacked_list); |
@@ -1126,14 +1145,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t) |
1126 | 1145 | "Shutting down for inactivity (more than %dms) from %pM\n", |
1127 | 1146 | BATADV_TP_RECV_TIMEOUT, tp_vars->other_end); |
1128 | 1147 |
|
1129 | | - spin_lock_bh(&tp_vars->bat_priv->tp_list_lock); |
1130 | | - hlist_del_rcu(&tp_vars->list); |
1131 | | - spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock); |
1132 | | - |
1133 | | - /* drop list reference */ |
1134 | | - batadv_tp_vars_put(tp_vars); |
1135 | | - |
1136 | | - atomic_dec(&bat_priv->tp_num); |
| 1148 | + batadv_tp_list_detach(tp_vars); |
1137 | 1149 |
|
1138 | 1150 | spin_lock_bh(&tp_vars->unacked_lock); |
1139 | 1151 | list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) { |
@@ -1496,6 +1508,52 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb) |
1496 | 1508 | consume_skb(skb); |
1497 | 1509 | } |
1498 | 1510 |
|
| 1511 | +/** |
| 1512 | + * batadv_tp_stop_all() - stop all currently running tp meter sessions |
| 1513 | + * @bat_priv: the bat priv with all the mesh interface information |
| 1514 | + */ |
| 1515 | +void batadv_tp_stop_all(struct batadv_priv *bat_priv) |
| 1516 | +{ |
| 1517 | + struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM]; |
| 1518 | + struct batadv_tp_vars *tp_var; |
| 1519 | + size_t count = 0; |
| 1520 | + size_t i; |
| 1521 | + |
| 1522 | + spin_lock_bh(&bat_priv->tp_list_lock); |
| 1523 | + hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) { |
| 1524 | + if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM)) |
| 1525 | + break; |
| 1526 | + |
| 1527 | + if (!kref_get_unless_zero(&tp_var->refcount)) |
| 1528 | + continue; |
| 1529 | + |
| 1530 | + tp_vars[count++] = tp_var; |
| 1531 | + } |
| 1532 | + spin_unlock_bh(&bat_priv->tp_list_lock); |
| 1533 | + |
| 1534 | + for (i = 0; i < count; i++) { |
| 1535 | + tp_var = tp_vars[i]; |
| 1536 | + |
| 1537 | + switch (tp_var->role) { |
| 1538 | + case BATADV_TP_SENDER: |
| 1539 | + batadv_tp_sender_shutdown(tp_var, |
| 1540 | + BATADV_TP_REASON_CANCEL); |
| 1541 | + wake_up(&tp_var->more_bytes); |
| 1542 | + wait_for_completion(&tp_var->finished); |
| 1543 | + break; |
| 1544 | + case BATADV_TP_RECEIVER: |
| 1545 | + batadv_tp_list_detach(tp_var); |
| 1546 | + if (timer_shutdown_sync(&tp_var->timer)) |
| 1547 | + batadv_tp_vars_put(tp_var); |
| 1548 | + break; |
| 1549 | + } |
| 1550 | + |
| 1551 | + batadv_tp_vars_put(tp_var); |
| 1552 | + } |
| 1553 | + |
| 1554 | + synchronize_net(); |
| 1555 | +} |
| 1556 | + |
1499 | 1557 | /** |
1500 | 1558 | * batadv_tp_meter_init() - initialize global tp_meter structures |
1501 | 1559 | */ |
|
0 commit comments