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:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user