mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Cen Zhang <zzzccc427@gmail.com>
To: Tejun Heo <tj@kernel.org>, Lai Jiangshan <jiangshanlai@gmail.com>,
	Marcel Holtmann <marcel@holtmann.org>,
	Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
	Marco Elver <elver@google.com>,
	Jukka Rissanen <jukka.rissanen@linux.intel.com>
Cc: linux-kernel@vger.kernel.org, linux-bluetooth@vger.kernel.org,
	baijiaju1990@gmail.com, jjzuming@gmail.com, zzzccc427@gmail.com
Subject: [PATCH 2/5] workqueue: add support for module-owned work
Date: Mon, 21 Sep 2026 23:38:59 +0800	[thread overview]
Message-ID: <pm-series-6lowpan-lifecycle-82fab5876048c8c9503c-2@gmail.com> (raw)
In-Reply-To: <pm-series-6lowpan-lifecycle-82fab5876048c8c9503c-0@gmail.com>

Queueing a callback on a system workqueue does not take a reference to
the module containing that callback. A caller which releases its last
module reference after queueing work can therefore leave a callback in
unloaded text. Releasing the reference from the callback itself also
leaves its return path unprotected.

Add module_work and schedule_module_work() to hold the callback's owner
from queueing until the callback returns. Run the dispatch and final
module_put() in workqueue core, which remains present when the callback's
module is unloaded. Cache the function and owner before invoking the
callback so that it can free the containing work item.

6LoWPAN needs this for deferred network-device deletion after removing
the last peer.

Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
 include/linux/workqueue.h | 15 ++++++++++++++
 kernel/workqueue.c        | 43 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index c8a36423cb34..9920796c8822 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -128,6 +128,14 @@ struct rcu_work {
 	struct workqueue_struct *wq;
 };
 
+struct module;
+
+struct module_work {
+	struct work_struct work;
+	struct module *owner;
+	work_func_t func;
+};
+
 enum wq_affn_scope {
 	WQ_AFFN_DFL,			/* use system default */
 	WQ_AFFN_CPU,			/* one pod per CPU */
@@ -220,6 +228,11 @@ static inline struct rcu_work *to_rcu_work(struct work_struct *work)
 	return container_of(work, struct rcu_work, work);
 }
 
+static inline struct module_work *to_module_work(struct work_struct *work)
+{
+	return container_of(work, struct module_work, work);
+}
+
 struct execute_work {
 	struct work_struct work;
 };
@@ -634,6 +647,8 @@ extern void __flush_workqueue(struct workqueue_struct *wq);
 extern void drain_workqueue(struct workqueue_struct *wq);
 
 extern int schedule_on_each_cpu(work_func_t func);
+bool schedule_module_work(struct module_work *mwork, work_func_t func,
+			  struct module *owner);
 
 int execute_in_process_context(work_func_t fn, struct execute_work *);
 
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 1ae3732a2c51..1a16bc5dfb68 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -48,6 +48,7 @@
 #include <linux/hashtable.h>
 #include <linux/rculist.h>
 #include <linux/nodemask.h>
+#include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/uaccess.h>
 #include <linux/sched/isolation.h>
@@ -4808,6 +4809,48 @@ int execute_in_process_context(work_func_t fn, struct execute_work *ew)
 }
 EXPORT_SYMBOL_GPL(execute_in_process_context);
 
+static void module_work_func(struct work_struct *work)
+{
+	struct module_work *mwork = to_module_work(work);
+	struct module *owner = mwork->owner;
+	work_func_t func = mwork->func;
+
+	func(work);
+	module_put(owner);
+}
+
+/**
+ * schedule_module_work - schedule work owned by a module
+ * @mwork: module work to schedule
+ * @func: work function to schedule
+ * @owner: module owning @func
+ *
+ * Take a reference to @owner before scheduling @func. The reference is
+ * released by workqueue core after the callback returns. The callback may
+ * free @mwork. @mwork must not be pending.
+ *
+ * Return: %false if the module is being removed or the work could not be
+ * queued, %true otherwise.
+ */
+bool schedule_module_work(struct module_work *mwork, work_func_t func,
+			  struct module *owner)
+{
+	if (!try_module_get(owner))
+		return false;
+
+	INIT_WORK(&mwork->work, module_work_func);
+	mwork->owner = owner;
+	mwork->func = func;
+
+	if (!schedule_work(&mwork->work)) {
+		module_put(owner);
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(schedule_module_work);
+
 /**
  * free_workqueue_attrs - free a workqueue_attrs
  * @attrs: workqueue_attrs to free
-- 
2.43.0


  parent reply	other threads:[~2026-09-21 15:39 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21 15:38 [PATCH 0/5] Bluetooth: 6LoWPAN lifecycle fixes Cen Zhang
2026-09-21 15:38 ` [PATCH 1/5] Bluetooth: L2CAP: ignore close requests for deleted channels Cen Zhang
2026-09-21 16:56   ` Pauli Virtanen
2026-09-21 15:38 ` Cen Zhang [this message]
2026-09-21 16:16   ` [PATCH 2/5] workqueue: add support for module-owned work Tejun Heo
2026-09-21 17:03     ` Cen Zhang
2026-09-21 15:39 ` [PATCH 3/5] Bluetooth: L2CAP: drain channel timers on connection teardown Cen Zhang
2026-09-21 15:54   ` Luiz Augusto von Dentz
2026-09-21 15:39 ` [PATCH 4/5] Bluetooth: 6lowpan: handle channel setup failure and callback lifetime Cen Zhang
2026-09-21 15:39 ` [PATCH 5/5] Bluetooth: 6lowpan: quiesce peers before channel deletion Cen Zhang
2026-09-21 16:07 ` [PATCH 0/5] Bluetooth: 6LoWPAN lifecycle fixes Luiz Augusto von Dentz
2026-09-21 16:59   ` Cen Zhang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=pm-series-6lowpan-lifecycle-82fab5876048c8c9503c-2@gmail.com \
    --to=zzzccc427@gmail.com \
    --cc=baijiaju1990@gmail.com \
    --cc=elver@google.com \
    --cc=jiangshanlai@gmail.com \
    --cc=jjzuming@gmail.com \
    --cc=jukka.rissanen@linux.intel.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=marcel@holtmann.org \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®