The cntr_val_show() function was intended to print the values of all
counters using a loop. However, due to a buffer overwrite issue with
sprintf(), it effectively only displayed the value of the last counter.
The companion function, cntr_val_store(), allows users to modify a
specific counter selected by 'cntr_idx'. To maintain consistency
between read and write operations and to align with the ETM4x driver
behavior, modify cntr_val_show() to report only the value of the
currently selected counter.
This change removes the loop and the "counter %d:" prefix, printing
only the hexadecimal value. It also adopts sysfs_emit() for standard
sysfs output formatting.
Fixes: a939fc5a71ad ("coresight-etm: add CoreSight ETM/PTM driver")
Cc: stable(a)vger.kernel.org
Signed-off-by: Kuan-Wei Chiu <visitorckw(a)gmail.com>
---
Build test only.
Changes in v3:
- Switch format specifier to %#x to include the 0x prefix.
- Add Cc stable
v2: https://lore.kernel.org/lkml/20251201095228.1905489-1-visitorckw@gmail.com/
.../hwtracing/coresight/coresight-etm3x-sysfs.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 762109307b86..b3c67e96a82a 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -717,26 +717,19 @@ static DEVICE_ATTR_RW(cntr_rld_event);
static ssize_t cntr_val_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int i, ret = 0;
u32 val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
struct etm_config *config = &drvdata->config;
if (!coresight_get_mode(drvdata->csdev)) {
spin_lock(&drvdata->spinlock);
- for (i = 0; i < drvdata->nr_cntr; i++)
- ret += sprintf(buf, "counter %d: %x\n",
- i, config->cntr_val[i]);
+ val = config->cntr_val[config->cntr_idx];
spin_unlock(&drvdata->spinlock);
- return ret;
- }
-
- for (i = 0; i < drvdata->nr_cntr; i++) {
- val = etm_readl(drvdata, ETMCNTVRn(i));
- ret += sprintf(buf, "counter %d: %x\n", i, val);
+ } else {
+ val = etm_readl(drvdata, ETMCNTVRn(config->cntr_idx));
}
- return ret;
+ return sysfs_emit(buf, "%#x\n", val);
}
static ssize_t cntr_val_store(struct device *dev,
--
2.52.0.158.g65b55ccf14-goog
A memory leak exists in the handling of repeat mode damon_call_control
objects by kdamond_call(). While damon_call() correctly allows multiple
repeat mode objects (with ->repeat set to true) to be added to the
per-context list, kdamond_call() incorrectly processes them.
The function moves all repeat mode objects from the context's list to a
temporary list (repeat_controls). However, it only moves the first
object back to the context's list for future calls, leaving the
remaining objects on the temporary list where they are abandoned and
leaked.
This patch fixes the leak by ensuring all repeat mode objects are
properly re-added to the context's list.
Fixes: 43df7676e550 ("mm/damon/core: introduce repeat mode damon_call()")
Signed-off-by: Enze Li <lienze(a)kylinos.cn>
Cc: <stable(a)vger.kernel.org> # 6.17.x
---
mm/damon/core.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 109b050c795a..66b5bae44f22 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -2526,13 +2526,19 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel)
list_add(&control->list, &repeat_controls);
}
}
- control = list_first_entry_or_null(&repeat_controls,
- struct damon_call_control, list);
- if (!control || cancel)
- return;
- mutex_lock(&ctx->call_controls_lock);
- list_add_tail(&control->list, &ctx->call_controls);
- mutex_unlock(&ctx->call_controls_lock);
+ while (true) {
+ control = list_first_entry_or_null(&repeat_controls,
+ struct damon_call_control, list);
+ if (!control)
+ break;
+ /* Unlink from the repeate_controls list. */
+ list_del(&control->list);
+ if (cancel)
+ continue;
+ mutex_lock(&ctx->call_controls_lock);
+ list_add(&control->list, &ctx->call_controls);
+ mutex_unlock(&ctx->call_controls_lock);
+ }
}
/* Returns negative error code if it's not activated but should return */
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
--
2.52.0
Hello Enze,
First of all, thank you for sharing this patch!
On Tue, 2 Dec 2025 10:14:07 +0800 Enze Li <lienze(a)kylinos.cn> wrote:
> The current implementation only supports repeated calls to a single
> damon_call_control request per context.
I understand "repeated calls to a single damon_call_control" means "single
damon_call_control object having ->repeat set as true". Let me call it "repeat
mode damon_call_control object".
This is not an intentionally designed limitation but a bug. damon_call()
allows callers adding multiple repeat mode damon_call_control objects per
context. Technically, it adds any requested damon_call_control object to the
per-context linked list, regardless of the number of repeat mode objects on the
list. But, the consumer of the damon_call_control objects list,
kdamond_call(), moves the repeat mode objects from the per-context list to a
temporal list (repeat_controls), and then move only the first repeat mode entry
from the temporal list to the per-context list.
If there were multiple repeat mode objects in the per-context list, what
happens to the remaining repeat mode damon_call_control objects on the temporal
list? Nothing. As a result, the memory for the objects are leaked.
Definitely this is a bug.
Luckily there is no such multiple repeat mode damon_call() requests, so no
upstream kernel user is exposed to the memory leak bug in real. But the bug is
a bug. We should fix this.
> This limitation introduces
> inefficiencies for scenarios that require registering multiple deferred
> operations.
I'm not very convinced with the above reasoning because 1. it is not a matter
of inefficiency but a clear memory leak bug. 2. there is no damon_call()
callers that want to have multiple deferred operations with high efficiency, at
the moment. In my opinion, the above sentence is better to be just dropped.
>
> This patch modifies the implementation of kdamond_call() to support
> repeated calls to multiple damon_call_control requests.
This change is rquired for fixing the bug, though.
> To demonstrate
> the effect of this change, I made minor modifications to
> samples/damon/prcl.c by adding a new request alongside the original
> damon_call_control request and performed comparative tests.
>
> Before applying the patch, I observed,
>
> [ 381.661821] damon_sample_prcl: start
> [ 381.668199] damon_sample_prcl: repeat_call_v2
> [ 381.668208] damon_sample_prcl: repeat_call
> [ 381.668211] damon_sample_prcl: wss: 0
> [ 381.675194] damon_sample_prcl: repeat_call
> [ 381.675202] damon_sample_prcl: wss: 0
>
> after applying the patch, I saw,
>
> [ 61.750723] damon_sample_prcl: start
> [ 61.757104] damon_sample_prcl: repeat_call_v2
> [ 61.757106] damon_sample_prcl: repeat_call
> [ 61.757107] damon_sample_prcl: wss: 0
> [ 61.763067] damon_sample_prcl: repeat_call_v2
> [ 61.763069] damon_sample_prcl: repeat_call
> [ 61.763070] damon_sample_prcl: wss: 0
>
> Signed-off-by: Enze Li <lienze(a)kylinos.cn>
Assuming we agree on the fact this is a fix of the bug, I think we should add
below tags.
Fixes: 43df7676e550 ("mm/damon/core: introduce repeat mode damon_call()")
Cc: <stable(a)vger.kernel.org> # 6.17.x
> ---
> mm/damon/core.c | 20 +++++++++++++-------
> 1 file changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index 109b050c795a..66b5bae44f22 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -2526,13 +2526,19 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel)
> list_add(&control->list, &repeat_controls);
> }
> }
> - control = list_first_entry_or_null(&repeat_controls,
> - struct damon_call_control, list);
> - if (!control || cancel)
> - return;
> - mutex_lock(&ctx->call_controls_lock);
> - list_add_tail(&control->list, &ctx->call_controls);
> - mutex_unlock(&ctx->call_controls_lock);
> + while (true) {
> + control = list_first_entry_or_null(&repeat_controls,
> + struct damon_call_control, list);
> + if (!control)
> + break;
> + /* Unlink from the repeate_controls list. */
> + list_del(&control->list);
> + if (cancel)
> + continue;
> + mutex_lock(&ctx->call_controls_lock);
> + list_add(&control->list, &ctx->call_controls);
> + mutex_unlock(&ctx->call_controls_lock);
> + }
This looks good enough to fix the bug.
Could you please resend this patch after rewording the commit message as
appripriate for the bug fix, adding points I listed above?
Again, thank you for letting us find this bug.
Thanks,
SJ
[...]
The patch below does not apply to the 6.12-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(a)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.12.y
git checkout FETCH_HEAD
git cherry-pick -x cff47b9e39a6abf03dde5f4f156f841b0c54bba0
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable(a)vger.kernel.org>' --in-reply-to '2025120102-geranium-elevator-ca86@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From cff47b9e39a6abf03dde5f4f156f841b0c54bba0 Mon Sep 17 00:00:00 2001
From: Wei Yang <richard.weiyang(a)gmail.com>
Date: Wed, 19 Nov 2025 23:53:02 +0000
Subject: [PATCH] mm/huge_memory: fix NULL pointer deference when splitting
folio
Commit c010d47f107f ("mm: thp: split huge page to any lower order pages")
introduced an early check on the folio's order via mapping->flags before
proceeding with the split work.
This check introduced a bug: for shmem folios in the swap cache and
truncated folios, the mapping pointer can be NULL. Accessing
mapping->flags in this state leads directly to a NULL pointer dereference.
This commit fixes the issue by moving the check for mapping != NULL before
any attempt to access mapping->flags.
Link: https://lkml.kernel.org/r/20251119235302.24773-1-richard.weiyang@gmail.com
Fixes: c010d47f107f ("mm: thp: split huge page to any lower order pages")
Signed-off-by: Wei Yang <richard.weiyang(a)gmail.com>
Reviewed-by: Zi Yan <ziy(a)nvidia.com>
Acked-by: David Hildenbrand (Red Hat) <david(a)kernel.org>
Reviewed-by: Baolin Wang <baolin.wang(a)linux.alibaba.com>
Cc: <stable(a)vger.kernel.org>
Signed-off-by: Andrew Morton <akpm(a)linux-foundation.org>
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2f2a521e5d68..6cba1cb14b23 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -3619,6 +3619,16 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
if (folio != page_folio(split_at) || folio != page_folio(lock_at))
return -EINVAL;
+ /*
+ * Folios that just got truncated cannot get split. Signal to the
+ * caller that there was a race.
+ *
+ * TODO: this will also currently refuse shmem folios that are in the
+ * swapcache.
+ */
+ if (!is_anon && !folio->mapping)
+ return -EBUSY;
+
if (new_order >= folio_order(folio))
return -EINVAL;
@@ -3659,18 +3669,6 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
gfp_t gfp;
mapping = folio->mapping;
-
- /* Truncated ? */
- /*
- * TODO: add support for large shmem folio in swap cache.
- * When shmem is in swap cache, mapping is NULL and
- * folio_test_swapcache() is true.
- */
- if (!mapping) {
- ret = -EBUSY;
- goto out;
- }
-
min_order = mapping_min_folio_order(folio->mapping);
if (new_order < min_order) {
ret = -EINVAL;
epf_ntb_epc_destroy() duplicates the teardown that the caller is
supposed to perform later. This leads to an oops when .allow_link fails
or when .drop_link is performed. The following is an example oops of the
former case:
Unable to handle kernel paging request at virtual address dead000000000108
[...]
[dead000000000108] address between user and kernel address ranges
Internal error: Oops: 0000000096000044 [#1] SMP
[...]
Call trace:
pci_epc_remove_epf+0x78/0xe0 (P)
pci_primary_epc_epf_link+0x88/0xa8
configfs_symlink+0x1f4/0x5a0
vfs_symlink+0x134/0x1d8
do_symlinkat+0x88/0x138
__arm64_sys_symlinkat+0x74/0xe0
[...]
Remove the helper, and drop pci_epc_put(). EPC device refcounting is
tied to the configfs EPC group lifetime, and pci_epc_put() in the
.drop_link path is sufficient.
Cc: <stable(a)vger.kernel.org>
Fixes: e35f56bb0330 ("PCI: endpoint: Support NTB transfer between RC and EP")
Reviewed-by: Frank Li <Frank.Li(a)nxp.com>
Signed-off-by: Koichiro Den <den(a)valinux.co.jp>
---
drivers/pci/endpoint/functions/pci-epf-vntb.c | 19 +------------------
1 file changed, 1 insertion(+), 18 deletions(-)
diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 83e9ab10f9c4..49ce5d4b0ee5 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -644,19 +644,6 @@ static void epf_ntb_mw_bar_clear(struct epf_ntb *ntb, int num_mws)
}
}
-/**
- * epf_ntb_epc_destroy() - Cleanup NTB EPC interface
- * @ntb: NTB device that facilitates communication between HOST and VHOST
- *
- * Wrapper for epf_ntb_epc_destroy_interface() to cleanup all the NTB interfaces
- */
-static void epf_ntb_epc_destroy(struct epf_ntb *ntb)
-{
- pci_epc_remove_epf(ntb->epf->epc, ntb->epf, 0);
- pci_epc_put(ntb->epf->epc);
-}
-
-
/**
* epf_ntb_is_bar_used() - Check if a bar is used in the ntb configuration
* @ntb: NTB device that facilitates communication between HOST and VHOST
@@ -1406,7 +1393,7 @@ static int epf_ntb_bind(struct pci_epf *epf)
ret = epf_ntb_init_epc_bar(ntb);
if (ret) {
dev_err(dev, "Failed to create NTB EPC\n");
- goto err_bar_init;
+ return ret;
}
ret = epf_ntb_config_spad_bar_alloc(ntb);
@@ -1446,9 +1433,6 @@ static int epf_ntb_bind(struct pci_epf *epf)
err_bar_alloc:
epf_ntb_config_spad_bar_free(ntb);
-err_bar_init:
- epf_ntb_epc_destroy(ntb);
-
return ret;
}
@@ -1464,7 +1448,6 @@ static void epf_ntb_unbind(struct pci_epf *epf)
epf_ntb_epc_cleanup(ntb);
epf_ntb_config_spad_bar_free(ntb);
- epf_ntb_epc_destroy(ntb);
pci_unregister_driver(&vntb_pci_driver);
}
--
2.48.1
The unlink callbacks passed the parameters in the wrong order that led
to looking up the wrong group objects. Swap the arguments so that the
first parameter is the epf item and the second is the epc item.
Cc: <stable(a)vger.kernel.org>
Fixes: e85a2d783762 ("PCI: endpoint: Add support in configfs to associate two EPCs with EPF")
Reviewed-by: Frank Li <Frank.Li(a)nxp.com>
Signed-off-by: Koichiro Den <den(a)valinux.co.jp>
---
drivers/pci/endpoint/pci-ep-cfs.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c
index ef50c82e647f..c7cf6c76d116 100644
--- a/drivers/pci/endpoint/pci-ep-cfs.c
+++ b/drivers/pci/endpoint/pci-ep-cfs.c
@@ -69,8 +69,8 @@ static int pci_secondary_epc_epf_link(struct config_item *epf_item,
return 0;
}
-static void pci_secondary_epc_epf_unlink(struct config_item *epc_item,
- struct config_item *epf_item)
+static void pci_secondary_epc_epf_unlink(struct config_item *epf_item,
+ struct config_item *epc_item)
{
struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
@@ -133,8 +133,8 @@ static int pci_primary_epc_epf_link(struct config_item *epf_item,
return 0;
}
-static void pci_primary_epc_epf_unlink(struct config_item *epc_item,
- struct config_item *epf_item)
+static void pci_primary_epc_epf_unlink(struct config_item *epf_item,
+ struct config_item *epc_item)
{
struct pci_epf_group *epf_group = to_pci_epf_group(epf_item->ci_parent);
struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
--
2.48.1
When BAR_PEER_SPAD and BAR_CONFIG share one PCI BAR, the module teardown
path ends up calling pci_iounmap() on the same iomem with some offset,
which is unnecessary and triggers a kernel warning like the following:
Trying to vunmap() nonexistent vm area (0000000069a5ffe8)
WARNING: mm/vmalloc.c:3470 at vunmap+0x58/0x68, CPU#5: modprobe/2937
[...]
Call trace:
vunmap+0x58/0x68 (P)
iounmap+0x34/0x48
pci_iounmap+0x2c/0x40
ntb_epf_pci_remove+0x44/0x80 [ntb_hw_epf]
pci_device_remove+0x48/0xf8
device_remove+0x50/0x88
device_release_driver_internal+0x1c8/0x228
driver_detach+0x50/0xb0
bus_remove_driver+0x74/0x100
driver_unregister+0x34/0x68
pci_unregister_driver+0x34/0xa0
ntb_epf_pci_driver_exit+0x14/0xfe0 [ntb_hw_epf]
[...]
Fix it by unmapping only when PEER_SPAD and CONFIG use difference bars.
Cc: <stable(a)vger.kernel.org>
Fixes: e75d5ae8ab88 ("NTB: epf: Allow more flexibility in the memory BAR map method")
Reviewed-by: Frank Li <Frank.Li(a)nxp.com>
Signed-off-by: Koichiro Den <den(a)valinux.co.jp>
---
drivers/ntb/hw/epf/ntb_hw_epf.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c
index d3ecf25a5162..9935da48a52e 100644
--- a/drivers/ntb/hw/epf/ntb_hw_epf.c
+++ b/drivers/ntb/hw/epf/ntb_hw_epf.c
@@ -646,7 +646,8 @@ static void ntb_epf_deinit_pci(struct ntb_epf_dev *ndev)
struct pci_dev *pdev = ndev->ntb.pdev;
pci_iounmap(pdev, ndev->ctrl_reg);
- pci_iounmap(pdev, ndev->peer_spad_reg);
+ if (ndev->barno_map[BAR_PEER_SPAD] != ndev->barno_map[BAR_CONFIG])
+ pci_iounmap(pdev, ndev->peer_spad_reg);
pci_iounmap(pdev, ndev->db_reg);
pci_release_regions(pdev);
--
2.48.1