* FAILED: patch "[PATCH] batman-adv: stop tp_meter sessions during mesh teardown" failed to apply to 6.1-stable tree
@ 2026-05-15 8:44 gregkh
2026-05-15 11:03 ` [PATCH 6.1.y] batman-adv: stop tp_meter sessions during mesh teardown Sven Eckelmann
0 siblings, 1 reply; 2+ messages in thread
From: gregkh @ 2026-05-15 8:44 UTC (permalink / raw)
To: wangjiexun2025, bird, n05ec, sven, tomapufckgml, tr0jan,
yifanwucs, yuantan098
Cc: stable
The patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 3d3cf6a7314aca4df0a6dde28ce784a2a30d0166
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026051554-unbutton-gatherer-c472@gregkh' --subject-prefix 'PATCH 6.1.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 3d3cf6a7314aca4df0a6dde28ce784a2a30d0166 Mon Sep 17 00:00:00 2001
From: Jiexun Wang <wangjiexun2025@gmail.com>
Date: Mon, 27 Apr 2026 14:43:34 +0800
Subject: [PATCH] batman-adv: stop tp_meter sessions during mesh teardown
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: 33a3bb4a3345 ("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>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 3a35aadd8b41..a4d33ee0fda5 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -249,6 +249,7 @@ void batadv_mesh_free(struct net_device *mesh_iface)
atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
batadv_purge_outstanding_packets(bat_priv, NULL);
+ batadv_tp_stop_all(bat_priv);
batadv_gw_node_free(bat_priv);
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index d9a80e459c2e..58ca59a2799e 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -12,6 +12,7 @@
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
#include <linux/compiler.h>
+#include <linux/completion.h>
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/etherdevice.h>
@@ -365,23 +366,38 @@ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars)
}
/**
- * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
- * @bat_priv: the bat priv with all the mesh interface information
- * @tp_vars: the private data of the current TP meter session to cleanup
+ * batadv_tp_list_detach() - remove tp session from mesh session list once
+ * @tp_vars: the private data of the current TP meter session
*/
-static void batadv_tp_sender_cleanup(struct batadv_priv *bat_priv,
- struct batadv_tp_vars *tp_vars)
+static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
{
- cancel_delayed_work(&tp_vars->finish_work);
+ bool detached = false;
spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
- hlist_del_rcu(&tp_vars->list);
+ if (!hlist_unhashed(&tp_vars->list)) {
+ hlist_del_init_rcu(&tp_vars->list);
+ detached = true;
+ }
spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
+ if (!detached)
+ return;
+
+ atomic_dec(&tp_vars->bat_priv->tp_num);
+
/* drop list reference */
batadv_tp_vars_put(tp_vars);
+}
- atomic_dec(&tp_vars->bat_priv->tp_num);
+/**
+ * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
+ * @tp_vars: the private data of the current TP meter session to cleanup
+ */
+static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
+{
+ cancel_delayed_work_sync(&tp_vars->finish_work);
+
+ batadv_tp_list_detach(tp_vars);
/* kill the timer and remove its reference */
timer_delete_sync(&tp_vars->timer);
@@ -886,7 +902,8 @@ static int batadv_tp_send(void *arg)
batadv_orig_node_put(orig_node);
batadv_tp_sender_end(bat_priv, tp_vars);
- batadv_tp_sender_cleanup(bat_priv, tp_vars);
+ batadv_tp_sender_cleanup(tp_vars);
+ complete(&tp_vars->finished);
batadv_tp_vars_put(tp_vars);
@@ -918,7 +935,8 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
batadv_tp_vars_put(tp_vars);
/* cleanup of failed tp meter variables */
- batadv_tp_sender_cleanup(bat_priv, tp_vars);
+ batadv_tp_sender_cleanup(tp_vars);
+ complete(&tp_vars->finished);
return;
}
@@ -1024,6 +1042,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
tp_vars->start_time = jiffies;
init_waitqueue_head(&tp_vars->more_bytes);
+ init_completion(&tp_vars->finished);
spin_lock_init(&tp_vars->unacked_lock);
INIT_LIST_HEAD(&tp_vars->unacked_list);
@@ -1126,14 +1145,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
"Shutting down for inactivity (more than %dms) from %pM\n",
BATADV_TP_RECV_TIMEOUT, tp_vars->other_end);
- spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
- hlist_del_rcu(&tp_vars->list);
- spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
-
- /* drop list reference */
- batadv_tp_vars_put(tp_vars);
-
- atomic_dec(&bat_priv->tp_num);
+ batadv_tp_list_detach(tp_vars);
spin_lock_bh(&tp_vars->unacked_lock);
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)
consume_skb(skb);
}
+/**
+ * batadv_tp_stop_all() - stop all currently running tp meter sessions
+ * @bat_priv: the bat priv with all the mesh interface information
+ */
+void batadv_tp_stop_all(struct batadv_priv *bat_priv)
+{
+ struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM];
+ struct batadv_tp_vars *tp_var;
+ size_t count = 0;
+ size_t i;
+
+ spin_lock_bh(&bat_priv->tp_list_lock);
+ hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) {
+ if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM))
+ break;
+
+ if (!kref_get_unless_zero(&tp_var->refcount))
+ continue;
+
+ tp_vars[count++] = tp_var;
+ }
+ spin_unlock_bh(&bat_priv->tp_list_lock);
+
+ for (i = 0; i < count; i++) {
+ tp_var = tp_vars[i];
+
+ switch (tp_var->role) {
+ case BATADV_TP_SENDER:
+ batadv_tp_sender_shutdown(tp_var,
+ BATADV_TP_REASON_CANCEL);
+ wake_up(&tp_var->more_bytes);
+ wait_for_completion(&tp_var->finished);
+ break;
+ case BATADV_TP_RECEIVER:
+ batadv_tp_list_detach(tp_var);
+ if (timer_shutdown_sync(&tp_var->timer))
+ batadv_tp_vars_put(tp_var);
+ break;
+ }
+
+ batadv_tp_vars_put(tp_var);
+ }
+
+ synchronize_net();
+}
+
/**
* batadv_tp_meter_init() - initialize global tp_meter structures
*/
diff --git a/net/batman-adv/tp_meter.h b/net/batman-adv/tp_meter.h
index f0046d366eac..4e97cd10cd02 100644
--- a/net/batman-adv/tp_meter.h
+++ b/net/batman-adv/tp_meter.h
@@ -17,6 +17,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
u32 test_length, u32 *cookie);
void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
u8 return_value);
+void batadv_tp_stop_all(struct batadv_priv *bat_priv);
void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb);
#endif /* _NET_BATMAN_ADV_TP_METER_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 8fc5fe0e9b05..daa06f421154 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -14,6 +14,7 @@
#include <linux/average.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
+#include <linux/completion.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/kref.h>
@@ -1328,6 +1329,9 @@ struct batadv_tp_vars {
/** @finish_work: work item for the finishing procedure */
struct delayed_work finish_work;
+ /** @finished: completion signaled when a sender thread exits */
+ struct completion finished;
+
/** @test_length: test length in milliseconds */
u32 test_length;
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH 6.1.y] batman-adv: stop tp_meter sessions during mesh teardown
2026-05-15 8:44 FAILED: patch "[PATCH] batman-adv: stop tp_meter sessions during mesh teardown" failed to apply to 6.1-stable tree gregkh
@ 2026-05-15 11:03 ` Sven Eckelmann
0 siblings, 0 replies; 2+ messages in thread
From: Sven Eckelmann @ 2026-05-15 11:03 UTC (permalink / raw)
To: stable
Cc: Jiexun Wang, stable, Yuan Tan, Yifan Wu, Juefei Pu, Xin Liu,
Luxing Yin, Ren Wei, Sven Eckelmann
From: Jiexun Wang <wangjiexun2025@gmail.com>
commit 3d3cf6a7314aca4df0a6dde28ce784a2a30d0166 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: 33a3bb4a3345 ("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>
---
net/batman-adv/main.c | 1 +
net/batman-adv/tp_meter.c | 94 +++++++++++++++++++++++++++++++--------
net/batman-adv/tp_meter.h | 1 +
net/batman-adv/types.h | 4 ++
4 files changed, 82 insertions(+), 18 deletions(-)
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index e8a449915566..18b32c39ed4b 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -262,6 +262,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
batadv_purge_outstanding_packets(bat_priv, NULL);
+ batadv_tp_stop_all(bat_priv);
batadv_gw_node_free(bat_priv);
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 7f3dd3c393e0..8f7786d33f5f 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -12,6 +12,7 @@
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
#include <linux/compiler.h>
+#include <linux/completion.h>
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/etherdevice.h>
@@ -365,23 +366,38 @@ static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars)
}
/**
- * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
- * @bat_priv: the bat priv with all the soft interface information
- * @tp_vars: the private data of the current TP meter session to cleanup
+ * batadv_tp_list_detach() - remove tp session from mesh session list once
+ * @tp_vars: the private data of the current TP meter session
*/
-static void batadv_tp_sender_cleanup(struct batadv_priv *bat_priv,
- struct batadv_tp_vars *tp_vars)
+static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
{
- cancel_delayed_work(&tp_vars->finish_work);
+ bool detached = false;
spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
- hlist_del_rcu(&tp_vars->list);
+ if (!hlist_unhashed(&tp_vars->list)) {
+ hlist_del_init_rcu(&tp_vars->list);
+ detached = true;
+ }
spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
+ if (!detached)
+ return;
+
+ atomic_dec(&tp_vars->bat_priv->tp_num);
+
/* drop list reference */
batadv_tp_vars_put(tp_vars);
+}
- atomic_dec(&tp_vars->bat_priv->tp_num);
+/**
+ * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
+ * @tp_vars: the private data of the current TP meter session to cleanup
+ */
+static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
+{
+ cancel_delayed_work_sync(&tp_vars->finish_work);
+
+ batadv_tp_list_detach(tp_vars);
/* kill the timer and remove its reference */
del_timer_sync(&tp_vars->timer);
@@ -886,7 +902,8 @@ static int batadv_tp_send(void *arg)
batadv_orig_node_put(orig_node);
batadv_tp_sender_end(bat_priv, tp_vars);
- batadv_tp_sender_cleanup(bat_priv, tp_vars);
+ batadv_tp_sender_cleanup(tp_vars);
+ complete(&tp_vars->finished);
batadv_tp_vars_put(tp_vars);
@@ -918,7 +935,8 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
batadv_tp_vars_put(tp_vars);
/* cleanup of failed tp meter variables */
- batadv_tp_sender_cleanup(bat_priv, tp_vars);
+ batadv_tp_sender_cleanup(tp_vars);
+ complete(&tp_vars->finished);
return;
}
@@ -1017,6 +1035,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
tp_vars->start_time = jiffies;
init_waitqueue_head(&tp_vars->more_bytes);
+ init_completion(&tp_vars->finished);
spin_lock_init(&tp_vars->unacked_lock);
INIT_LIST_HEAD(&tp_vars->unacked_list);
@@ -1119,14 +1138,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
"Shutting down for inactivity (more than %dms) from %pM\n",
BATADV_TP_RECV_TIMEOUT, tp_vars->other_end);
- spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
- hlist_del_rcu(&tp_vars->list);
- spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
-
- /* drop list reference */
- batadv_tp_vars_put(tp_vars);
-
- atomic_dec(&bat_priv->tp_num);
+ batadv_tp_list_detach(tp_vars);
spin_lock_bh(&tp_vars->unacked_lock);
list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
@@ -1481,6 +1493,52 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
consume_skb(skb);
}
+/**
+ * batadv_tp_stop_all() - stop all currently running tp meter sessions
+ * @bat_priv: the bat priv with all the mesh interface information
+ */
+void batadv_tp_stop_all(struct batadv_priv *bat_priv)
+{
+ struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM];
+ struct batadv_tp_vars *tp_var;
+ size_t count = 0;
+ size_t i;
+
+ spin_lock_bh(&bat_priv->tp_list_lock);
+ hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) {
+ if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM))
+ break;
+
+ if (!kref_get_unless_zero(&tp_var->refcount))
+ continue;
+
+ tp_vars[count++] = tp_var;
+ }
+ spin_unlock_bh(&bat_priv->tp_list_lock);
+
+ for (i = 0; i < count; i++) {
+ tp_var = tp_vars[i];
+
+ switch (tp_var->role) {
+ case BATADV_TP_SENDER:
+ batadv_tp_sender_shutdown(tp_var,
+ BATADV_TP_REASON_CANCEL);
+ wake_up(&tp_var->more_bytes);
+ wait_for_completion(&tp_var->finished);
+ break;
+ case BATADV_TP_RECEIVER:
+ batadv_tp_list_detach(tp_var);
+ if (timer_shutdown_sync(&tp_var->timer))
+ batadv_tp_vars_put(tp_var);
+ break;
+ }
+
+ batadv_tp_vars_put(tp_var);
+ }
+
+ synchronize_net();
+}
+
/**
* batadv_tp_meter_init() - initialize global tp_meter structures
*/
diff --git a/net/batman-adv/tp_meter.h b/net/batman-adv/tp_meter.h
index f0046d366eac..4e97cd10cd02 100644
--- a/net/batman-adv/tp_meter.h
+++ b/net/batman-adv/tp_meter.h
@@ -17,6 +17,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
u32 test_length, u32 *cookie);
void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
u8 return_value);
+void batadv_tp_stop_all(struct batadv_priv *bat_priv);
void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb);
#endif /* _NET_BATMAN_ADV_TP_METER_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 6f30afaabfdf..f5a57c5f7ffa 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -14,6 +14,7 @@
#include <linux/average.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
+#include <linux/completion.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/kref.h>
@@ -1396,6 +1397,9 @@ struct batadv_tp_vars {
/** @finish_work: work item for the finishing procedure */
struct delayed_work finish_work;
+ /** @finished: completion signaled when a sender thread exits */
+ struct completion finished;
+
/** @test_length: test length in milliseconds */
u32 test_length;
--
2.47.3
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-15 11:03 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-15 8:44 FAILED: patch "[PATCH] batman-adv: stop tp_meter sessions during mesh teardown" failed to apply to 6.1-stable tree gregkh
2026-05-15 11:03 ` [PATCH 6.1.y] batman-adv: stop tp_meter sessions during mesh teardown Sven Eckelmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox