linuxkpi: Call lkpi_fpu_safe_exec() in the implementation of kvmalloc()

`kvmalloc()` was a simple wrapper around the FreeBSD native `malloc()`.
Unlike the more involved implementation of `kmalloc()`, it didn't end
and being the FPU context around the actual call to `malloc()`.

This caused the following panic in the amdgup DRM driver:

    panic: malloc: called with spinlock or critical section held

... triggered by the call:

    struct dc_3dlut *lut = kvzalloc(sizeof(*lut), GFP_KERNEL);

(for the record, GFP_KERNEL is defined as M_WAITOK)

Replicating the same behaviour as `kmalloc()`, in other words, ending
the FPU context before the call to the underlying `malloc()`, and
beginning it again afterwards solves the problem.

Reviewed by:	olce
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D51557
This commit is contained in:
Jean-Sébastien Pédron
2025-07-26 14:17:26 +02:00
parent 3c4b3bab19
commit c0fc0facf8
2 changed files with 19 additions and 1 deletions
@@ -99,6 +99,7 @@ void lkpi_kmem_cache_free(struct linux_kmem_cache *, void *);
void linux_kmem_cache_destroy(struct linux_kmem_cache *);
void *lkpi_kmalloc(size_t, gfp_t);
void *lkpi_kvmalloc(size_t, gfp_t);
void *lkpi___kmalloc(size_t, gfp_t);
void *lkpi___kmalloc_node(size_t, gfp_t, int);
void *lkpi_krealloc(void *, size_t, gfp_t);
@@ -225,7 +226,7 @@ vmalloc_32(size_t size)
static inline void *
kvmalloc(size_t size, gfp_t flags)
{
return (malloc(size, M_KMALLOC, linux_check_m_flags(flags)));
return (lkpi_kvmalloc(size, flags));
}
static inline void *
@@ -296,6 +296,23 @@ lkpi_kmalloc(size_t size, gfp_t flags)
return(lmc.addr);
}
static void
lkpi_kvmalloc_cb(void *ctx)
{
struct lkpi_kmalloc_ctx *lmc = ctx;
lmc->addr = malloc(lmc->size, M_KMALLOC, linux_check_m_flags(lmc->flags));
}
void *
lkpi_kvmalloc(size_t size, gfp_t flags)
{
struct lkpi_kmalloc_ctx lmc = { .size = size, .flags = flags };
lkpi_fpu_safe_exec(&lkpi_kvmalloc_cb, &lmc);
return(lmc.addr);
}
static void
linux_kfree_async_fn(void *context, int pending)
{