[PATCH] i2c: virtio: Reset virtqueue before freeing interrupted requests

From: Guangshuo Li

Date: Sun Jul 05 2026 - 12:00:01 EST


virtio_i2c_complete_reqs() waits for each queued request to complete
before releasing the per-message DMA-safe buffer. The request array is
then freed by virtio_i2c_xfer().

After wait_for_completion_interruptible() was introduced, the wait can
return before the current request has completed. In that case, the
request and the remaining requests may still be owned by the virtqueue
and may still be completed by the device later.

The error path nevertheless continues to release each message buffer and
virtio_i2c_xfer() frees the request array. A later device completion can
then write to freed request memory or call complete() on a freed
completion object.

Reset the virtqueue when the wait is interrupted so that outstanding
buffers are recovered before the request array and message buffers are
freed.

Fixes: a663b3c47ab1 ("i2c: virtio: Avoid hang by using interruptible completion wait")
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
drivers/i2c/busses/i2c-virtio.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c
index 5da6fef92bec..6ef09eda3ed0 100644
--- a/drivers/i2c/busses/i2c-virtio.c
+++ b/drivers/i2c/busses/i2c-virtio.c
@@ -117,12 +117,19 @@ static int virtio_i2c_complete_reqs(struct virtqueue *vq,
struct virtio_i2c_req *req = &reqs[i];

if (!failed) {
- if (wait_for_completion_interruptible(&req->completion))
+ if (wait_for_completion_interruptible(&req->completion)) {
+ /*
+ * The remaining buffers may still be owned by
+ * the device. Reset the virtqueue before freeing
+ * the request array and message buffers.
+ */
+ virtqueue_reset(vq, NULL, NULL);
failed = true;
- else if (req->in_hdr.status != VIRTIO_I2C_MSG_OK)
+ } else if (req->in_hdr.status != VIRTIO_I2C_MSG_OK) {
failed = true;
- else
+ } else {
j++;
+ }
}

i2c_put_dma_safe_msg_buf(reqs[i].buf, &msgs[i], !failed);
--
2.43.0