From: Barry Song <v-songbaohua(a)oppo.com>
In many cases, the pages passed to vmap() may include high-order
pages allocated with __GFP_COMP flags. For example, the systemheap
often allocates pages in descending order: order 8, then 4, then 0.
Currently, vmap() iterates over every page individually—even pages
inside a high-order block are handled one by one.
This patch detects high-order pages and maps them as a single
contiguous block whenever possible.
An alternative would be to implement a new API, vmap_sg(), but that
change seems to be large in scope.
When vmapping a 128MB dma-buf using the systemheap, this patch
makes system_heap_do_vmap() roughly 17× faster.
W/ patch:
[ 10.404769] system_heap_do_vmap took 2494000 ns
[ 12.525921] system_heap_do_vmap took 2467008 ns
[ 14.517348] system_heap_do_vmap took 2471008 ns
[ 16.593406] system_heap_do_vmap took 2444000 ns
[ 19.501341] system_heap_do_vmap took 2489008 ns
W/o patch:
[ 7.413756] system_heap_do_vmap took 42626000 ns
[ 9.425610] system_heap_do_vmap took 42500992 ns
[ 11.810898] system_heap_do_vmap took 42215008 ns
[ 14.336790] system_heap_do_vmap took 42134992 ns
[ 16.373890] system_heap_do_vmap took 42750000 ns
Cc: David Hildenbrand <david(a)kernel.org>
Cc: Uladzislau Rezki <urezki(a)gmail.com>
Cc: Sumit Semwal <sumit.semwal(a)linaro.org>
Cc: John Stultz <jstultz(a)google.com>
Cc: Maxime Ripard <mripard(a)kernel.org>
Tested-by: Tangquan Zheng <zhengtangquan(a)oppo.com>
Signed-off-by: Barry Song <v-songbaohua(a)oppo.com>
---
* diff with rfc:
Many code refinements based on David's suggestions, thanks!
Refine comment and changelog according to Uladzislau, thanks!
rfc link:
https://lore.kernel.org/linux-mm/20251122090343.81243-1-21cnbao@gmail.com/
mm/vmalloc.c | 45 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 39 insertions(+), 6 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 41dd01e8430c..8d577767a9e5 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -642,6 +642,29 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
return err;
}
+static inline int get_vmap_batch_order(struct page **pages,
+ unsigned int stride, unsigned int max_steps, unsigned int idx)
+{
+ int nr_pages = 1;
+
+ /*
+ * Currently, batching is only supported in vmap_pages_range
+ * when page_shift == PAGE_SHIFT.
+ */
+ if (stride != 1)
+ return 0;
+
+ nr_pages = compound_nr(pages[idx]);
+ if (nr_pages == 1)
+ return 0;
+ if (max_steps < nr_pages)
+ return 0;
+
+ if (num_pages_contiguous(&pages[idx], nr_pages) == nr_pages)
+ return compound_order(pages[idx]);
+ return 0;
+}
+
/*
* vmap_pages_range_noflush is similar to vmap_pages_range, but does not
* flush caches.
@@ -655,23 +678,33 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
pgprot_t prot, struct page **pages, unsigned int page_shift)
{
unsigned int i, nr = (end - addr) >> PAGE_SHIFT;
+ unsigned int stride;
WARN_ON(page_shift < PAGE_SHIFT);
+ /*
+ * For vmap(), users may allocate pages from high orders down to
+ * order 0, while always using PAGE_SHIFT as the page_shift.
+ * We first check whether the initial page is a compound page. If so,
+ * there may be an opportunity to batch multiple pages together.
+ */
if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC) ||
- page_shift == PAGE_SHIFT)
+ (page_shift == PAGE_SHIFT && !PageCompound(pages[0])))
return vmap_small_pages_range_noflush(addr, end, prot, pages);
- for (i = 0; i < nr; i += 1U << (page_shift - PAGE_SHIFT)) {
- int err;
+ stride = 1U << (page_shift - PAGE_SHIFT);
+ for (i = 0; i < nr; ) {
+ int err, order;
- err = vmap_range_noflush(addr, addr + (1UL << page_shift),
+ order = get_vmap_batch_order(pages, stride, nr - i, i);
+ err = vmap_range_noflush(addr, addr + (1UL << (page_shift + order)),
page_to_phys(pages[i]), prot,
- page_shift);
+ page_shift + order);
if (err)
return err;
- addr += 1UL << page_shift;
+ addr += 1UL << (page_shift + order);
+ i += 1U << (order + page_shift - PAGE_SHIFT);
}
return 0;
--
2.39.3 (Apple Git-146)
By combining cross-chain tracing, rapid response, and data-driven investigation, Cipher Rescue Chain stands as the global benchmark for crypto recovery. Every traced transaction, every reconstructed path, and every recovered asset reinforces the same conclusion: with the right forensic expertise, recovery is not only possible—it is highly achievable.
The kerneldoc comment on dma_fence_init() and dma_fence_init64() describe
the legacy reason to pass an external lock as a need to prevent multiple
fences "from signaling out of order". However, this wording is a bit
misleading: a shared spinlock does not (and cannot) prevent the signaler
from signaling out of order. Signaling order is the driver's responsibility
regardless of whether the lock is shared or per-fence.
What a shared lock actually provides is serialization of signaling and
observation across fences in a given context, so that observers never
see a later fence signaled while an earlier one is not.
Reword both comments to describe this more accurately.
Signed-off-by: Maíra Canal <mcanal(a)igalia.com>
---
Hi,
While reading the documentation, I found this particular paragraph quite
hard to understand. As I understand it, locks don't enforce order, only
serialization, but the paragraph seems to communicate the other way around.
Due to that, I had the impression that the current wording can be
misleading for driver developers.
I'm proposing a new wording to better describe the use case of the
external lock based on my understanding, but it would be great to hear
the feedback and suggestions from more experienced developers who might
have more insight about these legacy use cases.
Best regards,
- Maíra
drivers/dma-buf/dma-fence.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 1826ba73094c..bdc29d1c1b5c 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -1102,8 +1102,10 @@ __dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
* to check which fence is later by simply using dma_fence_later().
*
* It is strongly discouraged to provide an external lock because this couples
- * lock and fence life time. This is only allowed for legacy use cases when
- * multiple fences need to be prevented from signaling out of order.
+ * lock and fence lifetime. This is only allowed for legacy use cases that need
+ * a shared lock to serialize signaling and observation of fences within a
+ * context, so that observers never see a later fence signaled while an earlier
+ * one isn't.
*/
void
dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
@@ -1129,8 +1131,10 @@ EXPORT_SYMBOL(dma_fence_init);
* to check which fence is later by simply using dma_fence_later().
*
* It is strongly discouraged to provide an external lock because this couples
- * lock and fence life time. This is only allowed for legacy use cases when
- * multiple fences need to be prevented from signaling out of order.
+ * lock and fence lifetime. This is only allowed for legacy use cases that need
+ * a shared lock to serialize signaling and observation of fences within a
+ * context, so that observers never see a later fence signaled while an earlier
+ * one isn't.
*/
void
dma_fence_init64(struct dma_fence *fence, const struct dma_fence_ops *ops,
--
2.53.0
Dropping the last reference to the DMA-buf and then accessing the name
for tracing can't work correctly.
Only compile tested!
Signed-off-by: Christian König <christian.koenig(a)amd.com>
Fixed: 281a22631423 ("dma-buf: add some tracepoints to debug.")
---
drivers/dma-buf/dma-buf.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 11711874a325..3a9d5113b98c 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -845,9 +845,8 @@ void dma_buf_put(struct dma_buf *dmabuf)
if (WARN_ON(!dmabuf || !dmabuf->file))
return;
- fput(dmabuf->file);
-
DMA_BUF_TRACE(trace_dma_buf_put, dmabuf);
+ fput(dmabuf->file);
}
EXPORT_SYMBOL_NS_GPL(dma_buf_put, "DMA_BUF");
--
2.43.0
The VFS now warns if an inode flagged with S_ANON_INODE is located on a
filesystem that does not have SB_I_NOEXEC set. dmabuf inodes are
created using alloc_anon_inode(), which sets S_ANON_INODE.
This triggers a warning in path_noexec() when a dmabuf is mmapped, for
example by GStreamer's v4l2src element.
[ 60.061328] WARNING: CPU: 2 PID: 2803 at fs/exec.c:125 path_noexec+0xa0/0xd0
...
[ 60.061637] do_mmap+0x2b5/0x680
The warning was introduced by commit 1e7ab6f67824 ("anon_inode: rework
assertions") which added enforcement that anonymous inodes must be on
filesystems with SB_I_NOEXEC set.
Fix this by setting SB_I_NOEXEC and SB_I_NODEV on the dmabuf filesystem
context, following the same pattern as commit ce7419b6cf23d ("anon_inode:
raise SB_I_NODEV and SB_I_NOEXEC") and commit 98f99394a104c ("secretmem:
use SB_I_NOEXEC").
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao(a)canonical.com>
---
drivers/dma-buf/dma-buf.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index a4d8f2ff94e46..dea79aaab10ce 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -221,6 +221,8 @@ static int dma_buf_fs_init_context(struct fs_context *fc)
if (!ctx)
return -ENOMEM;
ctx->dops = &dma_buf_dentry_ops;
+ fc->s_iflags |= SB_I_NOEXEC;
+ fc->s_iflags |= SB_I_NODEV;
return 0;
}
--
2.51.0
In GPI mode, the I2C GENI driver programs an extra TX DMA transfer
descriptor (TRE) on the TX channel when handling a single read message.
This results in an unintended write phase being issued on the I2C bus,
even though a read transaction does not require any TX data.
For a single-byte read, the correct hardware sequence consists of the
CONFIG and GO commands followed by a single RX DMA TRE. Programming an
additional TX DMA TRE is redundant, causes unnecessary DMA buffer
mapping on the TX channel, and may lead to incorrect bus behavior.
Update the transfer logic to avoid programming a TX DMA TRE for single
read messages in GPI mode.
Co-developed-by: Maramaina Naresh <naresh.maramaina(a)oss.qualcomm.com>
Signed-off-by: Maramaina Naresh <naresh.maramaina(a)oss.qualcomm.com>
Signed-off-by: Aniket Randive <aniket.randive(a)oss.qualcomm.com>
---
Changes in v4:
- Added some more description in comment and changed the label name.
Changes in v3:
- Added comment in the driver for better readability and changed the
position of 'skip_dma' label to allow dma engine configuration.
Changes in v2:
- Updated the commit message.
drivers/i2c/busses/i2c-qcom-geni.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index a4acb78fafb6..a482a4c60744 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -625,8 +625,8 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
{
struct gpi_i2c_config *peripheral;
unsigned int flags;
- void *dma_buf;
- dma_addr_t addr;
+ void *dma_buf = NULL;
+ dma_addr_t addr = 0;
enum dma_data_direction map_dirn;
enum dma_transfer_direction dma_dirn;
struct dma_async_tx_descriptor *desc;
@@ -639,6 +639,16 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config;
msg_idx = gi2c_gpi_xfer->msg_idx_cnt;
+ /*
+ * Skip TX DMA mapping for a read message (I2C_M_RD) to avoid
+ * programming an extra TX DMA TRE that would cause an unintended
+ * write cycle on the I2C bus before the actual read operation.
+ */
+ if (op == I2C_WRITE && msgs[msg_idx].flags & I2C_M_RD) {
+ peripheral->multi_msg = true;
+ goto skip_tx_dma_map;
+ }
+
dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1);
if (!dma_buf) {
ret = -ENOMEM;
@@ -658,6 +668,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
goto out;
}
+skip_tx_dma_map:
if (gi2c->is_tx_multi_desc_xfer) {
flags = DMA_CTRL_ACK;
@@ -740,9 +751,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
return 0;
err_config:
- dma_unmap_single(gi2c->se.dev->parent, addr,
- msgs[msg_idx].len, map_dirn);
- i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false);
+ /* Avoid DMA unmap as the write operation skipped DMA mapping */
+ if (dma_buf) {
+ dma_unmap_single(gi2c->se.dev->parent, addr,
+ msgs[msg_idx].len, map_dirn);
+ i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false);
+ }
out:
gi2c->err = ret;
--
2.34.1
From: Jiri Pirko <jiri(a)nvidia.com>
Document the system_cc_shared dma-buf heap that was introduced
recently. Describe its purpose, availability conditions and
relation to confidential computing VMs.
Signed-off-by: Jiri Pirko <jiri(a)nvidia.com>
Reviewed-by: T.J.Mercier <tjmercier(a)google.com>
---
Documentation/userspace-api/dma-buf-heaps.rst | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Documentation/userspace-api/dma-buf-heaps.rst b/Documentation/userspace-api/dma-buf-heaps.rst
index 05445c83b79a..f56b743cdb36 100644
--- a/Documentation/userspace-api/dma-buf-heaps.rst
+++ b/Documentation/userspace-api/dma-buf-heaps.rst
@@ -16,6 +16,13 @@ following heaps:
- The ``system`` heap allocates virtually contiguous, cacheable, buffers.
+ - The ``system_cc_shared`` heap allocates virtually contiguous, cacheable,
+ buffers using shared (decrypted) memory. It is only present on
+ confidential computing (CoCo) VMs where memory encryption is active
+ (e.g., AMD SEV, Intel TDX). The allocated pages have the encryption
+ bit cleared, making them accessible for device DMA without TDISP
+ support. On non-CoCo VM configurations, this heap is not registered.
+
- The ``default_cma_region`` heap allocates physically contiguous,
cacheable, buffers. Only present if a CMA region is present. Such a
region is usually created either through the kernel commandline
--
2.51.1