mei: pull kvfree out of spinlock

The read buffer allocation was changed from kmalloc() to kvmalloc().

This buffer is part of mei_cl_cb structure that can be queued in
rd_complete queue protected by spinlock.
Releasing the structure leads to errors like below when freeing buffer
that allocated non-contiguous:

BUG: sleeping function called from invalid context at mm/vmalloc.c:3448

Separate mei_cl_cb structure dequeue and release to
perform only dequeue under spinlock and push release out of spinlock.

Cc: stable <stable@kernel.org>
Fixes: 4adf613e01 ("mei: use kvmalloc for read buffer")
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/work_items/16359
Reviewed-by: Menachem Adin <menachem.adin@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Link: https://patch.msgid.link/20260719-kvfree_out_of_spinlock-v1-1-e07d6333bea7@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Alexander Usyskin 2026-07-19 12:57:55 +03:00 committed by Greg Kroah-Hartman
parent dd7aea9ee2
commit b0495bb58a

View File

@ -425,18 +425,24 @@ static void mei_io_tx_list_free_cl(struct list_head *head,
}
/**
* mei_io_list_free_fp - free cb from a list that matches file pointer
* mei_io_rd_list_free_fp - free cb from a rd_completed list that matches file pointer
*
* @head: io list
* @cl: host client
* @fp: file pointer (matching cb file object), may be NULL
*/
static void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
static void mei_io_rd_list_free_fp(struct mei_cl *cl, const struct file *fp)
{
struct mei_cl_cb *cb, *next;
LIST_HEAD(cmpl_list);
list_for_each_entry_safe(cb, next, head, list)
spin_lock(&cl->rd_completed_lock);
list_for_each_entry_safe(cb, next, &cl->rd_completed, list)
if (!fp || fp == cb->fp)
mei_io_cb_free(cb);
list_move(&cb->list, &cmpl_list);
spin_unlock(&cl->rd_completed_lock);
list_for_each_entry_safe(cb, next, &cmpl_list, list)
mei_io_cb_free(cb);
}
/**
@ -565,9 +571,7 @@ 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);
mei_io_list_free_fp(&cl->rd_completed, fp);
spin_unlock(&cl->rd_completed_lock);
mei_io_rd_list_free_fp(cl, fp);
return 0;
}
@ -1401,7 +1405,7 @@ void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
}
/**
* mei_cl_del_rd_completed - free read completed callback with lock
* mei_cl_del_rd_completed - unlink read completed callback with lock and free it
*
* @cl: host client
* @cb: callback block
@ -1410,8 +1414,9 @@ 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);
mei_io_cb_free(cb);
list_del_init(&cb->list);
spin_unlock(&cl->rd_completed_lock);
mei_io_cb_free(cb);
}
/**