* [ndctl PATCH v3 0/2] daxctl, util/sysfs: fix builtin-driver false failure on enable
@ 2026-06-18 9:06 Chen Pei
2026-06-18 9:06 ` [ndctl PATCH v3 1/2] daxctl: fix kmod reference leak on probe-insert failure Chen Pei
2026-06-18 9:06 ` [ndctl PATCH v3 2/2] daxctl, util/sysfs: skip module probe-insert when driver is builtin or live Chen Pei
0 siblings, 2 replies; 4+ messages in thread
From: Chen Pei @ 2026-06-18 9:06 UTC (permalink / raw)
To: alison.schofield, dave.jiang, jic23, nvdimm; +Cc: guoren, linux-cxl
When a DAX / ndctl driver is builtin (not a loadable module),
daxctl_insert_kmod_for_mode() and __util_bind() still call
kmod_module_probe_insert_module() unconditionally. libkmod only
short-circuits builtin modules when it can find the modules.builtin
index; otherwise it falls through to init_module() and returns -ENOENT,
surfacing as a spurious "insert failure".
Pre-check kmod_module_get_initstate() and skip probe-insert when the
module is already BUILTIN or LIVE, matching the pattern used by ndctl's
own test/core.c.
Changes since v2 [3]:
- Patch 2/2: Add a Reviewed-by tag.
Changes since v1 [1]:
- Patch 1/2: unchanged; collected Reviewed-by from Dave and Alison.
- Patch 2/2: factored the state check into a new helper
util_kmod_skip_probe_insert() in util/sysfs.{c,h} so both
daxctl_insert_kmod_for_mode() and __util_bind() share it. The
helper also returns the observed libkmod state via an out
parameter so the caller does not re-read /sys/module/<name>/
initstate to distinguish LIVE from BUILTIN.
- Patch 2/2: additionally treat KMOD_MODULE_COMING as builtin when
/sys/module/<name>/ exists but the initstate file does not. This
is the pattern libkmod's sysfs fallback emits for builtin drivers
when the modules.builtin index is missing (e.g. a kernel installed
without running modules_install). This was the case Jonathan hit
on a builtin DAX VM setup; rather than rely on a libkmod fix, ndctl
handles the corner case directly. Suggested by Alison [2].
[1]: https://lore.kernel.org/nvdimm/20260514063234.86439-1-cp0613@linux.alibaba.com/
[2]: https://lore.kernel.org/nvdimm/agtf5uwBJOaCDR6l@aschofie-mobl2.lan/
[3]: https://lore.kernel.org/nvdimm/20260526132251.254476-1-cp0613@linux.alibaba.com/
Chen Pei (2):
daxctl: fix kmod reference leak on probe-insert failure
daxctl, util/sysfs: skip module probe-insert when driver is builtin or
live
daxctl/lib/libdaxctl.c | 23 ++++++++++++++++++++--
util/sysfs.c | 44 +++++++++++++++++++++++++++++++++++++++++-
util/sysfs.h | 16 +++++++++++++++
3 files changed, 80 insertions(+), 3 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [ndctl PATCH v3 1/2] daxctl: fix kmod reference leak on probe-insert failure
2026-06-18 9:06 [ndctl PATCH v3 0/2] daxctl, util/sysfs: fix builtin-driver false failure on enable Chen Pei
@ 2026-06-18 9:06 ` Chen Pei
2026-06-18 9:06 ` [ndctl PATCH v3 2/2] daxctl, util/sysfs: skip module probe-insert when driver is builtin or live Chen Pei
1 sibling, 0 replies; 4+ messages in thread
From: Chen Pei @ 2026-06-18 9:06 UTC (permalink / raw)
To: alison.schofield, dave.jiang, jic23, nvdimm; +Cc: guoren, linux-cxl
daxctl_insert_kmod_for_mode() obtains a kmod reference via
kmod_module_new_from_name() and only stores it in dev->module after a
successful kmod_module_probe_insert_module() call. On the failure path
the local reference was returned without being released, leaking one
reference per failed enable attempt.
Drop the reference before returning the error code.
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
---
daxctl/lib/libdaxctl.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 01b1915..8c3ac47 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -975,6 +975,7 @@ static int daxctl_insert_kmod_for_mode(struct daxctl_dev *dev,
NULL, NULL, NULL, NULL);
if (rc < 0) {
err(ctx, "%s: insert failure: %d\n", devname, rc);
+ kmod_module_unref(kmod);
return rc;
}
dev->module = kmod;
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [ndctl PATCH v3 2/2] daxctl, util/sysfs: skip module probe-insert when driver is builtin or live
2026-06-18 9:06 [ndctl PATCH v3 0/2] daxctl, util/sysfs: fix builtin-driver false failure on enable Chen Pei
2026-06-18 9:06 ` [ndctl PATCH v3 1/2] daxctl: fix kmod reference leak on probe-insert failure Chen Pei
@ 2026-06-18 9:06 ` Chen Pei
2026-07-09 23:03 ` Jonathan Cameron
1 sibling, 1 reply; 4+ messages in thread
From: Chen Pei @ 2026-06-18 9:06 UTC (permalink / raw)
To: alison.schofield, dave.jiang, jic23, nvdimm; +Cc: guoren, linux-cxl
kmod_module_probe_insert_module() is supposed to return 0 for builtin
modules, but only when libkmod can locate the modules.builtin index. If
the index is missing (e.g. a kernel built with the driver as builtin
but installed without running modules_install), libkmod falls through
to the real init_module() syscall and returns an error such as -ENOENT,
producing a spurious "insert failure" even though the driver is already
part of the running kernel.
Add a helper util_kmod_skip_probe_insert() that returns true when the
module state is KMOD_MODULE_BUILTIN or KMOD_MODULE_LIVE. As an
additional heuristic, treat KMOD_MODULE_COMING as builtin when
/sys/module/<name>/ exists but the initstate file does not - this is
the exact pattern libkmod's sysfs fallback emits for builtin drivers
when the modules.builtin index is unavailable. The pattern mirrors the
KMOD_MODULE_LIVE / KMOD_MODULE_BUILTIN check already used by ndctl's
own test/core.c (see test/core.c:218-236).
The helper also returns the observed libkmod state via an out parameter
so daxctl_insert_kmod_for_mode() can distinguish LIVE (retain the kmod
reference in dev->module) from BUILTIN (drop it, since builtin drivers
cannot be unloaded) without re-reading /sys/module/<name>/initstate.
__util_bind() passes NULL since it does not need the state.
Reported-by: Jonathan Cameron <jic23@kernel.org>
Suggested-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
---
daxctl/lib/libdaxctl.c | 22 +++++++++++++++++++--
util/sysfs.c | 44 +++++++++++++++++++++++++++++++++++++++++-
util/sysfs.h | 16 +++++++++++++++
3 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 8c3ac47..5b47c77 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -958,7 +958,7 @@ static int daxctl_insert_kmod_for_mode(struct daxctl_dev *dev,
const char *devname = daxctl_dev_get_devname(dev);
struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
struct kmod_module *kmod;
- int rc;
+ int state, rc;
rc = kmod_module_new_from_name(ctx->kmod_ctx, mod_name, &kmod);
if (rc < 0) {
@@ -967,7 +967,25 @@ static int daxctl_insert_kmod_for_mode(struct daxctl_dev *dev,
return rc;
}
- /* if the driver is builtin, this Just Works */
+ /*
+ * If the driver is builtin or already live, skip probe-insert.
+ * For live modules retain the local reference in dev->module so
+ * the module can be unreffed alongside the device; for builtin
+ * drivers drop it because builtin modules cannot be unloaded.
+ */
+ if (util_kmod_skip_probe_insert(kmod, ctx, &state)) {
+ if (state == KMOD_MODULE_LIVE) {
+ dbg(ctx, "%s: module %s already loaded\n", devname,
+ kmod_module_get_name(kmod));
+ dev->module = kmod;
+ } else {
+ dbg(ctx, "%s: module %s is builtin\n", devname,
+ kmod_module_get_name(kmod));
+ kmod_module_unref(kmod);
+ }
+ return 0;
+ }
+
dbg(ctx, "%s inserting module: %s\n", devname,
kmod_module_get_name(kmod));
rc = kmod_module_probe_insert_module(kmod,
diff --git a/util/sysfs.c b/util/sysfs.c
index e027e38..eaf4b60 100644
--- a/util/sysfs.c
+++ b/util/sysfs.c
@@ -6,6 +6,7 @@
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
+#include <limits.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
@@ -168,6 +169,47 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,
return mod;
}
+bool __util_kmod_skip_probe_insert(struct kmod_module *module,
+ struct log_ctx *ctx, int *state_out)
+{
+ const char *name = kmod_module_get_name(module);
+ int state = kmod_module_get_initstate(module);
+ char path[PATH_MAX];
+ struct stat st;
+
+ if (state_out)
+ *state_out = state;
+
+ if (state == KMOD_MODULE_BUILTIN || state == KMOD_MODULE_LIVE)
+ return true;
+
+ /*
+ * When modules.builtin is missing (e.g. a kernel installed
+ * without modules_install), libkmod's sysfs fallback returns
+ * KMOD_MODULE_COMING for builtin drivers because /sys/module/<name>/
+ * exists but the initstate file does not. Treat that pattern as
+ * builtin to avoid a spurious "insert failure" message.
+ */
+ if (state != KMOD_MODULE_COMING)
+ return false;
+
+ if (snprintf(path, sizeof(path), "/sys/module/%s/initstate", name)
+ >= (int)sizeof(path))
+ return false;
+ if (stat(path, &st) == 0 || errno != ENOENT)
+ return false;
+
+ if (snprintf(path, sizeof(path), "/sys/module/%s", name)
+ >= (int)sizeof(path))
+ return false;
+ if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode))
+ return false;
+
+ log_dbg(ctx, "module %s appears builtin (no modules.builtin index)\n",
+ name);
+ return true;
+}
+
int __util_bind(const char *devname, struct kmod_module *module,
const char *bus, struct log_ctx *ctx)
{
@@ -182,7 +224,7 @@ int __util_bind(const char *devname, struct kmod_module *module,
return -EINVAL;
}
- if (module) {
+ if (module && !__util_kmod_skip_probe_insert(module, ctx, NULL)) {
rc = kmod_module_probe_insert_module(module,
KMOD_PROBE_APPLY_BLACKLIST,
NULL, NULL, NULL, NULL);
diff --git a/util/sysfs.h b/util/sysfs.h
index 4c95c70..e4f6115 100644
--- a/util/sysfs.h
+++ b/util/sysfs.h
@@ -3,6 +3,7 @@
#ifndef __UTIL_SYSFS_H__
#define __UTIL_SYSFS_H__
+#include <stdbool.h>
#include <string.h>
typedef void *(*add_dev_fn)(void *parent, int id, const char *dev_path);
@@ -36,6 +37,21 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx,
#define util_modalias_to_module(ctx, buf) \
__util_modalias_to_module((ctx)->kmod_ctx, buf, &(ctx)->ctx)
+/*
+ * __util_kmod_skip_probe_insert - true when kmod_module_probe_insert_module()
+ * should be skipped because @module is already part of the running kernel:
+ * KMOD_MODULE_BUILTIN, KMOD_MODULE_LIVE, or KMOD_MODULE_COMING with
+ * /sys/module/<name>/ existing but no initstate file (the fingerprint
+ * libkmod's sysfs fallback emits for builtin drivers when the
+ * modules.builtin index is missing). If @state_out is non-NULL, the
+ * libkmod state actually observed is stored there so callers can avoid
+ * an extra kmod_module_get_initstate() call.
+ */
+bool __util_kmod_skip_probe_insert(struct kmod_module *module,
+ struct log_ctx *ctx, int *state_out);
+#define util_kmod_skip_probe_insert(m, c, s) \
+ __util_kmod_skip_probe_insert((m), &(c)->ctx, (s))
+
int __util_bind(const char *devname, struct kmod_module *module, const char *bus,
struct log_ctx *ctx);
#define util_bind(n, m, b, c) __util_bind(n, m, b, &(c)->ctx)
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [ndctl PATCH v3 2/2] daxctl, util/sysfs: skip module probe-insert when driver is builtin or live
2026-06-18 9:06 ` [ndctl PATCH v3 2/2] daxctl, util/sysfs: skip module probe-insert when driver is builtin or live Chen Pei
@ 2026-07-09 23:03 ` Jonathan Cameron
0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Cameron @ 2026-07-09 23:03 UTC (permalink / raw)
To: Chen Pei; +Cc: alison.schofield, dave.jiang, jic23, nvdimm, guoren, linux-cxl
On Thu, 18 Jun 2026 17:06:53 +0800
Chen Pei <cp0613@linux.alibaba.com> wrote:
> kmod_module_probe_insert_module() is supposed to return 0 for builtin
> modules, but only when libkmod can locate the modules.builtin index. If
> the index is missing (e.g. a kernel built with the driver as builtin
> but installed without running modules_install), libkmod falls through
> to the real init_module() syscall and returns an error such as -ENOENT,
> producing a spurious "insert failure" even though the driver is already
> part of the running kernel.
>
> Add a helper util_kmod_skip_probe_insert() that returns true when the
> module state is KMOD_MODULE_BUILTIN or KMOD_MODULE_LIVE. As an
> additional heuristic, treat KMOD_MODULE_COMING as builtin when
> /sys/module/<name>/ exists but the initstate file does not - this is
> the exact pattern libkmod's sysfs fallback emits for builtin drivers
> when the modules.builtin index is unavailable. The pattern mirrors the
> KMOD_MODULE_LIVE / KMOD_MODULE_BUILTIN check already used by ndctl's
> own test/core.c (see test/core.c:218-236).
>
> The helper also returns the observed libkmod state via an out parameter
> so daxctl_insert_kmod_for_mode() can distinguish LIVE (retain the kmod
> reference in dev->module) from BUILTIN (drop it, since builtin drivers
> cannot be unloaded) without re-reading /sys/module/<name>/initstate.
> __util_bind() passes NULL since it does not need the state.
>
> Reported-by: Jonathan Cameron <jic23@kernel.org>
> Suggested-by: Alison Schofield <alison.schofield@intel.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Signed-off-by: Chen Pei <cp0613@linux.alibaba.com>
I'm not set up to test this right now but fix looks good to me.
So a tentative
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-09 23:03 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18 9:06 [ndctl PATCH v3 0/2] daxctl, util/sysfs: fix builtin-driver false failure on enable Chen Pei
2026-06-18 9:06 ` [ndctl PATCH v3 1/2] daxctl: fix kmod reference leak on probe-insert failure Chen Pei
2026-06-18 9:06 ` [ndctl PATCH v3 2/2] daxctl, util/sysfs: skip module probe-insert when driver is builtin or live Chen Pei
2026-07-09 23:03 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox