Skip to content

Commit 850675c

Browse files
committed
fast-get: fix partition leak for multi-thread usage
Each thread that calls fast_get() on a large buffer gets a partition added to its memory domain. Previously, fast_put() only removed the partition from the allocating thread's domain (entry->thread), leaking partitions for any additional threads that were granted access. Fix by having each thread remove its OWN partition on fast_put() using k_current_get() instead of entry->thread. The partition removal now happens unconditionally (not just on last reference), ensuring each thread cleans up after itself. Order of operations: 1. Free buffer if last reference (while partition still grants access) 2. Remove current thread's partition (prevents leaks) 3. Clear entry if last reference Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
1 parent a32d983 commit 850675c

1 file changed

Lines changed: 22 additions & 28 deletions

File tree

zephyr/lib/fast-get.c

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -277,40 +277,34 @@ void fast_put(struct k_heap *heap, const void *sram_ptr)
277277
LOG_ERR("Put called to unknown address %p", sram_ptr);
278278
goto out;
279279
}
280+
280281
entry->refcount--;
281282

282283
if (!entry->refcount) {
283-
#if CONFIG_USERSPACE
284-
/* For large buffers, we need to:
285-
* 1. Free the heap buffer FIRST (while partition still grants us access)
286-
* 2. Then remove the partition (to prevent partition leaks)
287-
* This order is critical - we must free while we still have access.
288-
*/
289-
if (entry->size > FAST_GET_MAX_COPY_SIZE) {
290-
struct k_mem_partition part;
291-
struct k_mem_domain *domain = entry->thread->mem_domain_info.mem_domain;
292-
void *addr = entry->sram_ptr;
293-
294-
sof_heap_free(heap, addr);
295-
296-
part.start = (uintptr_t)addr;
297-
part.size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE);
298-
part.attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB;
299-
300-
int err = k_mem_domain_remove_partition(domain, &part);
301-
302-
if (err < 0)
303-
LOG_WRN("partition removal failed err=%d", err);
284+
LOG_DBG("freeing buffer %p", entry->sram_ptr);
285+
sof_heap_free(heap, entry->sram_ptr);
286+
}
304287

305-
} else
306-
#endif /* CONFIG_USERSPACE */
307-
{
308-
/* Small buffers have no partitions, just free */
309-
sof_heap_free(heap, entry->sram_ptr);
310-
}
288+
#if CONFIG_USERSPACE
289+
if (entry->size > FAST_GET_MAX_COPY_SIZE) {
290+
struct k_mem_partition part = {
291+
.start = (uintptr_t)entry->sram_ptr,
292+
.size = ALIGN_UP(entry->size, CONFIG_MM_DRV_PAGE_SIZE),
293+
.attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB,
294+
};
295+
struct k_mem_domain *domain = k_current_get()->mem_domain_info.mem_domain;
296+
297+
LOG_DBG("removing partition %p size %#zx from thread %p",
298+
(void *)part.start, part.size, k_current_get());
299+
int err = k_mem_domain_remove_partition(domain, &part);
300+
301+
if (err)
302+
LOG_WRN("partition removal failed: %d", err);
303+
}
304+
#endif
311305

306+
if (!entry->refcount)
312307
memset(entry, 0, sizeof(*entry));
313-
}
314308
out:
315309
LOG_DBG("put %p, DRAM %p size %u refcnt %u", sram_ptr, entry ? entry->dram_ptr : 0,
316310
entry ? entry->size : 0, entry ? entry->refcount : 0);

0 commit comments

Comments
 (0)