From: physicalmtea <physicalmtea@gmail.com>
To: Peter Hilber <peter.hilber@oss.qualcomm.com>
Cc: mst@redhat.com, jasowang@redhat.com, xuanzhuo@linux.alibaba.com,
eperezma@redhat.com, virtualization@lists.linux.dev,
linux-kernel@vger.kernel.org, JiaJia <physicalmtea@gmail.com>
Subject: [PATCH v3] virtio: rtc: tear down old virtqueues before restore
Date: Sat, 25 Apr 2026 15:08:40 +0800 [thread overview]
Message-ID: <20260425070840.488634-1-physicalmtea@gmail.com> (raw)
In-Reply-To: <d2gtdzjz3bfs47rmeslo46dkwmjqpv2qjcxmpgbkcbxjrqbf6m@bkeeynnavvy3>
From: JiaJia <physicalmtea@gmail.com>
virtio_device_restore() resets the device and restores the negotiated
features before calling ->restore(). viortc_freeze() intentionally
leaves the existing virtqueues in place so the alarm queue can still
wake the system, but viortc_restore() immediately calls
viortc_init_vqs() without first deleting those old queues.
If virtqueue reinitialization fails on virtio-pci, the transport error
path can run vp_del_vqs() against a newly allocated vp_dev->vqs array
while vdev->vqs still contains the old virtqueues. vp_del_vqs() then
looks up queue state through the new array and can dereference a NULL
info pointer in vp_del_vq(), crashing the guest kernel during restore.
This can also happen during a non-faulty reinitialization, when one of
the vp_find_vqs_msix() attempts is unsuccessful before a later attempt
would succeed.
Delete the stale virtqueues before rebuilding them. If restore fails
before virtio_device_ready(), reuse the remove path to stop the device.
Once the device is ready, return errors directly instead of deleting the
virtqueues again.
Fixes: 0623c7592768 ("virtio_rtc: Add module and driver core")
Signed-off-by: JiaJia <physicalmtea@gmail.com>
Reviewed-by: Peter Hilber <peter.hilber@oss.qualcomm.com>
---
v3:
- Add Fixes tag.
- Add Peter's Reviewed-by tag.
- Clarify commit message regarding reinitialization scenarios.
Apologies for missing the Fixes tag, and thanks for catching that!
I've also updated the commit message to include the scenario you
mentioned.
drivers/virtio/virtio_rtc_driver.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/drivers/virtio/virtio_rtc_driver.c b/drivers/virtio/virtio_rtc_driver.c
index a57d5e06e..4419735b0 100644
--- a/drivers/virtio/virtio_rtc_driver.c
+++ b/drivers/virtio/virtio_rtc_driver.c
@@ -1257,6 +1257,15 @@ static int viortc_init_vqs(struct viortc_dev *viortc)
return 0;
}
+static void __viortc_remove(struct viortc_dev *viortc)
+{
+ struct virtio_device *vdev = viortc->vdev;
+
+ viortc_clocks_deinit(viortc);
+ virtio_reset_device(vdev);
+ vdev->config->del_vqs(vdev);
+}
+
/**
* viortc_probe() - probe a virtio_rtc virtio device
* @vdev: virtio device
@@ -1282,7 +1291,7 @@ static int viortc_probe(struct virtio_device *vdev)
ret = viortc_init_vqs(viortc);
if (ret)
- return ret;
+ goto err_reset_vdev;
virtio_device_ready(vdev);
@@ -1329,10 +1338,7 @@ static void viortc_remove(struct virtio_device *vdev)
{
struct viortc_dev *viortc = vdev->priv;
- viortc_clocks_deinit(viortc);
-
- virtio_reset_device(vdev);
- vdev->config->del_vqs(vdev);
+ __viortc_remove(viortc);
}
static int viortc_freeze(struct virtio_device *dev)
@@ -1353,9 +1359,11 @@ static int viortc_restore(struct virtio_device *dev)
bool notify = false;
int ret;
+ dev->config->del_vqs(dev);
+
ret = viortc_init_vqs(viortc);
if (ret)
- return ret;
+ goto err_remove;
alarm_viortc_vq = &viortc->vqs[VIORTC_ALARMQ];
alarm_vq = alarm_viortc_vq->vq;
@@ -1364,7 +1372,7 @@ static int viortc_restore(struct virtio_device *dev)
ret = viortc_populate_vq(viortc, alarm_viortc_vq,
VIORTC_ALARMQ_BUF_CAP, false);
if (ret)
- return ret;
+ goto err_remove;
notify = virtqueue_kick_prepare(alarm_vq);
}
@@ -1372,8 +1380,12 @@ static int viortc_restore(struct virtio_device *dev)
virtio_device_ready(dev);
if (notify && !virtqueue_notify(alarm_vq))
- ret = -EIO;
+ return -EIO;
+
+ return 0;
+err_remove:
+ __viortc_remove(viortc);
return ret;
}
--
2.34.1
next prev parent reply other threads:[~2026-04-25 7:09 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-17 9:08 [PATCH] virtio: rtc: tear down old virtqueues before restore JiaJia
2026-04-23 18:02 ` Peter Hilber
2026-04-24 3:14 ` [PATCH v2] " JiaJia
2026-04-24 13:54 ` Peter Hilber
2026-04-25 7:08 ` physicalmtea [this message]
2026-04-25 15:10 ` [PATCH v3] " Michael S. Tsirkin
2026-04-25 16:09 ` Jia Jia
2026-04-25 17:03 ` Michael S. Tsirkin
2026-05-07 11:24 ` Jia Jia
2026-05-07 11:40 ` Michael S. Tsirkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260425070840.488634-1-physicalmtea@gmail.com \
--to=physicalmtea@gmail.com \
--cc=eperezma@redhat.com \
--cc=jasowang@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mst@redhat.com \
--cc=peter.hilber@oss.qualcomm.com \
--cc=virtualization@lists.linux.dev \
--cc=xuanzhuo@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.