Skip to content

Commit 79bc0ea

Browse files
JiexunWanggregkh
authored andcommitted
batman-adv: stop tp_meter sessions during mesh teardown
commit 3d3cf6a upstream. TP meter sessions remain linked on bat_priv->tp_list after the netlink request has already finished. When the mesh interface is removed, batadv_mesh_free() currently tears down the mesh without first draining these sessions. A running sender thread or a late incoming tp_meter packet can then keep processing against a mesh instance which is already shutting down. Synchronize tp_meter with the mesh lifetime by stopping all active sessions from batadv_mesh_free() and waiting for sender threads to exit before teardown continues. Fixes: 33a3bb4 ("batman-adv: throughput meter implementation") Cc: stable@kernel.org Reported-by: Yuan Tan <yuantan098@gmail.com> Reported-by: Yifan Wu <yifanwucs@gmail.com> Reported-by: Juefei Pu <tomapufckgml@gmail.com> Reported-by: Xin Liu <bird@lzu.edu.cn> Co-developed-by: Luxing Yin <tr0jan@lzu.edu.cn> Signed-off-by: Luxing Yin <tr0jan@lzu.edu.cn> Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn> [ Context ] Signed-off-by: Sven Eckelmann <sven@narfation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c228725 commit 79bc0ea

4 files changed

Lines changed: 82 additions & 18 deletions

File tree

net/batman-adv/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
262262
atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
263263

264264
batadv_purge_outstanding_packets(bat_priv, NULL);
265+
batadv_tp_stop_all(bat_priv);
265266

266267
batadv_gw_node_free(bat_priv);
267268

net/batman-adv/tp_meter.c

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/byteorder/generic.h>
1313
#include <linux/cache.h>
1414
#include <linux/compiler.h>
15+
#include <linux/completion.h>
1516
#include <linux/container_of.h>
1617
#include <linux/err.h>
1718
#include <linux/etherdevice.h>
@@ -365,23 +366,38 @@ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars)
365366
}
366367

367368
/**
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
371371
*/
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)
374373
{
375-
cancel_delayed_work(&tp_vars->finish_work);
374+
bool detached = false;
376375

377376
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+
}
379381
spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
380382

383+
if (!detached)
384+
return;
385+
386+
atomic_dec(&tp_vars->bat_priv->tp_num);
387+
381388
/* drop list reference */
382389
batadv_tp_vars_put(tp_vars);
390+
}
383391

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);
385401

386402
/* kill the timer and remove its reference */
387403
del_timer_sync(&tp_vars->timer);
@@ -886,7 +902,8 @@ static int batadv_tp_send(void *arg)
886902
batadv_orig_node_put(orig_node);
887903

888904
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);
890907

891908
batadv_tp_vars_put(tp_vars);
892909

@@ -918,7 +935,8 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
918935
batadv_tp_vars_put(tp_vars);
919936

920937
/* 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);
922940
return;
923941
}
924942

@@ -1024,6 +1042,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
10241042
tp_vars->start_time = jiffies;
10251043

10261044
init_waitqueue_head(&tp_vars->more_bytes);
1045+
init_completion(&tp_vars->finished);
10271046

10281047
spin_lock_init(&tp_vars->unacked_lock);
10291048
INIT_LIST_HEAD(&tp_vars->unacked_list);
@@ -1126,14 +1145,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
11261145
"Shutting down for inactivity (more than %dms) from %pM\n",
11271146
BATADV_TP_RECV_TIMEOUT, tp_vars->other_end);
11281147

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);
11371149

11381150
spin_lock_bh(&tp_vars->unacked_lock);
11391151
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)
14961508
consume_skb(skb);
14971509
}
14981510

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+
14991557
/**
15001558
* batadv_tp_meter_init() - initialize global tp_meter structures
15011559
*/

net/batman-adv/tp_meter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
1717
u32 test_length, u32 *cookie);
1818
void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
1919
u8 return_value);
20+
void batadv_tp_stop_all(struct batadv_priv *bat_priv);
2021
void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb);
2122

2223
#endif /* _NET_BATMAN_ADV_TP_METER_H_ */

net/batman-adv/types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/average.h>
1515
#include <linux/bitops.h>
1616
#include <linux/compiler.h>
17+
#include <linux/completion.h>
1718
#include <linux/if.h>
1819
#include <linux/if_ether.h>
1920
#include <linux/kref.h>
@@ -1396,6 +1397,9 @@ struct batadv_tp_vars {
13961397
/** @finish_work: work item for the finishing procedure */
13971398
struct delayed_work finish_work;
13981399

1400+
/** @finished: completion signaled when a sender thread exits */
1401+
struct completion finished;
1402+
13991403
/** @test_length: test length in milliseconds */
14001404
u32 test_length;
14011405

0 commit comments

Comments
 (0)