diff --git a/os/mkosi/components/kernel/kernel-build.sh b/os/mkosi/components/kernel/kernel-build.sh index 548b943bf..f6ea91c31 100755 --- a/os/mkosi/components/kernel/kernel-build.sh +++ b/os/mkosi/components/kernel/kernel-build.sh @@ -52,7 +52,11 @@ rm -rf "$src" "$BUILD_DIR/kernel-build" "$STAGING/usr/lib/modules/$KERNEL_VERSIO tar -C "$BUILD_DIR" --no-same-owner -xf "$tarball" for patch in \ "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0001-x86-tdx-select-dma-direct-remap.patch" \ - "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0002-acpi-sandbox-block-aml-systemmemory-ram-access.patch"; do + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0002-acpi-sandbox-block-aml-systemmemory-ram-access.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0003-dma-direct-return-struct-page-from-alloc-from-pool.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0004-dma-pool-free-atomic-pool-pages-by-physical-address.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0005-swiotlb-preserve-allocation-virtual-address.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0006-swiotlb-free-dynamic-pools-from-process-context.patch"; do patch -d "$src" -p1 --fuzz=0 < "$patch" done diff --git a/os/mkosi/components/kernel/kernel.sh b/os/mkosi/components/kernel/kernel.sh index b98d23486..62817415b 100644 --- a/os/mkosi/components/kernel/kernel.sh +++ b/os/mkosi/components/kernel/kernel.sh @@ -9,7 +9,11 @@ component_cache_key() { key_value "$KERNEL_VERSION" "$KERNEL_SHA256" key_file "$COMPONENT_PATH/kernel-build.sh" "$COMPONENT_PATH/kernel.config" \ "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0001-x86-tdx-select-dma-direct-remap.patch" \ - "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0002-acpi-sandbox-block-aml-systemmemory-ram-access.patch" + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0002-acpi-sandbox-block-aml-systemmemory-ram-access.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0003-dma-direct-return-struct-page-from-alloc-from-pool.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0004-dma-pool-free-atomic-pool-pages-by-physical-address.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0005-swiotlb-preserve-allocation-virtual-address.patch" \ + "$ROOT/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0006-swiotlb-free-dynamic-pools-from-process-context.patch" key_tools gcc ld make pahole key_packages binutils dwarves bc bison flex libssl-dev libelf-dev } diff --git a/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0003-dma-direct-return-struct-page-from-alloc-from-pool.patch b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0003-dma-direct-return-struct-page-from-alloc-from-pool.patch new file mode 100644 index 000000000..63f46081e --- /dev/null +++ b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0003-dma-direct-return-struct-page-from-alloc-from-pool.patch @@ -0,0 +1,83 @@ +From 94a04ad732c9f8b9554270fc4038a06737de5c22 Mon Sep 17 00:00:00 2001 +From: "Aneesh Kumar K.V (Arm)" +Date: Fri, 17 Jul 2026 23:34:19 +0530 +Subject: [PATCH] dma-direct: return struct page from + dma_direct_alloc_from_pool() + +Commit 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool +helper") changed dma_direct_alloc_from_pool() to return the CPU address +from dma_alloc_from_pool(). That fits dma_direct_alloc(), but +dma_direct_alloc_pages() also uses the helper and expects a struct page *. + +Fix this by making dma_direct_alloc_from_pool() return the struct page * +again, and pass the CPU address back through an out-parameter for the +dma_direct_alloc() caller. + +Upstream-Status: Backport [https://git.kernel.org/linus/94a04ad732c9] +Fixes: 5b138c534fda ("dma-direct: factor out a dma_direct_alloc_from_pool helper") +Cc: stable@vger.kernel.org +Tested-by: Michael Kelley +Tested-by: Mostafa Saleh +Reviewed-by: Jason Gunthorpe +Signed-off-by: Aneesh Kumar K.V (Arm) +Reviewed-by: Mostafa Saleh +Link: https://lore.kernel.org/r/20260717180442.110954-2-aneesh.kumar@kernel.org +Signed-off-by: Marek Szyprowski +--- + kernel/dma/direct.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c +index 4391b797d4db81..b4cb2c03e5d7c7 100644 +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -164,22 +164,21 @@ static bool dma_direct_use_pool(struct device *dev, gfp_t gfp) + return !gfpflags_allow_blocking(gfp) && !is_swiotlb_for_alloc(dev); + } + +-static void *dma_direct_alloc_from_pool(struct device *dev, size_t size, +- dma_addr_t *dma_handle, gfp_t gfp) ++static struct page *dma_direct_alloc_from_pool(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, void **cpu_addr, gfp_t gfp) + { + struct page *page; + u64 phys_limit; +- void *ret; + + if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_DMA_COHERENT_POOL))) + return NULL; + + gfp |= dma_direct_optimal_gfp_mask(dev, &phys_limit); +- page = dma_alloc_from_pool(dev, size, &ret, gfp, dma_coherent_ok); ++ page = dma_alloc_from_pool(dev, size, cpu_addr, gfp, dma_coherent_ok); + if (!page) + return NULL; + *dma_handle = phys_to_dma_direct(dev, page_to_phys(page)); +- return ret; ++ return page; + } + + static void *dma_direct_alloc_no_mapping(struct device *dev, size_t size, +@@ -247,8 +246,11 @@ void *dma_direct_alloc(struct device *dev, size_t size, + * the atomic pools instead if we aren't allowed block. + */ + if ((remap || force_dma_unencrypted(dev)) && +- dma_direct_use_pool(dev, gfp)) +- return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp); ++ dma_direct_use_pool(dev, gfp)) { ++ page = dma_direct_alloc_from_pool(dev, size, dma_handle, ++ &ret, gfp); ++ return page ? ret : NULL; ++ } + + /* we always manually zero the memory once we are done */ + page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO, true); +@@ -357,7 +359,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size, + void *ret; + + if (force_dma_unencrypted(dev) && dma_direct_use_pool(dev, gfp)) +- return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp); ++ return dma_direct_alloc_from_pool(dev, size, dma_handle, &ret, gfp); + + page = __dma_direct_alloc_pages(dev, size, gfp, false); + if (!page) diff --git a/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0004-dma-pool-free-atomic-pool-pages-by-physical-address.patch b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0004-dma-pool-free-atomic-pool-pages-by-physical-address.patch new file mode 100644 index 000000000..d2a4df926 --- /dev/null +++ b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0004-dma-pool-free-atomic-pool-pages-by-physical-address.patch @@ -0,0 +1,131 @@ +From 8a9dc4a028e726ff64f0a7b2931485c9ce87e2c0 Mon Sep 17 00:00:00 2001 +From: "Aneesh Kumar K.V (Arm)" +Date: Fri, 17 Jul 2026 23:34:22 +0530 +Subject: [PATCH] dma: free atomic pool pages by physical address + +dma_direct_alloc_pages() may satisfy atomic allocations from the coherent +atomic pools. The pool allocation is keyed by the virtual address stored in +the gen_pool, but the pages API returns only the backing struct page. + +On architectures with CONFIG_DMA_DIRECT_REMAP, atomic pool chunks are added +to the gen_pool using their remapped virtual address. +dma_direct_free_pages() reconstructs a linear-map address with +page_address(page) and passes that to dma_free_from_pool(). That address +does not match the gen_pool virtual range, so the pool lookup can fail and +the code can fall through to freeing a pool-owned page through the normal +page allocator path. + +Add a page-based pool free helper that looks up the owning pool chunk by +physical address, translates it back to the gen_pool virtual address, and +frees that address to the pool. Use it from dma_direct_free_pages() while +keeping the existing virtual-address helper for coherent allocation frees. + +Upstream-Status: Backport [https://git.kernel.org/linus/8a9dc4a028e7] +Tested-by: Michael Kelley +Tested-by: Mostafa Saleh +Signed-off-by: Aneesh Kumar K.V (Arm) +Link: https://lore.kernel.org/r/20260717180442.110954-5-aneesh.kumar@kernel.org +Signed-off-by: Marek Szyprowski +--- + include/linux/dma-map-ops.h | 1 + + kernel/dma/direct.c | 4 +-- + kernel/dma/pool.c | 61 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 64 insertions(+), 2 deletions(-) + +diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h +index bcb5b5428aea94..137e015c175006 100644 +--- a/include/linux/dma-map-ops.h ++++ b/include/linux/dma-map-ops.h +@@ -215,6 +215,7 @@ struct page *dma_alloc_from_pool(struct device *dev, size_t size, + void **cpu_addr, gfp_t flags, + bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t)); + bool dma_free_from_pool(struct device *dev, void *start, size_t size); ++bool dma_free_from_pool_page(struct device *dev, struct page *page, size_t size); + + int dma_direct_set_offset(struct device *dev, phys_addr_t cpu_start, + dma_addr_t dma_start, u64 size); +diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c +index b4cb2c03e5d7c7..17f1e097499e2b 100644 +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -381,9 +381,9 @@ void dma_direct_free_pages(struct device *dev, size_t size, + { + void *vaddr = page_address(page); + +- /* If cpu_addr is not from an atomic pool, dma_free_from_pool() fails */ ++ /* If page is not from an atomic pool, dma_free_from_pool_page() fails */ + if (IS_ENABLED(CONFIG_DMA_COHERENT_POOL) && +- dma_free_from_pool(dev, vaddr, size)) ++ dma_free_from_pool_page(dev, page, size)) + return; + + if (dma_set_encrypted(dev, vaddr, size)) +diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c +index b0303efbc15327..e981c1faaadfae 100644 +--- a/kernel/dma/pool.c ++++ b/kernel/dma/pool.c +@@ -311,3 +311,64 @@ bool dma_free_from_pool(struct device *dev, void *start, size_t size) + + return false; + } ++ ++struct dma_pool_phys_match { ++ phys_addr_t phys; ++ size_t size; ++ unsigned long addr; ++ bool found; ++}; ++ ++static void dma_pool_find_phys(struct gen_pool *pool, struct gen_pool_chunk *chunk, ++ void *data) ++{ ++ struct dma_pool_phys_match *match = data; ++ phys_addr_t end = match->phys + match->size - 1; ++ phys_addr_t chunk_end; ++ ++ if (match->found) ++ return; ++ ++ chunk_end = chunk->phys_addr + (chunk->end_addr - chunk->start_addr); ++ if (match->phys < chunk->phys_addr || end > chunk_end) ++ return; ++ ++ match->addr = chunk->start_addr + (match->phys - chunk->phys_addr); ++ match->found = true; ++} ++ ++static bool dma_free_from_pool_phys(struct gen_pool *pool, phys_addr_t phys, ++ size_t size) ++{ ++ struct dma_pool_phys_match match = { ++ .phys = phys, ++ .size = size, ++ }; ++ ++ gen_pool_for_each_chunk(pool, dma_pool_find_phys, &match); ++ if (!match.found) ++ return false; ++ ++ gen_pool_free(pool, match.addr, size); ++ return true; ++} ++ ++/* ++ * FIXME: We could avoid this by storing the remapped virtual address in ++ * struct page and using that for lookup. ++ */ ++bool dma_free_from_pool_page(struct device *dev, struct page *page, size_t size) ++{ ++ struct gen_pool *pool = NULL; ++ phys_addr_t phys = page_to_phys(page); ++ ++ if (!IS_ENABLED(CONFIG_DMA_DIRECT_REMAP)) ++ return dma_free_from_pool(dev, page_address(page), size); ++ ++ while ((pool = dma_guess_pool(pool, 0))) { ++ if (dma_free_from_pool_phys(pool, phys, size)) ++ return true; ++ } ++ ++ return false; ++} diff --git a/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0005-swiotlb-preserve-allocation-virtual-address.patch b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0005-swiotlb-preserve-allocation-virtual-address.patch new file mode 100644 index 000000000..7884e0970 --- /dev/null +++ b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0005-swiotlb-preserve-allocation-virtual-address.patch @@ -0,0 +1,152 @@ +From 57d29044d0f29a76c6ec0c112c8c7371d5608dc7 Mon Sep 17 00:00:00 2001 +From: "Aneesh Kumar K.V (Arm)" +Date: Fri, 17 Jul 2026 23:34:23 +0530 +Subject: [PATCH] swiotlb: Preserve allocation virtual address for dynamic + pools + +swiotlb_alloc_tlb() can allocate from the DMA atomic pool when a decrypted +pool is needed from atomic context. With CONFIG_DMA_DIRECT_REMAP, the +atomic pool is backed by remapped virtual addresses, which are not the same +as the direct-map addresses returned by phys_to_virt(). + +swiotlb_init_io_tlb_pool() currently reconstructs the pool virtual address +from the physical start address. For atomic-pool backed allocations this +stores the wrong address in pool->vaddr. Later, swiotlb_free_tlb() passes +that address to dma_free_from_pool(), which will fail to recognize the +chunk + +Pass the virtual address returned by the allocation path into +swiotlb_init_io_tlb_pool(), and store that address in pool->vaddr. This +keeps the pool free path using the same virtual address as the allocator. + +Upstream-Status: Backport [https://git.kernel.org/linus/57d29044d0f2] +Fixes: 79636caad361 ("swiotlb: if swiotlb is full, fall back to a transient memory pool") +Reviewed-by: Jason Gunthorpe +Tested-by: Michael Kelley +Tested-by: Mostafa Saleh +Reviewed-by: Petr Tesarik +Signed-off-by: Aneesh Kumar K.V (Arm) +Reviewed-by: Mostafa Saleh +Link: https://lore.kernel.org/r/20260717180442.110954-6-aneesh.kumar@kernel.org +Signed-off-by: Marek Szyprowski +--- + kernel/dma/swiotlb.c | 31 +++++++++++++++++++------------ + 1 file changed, 19 insertions(+), 12 deletions(-) + +diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c +index 1abd3e6146f450..6e8db52866bffe 100644 +--- a/kernel/dma/swiotlb.c ++++ b/kernel/dma/swiotlb.c +@@ -266,9 +266,9 @@ void __init swiotlb_update_mem_attributes(void) + } + + static void swiotlb_init_io_tlb_pool(struct io_tlb_pool *mem, phys_addr_t start, +- unsigned long nslabs, bool late_alloc, unsigned int nareas) ++ void *vaddr, unsigned long nslabs, bool late_alloc, ++ unsigned int nareas) + { +- void *vaddr = phys_to_virt(start); + unsigned long bytes = nslabs << IO_TLB_SHIFT, i; + + mem->nslabs = nslabs; +@@ -409,7 +409,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, + return; + } + +- swiotlb_init_io_tlb_pool(mem, __pa(tlb), nslabs, false, nareas); ++ swiotlb_init_io_tlb_pool(mem, __pa(tlb), tlb, nslabs, false, nareas); + add_mem_pool(&io_tlb_default_mem, mem); + + if (flags & SWIOTLB_VERBOSE) +@@ -507,7 +507,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask, + + set_memory_decrypted((unsigned long)vstart, + (nslabs << IO_TLB_SHIFT) >> PAGE_SHIFT); +- swiotlb_init_io_tlb_pool(mem, virt_to_phys(vstart), nslabs, true, ++ swiotlb_init_io_tlb_pool(mem, virt_to_phys(vstart), vstart, nslabs, true, + nareas); + add_mem_pool(&io_tlb_default_mem, mem); + +@@ -605,25 +605,26 @@ static struct page *alloc_dma_pages(gfp_t gfp, size_t bytes, u64 phys_limit) + * @bytes: Size of the buffer. + * @phys_limit: Maximum allowed physical address of the buffer. + * @gfp: GFP flags for the allocation. ++ * @vaddr: Receives the virtual address for the allocated buffer. + * + * Return: Allocated pages, or %NULL on allocation failure. + */ + static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes, +- u64 phys_limit, gfp_t gfp) ++ u64 phys_limit, gfp_t gfp, void **vaddr) + { + struct page *page; + ++ *vaddr = NULL; ++ + /* + * Allocate from the atomic pools if memory is encrypted and + * the allocation is atomic, because decrypting may block. + */ + if (!gfpflags_allow_blocking(gfp) && dev && force_dma_unencrypted(dev)) { +- void *vaddr; +- + if (!IS_ENABLED(CONFIG_DMA_COHERENT_POOL)) + return NULL; + +- return dma_alloc_from_pool(dev, bytes, &vaddr, gfp, ++ return dma_alloc_from_pool(dev, bytes, vaddr, gfp, + dma_coherent_ok); + } + +@@ -645,6 +646,8 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes, + return NULL; + } + ++ if (page) ++ *vaddr = phys_to_virt(page_to_phys(page)); + return page; + } + +@@ -685,6 +688,7 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, + { + struct io_tlb_pool *pool; + unsigned int slot_order; ++ void *tlb_vaddr; + struct page *tlb; + size_t pool_size; + size_t tlb_size; +@@ -701,7 +705,8 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, + pool->areas = (void *)pool + sizeof(*pool); + + tlb_size = nslabs << IO_TLB_SHIFT; +- while (!(tlb = swiotlb_alloc_tlb(dev, tlb_size, phys_limit, gfp))) { ++ while (!(tlb = swiotlb_alloc_tlb(dev, tlb_size, phys_limit, gfp, ++ &tlb_vaddr))) { + if (nslabs <= minslabs) + goto error_tlb; + nslabs = ALIGN(nslabs >> 1, IO_TLB_SEGSIZE); +@@ -715,11 +720,12 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, + if (!pool->slots) + goto error_slots; + +- swiotlb_init_io_tlb_pool(pool, page_to_phys(tlb), nslabs, true, nareas); ++ swiotlb_init_io_tlb_pool(pool, page_to_phys(tlb), tlb_vaddr, nslabs, ++ true, nareas); + return pool; + + error_slots: +- swiotlb_free_tlb(page_address(tlb), tlb_size); ++ swiotlb_free_tlb(tlb_vaddr, tlb_size); + error_tlb: + kfree(pool); + error: +@@ -1851,7 +1857,8 @@ static int rmem_swiotlb_device_init(struct reserved_mem *rmem, + + set_memory_decrypted((unsigned long)phys_to_virt(rmem->base), + rmem->size >> PAGE_SHIFT); +- swiotlb_init_io_tlb_pool(pool, rmem->base, nslabs, ++ swiotlb_init_io_tlb_pool(pool, rmem->base, phys_to_virt(rmem->base), ++ nslabs, + false, nareas); + mem->force_bounce = true; + mem->for_alloc = true; diff --git a/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0006-swiotlb-free-dynamic-pools-from-process-context.patch b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0006-swiotlb-free-dynamic-pools-from-process-context.patch new file mode 100644 index 000000000..71566717f --- /dev/null +++ b/os/yocto/layers/meta-dstack/recipes-kernel/linux/files/0006-swiotlb-free-dynamic-pools-from-process-context.patch @@ -0,0 +1,102 @@ +From e13d4d9a4915d9dbd0961594442704a4f26160dc Mon Sep 17 00:00:00 2001 +From: "Aneesh Kumar K.V (Arm)" +Date: Fri, 17 Jul 2026 23:34:39 +0530 +Subject: [PATCH] dma: swiotlb: free dynamic pools from process context + +Backport of upstream e13d4d9a4915 ("dma: swiotlb: free dynamic pools from +process context"), merged for v7.3 and not present in linux-6.18.y. Rebased +onto 6.18 context; no functional change from upstream. + +swiotlb_dyn_free() is used after removing a dynamic swiotlb pool from +RCU-protected lists. It can call swiotlb_free_tlb(), which may need to +restore the encryption state of an unencrypted pool with +set_memory_encrypted() before freeing the pages. + +RCU callbacks run in atomic context, but set_memory_encrypted() is not +guaranteed to be atomic-safe on all architectures. For example, page +attribute updates may allocate page tables or take sleeping locks. + +Use queue_rcu_work() for dynamic pool freeing instead. This keeps the RCU +grace period before freeing a published pool, while running the actual pool +teardown from workqueue context. Use the same helper for the transient-pool +error path, since that path may also be reached from atomic DMA mapping +context. + +Upstream-Status: Backport [https://git.kernel.org/linus/e13d4d9a4915] +Tested-by: Michael Kelley +Tested-by: Mostafa Saleh +Reviewed-by: Petr Tesarik +Signed-off-by: Aneesh Kumar K.V (Arm) +Link: https://lore.kernel.org/r/20260717180442.110954-22-aneesh.kumar@kernel.org +Signed-off-by: Marek Szyprowski +--- +--- a/include/linux/swiotlb.h ++++ b/include/linux/swiotlb.h +@@ -64,7 +64,7 @@ + * @areas: Array of memory area descriptors. + * @slots: Array of slot descriptors. + * @node: Member of the IO TLB memory pool list. +- * @rcu: RCU head for swiotlb_dyn_free(). ++ * @dyn_free: RCU work item used to free the pool from process context. + * @transient: %true if transient memory pool. + */ + struct io_tlb_pool { +@@ -79,7 +79,7 @@ + struct io_tlb_slot *slots; + #ifdef CONFIG_SWIOTLB_DYNAMIC + struct list_head node; +- struct rcu_head rcu; ++ struct rcu_work dyn_free; + bool transient; + #endif + }; +--- a/kernel/dma/swiotlb.c ++++ b/kernel/dma/swiotlb.c +@@ -748,13 +748,10 @@ + add_mem_pool(mem, pool); + } + +-/** +- * swiotlb_dyn_free() - RCU callback to free a memory pool +- * @rcu: RCU head in the corresponding struct io_tlb_pool. +- */ +-static void swiotlb_dyn_free(struct rcu_head *rcu) ++static void swiotlb_dyn_free_work(struct work_struct *work) + { +- struct io_tlb_pool *pool = container_of(rcu, struct io_tlb_pool, rcu); ++ struct io_tlb_pool *pool = ++ container_of(to_rcu_work(work), struct io_tlb_pool, dyn_free); + size_t slots_size = array_size(sizeof(*pool->slots), pool->nslabs); + size_t tlb_size = pool->end - pool->start; + +@@ -763,6 +760,12 @@ + kfree(pool); + } + ++static void swiotlb_schedule_dyn_free(struct io_tlb_pool *pool) ++{ ++ INIT_RCU_WORK(&pool->dyn_free, swiotlb_dyn_free_work); ++ queue_rcu_work(system_wq, &pool->dyn_free); ++} ++ + /** + * __swiotlb_find_pool() - find the IO TLB pool for a physical address + * @dev: Device which has mapped the DMA buffer. +@@ -809,7 +812,7 @@ + list_del_rcu(&pool->node); + spin_unlock_irqrestore(&dev->dma_io_tlb_lock, flags); + +- call_rcu(&pool->rcu, swiotlb_dyn_free); ++ swiotlb_schedule_dyn_free(pool); + } + + #endif /* CONFIG_SWIOTLB_DYNAMIC */ +@@ -1233,7 +1236,7 @@ + index = swiotlb_search_pool_area(dev, pool, 0, orig_addr, + alloc_size, alloc_align_mask); + if (index < 0) { +- swiotlb_dyn_free(&pool->rcu); ++ swiotlb_schedule_dyn_free(pool); + return -1; + } + diff --git a/os/yocto/layers/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend b/os/yocto/layers/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend index cdce33451..d9e1aeccf 100644 --- a/os/yocto/layers/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend +++ b/os/yocto/layers/meta-dstack/recipes-kernel/linux/linux-yocto%.bbappend @@ -30,6 +30,44 @@ SRC_URI:append:dstack = " file://0001-x86-tdx-select-dma-direct-remap.patch" # reports no memory encryption). SRC_URI:append = " file://0002-acpi-sandbox-block-aml-systemmemory-ram-access.patch" +# Upstream fixes for the atomic DMA pool on confidential guests, backported +# from the dma-mapping tree merged for v7.3 and absent from linux-6.18.y. +# 0001 above turns on DMA_DIRECT_REMAP, and with it atomic_pool_expand() +# registers each pool chunk in the gen_pool under the remapped virtual +# address returned by dma_common_contiguous_remap(). Both fixes are cases of +# dma-direct reconstructing a direct-map address from a struct page, which no +# longer matches that registration: +# +# 0003 dma_direct_alloc_pages() returns the CPU address from +# dma_direct_alloc_from_pool() cast to a struct page * on the +# atomic-pool path. Carries Cc: stable upstream. +# 0004 dma_direct_free_pages() looks the chunk up by page_address(), the +# lookup misses, and the page is re-encrypted and returned to the page +# allocator while the pool still owns it. +# +# Applied unconditionally: upstream bug fixes, inert on builds where the +# atomic DMA pool is never used. +SRC_URI:append = " file://0003-dma-direct-return-struct-page-from-alloc-from-pool.patch \ + file://0004-dma-pool-free-atomic-pool-pages-by-physical-address.patch" + +# The same address mismatch inside swiotlb's dynamic pools, plus its +# atomic-context consequence. Backported from the same v7.3 dma-mapping tree; +# neither commit is in linux-6.18.y. +# +# 0005 swiotlb_alloc_tlb() drops the virtual address dma_alloc_from_pool() +# hands back through its out-parameter, and swiotlb_init_io_tlb_pool() +# recomputes one with phys_to_virt(). For an atomic-pool backed +# transient pool that address is wrong, so dma_free_from_pool() cannot +# recognize the chunk on release. +# 0006 the release then falls through to set_memory_encrypted(), which takes +# vmap_purge_lock from an RCU callback -- "BUG: scheduling while +# atomic", followed by a kernel panic. Run the teardown from a +# workqueue with queue_rcu_work() instead. +# +# Both paths need CONFIG_SWIOTLB_DYNAMIC=y (dstack.cfg) to be reachable. +SRC_URI:append = " file://0005-swiotlb-preserve-allocation-virtual-address.patch \ + file://0006-swiotlb-free-dynamic-pools-from-process-context.patch" + KERNEL_FEATURES:append = " features/cgroups/cgroups.scc \ features/overlayfs/overlayfs.scc \ features/netfilter/netfilter.scc \