[char-misc] mei: replace spinlock with mutex for kvfree
From: Alexander Usyskin
Date: Sun Jun 21 2026 - 09:23:36 EST
The read buffer allocation that protected by spinlock was
changed from kmalloc() to kvmalloc().
This buffer is part of structure protected by spinlock.
That leads to errors like below when freeing buffer
that allocated non-contiguous:
BUG: sleeping function called from invalid context at mm/vmalloc.c:3448
Replace spinlock with mutex to allow non-contiguous free that can wait.
Cc: stable@xxxxxxxxxxxxxxx
Fixes: 4adf613e01bf ("mei: use kvmalloc for read buffer")
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/16359
Reviewed-by: Menachem Adin <menachem.adin@xxxxxxxxx>
Signed-off-by: Alexander Usyskin <alexander.usyskin@xxxxxxxxx>
---
drivers/misc/mei/client.c | 37 ++++++++++++++++---------------------
drivers/misc/mei/mei_dev.h | 7 ++++---
2 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 643b0039cc72..1da4fc8d028e 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -4,14 +4,15 @@
* Intel Management Engine Interface (Intel MEI) Linux driver
*/
-#include <linux/sched/signal.h>
-#include <linux/wait.h>
+#include <linux/cleanup.h>
+#include <linux/mei.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/pm_runtime.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/mei.h>
+#include <linux/slab.h>
+#include <linux/sched/signal.h>
+#include <linux/wait.h>
#include "mei_dev.h"
#include "hbm.h"
@@ -527,16 +528,12 @@ struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
struct mei_cl_cb *mei_cl_read_cb(struct mei_cl *cl, const struct file *fp)
{
struct mei_cl_cb *cb;
- struct mei_cl_cb *ret_cb = NULL;
- spin_lock(&cl->rd_completed_lock);
+ guard(mutex)(&cl->rd_completed_lock);
list_for_each_entry(cb, &cl->rd_completed, list)
- if (!fp || fp == cb->fp) {
- ret_cb = cb;
- break;
- }
- spin_unlock(&cl->rd_completed_lock);
- return ret_cb;
+ if (!fp || fp == cb->fp)
+ return cb;
+ return NULL;
}
/**
@@ -565,9 +562,9 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl);
mei_cl_free_pending(cl);
}
- spin_lock(&cl->rd_completed_lock);
+
+ guard(mutex)(&cl->rd_completed_lock);
mei_io_list_free_fp(&cl->rd_completed, fp);
- spin_unlock(&cl->rd_completed_lock);
return 0;
}
@@ -586,7 +583,7 @@ static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
init_waitqueue_head(&cl->tx_wait);
init_waitqueue_head(&cl->ev_wait);
INIT_LIST_HEAD(&cl->vtag_map);
- spin_lock_init(&cl->rd_completed_lock);
+ mutex_init(&cl->rd_completed_lock);
INIT_LIST_HEAD(&cl->rd_completed);
INIT_LIST_HEAD(&cl->rd_pending);
INIT_LIST_HEAD(&cl->link);
@@ -1395,9 +1392,8 @@ void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
mei_cl_read_vtag_add_fc(cl);
}
- spin_lock(&cl->rd_completed_lock);
+ guard(mutex)(&cl->rd_completed_lock);
list_add_tail(&cb->list, &cl->rd_completed);
- spin_unlock(&cl->rd_completed_lock);
}
/**
@@ -1409,9 +1405,8 @@ void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
*/
void mei_cl_del_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
{
- spin_lock(&cl->rd_completed_lock);
+ guard(mutex)(&cl->rd_completed_lock);
mei_io_cb_free(cb);
- spin_unlock(&cl->rd_completed_lock);
}
/**
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d8634a726990..ca19b4e45ac9 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -7,11 +7,12 @@
#ifndef _MEI_DEV_H_
#define _MEI_DEV_H_
-#include <linux/types.h>
#include <linux/cdev.h>
-#include <linux/poll.h>
#include <linux/mei.h>
#include <linux/mei_cl_bus.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/types.h>
static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
{
@@ -314,7 +315,7 @@ struct mei_cl {
u8 tx_cb_queued;
enum mei_file_transaction_states writing_state;
struct list_head rd_pending;
- spinlock_t rd_completed_lock; /* protects rd_completed queue */
+ struct mutex rd_completed_lock; /* protects rd_completed queue */
struct list_head rd_completed;
struct mei_dma_data dma;
u8 dma_mapped;
--
2.53.0