* [PATCH v2] vduse: Add suspend
@ 2026-03-10 19:10 Eugenio Pérez
2026-03-12 4:03 ` Jason Wang
0 siblings, 1 reply; 4+ messages in thread
From: Eugenio Pérez @ 2026-03-10 19:10 UTC (permalink / raw)
To: Michael S . Tsirkin
Cc: Xuan Zhuo, Yongji Xie, Cindy Lu, Maxime Coquelin,
Stefano Garzarella, linux-kernel, virtualization, Laurent Vivier,
Eugenio Pérez, Jason Wang
Implement suspend operation for vduse devices, so vhost-vdpa will offer
that backend feature and userspace can effectively suspend the device.
This is a must before get virtqueue indexes (base) for live migration,
since the device could modify them after userland gets them.
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
---
This patch depends on
https://lore.kernel.org/lkml/20260310190759.1097506-1-eperezma@redhat.com
v2:
* Take the rwsem only before the actual kick, not in vduse_vdpa_kick_vq.
This assures that we're not in a critical section.
---
drivers/vdpa/vdpa_user/vduse_dev.c | 86 +++++++++++++++++++++++++++++-
include/uapi/linux/vduse.h | 4 ++
2 files changed, 88 insertions(+), 2 deletions(-)
diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
index 4f642b95a7cb..f56b1e3eb82d 100644
--- a/drivers/vdpa/vdpa_user/vduse_dev.c
+++ b/drivers/vdpa/vdpa_user/vduse_dev.c
@@ -54,7 +54,8 @@
#define IRQ_UNBOUND -1
/* Supported VDUSE features */
-static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY);
+static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY) |
+ BIT_U64(VDUSE_F_SUSPEND);
/*
* VDUSE instance have not asked the vduse API version, so assume 0.
@@ -85,6 +86,7 @@ struct vduse_virtqueue {
int irq_effective_cpu;
struct cpumask irq_affinity;
struct kobject kobj;
+ struct vduse_dev *dev;
};
struct vduse_dev;
@@ -134,6 +136,7 @@ struct vduse_dev {
int minor;
bool broken;
bool connected;
+ bool suspended;
u64 api_version;
u64 device_features;
u64 driver_features;
@@ -480,6 +483,7 @@ static void vduse_dev_reset(struct vduse_dev *dev)
down_write(&dev->rwsem);
+ dev->suspended = false;
dev->status = 0;
dev->driver_features = 0;
dev->generation++;
@@ -538,6 +542,10 @@ static void vduse_vq_kick(struct vduse_virtqueue *vq)
if (!vq->ready)
goto unlock;
+ guard(rwsem_read)(&vq->dev->rwsem);
+ if (vq->dev->suspended)
+ return;
+
if (vq->kickfd)
eventfd_signal(vq->kickfd);
else
@@ -896,6 +904,27 @@ static int vduse_vdpa_set_map(struct vdpa_device *vdpa,
return 0;
}
+static int vduse_vdpa_suspend(struct vdpa_device *vdpa)
+{
+ struct vduse_dev *dev = vdpa_to_vduse(vdpa);
+ struct vduse_dev_msg msg = { 0 };
+ int ret;
+
+ msg.req.type = VDUSE_SUSPEND;
+
+ ret = vduse_dev_msg_sync(dev, &msg);
+ if (ret == 0) {
+ scoped_guard(rwsem_write, &dev->rwsem)
+ dev->suspended = true;
+
+ cancel_work_sync(&dev->inject);
+ for (u32 i = 0; i < dev->vq_num; i++)
+ cancel_work_sync(&dev->vqs[i]->inject);
+ }
+
+ return ret;
+}
+
static void vduse_vdpa_free(struct vdpa_device *vdpa)
{
struct vduse_dev *dev = vdpa_to_vduse(vdpa);
@@ -937,6 +966,41 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = {
.free = vduse_vdpa_free,
};
+static const struct vdpa_config_ops vduse_vdpa_config_ops_with_suspend = {
+ .set_vq_address = vduse_vdpa_set_vq_address,
+ .kick_vq = vduse_vdpa_kick_vq,
+ .set_vq_cb = vduse_vdpa_set_vq_cb,
+ .set_vq_num = vduse_vdpa_set_vq_num,
+ .get_vq_size = vduse_vdpa_get_vq_size,
+ .get_vq_group = vduse_get_vq_group,
+ .set_vq_ready = vduse_vdpa_set_vq_ready,
+ .get_vq_ready = vduse_vdpa_get_vq_ready,
+ .set_vq_state = vduse_vdpa_set_vq_state,
+ .get_vq_state = vduse_vdpa_get_vq_state,
+ .get_vq_align = vduse_vdpa_get_vq_align,
+ .get_device_features = vduse_vdpa_get_device_features,
+ .set_driver_features = vduse_vdpa_set_driver_features,
+ .get_driver_features = vduse_vdpa_get_driver_features,
+ .set_config_cb = vduse_vdpa_set_config_cb,
+ .get_vq_num_max = vduse_vdpa_get_vq_num_max,
+ .get_device_id = vduse_vdpa_get_device_id,
+ .get_vendor_id = vduse_vdpa_get_vendor_id,
+ .get_status = vduse_vdpa_get_status,
+ .set_status = vduse_vdpa_set_status,
+ .get_config_size = vduse_vdpa_get_config_size,
+ .get_config = vduse_vdpa_get_config,
+ .set_config = vduse_vdpa_set_config,
+ .get_generation = vduse_vdpa_get_generation,
+ .set_vq_affinity = vduse_vdpa_set_vq_affinity,
+ .get_vq_affinity = vduse_vdpa_get_vq_affinity,
+ .reset = vduse_vdpa_reset,
+ .set_map = vduse_vdpa_set_map,
+ .set_group_asid = vduse_set_group_asid,
+ .get_vq_map = vduse_get_vq_map,
+ .suspend = vduse_vdpa_suspend,
+ .free = vduse_vdpa_free,
+};
+
static void vduse_dev_sync_single_for_device(union virtio_map token,
dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
@@ -1148,6 +1212,10 @@ static void vduse_dev_irq_inject(struct work_struct *work)
{
struct vduse_dev *dev = container_of(work, struct vduse_dev, inject);
+ guard(rwsem_read)(&dev->rwsem);
+ if (dev->suspended)
+ return;
+
spin_lock_bh(&dev->irq_lock);
if (dev->config_cb.callback)
dev->config_cb.callback(dev->config_cb.private);
@@ -1159,6 +1227,10 @@ static void vduse_vq_irq_inject(struct work_struct *work)
struct vduse_virtqueue *vq = container_of(work,
struct vduse_virtqueue, inject);
+ guard(rwsem_read)(&vq->dev->rwsem);
+ if (vq->dev->suspended)
+ return;
+
spin_lock_bh(&vq->irq_lock);
if (vq->ready && vq->cb.callback)
vq->cb.callback(vq->cb.private);
@@ -1189,6 +1261,9 @@ static int vduse_dev_queue_irq_work(struct vduse_dev *dev,
int ret = -EINVAL;
down_read(&dev->rwsem);
+ if (dev->suspended)
+ return ret;
+
if (!(dev->status & VIRTIO_CONFIG_S_DRIVER_OK))
goto unlock;
@@ -1839,6 +1914,7 @@ static int vduse_dev_init_vqs(struct vduse_dev *dev, u32 vq_align, u32 vq_num)
}
dev->vqs[i]->index = i;
+ dev->vqs[i]->dev = dev;
dev->vqs[i]->irq_effective_cpu = IRQ_UNBOUND;
INIT_WORK(&dev->vqs[i]->inject, vduse_vq_irq_inject);
INIT_WORK(&dev->vqs[i]->kick, vduse_vq_kick_work);
@@ -2290,12 +2366,18 @@ static struct vduse_mgmt_dev *vduse_mgmt;
static int vduse_dev_init_vdpa(struct vduse_dev *dev, const char *name)
{
struct vduse_vdpa *vdev;
+ const struct vdpa_config_ops *ops;
if (dev->vdev)
return -EEXIST;
+ if (dev->vduse_features & BIT_U64(VDUSE_F_SUSPEND))
+ ops = &vduse_vdpa_config_ops_with_suspend;
+ else
+ ops = &vduse_vdpa_config_ops;
+
vdev = vdpa_alloc_device(struct vduse_vdpa, vdpa, dev->dev,
- &vduse_vdpa_config_ops, &vduse_map_ops,
+ ops, &vduse_map_ops,
dev->ngroups, dev->nas, name, true);
if (IS_ERR(vdev))
return PTR_ERR(vdev);
diff --git a/include/uapi/linux/vduse.h b/include/uapi/linux/vduse.h
index 7324faea5df4..8c616895c511 100644
--- a/include/uapi/linux/vduse.h
+++ b/include/uapi/linux/vduse.h
@@ -17,6 +17,9 @@
/* The VDUSE instance expects a request for vq ready */
#define VDUSE_F_QUEUE_READY 0
+/* The VDUSE instance expects a request for suspend */
+#define VDUSE_F_SUSPEND 1
+
/*
* Get the version of VDUSE API that kernel supported (VDUSE_API_VERSION).
* This is used for future extension.
@@ -334,6 +337,7 @@ enum vduse_req_type {
VDUSE_UPDATE_IOTLB,
VDUSE_SET_VQ_GROUP_ASID,
VDUSE_SET_VQ_READY,
+ VDUSE_SUSPEND,
};
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2] vduse: Add suspend
2026-03-10 19:10 [PATCH v2] vduse: Add suspend Eugenio Pérez
@ 2026-03-12 4:03 ` Jason Wang
2026-03-12 6:27 ` Eugenio Perez Martin
0 siblings, 1 reply; 4+ messages in thread
From: Jason Wang @ 2026-03-12 4:03 UTC (permalink / raw)
To: Eugenio Pérez
Cc: Michael S . Tsirkin, Xuan Zhuo, Yongji Xie, Cindy Lu,
Maxime Coquelin, Stefano Garzarella, linux-kernel, virtualization,
Laurent Vivier
On Wed, Mar 11, 2026 at 3:10 AM Eugenio Pérez <eperezma@redhat.com> wrote:
>
> Implement suspend operation for vduse devices, so vhost-vdpa will offer
> that backend feature and userspace can effectively suspend the device.
>
> This is a must before get virtqueue indexes (base) for live migration,
> since the device could modify them after userland gets them.
As discussed in the pervious version, let's explain why and the plan
to support resume.
>
> Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
> ---
> This patch depends on
> https://lore.kernel.org/lkml/20260310190759.1097506-1-eperezma@redhat.com
>
> v2:
> * Take the rwsem only before the actual kick, not in vduse_vdpa_kick_vq.
> This assures that we're not in a critical section.
> ---
> drivers/vdpa/vdpa_user/vduse_dev.c | 86 +++++++++++++++++++++++++++++-
> include/uapi/linux/vduse.h | 4 ++
> 2 files changed, 88 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> index 4f642b95a7cb..f56b1e3eb82d 100644
> --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> @@ -54,7 +54,8 @@
> #define IRQ_UNBOUND -1
>
> /* Supported VDUSE features */
> -static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY);
> +static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY) |
> + BIT_U64(VDUSE_F_SUSPEND);
>
> /*
> * VDUSE instance have not asked the vduse API version, so assume 0.
> @@ -85,6 +86,7 @@ struct vduse_virtqueue {
> int irq_effective_cpu;
> struct cpumask irq_affinity;
> struct kobject kobj;
> + struct vduse_dev *dev;
> };
>
> struct vduse_dev;
> @@ -134,6 +136,7 @@ struct vduse_dev {
> int minor;
> bool broken;
> bool connected;
> + bool suspended;
> u64 api_version;
> u64 device_features;
> u64 driver_features;
> @@ -480,6 +483,7 @@ static void vduse_dev_reset(struct vduse_dev *dev)
>
> down_write(&dev->rwsem);
>
> + dev->suspended = false;
> dev->status = 0;
> dev->driver_features = 0;
> dev->generation++;
> @@ -538,6 +542,10 @@ static void vduse_vq_kick(struct vduse_virtqueue *vq)
> if (!vq->ready)
> goto unlock;
>
> + guard(rwsem_read)(&vq->dev->rwsem);
> + if (vq->dev->suspended)
> + return;
Any reason for this? E.g We don't do this for other transports.
Everything else looks good.
Thanks
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] vduse: Add suspend
2026-03-12 4:03 ` Jason Wang
@ 2026-03-12 6:27 ` Eugenio Perez Martin
2026-03-13 5:57 ` Jason Wang
0 siblings, 1 reply; 4+ messages in thread
From: Eugenio Perez Martin @ 2026-03-12 6:27 UTC (permalink / raw)
To: Jason Wang
Cc: Michael S . Tsirkin, Xuan Zhuo, Yongji Xie, Cindy Lu,
Maxime Coquelin, Stefano Garzarella, linux-kernel, virtualization,
Laurent Vivier
On Thu, Mar 12, 2026 at 5:03 AM Jason Wang <jasowang@redhat.com> wrote:
>
> On Wed, Mar 11, 2026 at 3:10 AM Eugenio Pérez <eperezma@redhat.com> wrote:
> >
> > Implement suspend operation for vduse devices, so vhost-vdpa will offer
> > that backend feature and userspace can effectively suspend the device.
> >
> > This is a must before get virtqueue indexes (base) for live migration,
> > since the device could modify them after userland gets them.
>
> As discussed in the pervious version, let's explain why and the plan
> to support resume.
>
Is it ok to explain it just in the patch message or do you prefer
something like a /* TODO: resume op */ before the suspend callback?
> >
> > Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
> > ---
> > This patch depends on
> > https://lore.kernel.org/lkml/20260310190759.1097506-1-eperezma@redhat.com
> >
> > v2:
> > * Take the rwsem only before the actual kick, not in vduse_vdpa_kick_vq.
> > This assures that we're not in a critical section.
> > ---
> > drivers/vdpa/vdpa_user/vduse_dev.c | 86 +++++++++++++++++++++++++++++-
> > include/uapi/linux/vduse.h | 4 ++
> > 2 files changed, 88 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> > index 4f642b95a7cb..f56b1e3eb82d 100644
> > --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> > +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> > @@ -54,7 +54,8 @@
> > #define IRQ_UNBOUND -1
> >
> > /* Supported VDUSE features */
> > -static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY);
> > +static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY) |
> > + BIT_U64(VDUSE_F_SUSPEND);
> >
> > /*
> > * VDUSE instance have not asked the vduse API version, so assume 0.
> > @@ -85,6 +86,7 @@ struct vduse_virtqueue {
> > int irq_effective_cpu;
> > struct cpumask irq_affinity;
> > struct kobject kobj;
> > + struct vduse_dev *dev;
> > };
> >
> > struct vduse_dev;
> > @@ -134,6 +136,7 @@ struct vduse_dev {
> > int minor;
> > bool broken;
> > bool connected;
> > + bool suspended;
> > u64 api_version;
> > u64 device_features;
> > u64 driver_features;
> > @@ -480,6 +483,7 @@ static void vduse_dev_reset(struct vduse_dev *dev)
> >
> > down_write(&dev->rwsem);
> >
> > + dev->suspended = false;
> > dev->status = 0;
> > dev->driver_features = 0;
> > dev->generation++;
> > @@ -538,6 +542,10 @@ static void vduse_vq_kick(struct vduse_virtqueue *vq)
> > if (!vq->ready)
> > goto unlock;
> >
> > + guard(rwsem_read)(&vq->dev->rwsem);
> > + if (vq->dev->suspended)
> > + return;
>
> Any reason for this? E.g We don't do this for other transports.
>
It's just a hardening but I'm happy to remove it.
> Everything else looks good.
>
> Thanks
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2] vduse: Add suspend
2026-03-12 6:27 ` Eugenio Perez Martin
@ 2026-03-13 5:57 ` Jason Wang
0 siblings, 0 replies; 4+ messages in thread
From: Jason Wang @ 2026-03-13 5:57 UTC (permalink / raw)
To: Eugenio Perez Martin
Cc: Michael S . Tsirkin, Xuan Zhuo, Yongji Xie, Cindy Lu,
Maxime Coquelin, Stefano Garzarella, linux-kernel, virtualization,
Laurent Vivier
On Thu, Mar 12, 2026 at 2:28 PM Eugenio Perez Martin
<eperezma@redhat.com> wrote:
>
> On Thu, Mar 12, 2026 at 5:03 AM Jason Wang <jasowang@redhat.com> wrote:
> >
> > On Wed, Mar 11, 2026 at 3:10 AM Eugenio Pérez <eperezma@redhat.com> wrote:
> > >
> > > Implement suspend operation for vduse devices, so vhost-vdpa will offer
> > > that backend feature and userspace can effectively suspend the device.
> > >
> > > This is a must before get virtqueue indexes (base) for live migration,
> > > since the device could modify them after userland gets them.
> >
> > As discussed in the pervious version, let's explain why and the plan
> > to support resume.
> >
>
> Is it ok to explain it just in the patch message or do you prefer
> something like a /* TODO: resume op */ before the suspend callback?
Maybe, but I wonder why lacking resume can make thing like migration
work (e.g when migration fails, we should resume the device, or it's
workaround by reset + DRIVER_OK?).
>
> > >
> > > Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
> > > ---
> > > This patch depends on
> > > https://lore.kernel.org/lkml/20260310190759.1097506-1-eperezma@redhat.com
> > >
> > > v2:
> > > * Take the rwsem only before the actual kick, not in vduse_vdpa_kick_vq.
> > > This assures that we're not in a critical section.
> > > ---
> > > drivers/vdpa/vdpa_user/vduse_dev.c | 86 +++++++++++++++++++++++++++++-
> > > include/uapi/linux/vduse.h | 4 ++
> > > 2 files changed, 88 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
> > > index 4f642b95a7cb..f56b1e3eb82d 100644
> > > --- a/drivers/vdpa/vdpa_user/vduse_dev.c
> > > +++ b/drivers/vdpa/vdpa_user/vduse_dev.c
> > > @@ -54,7 +54,8 @@
> > > #define IRQ_UNBOUND -1
> > >
> > > /* Supported VDUSE features */
> > > -static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY);
> > > +static const uint64_t vduse_features = BIT_U64(VDUSE_F_QUEUE_READY) |
> > > + BIT_U64(VDUSE_F_SUSPEND);
> > >
> > > /*
> > > * VDUSE instance have not asked the vduse API version, so assume 0.
> > > @@ -85,6 +86,7 @@ struct vduse_virtqueue {
> > > int irq_effective_cpu;
> > > struct cpumask irq_affinity;
> > > struct kobject kobj;
> > > + struct vduse_dev *dev;
> > > };
> > >
> > > struct vduse_dev;
> > > @@ -134,6 +136,7 @@ struct vduse_dev {
> > > int minor;
> > > bool broken;
> > > bool connected;
> > > + bool suspended;
> > > u64 api_version;
> > > u64 device_features;
> > > u64 driver_features;
> > > @@ -480,6 +483,7 @@ static void vduse_dev_reset(struct vduse_dev *dev)
> > >
> > > down_write(&dev->rwsem);
> > >
> > > + dev->suspended = false;
> > > dev->status = 0;
> > > dev->driver_features = 0;
> > > dev->generation++;
> > > @@ -538,6 +542,10 @@ static void vduse_vq_kick(struct vduse_virtqueue *vq)
> > > if (!vq->ready)
> > > goto unlock;
> > >
> > > + guard(rwsem_read)(&vq->dev->rwsem);
> > > + if (vq->dev->suspended)
> > > + return;
> >
> > Any reason for this? E.g We don't do this for other transports.
> >
>
> It's just a hardening but I'm happy to remove it.
Either should be fine.
>
> > Everything else looks good.
> >
> > Thanks
> >
>
Thanks
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-03-13 5:57 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-10 19:10 [PATCH v2] vduse: Add suspend Eugenio Pérez
2026-03-12 4:03 ` Jason Wang
2026-03-12 6:27 ` Eugenio Perez Martin
2026-03-13 5:57 ` Jason Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox