[PATCH v2 4/6] vhost-net: vhost-user: update vhost_net_virtqueue_restart()

2022-09-11 Thread Kangjie Xu
Update vhost_net_virtqueue_restart() for vhost-user scenario.

In order to reuse some functions, we process the idx for
vhost-user case. It is because vhost_get_vq_index behave
differently in vhost-user.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 25e5665489..8b80942e7c 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -577,6 +577,9 @@ int vhost_net_virtqueue_restart(VirtIODevice *vdev, 
NetClientState *nc,
 assert(vhost_ops);
 
 idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+idx -= net->dev.vq_index;
+}
 
 r = vhost_virtqueue_start(>dev,
   vdev,
-- 
2.32.0




[PATCH v2 5/6] virtio-net: vhost-user: update queue_reset and queue_enable

2022-09-11 Thread Kangjie Xu
Update virtio_net_queue_reset() and virtio_net_queue_enable()
for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/virtio-net.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 6ab796b399..19a2132180 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -550,7 +550,8 @@ static void virtio_net_queue_reset(VirtIODevice *vdev, 
uint32_t queue_index)
 }
 
 if (get_vhost_net(nc->peer) &&
-nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+(nc->peer->info->type == NET_CLIENT_DRIVER_TAP ||
+ nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER)) {
 vhost_net_virtqueue_reset(vdev, nc, queue_index);
 }
 
@@ -568,7 +569,8 @@ static void virtio_net_queue_enable(VirtIODevice *vdev, 
uint32_t queue_index)
 }
 
 if (get_vhost_net(nc->peer) &&
-nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+(nc->peer->info->type == NET_CLIENT_DRIVER_TAP ||
+ nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER)) {
 r = vhost_net_virtqueue_restart(vdev, nc, queue_index);
 if (r < 0) {
 error_report("unable to restart vhost net virtqueue: %d, "
-- 
2.32.0




[PATCH v2 3/6] vhost-net: vhost-user: update vhost_net_virtqueue_reset()

2022-09-11 Thread Kangjie Xu
Update vhost_net_virtqueue_reset() for vhost-user scenario.

In order to reuse some functions, we process the idx for
vhost-user scenario because vhost_get_vq_index behave
differently for vhost-user.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index ea896ea75b..25e5665489 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -545,6 +545,9 @@ void vhost_net_virtqueue_reset(VirtIODevice *vdev, 
NetClientState *nc,
 assert(vhost_ops);
 
 idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+idx -= net->dev.vq_index;
+}
 
 if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
 file.index = idx;
-- 
2.32.0




[PATCH v2 6/6] vhost: vhost-user: enable vq reset feature

2022-09-11 Thread Kangjie Xu
Add virtqueue reset feature for vhost-user.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 8b80942e7c..ad319faee8 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -74,6 +74,7 @@ static const int user_feature_bits[] = {
 VIRTIO_NET_F_MTU,
 VIRTIO_F_IOMMU_PLATFORM,
 VIRTIO_F_RING_PACKED,
+VIRTIO_F_RING_RESET,
 VIRTIO_NET_F_RSS,
 VIRTIO_NET_F_HASH_REPORT,
 
-- 
2.32.0




[PATCH v2 0/6] Support VIRTIO_F_RING_RESET for vhost-user in virtio pci-modern

2022-09-11 Thread Kangjie Xu
This patch set is based on the patch set that supports VIRTIO_F_RING_RESET for 
vhost-kernel:

https://lore.kernel.org/qemu-devel/cover.1662916759.git.kangjie...@linux.alibaba.com/

The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:
https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

The detailed process is listed below:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> vhost_net_virtqueue_reset() [vhost-net]
-> vhost_virtqueue_stop()
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> virtio_queue_enable() [virtio]
-> virtio_net_queue_enable() [virtio-net]
-> vhost_net_virtqueue_restart() [vhost-net]
-> vhost_virtqueue_start()
-> vhost_user_set_vring_enable [vhost-user]
-> send VHOST_USER_SET_VRING_ENABLE to the device
-> set enabled, reset status of vq.

changelog:
  1. Reuse the vhost_virtqueue_stop() when resetting a vq.

Test environment:
Qemu: QEMU emulator version 7.1.50
Guest: 5.19.0-rc3 (With vq reset support)
DPDK: 22.11-rc0 (With vq reset support)
Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

The drvier can resize the virtio queue, then virtio queue reset function 
should
be triggered.

The default is split mode, modify Qemu virtio-net to add PACKED feature to 
test packed mode.

Guest Kernel Patch:

https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

DPDK Patch:

https://github.com/middaywords/dpdk/compare/72206323a5dd3182b13f61b25a64abdddfee595c...080d9d5a6bba8ff8dce5186e2c6cb35cabef77c9

Kangjie Xu (6):
  net: virtio: rename vhost_set_vring_enable to vhost_set_dev_enable
  vhost-user: add op to enable or disable a single vring
  vhost-net: vhost-user: update vhost_net_virtqueue_reset()
  vhost-net: vhost-user: update vhost_net_virtqueue_restart()
  virtio-net: vhost-user: update queue_reset and queue_enable
  vhost: vhost-user: enable vq reset feature

 backends/cryptodev-vhost.c| 12 ++--
 hw/net/vhost_net-stub.c   |  2 +-
 hw/net/vhost_net.c| 15 +++
 hw/net/virtio-net.c   | 10 ++
 hw/virtio/vhost-user.c| 27 +++
 include/hw/virtio/vhost-backend.h |  5 -
 include/net/vhost_net.h   |  2 +-
 7 files changed, 48 insertions(+), 25 deletions(-)

-- 
2.32.0




[PATCH v2 2/6] vhost-user: add op to enable or disable a single vring

2022-09-11 Thread Kangjie Xu
There is only vhost_set_dev_enable op in VhostOps. Thus, we introduce
the interface vhost_set_vring_enable to set the enable status for a
single vring.

Resetting a single vq will rely on this interface.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost-user.c| 25 ++---
 include/hw/virtio/vhost-backend.h |  3 +++
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 794519359b..3f140d5085 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1198,6 +1198,22 @@ static int vhost_user_set_vring_base(struct vhost_dev 
*dev,
 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
 }
 
+static int vhost_user_set_vring_enable(struct vhost_dev *dev,
+   int index,
+   int enable)
+{
+if (index < dev->vq_index || index >= dev->vq_index + dev->nvqs) {
+return -EINVAL;
+}
+
+struct vhost_vring_state state = {
+.index = index,
+.num   = enable,
+};
+
+return vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+}
+
 static int vhost_user_set_dev_enable(struct vhost_dev *dev, int enable)
 {
 int i;
@@ -1207,13 +1223,7 @@ static int vhost_user_set_dev_enable(struct vhost_dev 
*dev, int enable)
 }
 
 for (i = 0; i < dev->nvqs; ++i) {
-int ret;
-struct vhost_vring_state state = {
-.index = dev->vq_index + i,
-.num   = enable,
-};
-
-ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+int ret = vhost_user_set_vring_enable(dev, dev->vq_index + i, enable);
 if (ret < 0) {
 /*
  * Restoring the previous state is likely infeasible, as well as
@@ -2627,6 +2637,7 @@ const VhostOps user_ops = {
 .vhost_set_owner = vhost_user_set_owner,
 .vhost_reset_device = vhost_user_reset_device,
 .vhost_get_vq_index = vhost_user_get_vq_index,
+.vhost_set_vring_enable = vhost_user_set_vring_enable,
 .vhost_set_dev_enable = vhost_user_set_dev_enable,
 .vhost_requires_shm_log = vhost_user_requires_shm_log,
 .vhost_migration_done = vhost_user_migration_done,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h
index b49432045f..dad7191bac 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -81,6 +81,8 @@ typedef int (*vhost_set_backend_cap_op)(struct vhost_dev 
*dev);
 typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
 typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
 typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
+typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
+ int index, int enable);
 typedef int (*vhost_set_dev_enable_op)(struct vhost_dev *dev,
int enable);
 typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
@@ -155,6 +157,7 @@ typedef struct VhostOps {
 vhost_set_owner_op vhost_set_owner;
 vhost_reset_device_op vhost_reset_device;
 vhost_get_vq_index_op vhost_get_vq_index;
+vhost_set_vring_enable_op vhost_set_vring_enable;
 vhost_set_dev_enable_op vhost_set_dev_enable;
 vhost_requires_shm_log_op vhost_requires_shm_log;
 vhost_migration_done_op vhost_migration_done;
-- 
2.32.0




[PATCH v2 1/6] net: virtio: rename vhost_set_vring_enable to vhost_set_dev_enable

2022-09-11 Thread Kangjie Xu
Previously, vhost_set_vring_enable will enable/disable all vrings
in a device, which causes ambiguity. So we rename it to
vhost_set_dev_enable.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 backends/cryptodev-vhost.c| 12 ++--
 hw/net/vhost_net-stub.c   |  2 +-
 hw/net/vhost_net.c|  8 
 hw/net/virtio-net.c   |  4 ++--
 hw/virtio/vhost-user.c|  4 ++--
 include/hw/virtio/vhost-backend.h |  6 +++---
 include/net/vhost_net.h   |  2 +-
 7 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/backends/cryptodev-vhost.c b/backends/cryptodev-vhost.c
index bc13e466b4..b83e939760 100644
--- a/backends/cryptodev-vhost.c
+++ b/backends/cryptodev-vhost.c
@@ -147,9 +147,9 @@ cryptodev_vhost_set_vq_index(CryptoDevBackendVhost *crypto,
 }
 
 static int
-vhost_set_vring_enable(CryptoDevBackendClient *cc,
-CryptoDevBackend *b,
-uint16_t queue, int enable)
+vhost_set_dev_enable(CryptoDevBackendClient *cc,
+ CryptoDevBackend *b,
+ uint16_t queue, int enable)
 {
 CryptoDevBackendVhost *crypto =
cryptodev_get_vhost(cc, b, queue);
@@ -162,8 +162,8 @@ vhost_set_vring_enable(CryptoDevBackendClient *cc,
 }
 
 vhost_ops = crypto->dev.vhost_ops;
-if (vhost_ops->vhost_set_vring_enable) {
-return vhost_ops->vhost_set_vring_enable(>dev, enable);
+if (vhost_ops->vhost_set_dev_enable) {
+return vhost_ops->vhost_set_dev_enable(>dev, enable);
 }
 
 return 0;
@@ -219,7 +219,7 @@ int cryptodev_vhost_start(VirtIODevice *dev, int 
total_queues)
 
 if (cc->vring_enable) {
 /* restore vring enable state */
-r = vhost_set_vring_enable(cc, b, i, cc->vring_enable);
+r = vhost_set_dev_enable(cc, b, i, cc->vring_enable);
 
 if (r < 0) {
 goto err_start;
diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c
index 89d71cfb8e..ac5f217dc1 100644
--- a/hw/net/vhost_net-stub.c
+++ b/hw/net/vhost_net-stub.c
@@ -92,7 +92,7 @@ VHostNetState *get_vhost_net(NetClientState *nc)
 return 0;
 }
 
-int vhost_set_vring_enable(NetClientState *nc, int enable)
+int vhost_set_dev_enable(NetClientState *nc, int enable)
 {
 return 0;
 }
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 97cdf9280b..ea896ea75b 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -396,7 +396,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
 
 if (peer->vring_enable) {
 /* restore vring enable state */
-r = vhost_set_vring_enable(peer, peer->vring_enable);
+r = vhost_set_dev_enable(peer, peer->vring_enable);
 
 if (r < 0) {
 vhost_net_stop_one(get_vhost_net(peer), dev);
@@ -508,15 +508,15 @@ VHostNetState *get_vhost_net(NetClientState *nc)
 return vhost_net;
 }
 
-int vhost_set_vring_enable(NetClientState *nc, int enable)
+int vhost_set_dev_enable(NetClientState *nc, int enable)
 {
 VHostNetState *net = get_vhost_net(nc);
 const VhostOps *vhost_ops = net->dev.vhost_ops;
 
 nc->vring_enable = enable;
 
-if (vhost_ops && vhost_ops->vhost_set_vring_enable) {
-return vhost_ops->vhost_set_vring_enable(>dev, enable);
+if (vhost_ops && vhost_ops->vhost_set_dev_enable) {
+return vhost_ops->vhost_set_dev_enable(>dev, enable);
 }
 
 return 0;
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 7817206596..6ab796b399 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -696,7 +696,7 @@ static int peer_attach(VirtIONet *n, int index)
 }
 
 if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
-vhost_set_vring_enable(nc->peer, 1);
+vhost_set_dev_enable(nc->peer, 1);
 }
 
 if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) {
@@ -719,7 +719,7 @@ static int peer_detach(VirtIONet *n, int index)
 }
 
 if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
-vhost_set_vring_enable(nc->peer, 0);
+vhost_set_dev_enable(nc->peer, 0);
 }
 
 if (nc->peer->info->type !=  NET_CLIENT_DRIVER_TAP) {
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index bd24741be8..794519359b 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1198,7 +1198,7 @@ static int vhost_user_set_vring_base(struct vhost_dev 
*dev,
 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
 }
 
-static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
+static int vhost_user_set_dev_enable(struct vhost_dev *dev, int enable)
 {
 int i;
 
@@ -2627,7 +2627,7 @@ const VhostOps user_ops = {
 .vhost_set_owner = vhost_user_set_owner,
 .vhost_reset_device = vhost_user

[PATCH v4 14/15] virtio-net: support queue_enable

2022-09-11 Thread Kangjie Xu
Support queue_enable in vhost-kernel scenario. It can be called when
a vq reset operation has been performed and the vq is restared.

It should be noted that we can restart the vq when the vhost has
already started. When launching a new vhost device, the vhost is not
started and all vqs are not initalized until VIRTIO_PCI_COMMON_STATUS
is written. Thus, we should use vhost_started to differentiate the
two cases: vq reset and device start.

Currently it only supports vhost-kernel.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/virtio-net.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index d774a3e652..7817206596 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -557,6 +557,26 @@ static void virtio_net_queue_reset(VirtIODevice *vdev, 
uint32_t queue_index)
 flush_or_purge_queued_packets(nc);
 }
 
+static void virtio_net_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtIONet *n = VIRTIO_NET(vdev);
+NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+int r;
+
+if (!nc->peer || !vdev->vhost_started) {
+return;
+}
+
+if (get_vhost_net(nc->peer) &&
+nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+r = vhost_net_virtqueue_restart(vdev, nc, queue_index);
+if (r < 0) {
+error_report("unable to restart vhost net virtqueue: %d, "
+"when resetting the queue", queue_index);
+}
+}
+}
+
 static void virtio_net_reset(VirtIODevice *vdev)
 {
 VirtIONet *n = VIRTIO_NET(vdev);
@@ -3802,6 +3822,7 @@ static void virtio_net_class_init(ObjectClass *klass, 
void *data)
 vdc->bad_features = virtio_net_bad_features;
 vdc->reset = virtio_net_reset;
 vdc->queue_reset = virtio_net_queue_reset;
+vdc->queue_enable = virtio_net_queue_enable;
 vdc->set_status = virtio_net_set_status;
 vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
 vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
-- 
2.32.0




[PATCH v4 11/15] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()

2022-09-11 Thread Kangjie Xu
Introduce vhost_net_virtqueue_restart(), which can restart the
specific virtqueue when the vhost net started running before.
If it fails to restart the virtqueue, the device will be stopped.

Here we do not reuse vhost_net_start_one() or vhost_dev_start()
because they work at queue pair level. The mem table and features
do not change, so we can call the vhost_virtqueue_start() to
restart a specific queue.

This patch only considers the case of vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c  | 52 +
 include/net/vhost_net.h |  2 ++
 2 files changed, 54 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 8beecb4d22..1059aa45b4 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -556,3 +556,55 @@ void vhost_net_virtqueue_reset(VirtIODevice *vdev, 
NetClientState *nc,
  net->dev.vqs + idx,
  net->dev.vq_index + idx);
 }
+
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+int vq_index)
+{
+VHostNetState *net = get_vhost_net(nc->peer);
+const VhostOps *vhost_ops = net->dev.vhost_ops;
+struct vhost_vring_file file = { };
+int idx, r;
+
+if (!net->dev.started) {
+return -ENOTSUP;
+}
+
+/* should only be called after backend is connected */
+assert(vhost_ops);
+
+idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+r = vhost_virtqueue_start(>dev,
+  vdev,
+  net->dev.vqs + idx,
+  net->dev.vq_index + idx);
+if (r < 0) {
+goto err_start;
+}
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.index = idx;
+file.fd = net->backend;
+r = vhost_net_set_backend(>dev, );
+if (r < 0) {
+r = -errno;
+goto err_start;
+}
+}
+
+return 0;
+
+err_start:
+error_report("Error when restarting the queue.");
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.fd = -1;
+file.index = idx;
+int r = vhost_net_set_backend(>dev, );
+assert(r >= 0);
+}
+
+vhost_dev_stop(>dev, vdev);
+
+return r;
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 85d85a4957..40b9a40074 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -50,4 +50,6 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
 
 void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
int vq_index);
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+int vq_index);
 #endif
-- 
2.32.0




[PATCH v4 05/15] virtio: core: vq reset feature negotation support

2022-09-11 Thread Kangjie Xu
A a new command line parameter "queue_reset" is added.

Meanwhile, the vq reset feature is disabled for pre-7.2 machines.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/core/machine.c  | 4 +++-
 include/hw/virtio/virtio.h | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index aa520e74a8..907fa78ff0 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -40,7 +40,9 @@
 #include "hw/virtio/virtio-pci.h"
 #include "qom/object_interfaces.h"
 
-GlobalProperty hw_compat_7_1[] = {};
+GlobalProperty hw_compat_7_1[] = {
+{ "virtio-device", "queue_reset", "false" },
+};
 const size_t hw_compat_7_1_len = G_N_ELEMENTS(hw_compat_7_1);
 
 GlobalProperty hw_compat_7_0[] = {
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 085997d8f3..ed3ecbef80 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -295,7 +295,9 @@ typedef struct VirtIORNGConf VirtIORNGConf;
 DEFINE_PROP_BIT64("iommu_platform", _state, _field, \
   VIRTIO_F_IOMMU_PLATFORM, false), \
 DEFINE_PROP_BIT64("packed", _state, _field, \
-  VIRTIO_F_RING_PACKED, false)
+  VIRTIO_F_RING_PACKED, false), \
+DEFINE_PROP_BIT64("queue_reset", _state, _field, \
+  VIRTIO_F_RING_RESET, true)
 
 hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
 bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n);
-- 
2.32.0




[PATCH v4 12/15] virtio-net: introduce flush_or_purge_queued_packets()

2022-09-11 Thread Kangjie Xu
Introduce the fucntion flush_or_purge_queued_packets(), it will be
used in device reset and virtqueue reset. Therefore, we extract the
common logic as a new function.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/net/virtio-net.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index dd0d056fde..27b59c0ad6 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -118,6 +118,16 @@ static int vq2q(int queue_index)
 return queue_index / 2;
 }
 
+static void flush_or_purge_queued_packets(NetClientState *nc)
+{
+if (!nc->peer) {
+return;
+}
+
+qemu_flush_or_purge_queued_packets(nc->peer, true);
+assert(!virtio_net_get_subqueue(nc)->async_tx.elem);
+}
+
 /* TODO
  * - we could suppress RX interrupt if we were so inclined.
  */
@@ -560,12 +570,7 @@ static void virtio_net_reset(VirtIODevice *vdev)
 
 /* Flush any async TX */
 for (i = 0;  i < n->max_queue_pairs; i++) {
-NetClientState *nc = qemu_get_subqueue(n->nic, i);
-
-if (nc->peer) {
-qemu_flush_or_purge_queued_packets(nc->peer, true);
-assert(!virtio_net_get_subqueue(nc)->async_tx.elem);
-}
+flush_or_purge_queued_packets(qemu_get_subqueue(n->nic, i));
 }
 }
 
-- 
2.32.0




[PATCH v4 10/15] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_reset()

2022-09-11 Thread Kangjie Xu
Introduce vhost_virtqueue_reset(), which can reset the specific
virtqueue in the device. Then it will unmap vrings and the desc
of the virtqueue.

Here we do not reuse the vhost_net_stop_one() or vhost_dev_stop(),
because they work at queue pair level. We do not use
vhost_virtqueue_stop() because it may stop the device in the
backend.

This patch only considers the case of vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Furthermore, we do not need net->nc->info->poll() because
it enables userspace datapath and we want to stop all
datapaths for this reset virtqueue here.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c  | 25 +
 include/net/vhost_net.h |  2 ++
 2 files changed, 27 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index d28f8b974b..8beecb4d22 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -531,3 +531,28 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
 
 return vhost_ops->vhost_net_set_mtu(>dev, mtu);
 }
+
+void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
+   int vq_index)
+{
+VHostNetState *net = get_vhost_net(nc->peer);
+const VhostOps *vhost_ops = net->dev.vhost_ops;
+struct vhost_vring_file file = { .fd = -1 };
+int idx;
+
+/* should only be called after backend is connected */
+assert(vhost_ops);
+
+idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.index = idx;
+int r = vhost_net_set_backend(>dev, );
+assert(r >= 0);
+}
+
+vhost_virtqueue_stop(>dev,
+ vdev,
+ net->dev.vqs + idx,
+ net->dev.vq_index + idx);
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 387e913e4e..85d85a4957 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -48,4 +48,6 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net);
 
 int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
 
+void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
+   int vq_index);
 #endif
-- 
2.32.0




[PATCH v4 13/15] virtio-net: support queue reset

2022-09-11 Thread Kangjie Xu
From: Xuan Zhuo 

virtio-net and vhost-kernel implement queue reset.
Queued packets in the corresponding queue pair are flushed
or purged.

For virtio-net, userspace datapath will be disabled later in
__virtio_queue_reset(). It will set addr of vring to 0 and idx to 0.
Thus, virtio_net_receive() and virtio_net_flush_tx() will not receive
or send packets.

For vhost-net, the datapath will be disabled in vhost_net_virtqueue_reset().

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
 hw/net/virtio-net.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 27b59c0ad6..d774a3e652 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -540,6 +540,23 @@ static RxFilterInfo 
*virtio_net_query_rxfilter(NetClientState *nc)
 return info;
 }
 
+static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtIONet *n = VIRTIO_NET(vdev);
+NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+
+if (!nc->peer) {
+return;
+}
+
+if (get_vhost_net(nc->peer) &&
+nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+vhost_net_virtqueue_reset(vdev, nc, queue_index);
+}
+
+flush_or_purge_queued_packets(nc);
+}
+
 static void virtio_net_reset(VirtIODevice *vdev)
 {
 VirtIONet *n = VIRTIO_NET(vdev);
@@ -3784,6 +3801,7 @@ static void virtio_net_class_init(ObjectClass *klass, 
void *data)
 vdc->set_features = virtio_net_set_features;
 vdc->bad_features = virtio_net_bad_features;
 vdc->reset = virtio_net_reset;
+vdc->queue_reset = virtio_net_queue_reset;
 vdc->set_status = virtio_net_set_status;
 vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
 vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
-- 
2.32.0




[PATCH v4 09/15] vhost: expose vhost_virtqueue_stop()

2022-09-11 Thread Kangjie Xu
Expose vhost_virtqueue_stop(), we need to use it when resetting a
virtqueue.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 8 
 include/hw/virtio/vhost.h | 2 ++
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 7900bc81ab..5407f60226 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1201,10 +1201,10 @@ fail_alloc_desc:
 return r;
 }
 
-static void vhost_virtqueue_stop(struct vhost_dev *dev,
-struct VirtIODevice *vdev,
-struct vhost_virtqueue *vq,
-unsigned idx)
+void vhost_virtqueue_stop(struct vhost_dev *dev,
+  struct VirtIODevice *vdev,
+  struct vhost_virtqueue *vq,
+  unsigned idx)
 {
 int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx);
 struct vhost_vring_state state = {
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index b092f57d98..2b168b2269 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -281,6 +281,8 @@ int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t 
iova, int write);
 
 int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev,
   struct vhost_virtqueue *vq, unsigned idx);
+void vhost_virtqueue_stop(struct vhost_dev *dev, struct VirtIODevice *vdev,
+  struct vhost_virtqueue *vq, unsigned idx);
 
 void vhost_dev_reset_inflight(struct vhost_inflight *inflight);
 void vhost_dev_free_inflight(struct vhost_inflight *inflight);
-- 
2.32.0




[PATCH v4 03/15] virtio: introduce virtio_queue_reset()

2022-09-11 Thread Kangjie Xu
From: Xuan Zhuo 

Introduce a new interface function virtio_queue_reset() to implement
reset for vq.

Add a new callback to VirtioDeviceClass for queue reset operation for
each child device.

Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/virtio.c | 11 +++
 include/hw/virtio/virtio.h |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 67d54832a9..0e9d41366f 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2039,6 +2039,17 @@ static void __virtio_queue_reset(VirtIODevice *vdev, 
uint32_t i)
 virtio_virtqueue_reset_region_cache(>vq[i]);
 }
 
+void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+
+if (k->queue_reset) {
+k->queue_reset(vdev, queue_index);
+}
+
+__virtio_queue_reset(vdev, queue_index);
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index db1c0ddf6b..879394299b 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -130,6 +130,7 @@ struct VirtioDeviceClass {
 void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
 void (*reset)(VirtIODevice *vdev);
 void (*set_status)(VirtIODevice *vdev, uint8_t val);
+void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index);
 /* For transitional devices, this is a bitmap of features
  * that are only exposed on the legacy interface but not
  * the modern one.
@@ -268,6 +269,7 @@ int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, 
int n,
   MemoryRegion *mr, bool assign);
 int virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
+void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index);
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint64_t val);
 
-- 
2.32.0




[PATCH v4 00/15] Support VIRTIO_F_RING_RESET for virtio-net, vhost-net kernel in virtio pci-modern

2022-09-11 Thread Kangjie Xu
The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-11 support vq reset and vq restart for vhost-kernel.
3. Patches 12-14 support vq reset and vq restart for virtio-net.
5. Patch 15 enables the vq reset feature for vhost-kernel.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

Since this patch set involves multiple modules and seems a bit messy, we 
briefly describe the
calling process for different modes below.
virtio-net:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> set enabled, reset status of vq.

vhost-kernel:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> vhost_net_virtqueue_stop() [vhost-net]
-> vhost_net_set_backend() [vhost]
-> vhost_virtqueue_stop()
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> virtio_queue_enable() [virtio]
-> virtio_net_queue_enable() [virtio-net]
-> vhost_net_virtqueue_restart() [vhost-net]
-> vhost_virtqueue_start() [vhost]
-> vhost_net_set_backend()
-> set enabled, reset status of vq.


Test environment and method:
Host: 5.19.0-rc3 (With vq reset support)
Qemu: QEMU emulator version 7.0.50
Guest: 5.19.0-rc3 (With vq reset support)
Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

The drvier can resize the virtio queue, then virtio queue reset function 
should
be triggered.

The default is split mode, modify Qemu virtio-net to add PACKED feature to
test packed mode.

Guest Kernel Patch:

https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

Host Kernel Patch:

https://lore.kernel.org/bpf/20220825085610.80315-1-kangjie...@linux.alibaba.com/

Looking forward to your review and comments. Thanks.

changelog:
v4:
  1. Add explanation for preventing userspace datapath in virtio-net.
  2. Return error when vhost is not started in vhost_net_virtqueue_restart().
  3. Reset the virtqueue in the device reusing vhost_virtqueue_stop().
  4. Disable queue reset feature for pre-7.2 machine.

v3:
  1. Remove support for vhost-user in this series and refactor the code.
  2. Rename 'vhost_net_virtqueue_stop' to 'vhost_net_virtqueue_reset'.
  3. Make PCI transport ready before device ready when queue_enabled is set to 
true.
  4. Add some comments.

v2:
  1. Add support for vhost-net kernel scenario.
  2. Add a new vhost-user message VHOST_USER_RESET_VRING.
  3. Add migration compatibility for virtqueue reset.

Kangjie Xu (10):
  virtio: introduce virtio_queue_enable()
  virtio: core: vq reset feature negotation support
  virtio-pci: support queue enable
  vhost: expose vhost_virtqueue_start()
  vhost: expose vhost_virtqueue_stop()
  vhost-net: vhost-kernel: introduce vhost_net_virtqueue_reset()
  vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()
  virtio-net: introduce flush_or_purge_queued_packets()
  virtio-net: support queue_enable
  vhost: vhost-kernel: enable vq reset feature

Xuan Zhuo (5):
  virtio: sync relevant definitions with linux
  virtio: introduce __virtio_queue_reset()
  virtio: introduce virtio_queue_reset()
  virtio-pci: support queue reset
  virtio-net: support queue reset

 hw/core/machine.c |  4 +-
 hw/net/vhost_net.c| 78 +++
 hw/net/virtio-net.c   | 56 +++--
 hw/virtio/vhost.c | 16 ++--
 hw/virtio/virtio-pci.c| 16 
 hw/virtio/virtio.c| 62 +++
 include/hw/virtio/vhost.h |  5 ++
 include/hw/virtio/virtio-pci.h|  5 ++
 include/hw/virtio/virtio.h|  8 +-
 include/net/vhost_net.h   |  4 +
 .../standard-headers/linux/virtio_config.h|  5 ++
 include/standard-headers/linux/virtio_pci.h   |  2 +
 12 files changed, 229 insertions(+), 32 deletions(-)

-- 
2.32.0




[PATCH v4 07/15] virtio-pci: support queue enable

2022-09-11 Thread Kangjie Xu
PCI devices support device specific vq enable.

Based on this function, the driver can re-enable the virtqueue after the
virtqueue is reset.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/virtio-pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 79b9e641dd..a53b5d9f1e 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1342,6 +1342,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
proxy->vqs[vdev->queue_sel].used[0]);
 proxy->vqs[vdev->queue_sel].enabled = 1;
 proxy->vqs[vdev->queue_sel].reset = 0;
+virtio_queue_enable(vdev, vdev->queue_sel);
 } else {
 virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val);
 }
-- 
2.32.0




[PATCH v4 02/15] virtio: introduce __virtio_queue_reset()

2022-09-11 Thread Kangjie Xu
From: Xuan Zhuo 

Separate the logic of vq reset. This logic will be called directly
later.

Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/virtio.c | 37 +
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 5d607aeaa0..67d54832a9 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2019,6 +2019,26 @@ static enum virtio_device_endian 
virtio_current_cpu_endian(void)
 }
 }
 
+static void __virtio_queue_reset(VirtIODevice *vdev, uint32_t i)
+{
+vdev->vq[i].vring.desc = 0;
+vdev->vq[i].vring.avail = 0;
+vdev->vq[i].vring.used = 0;
+vdev->vq[i].last_avail_idx = 0;
+vdev->vq[i].shadow_avail_idx = 0;
+vdev->vq[i].used_idx = 0;
+vdev->vq[i].last_avail_wrap_counter = true;
+vdev->vq[i].shadow_avail_wrap_counter = true;
+vdev->vq[i].used_wrap_counter = true;
+virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
+vdev->vq[i].signalled_used = 0;
+vdev->vq[i].signalled_used_valid = false;
+vdev->vq[i].notification = true;
+vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
+vdev->vq[i].inuse = 0;
+virtio_virtqueue_reset_region_cache(>vq[i]);
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
@@ -2050,22 +2070,7 @@ void virtio_reset(void *opaque)
 virtio_notify_vector(vdev, vdev->config_vector);
 
 for(i = 0; i < VIRTIO_QUEUE_MAX; i++) {
-vdev->vq[i].vring.desc = 0;
-vdev->vq[i].vring.avail = 0;
-vdev->vq[i].vring.used = 0;
-vdev->vq[i].last_avail_idx = 0;
-vdev->vq[i].shadow_avail_idx = 0;
-vdev->vq[i].used_idx = 0;
-vdev->vq[i].last_avail_wrap_counter = true;
-vdev->vq[i].shadow_avail_wrap_counter = true;
-vdev->vq[i].used_wrap_counter = true;
-virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
-vdev->vq[i].signalled_used = 0;
-vdev->vq[i].signalled_used_valid = false;
-vdev->vq[i].notification = true;
-vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
-vdev->vq[i].inuse = 0;
-virtio_virtqueue_reset_region_cache(>vq[i]);
+__virtio_queue_reset(vdev, i);
 }
 }
 
-- 
2.32.0




[PATCH v4 06/15] virtio-pci: support queue reset

2022-09-11 Thread Kangjie Xu
From: Xuan Zhuo 

PCI devices support vq reset.

Based on this function, the driver can adjust the size of the ring, and
quickly recycle the buffer in the ring.

The migration of the virtio devices will not happen during a reset
operation. This is becuase the global iothread lock is held. Migration
thread also needs the lock. As a result, when migration of virtio
devices starts, the 'reset' status of VirtIOPCIQueue will always be 0.
Thus, we do not need to add it in vmstate_virtio_pci_modern_queue_state.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
Acked-by: Jason Wang 
---
 hw/virtio/virtio-pci.c | 15 +++
 include/hw/virtio/virtio-pci.h |  5 +
 2 files changed, 20 insertions(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index a50c5a57d7..79b9e641dd 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1251,6 +1251,9 @@ static uint64_t virtio_pci_common_read(void *opaque, 
hwaddr addr,
 case VIRTIO_PCI_COMMON_Q_USEDHI:
 val = proxy->vqs[vdev->queue_sel].used[1];
 break;
+case VIRTIO_PCI_COMMON_Q_RESET:
+val = proxy->vqs[vdev->queue_sel].reset;
+break;
 default:
 val = 0;
 }
@@ -1338,6 +1341,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
 proxy->vqs[vdev->queue_sel].enabled = 1;
+proxy->vqs[vdev->queue_sel].reset = 0;
 } else {
 virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val);
 }
@@ -1360,6 +1364,16 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
 case VIRTIO_PCI_COMMON_Q_USEDHI:
 proxy->vqs[vdev->queue_sel].used[1] = val;
 break;
+case VIRTIO_PCI_COMMON_Q_RESET:
+if (val == 1) {
+proxy->vqs[vdev->queue_sel].reset = 1;
+
+virtio_queue_reset(vdev, vdev->queue_sel);
+
+proxy->vqs[vdev->queue_sel].reset = 0;
+proxy->vqs[vdev->queue_sel].enabled = 0;
+}
+break;
 default:
 break;
 }
@@ -1954,6 +1968,7 @@ static void virtio_pci_reset(DeviceState *qdev)
 
 for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
 proxy->vqs[i].enabled = 0;
+proxy->vqs[i].reset = 0;
 proxy->vqs[i].num = 0;
 proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
 proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
index 2446dcd9ae..938799e8f6 100644
--- a/include/hw/virtio/virtio-pci.h
+++ b/include/hw/virtio/virtio-pci.h
@@ -117,6 +117,11 @@ typedef struct VirtIOPCIRegion {
 typedef struct VirtIOPCIQueue {
   uint16_t num;
   bool enabled;
+  /*
+   * No need to migrate the reset status, because it is always 0
+   * when the migration starts.
+   */
+  bool reset;
   uint32_t desc[2];
   uint32_t avail[2];
   uint32_t used[2];
-- 
2.32.0




[PATCH v4 01/15] virtio: sync relevant definitions with linux

2022-09-11 Thread Kangjie Xu
From: Xuan Zhuo 

This is updated using scripts/update-linux-headers.sh.

Added VIRTIO_F_RING_RESET, VIRTIO_PCI_COMMON_Q_RESET. It came from here:
https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

Add VIRTIO_PCI_COMMON_Q_NDATA, which comes from here:
https://github.com/oasis-tcs/virtio-spec/issues/89

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
Acked-by: Jason Wang 
---
 include/standard-headers/linux/virtio_config.h | 5 +
 include/standard-headers/linux/virtio_pci.h| 2 ++
 2 files changed, 7 insertions(+)

diff --git a/include/standard-headers/linux/virtio_config.h 
b/include/standard-headers/linux/virtio_config.h
index 7acd8d4abc..47a7eef5e4 100644
--- a/include/standard-headers/linux/virtio_config.h
+++ b/include/standard-headers/linux/virtio_config.h
@@ -96,4 +96,9 @@
  * Does the device support Single Root I/O Virtualization?
  */
 #define VIRTIO_F_SR_IOV37
+
+/*
+ * This feature indicates that the driver can reset a queue individually.
+ */
+#define VIRTIO_F_RING_RESET40
 #endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/standard-headers/linux/virtio_pci.h 
b/include/standard-headers/linux/virtio_pci.h
index db7a8e2fcb..be912cfc95 100644
--- a/include/standard-headers/linux/virtio_pci.h
+++ b/include/standard-headers/linux/virtio_pci.h
@@ -202,6 +202,8 @@ struct virtio_pci_cfg_cap {
 #define VIRTIO_PCI_COMMON_Q_AVAILHI44
 #define VIRTIO_PCI_COMMON_Q_USEDLO 48
 #define VIRTIO_PCI_COMMON_Q_USEDHI 52
+#define VIRTIO_PCI_COMMON_Q_NDATA  56
+#define VIRTIO_PCI_COMMON_Q_RESET  58
 
 #endif /* VIRTIO_PCI_NO_MODERN */
 
-- 
2.32.0




[PATCH v4 08/15] vhost: expose vhost_virtqueue_start()

2022-09-11 Thread Kangjie Xu
Expose vhost_virtqueue_start(), we need to use it when restarting a
virtqueue.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 8 
 include/hw/virtio/vhost.h | 3 +++
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index f758f177bb..7900bc81ab 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1081,10 +1081,10 @@ out:
 return ret;
 }
 
-static int vhost_virtqueue_start(struct vhost_dev *dev,
-struct VirtIODevice *vdev,
-struct vhost_virtqueue *vq,
-unsigned idx)
+int vhost_virtqueue_start(struct vhost_dev *dev,
+  struct VirtIODevice *vdev,
+  struct vhost_virtqueue *vq,
+  unsigned idx)
 {
 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
 VirtioBusState *vbus = VIRTIO_BUS(qbus);
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index a346f23d13..b092f57d98 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -279,6 +279,9 @@ int vhost_net_set_backend(struct vhost_dev *hdev,
 
 int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write);
 
+int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev,
+  struct vhost_virtqueue *vq, unsigned idx);
+
 void vhost_dev_reset_inflight(struct vhost_inflight *inflight);
 void vhost_dev_free_inflight(struct vhost_inflight *inflight);
 void vhost_dev_save_inflight(struct vhost_inflight *inflight, QEMUFile *f);
-- 
2.32.0




[PATCH v4 15/15] vhost: vhost-kernel: enable vq reset feature

2022-09-11 Thread Kangjie Xu
Add virtqueue reset feature for vhost-kernel.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 1059aa45b4..97cdf9280b 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -46,6 +46,7 @@ static const int kernel_feature_bits[] = {
 VIRTIO_NET_F_MTU,
 VIRTIO_F_IOMMU_PLATFORM,
 VIRTIO_F_RING_PACKED,
+VIRTIO_F_RING_RESET,
 VIRTIO_NET_F_HASH_REPORT,
 VHOST_INVALID_FEATURE_BIT
 };
-- 
2.32.0




[PATCH v4 04/15] virtio: introduce virtio_queue_enable()

2022-09-11 Thread Kangjie Xu
Introduce the interface queue_enable() in VirtioDeviceClass and the
fucntion virtio_queue_enable() in virtio, it can be called when
VIRTIO_PCI_COMMON_Q_ENABLE is written and related virtqueue can be
started. It only supports the devices of virtio 1 or later. The
not-supported devices can only start the virtqueue when DRIVER_OK.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/virtio.c | 14 ++
 include/hw/virtio/virtio.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 0e9d41366f..141f18c633 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2050,6 +2050,20 @@ void virtio_queue_reset(VirtIODevice *vdev, uint32_t 
queue_index)
 __virtio_queue_reset(vdev, queue_index);
 }
 
+void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+
+if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+error_report("queue_enable is only suppported in devices of virtio "
+ "1.0 or later.");
+}
+
+if (k->queue_enable) {
+k->queue_enable(vdev, queue_index);
+}
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 879394299b..085997d8f3 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -131,6 +131,7 @@ struct VirtioDeviceClass {
 void (*reset)(VirtIODevice *vdev);
 void (*set_status)(VirtIODevice *vdev, uint8_t val);
 void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index);
+void (*queue_enable)(VirtIODevice *vdev, uint32_t queue_index);
 /* For transitional devices, this is a bitmap of features
  * that are only exposed on the legacy interface but not
  * the modern one.
@@ -270,6 +271,7 @@ int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, 
int n,
 int virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
 void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index);
+void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index);
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint64_t val);
 
-- 
2.32.0




Re: [PATCH v3 13/15] virtio-net: support queue reset

2022-09-05 Thread Kangjie Xu



在 2022/9/5 16:30, Jason Wang 写道:


在 2022/8/25 16:08, Kangjie Xu 写道:

From: Xuan Zhuo 

virtio-net and vhost-kernel implement queue reset.
Queued packets in the corresponding queue pair are flushed
or purged.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
  hw/net/virtio-net.c | 18 ++
  1 file changed, 18 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 27b59c0ad6..d774a3e652 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -540,6 +540,23 @@ static RxFilterInfo 
*virtio_net_query_rxfilter(NetClientState *nc)

  return info;
  }
  +static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t 
queue_index)

+{
+    VirtIONet *n = VIRTIO_NET(vdev);
+    NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+
+    if (!nc->peer) {
+    return;
+    }
+
+    if (get_vhost_net(nc->peer) &&
+    nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+    vhost_net_virtqueue_reset(vdev, nc, queue_index);
+    }
+
+    flush_or_purge_queued_packets(nc);



But the codes doesn't prevent the usersapce datapath from being used? 
(e.g vhost=off)


I think we do not need to prevent it for vhost=off, because the 
virtio-net device is in control of the tap device.


After we reset the vq, the virtio-net send and recv will not use the 
userspace datapath. (virtio_net_flush_tx() and virtio_net_receive() will 
early returns because vq->vring.avail == 0)


So even if we don't prevent it using net->nc->info->poll, virtio-net 
device will prevent it. And the logic here is similar to virtio_reset(), 
I think it will not cause problems.


Thanks.



E.g vhost_net_start_one() had:

    if (net->nc->info->poll) {
    net->nc->info->poll(net->nc, false);
    }

And I will wonder if it's better to consider to:

1) factor out the per virtqueue start/stop from 
vhost_net_start/stop_one()


2) simply use the helper factored out via step 1)

Thanks



+}
+
  static void virtio_net_reset(VirtIODevice *vdev)
  {
  VirtIONet *n = VIRTIO_NET(vdev);
@@ -3784,6 +3801,7 @@ static void virtio_net_class_init(ObjectClass 
*klass, void *data)

  vdc->set_features = virtio_net_set_features;
  vdc->bad_features = virtio_net_bad_features;
  vdc->reset = virtio_net_reset;
+    vdc->queue_reset = virtio_net_queue_reset;
  vdc->set_status = virtio_net_set_status;
  vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
  vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;




Re: [PATCH v3 13/15] virtio-net: support queue reset

2022-09-05 Thread Kangjie Xu



在 2022/9/5 16:30, Jason Wang 写道:


在 2022/8/25 16:08, Kangjie Xu 写道:

From: Xuan Zhuo 

virtio-net and vhost-kernel implement queue reset.
Queued packets in the corresponding queue pair are flushed
or purged.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
  hw/net/virtio-net.c | 18 ++
  1 file changed, 18 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 27b59c0ad6..d774a3e652 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -540,6 +540,23 @@ static RxFilterInfo 
*virtio_net_query_rxfilter(NetClientState *nc)

  return info;
  }
  +static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t 
queue_index)

+{
+    VirtIONet *n = VIRTIO_NET(vdev);
+    NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+
+    if (!nc->peer) {
+    return;
+    }
+
+    if (get_vhost_net(nc->peer) &&
+    nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+    vhost_net_virtqueue_reset(vdev, nc, queue_index);
+    }
+
+    flush_or_purge_queued_packets(nc);



But the codes doesn't prevent the usersapce datapath from being used? 
(e.g vhost=off)


E.g vhost_net_start_one() had:

    if (net->nc->info->poll) {
    net->nc->info->poll(net->nc, false);
    }

I review this part in vhost_net_start/stop_one().

I didn't take the usersapce datapath into consideration. If we don't 
prevent it, the userspace datapath may access it and causes some 
problems. From this point, we should disable it.


But if we add net->nc->info->poll in vq reset, it can only operate at 
queue-pair level, which obeys "per-virtqueue".


What's your opinion on this point? I think it's ok to add it in vq reset.



And I will wonder if it's better to consider to:

1) factor out the per virtqueue start/stop from 
vhost_net_start/stop_one()


2) simply use the helper factored out via step 1)

Thanks

I have a different idea about it, vhost_virtqueue_start/stop()(in 
hw/virtio/vhost.c) are already good abstractions of per virtqueue 
start/stop.


These two functions are used in vhost_dev_start. It's just because 
vhost-net needs some configuration, so we add net->nc->info->poll and 
set_backend for it. But for other devices using vhost_dev_start, 
set_backend and net->nc->info->poll may be not necessary.


I think your apporach to abstract per virtqueue start/stop from 
vhost_net_start/stop_one() will break the generality of 
vhost_dev_start(), which is a common interface for different devices.


To conclude my opinions

1. I think we need to add net->nc->info->poll in our 
vhost_net_virtqueue_reset() and vhost_net_virtqueue_restart()


2. We still need vhost_net_virtqueue_reset() and 
vhost_net_virtqueue_restart().


    a. vhost_net_virtqueue_reset() is a wrapper for vhost_virtqueue_stop().

    b. vhost_net_virtqueue_restart() is a wrapper for 
vhost_virtqueue_start().


Thanks




+}
+
  static void virtio_net_reset(VirtIODevice *vdev)
  {
  VirtIONet *n = VIRTIO_NET(vdev);
@@ -3784,6 +3801,7 @@ static void virtio_net_class_init(ObjectClass 
*klass, void *data)

  vdc->set_features = virtio_net_set_features;
  vdc->bad_features = virtio_net_bad_features;
  vdc->reset = virtio_net_reset;
+    vdc->queue_reset = virtio_net_queue_reset;
  vdc->set_status = virtio_net_set_status;
  vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
  vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;




Re: [PATCH v3 10/15] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_reset()

2022-09-05 Thread Kangjie Xu



在 2022/9/5 16:03, Jason Wang 写道:


在 2022/8/25 16:08, Kangjie Xu 写道:

Introduce vhost_virtqueue_reset(), which can reset the specific
virtqueue in the device. Then it will unmap vrings and the desc
of the virtqueue.

Here we do not reuse the vhost_net_stop_one() or vhost_dev_stop(),
because they work at queue pair level. We do not use
vhost_virtqueue_stop() because it may stop the device in the
backend.



So I think this is not true at least for vhost-net kernel baceknd.



But vhost-user(OVS-DPDK) will stop the device.

When DPDK vhost received VHOST_USER_GET_VRING_BASE message, it will call 
vhost_destroy_device_notify() to destroy the device.


It seems like it is a inconsistency error in DPDK. Maybe I should submit 
a patch to DPDK. We can stop the device only when all the virtqueues in 
one device are destroyed.




This patch only considers the case of vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/net/vhost_net.c  | 22 ++
  include/net/vhost_net.h |  2 ++
  2 files changed, 24 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index ccac5b7a64..be51be98b3 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -514,3 +514,25 @@ int vhost_net_set_mtu(struct vhost_net *net, 
uint16_t mtu)

    return vhost_ops->vhost_net_set_mtu(>dev, mtu);
  }
+
+void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
+   int vq_index)
+{
+    VHostNetState *net = get_vhost_net(nc->peer);
+    const VhostOps *vhost_ops = net->dev.vhost_ops;
+    struct vhost_vring_file file = { .fd = -1 };
+    int idx;
+
+    /* should only be called after backend is connected */
+    assert(vhost_ops);
+
+    idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.index = idx;
+    int r = vhost_net_set_backend(>dev, );
+    assert(r >= 0);
+    }



Do we need to reset e.g last_avail_idx here?

Thanks

I did not reset it because we will re-configure them when we restart 
virtqueue.


Thanks




+
+    vhost_virtqueue_unmap(>dev, vdev, net->dev.vqs + idx, idx);
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 387e913e4e..85d85a4957 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -48,4 +48,6 @@ uint64_t vhost_net_get_acked_features(VHostNetState 
*net);

    int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
  +void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState 
*nc,

+   int vq_index);
  #endif




Re: [PATCH v3 13/15] virtio-net: support queue reset

2022-09-05 Thread Kangjie Xu



在 2022/9/5 16:30, Jason Wang 写道:


在 2022/8/25 16:08, Kangjie Xu 写道:

From: Xuan Zhuo 

virtio-net and vhost-kernel implement queue reset.
Queued packets in the corresponding queue pair are flushed
or purged.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
  hw/net/virtio-net.c | 18 ++
  1 file changed, 18 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 27b59c0ad6..d774a3e652 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -540,6 +540,23 @@ static RxFilterInfo 
*virtio_net_query_rxfilter(NetClientState *nc)

  return info;
  }
  +static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t 
queue_index)

+{
+    VirtIONet *n = VIRTIO_NET(vdev);
+    NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+
+    if (!nc->peer) {
+    return;
+    }
+
+    if (get_vhost_net(nc->peer) &&
+    nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+    vhost_net_virtqueue_reset(vdev, nc, queue_index);
+    }
+
+    flush_or_purge_queued_packets(nc);



But the codes doesn't prevent the usersapce datapath from being used? 
(e.g vhost=off)


E.g vhost_net_start_one() had:

    if (net->nc->info->poll) {
    net->nc->info->poll(net->nc, false);
    }

And I will wonder if it's better to consider to:

1) factor out the per virtqueue start/stop from 
vhost_net_start/stop_one()


2) simply use the helper factored out via step 1)

Thanks


Will update it based on your suggestions.

Thanks




+}
+
  static void virtio_net_reset(VirtIODevice *vdev)
  {
  VirtIONet *n = VIRTIO_NET(vdev);
@@ -3784,6 +3801,7 @@ static void virtio_net_class_init(ObjectClass 
*klass, void *data)

  vdc->set_features = virtio_net_set_features;
  vdc->bad_features = virtio_net_bad_features;
  vdc->reset = virtio_net_reset;
+    vdc->queue_reset = virtio_net_queue_reset;
  vdc->set_status = virtio_net_set_status;
  vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
  vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;




Re: [PATCH v3 11/15] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()

2022-09-05 Thread Kangjie Xu



在 2022/9/5 16:24, Jason Wang 写道:


在 2022/8/25 16:08, Kangjie Xu 写道:

Introduce vhost_net_virtqueue_restart(), which can restart the
specific virtqueue when the vhost net started running before.
If it fails to restart the virtqueue, the device will be stopped.

Here we do not reuse vhost_net_start_one() or vhost_dev_start()
because they work at queue pair level. The mem table and features
do not change, so we can call the vhost_virtqueue_start() to
restart a specific queue.

This patch only considers the case of vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/net/vhost_net.c  | 52 +
  include/net/vhost_net.h |  2 ++
  2 files changed, 54 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index be51be98b3..0716f6cd96 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -536,3 +536,55 @@ void vhost_net_virtqueue_reset(VirtIODevice 
*vdev, NetClientState *nc,

    vhost_virtqueue_unmap(>dev, vdev, net->dev.vqs + idx, idx);
  }
+
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+    int vq_index)
+{
+    VHostNetState *net = get_vhost_net(nc->peer);
+    const VhostOps *vhost_ops = net->dev.vhost_ops;
+    struct vhost_vring_file file = { };
+    int idx, r;
+
+    if (!net->dev.started) {
+    return 0;
+    }



Should we return error in this case?

Thanks


Yes, I think so. Will fix.

Thanks.




+
+    /* should only be called after backend is connected */
+    assert(vhost_ops);
+
+    idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+    r = vhost_virtqueue_start(>dev,
+  vdev,
+  net->dev.vqs + idx,
+  net->dev.vq_index + idx);
+    if (r < 0) {
+    goto err_start;
+    }
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.index = idx;
+    file.fd = net->backend;
+    r = vhost_net_set_backend(>dev, );
+    if (r < 0) {
+    r = -errno;
+    goto err_start;
+    }
+    }
+
+    return 0;
+
+err_start:
+    error_report("Error when restarting the queue.");
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.fd = -1;
+    file.index = idx;
+    int r = vhost_net_set_backend(>dev, );
+    assert(r >= 0);
+    }
+
+    vhost_dev_stop(>dev, vdev);
+
+    return r;
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 85d85a4957..40b9a40074 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -50,4 +50,6 @@ int vhost_net_set_mtu(struct vhost_net *net, 
uint16_t mtu);
    void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState 
*nc,

 int vq_index);
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+    int vq_index);
  #endif




Re: [PATCH v3 00/15] Support VIRTIO_F_RING_RESET for virtio-net, vhost-net kernel in virtio pci-modern

2022-09-01 Thread Kangjie Xu

Do you have any comments about this patch set?

Thanks

在 2022/8/25 16:08, Kangjie Xu 写道:

The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

 https://github.com/oasis-tcs/virtio-spec/issues/124
 https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-11 support vq reset and vq restart for vhost-kernel.
3. Patches 12-14 support vq reset and vq restart for virtio-net.
5. Patch 15 enables the vq reset feature for vhost-kernel.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

Since this patch set involves multiple modules and seems a bit messy, we 
briefly describe the
calling process for different modes below.
virtio-net:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> set enabled, reset status of vq.

vhost-kernel:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> vhost_net_virtqueue_stop() [vhost-net]
 -> vhost_net_set_backend() [vhost]
 -> vhost_virtqueue_unmap()
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> virtio_queue_enable() [virtio]
 -> virtio_net_queue_enable() [virtio-net]
 -> vhost_net_virtqueue_restart() [vhost-net]
 -> vhost_virtqueue_start() [vhost]
 -> vhost_net_set_backend()
 -> set enabled, reset status of vq.


Test environment and method:
 Host: 5.19.0-rc3 (With vq reset support)
 Qemu: QEMU emulator version 7.0.50
 Guest: 5.19.0-rc3 (With vq reset support)
 Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

 The drvier can resize the virtio queue, then virtio queue reset function 
should
 be triggered.

 The default is split mode, modify Qemu virtio-net to add PACKED feature to
 test packed mode.

Guest Kernel Patch:
 
https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

Host Kernel Patch:
 
https://github.com/middaywords/linux/commit/a845098f0df6b8bdf7e1e5db57af6ebd1c8eaf47

Looking forward to your review and comments. Thanks.

changelog:
v3:
   1. Remove support for vhost-user in this series and refactor the code.
   2. Rename 'vhost_net_virtqueue_stop' to 'vhost_net_virtqueue_reset'.
   3. Make PCI transport ready before device ready when queue_enabled is set to 
true.
   3. Add some comments.

v2:
   1. Add support for vhost-net kernel scenario.
   2. Add a new vhost-user message VHOST_USER_RESET_VRING.
   3. Add migration compatibility for virtqueue reset.

Kangjie Xu (10):
   virtio: introduce virtio_queue_enable()
   virtio: core: vq reset feature negotation support
   virtio-pci: support queue enable
   vhost: extract the logic of unmapping the vrings and desc
   vhost: expose vhost_virtqueue_start()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_reset()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()
   virtio-net: introduce flush_or_purge_queued_packets()
   virtio-net: support queue_enable
   vhost: vhost-kernel: enable vq reset feature

Xuan Zhuo (5):
   virtio: sync relevant definitions with linux
   virtio: introduce __virtio_queue_reset()
   virtio: introduce virtio_queue_reset()
   virtio-pci: support queue reset
   virtio-net: support queue reset

  hw/core/machine.c |  1 +
  hw/net/vhost_net.c| 75 +++
  hw/net/virtio-net.c   | 56 --
  hw/virtio/vhost.c | 28 ---
  hw/virtio/virtio-pci.c| 16 
  hw/virtio/virtio.c| 62 +++
  include/hw/virtio/vhost.h |  5 ++
  include/hw/virtio/virtio-pci.h|  5 ++
  include/hw/virtio/virtio.h|  8 +-
  include/net/vhost_net.h   |  4 +
  .../standard-headers/linux/virtio_config.h|  5 ++
  include/standard-headers/linux/virtio_pci.h   |  2 +
  12 files changed, 234 insertions(+), 33 deletions(-)





[PATCH 6/8] vhost-net: vhost-user: update vhost_net_virtqueue_restart()

2022-08-26 Thread Kangjie Xu
Update vhost_net_virtqueue_restart() for vhost-user scenario.

In order to reuse some functions, we process the idx for
vhost-user case. It is because vhost_get_vq_index behave
differently in vhost-user.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 8ad5743f7c..13b9c11e68 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -563,6 +563,9 @@ int vhost_net_virtqueue_restart(VirtIODevice *vdev, 
NetClientState *nc,
 assert(vhost_ops);
 
 idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+idx -= net->dev.vq_index;
+}
 
 r = vhost_virtqueue_start(>dev,
   vdev,
@@ -572,6 +575,15 @@ int vhost_net_virtqueue_restart(VirtIODevice *vdev, 
NetClientState *nc,
 goto err_start;
 }
 
+if (vhost_ops->vhost_set_vring_enable) {
+r = vhost_ops->vhost_set_vring_enable(>dev,
+  net->dev.vq_index + idx,
+  1);
+if (r < 0) {
+goto err_start;
+}
+}
+
 if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
 file.index = idx;
 file.fd = net->backend;
-- 
2.32.0




[PATCH 4/8] vhost-user: introduce vhost_reset_vring() interface

2022-08-26 Thread Kangjie Xu
Introduce the interface vhost_reset_vring(). The interface is a wrapper
to send a VHOST_USER_RESET_VRING message to the back-end. It will reset
an individual vring in the back-end. Meanwhile, it will wait for a reply
to ensure the reset has been completed.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost-user.c| 41 +++
 include/hw/virtio/vhost-backend.h |  3 +++
 2 files changed, 44 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 3f140d5085..b49076fdc4 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -126,6 +126,7 @@ typedef enum VhostUserRequest {
 VHOST_USER_GET_MAX_MEM_SLOTS = 36,
 VHOST_USER_ADD_MEM_REG = 37,
 VHOST_USER_REM_MEM_REG = 38,
+VHOST_USER_RESET_VRING = 41,
 VHOST_USER_MAX
 } VhostUserRequest;
 
@@ -1508,6 +1509,45 @@ static int vhost_user_get_max_memslots(struct vhost_dev 
*dev,
 return 0;
 }
 
+static int vhost_user_reset_vring(struct vhost_dev *dev,
+  struct vhost_vring_state *ring)
+{
+int ret;
+VhostUserMsg msg = {
+.hdr.request = VHOST_USER_RESET_VRING,
+.hdr.flags = VHOST_USER_VERSION,
+.payload.state = *ring,
+.hdr.size = sizeof(msg.payload.state),
+};
+
+if (!virtio_has_feature(dev->acked_features, VIRTIO_F_RING_RESET)) {
+return -ENOTSUP;
+}
+
+ret = vhost_user_write(dev, , NULL, 0);
+if (ret < 0) {
+return ret;
+}
+
+ret = vhost_user_read(dev, );
+if (ret < 0) {
+return ret;
+}
+
+if (msg.hdr.request != VHOST_USER_RESET_VRING) {
+error_report("Received unexpected msg type. Expected %d received %d",
+ VHOST_USER_RESET_VRING, msg.hdr.request);
+return -EPROTO;
+}
+
+if (msg.hdr.size != sizeof(msg.payload.state)) {
+error_report("Received bad msg size.");
+return -EPROTO;
+}
+
+return 0;
+}
+
 static int vhost_user_reset_device(struct vhost_dev *dev)
 {
 VhostUserMsg msg = {
@@ -2635,6 +2675,7 @@ const VhostOps user_ops = {
 .vhost_set_features = vhost_user_set_features,
 .vhost_get_features = vhost_user_get_features,
 .vhost_set_owner = vhost_user_set_owner,
+.vhost_reset_vring = vhost_user_reset_vring,
 .vhost_reset_device = vhost_user_reset_device,
 .vhost_get_vq_index = vhost_user_get_vq_index,
 .vhost_set_vring_enable = vhost_user_set_vring_enable,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h
index dad7191bac..ec65a55a77 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -79,6 +79,8 @@ typedef int (*vhost_get_features_op)(struct vhost_dev *dev,
  uint64_t *features);
 typedef int (*vhost_set_backend_cap_op)(struct vhost_dev *dev);
 typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
+typedef int (*vhost_reset_vring_op)(struct vhost_dev *dev,
+struct vhost_vring_state *ring);
 typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
 typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
 typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
@@ -156,6 +158,7 @@ typedef struct VhostOps {
 vhost_set_backend_cap_op vhost_set_backend_cap;
 vhost_set_owner_op vhost_set_owner;
 vhost_reset_device_op vhost_reset_device;
+vhost_reset_vring_op vhost_reset_vring;
 vhost_get_vq_index_op vhost_get_vq_index;
 vhost_set_vring_enable_op vhost_set_vring_enable;
 vhost_set_dev_enable_op vhost_set_dev_enable;
-- 
2.32.0




[PATCH 7/8] virtio-net: vhost-user: update queue_reset and queue_enable

2022-08-26 Thread Kangjie Xu
Update virtio_net_queue_reset() and virtio_net_queue_enable()
for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/virtio-net.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 6ab796b399..19a2132180 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -550,7 +550,8 @@ static void virtio_net_queue_reset(VirtIODevice *vdev, 
uint32_t queue_index)
 }
 
 if (get_vhost_net(nc->peer) &&
-nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+(nc->peer->info->type == NET_CLIENT_DRIVER_TAP ||
+ nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER)) {
 vhost_net_virtqueue_reset(vdev, nc, queue_index);
 }
 
@@ -568,7 +569,8 @@ static void virtio_net_queue_enable(VirtIODevice *vdev, 
uint32_t queue_index)
 }
 
 if (get_vhost_net(nc->peer) &&
-nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+(nc->peer->info->type == NET_CLIENT_DRIVER_TAP ||
+ nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER)) {
 r = vhost_net_virtqueue_restart(vdev, nc, queue_index);
 if (r < 0) {
 error_report("unable to restart vhost net virtqueue: %d, "
-- 
2.32.0




[PATCH 5/8] vhost-net: vhost-user: update vhost_net_virtqueue_reset()

2022-08-26 Thread Kangjie Xu
Update vhost_net_virtqueue_reset() for vhost-user scenario.

In order to reuse some functions, we process the idx for
vhost-user scenario because vhost_get_vq_index behave
differently for vhost-user.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index c0c1456172..8ad5743f7c 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -522,19 +522,28 @@ void vhost_net_virtqueue_reset(VirtIODevice *vdev, 
NetClientState *nc,
 VHostNetState *net = get_vhost_net(nc->peer);
 const VhostOps *vhost_ops = net->dev.vhost_ops;
 struct vhost_vring_file file = { .fd = -1 };
-int idx;
+struct vhost_vring_state state;
+int idx, r;
 
 /* should only be called after backend is connected */
 assert(vhost_ops);
 
 idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+idx -= net->dev.vq_index;
+}
 
 if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
 file.index = idx;
-int r = vhost_net_set_backend(>dev, );
+r = vhost_net_set_backend(>dev, );
 assert(r >= 0);
 }
 
+if (vhost_ops->vhost_reset_vring) {
+state.index = net->dev.vq_index + idx;
+r = vhost_ops->vhost_reset_vring(>dev, );
+}
+
 vhost_virtqueue_unmap(>dev, vdev, net->dev.vqs + idx, idx);
 }
 
-- 
2.32.0




[PATCH 2/8] net: virtio: rename vhost_set_vring_enable to vhost_set_dev_enable

2022-08-26 Thread Kangjie Xu
Previously, vhost_set_vring_enable will enable/disable all vrings
in a device, which causes ambiguity. So we rename it to
vhost_set_dev_enable.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 backends/cryptodev-vhost.c| 12 ++--
 hw/net/vhost_net-stub.c   |  2 +-
 hw/net/vhost_net.c|  8 
 hw/net/virtio-net.c   |  4 ++--
 hw/virtio/vhost-user.c|  4 ++--
 include/hw/virtio/vhost-backend.h |  6 +++---
 include/net/vhost_net.h   |  2 +-
 7 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/backends/cryptodev-vhost.c b/backends/cryptodev-vhost.c
index bc13e466b4..b83e939760 100644
--- a/backends/cryptodev-vhost.c
+++ b/backends/cryptodev-vhost.c
@@ -147,9 +147,9 @@ cryptodev_vhost_set_vq_index(CryptoDevBackendVhost *crypto,
 }
 
 static int
-vhost_set_vring_enable(CryptoDevBackendClient *cc,
-CryptoDevBackend *b,
-uint16_t queue, int enable)
+vhost_set_dev_enable(CryptoDevBackendClient *cc,
+ CryptoDevBackend *b,
+ uint16_t queue, int enable)
 {
 CryptoDevBackendVhost *crypto =
cryptodev_get_vhost(cc, b, queue);
@@ -162,8 +162,8 @@ vhost_set_vring_enable(CryptoDevBackendClient *cc,
 }
 
 vhost_ops = crypto->dev.vhost_ops;
-if (vhost_ops->vhost_set_vring_enable) {
-return vhost_ops->vhost_set_vring_enable(>dev, enable);
+if (vhost_ops->vhost_set_dev_enable) {
+return vhost_ops->vhost_set_dev_enable(>dev, enable);
 }
 
 return 0;
@@ -219,7 +219,7 @@ int cryptodev_vhost_start(VirtIODevice *dev, int 
total_queues)
 
 if (cc->vring_enable) {
 /* restore vring enable state */
-r = vhost_set_vring_enable(cc, b, i, cc->vring_enable);
+r = vhost_set_dev_enable(cc, b, i, cc->vring_enable);
 
 if (r < 0) {
 goto err_start;
diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c
index 89d71cfb8e..ac5f217dc1 100644
--- a/hw/net/vhost_net-stub.c
+++ b/hw/net/vhost_net-stub.c
@@ -92,7 +92,7 @@ VHostNetState *get_vhost_net(NetClientState *nc)
 return 0;
 }
 
-int vhost_set_vring_enable(NetClientState *nc, int enable)
+int vhost_set_dev_enable(NetClientState *nc, int enable)
 {
 return 0;
 }
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 74c5147d6e..c0c1456172 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -379,7 +379,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
 
 if (peer->vring_enable) {
 /* restore vring enable state */
-r = vhost_set_vring_enable(peer, peer->vring_enable);
+r = vhost_set_dev_enable(peer, peer->vring_enable);
 
 if (r < 0) {
 vhost_net_stop_one(get_vhost_net(peer), dev);
@@ -491,15 +491,15 @@ VHostNetState *get_vhost_net(NetClientState *nc)
 return vhost_net;
 }
 
-int vhost_set_vring_enable(NetClientState *nc, int enable)
+int vhost_set_dev_enable(NetClientState *nc, int enable)
 {
 VHostNetState *net = get_vhost_net(nc);
 const VhostOps *vhost_ops = net->dev.vhost_ops;
 
 nc->vring_enable = enable;
 
-if (vhost_ops && vhost_ops->vhost_set_vring_enable) {
-return vhost_ops->vhost_set_vring_enable(>dev, enable);
+if (vhost_ops && vhost_ops->vhost_set_dev_enable) {
+return vhost_ops->vhost_set_dev_enable(>dev, enable);
 }
 
 return 0;
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 7817206596..6ab796b399 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -696,7 +696,7 @@ static int peer_attach(VirtIONet *n, int index)
 }
 
 if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
-vhost_set_vring_enable(nc->peer, 1);
+vhost_set_dev_enable(nc->peer, 1);
 }
 
 if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) {
@@ -719,7 +719,7 @@ static int peer_detach(VirtIONet *n, int index)
 }
 
 if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
-vhost_set_vring_enable(nc->peer, 0);
+vhost_set_dev_enable(nc->peer, 0);
 }
 
 if (nc->peer->info->type !=  NET_CLIENT_DRIVER_TAP) {
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index bd24741be8..794519359b 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1198,7 +1198,7 @@ static int vhost_user_set_vring_base(struct vhost_dev 
*dev,
 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
 }
 
-static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
+static int vhost_user_set_dev_enable(struct vhost_dev *dev, int enable)
 {
 int i;
 
@@ -2627,7 +2627,7 @@ const VhostOps user_ops = {
 .vhost_set_owner = vhost_user_set_owner,
 .vhost_reset_device = vhost_user

[PATCH 8/8] vhost: vhost-user: enable vq reset feature

2022-08-26 Thread Kangjie Xu
Add virtqueue reset feature for vhost-user.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 13b9c11e68..745cb4375b 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -74,6 +74,7 @@ static const int user_feature_bits[] = {
 VIRTIO_NET_F_MTU,
 VIRTIO_F_IOMMU_PLATFORM,
 VIRTIO_F_RING_PACKED,
+VIRTIO_F_RING_RESET,
 VIRTIO_NET_F_RSS,
 VIRTIO_NET_F_HASH_REPORT,
 
-- 
2.32.0




[PATCH 3/8] vhost-user: add op to enable or disable a single vring

2022-08-26 Thread Kangjie Xu
There is only vhost_set_dev_enable op in VhostOps. Thus, we introduce
the interface vhost_set_vring_enable to set the enable status for a
single vring.

Resetting a single vq will rely on this interface.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost-user.c| 25 ++---
 include/hw/virtio/vhost-backend.h |  3 +++
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 794519359b..3f140d5085 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1198,6 +1198,22 @@ static int vhost_user_set_vring_base(struct vhost_dev 
*dev,
 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
 }
 
+static int vhost_user_set_vring_enable(struct vhost_dev *dev,
+   int index,
+   int enable)
+{
+if (index < dev->vq_index || index >= dev->vq_index + dev->nvqs) {
+return -EINVAL;
+}
+
+struct vhost_vring_state state = {
+.index = index,
+.num   = enable,
+};
+
+return vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+}
+
 static int vhost_user_set_dev_enable(struct vhost_dev *dev, int enable)
 {
 int i;
@@ -1207,13 +1223,7 @@ static int vhost_user_set_dev_enable(struct vhost_dev 
*dev, int enable)
 }
 
 for (i = 0; i < dev->nvqs; ++i) {
-int ret;
-struct vhost_vring_state state = {
-.index = dev->vq_index + i,
-.num   = enable,
-};
-
-ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+int ret = vhost_user_set_vring_enable(dev, dev->vq_index + i, enable);
 if (ret < 0) {
 /*
  * Restoring the previous state is likely infeasible, as well as
@@ -2627,6 +2637,7 @@ const VhostOps user_ops = {
 .vhost_set_owner = vhost_user_set_owner,
 .vhost_reset_device = vhost_user_reset_device,
 .vhost_get_vq_index = vhost_user_get_vq_index,
+.vhost_set_vring_enable = vhost_user_set_vring_enable,
 .vhost_set_dev_enable = vhost_user_set_dev_enable,
 .vhost_requires_shm_log = vhost_user_requires_shm_log,
 .vhost_migration_done = vhost_user_migration_done,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h
index b49432045f..dad7191bac 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -81,6 +81,8 @@ typedef int (*vhost_set_backend_cap_op)(struct vhost_dev 
*dev);
 typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
 typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
 typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
+typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
+ int index, int enable);
 typedef int (*vhost_set_dev_enable_op)(struct vhost_dev *dev,
int enable);
 typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
@@ -155,6 +157,7 @@ typedef struct VhostOps {
 vhost_set_owner_op vhost_set_owner;
 vhost_reset_device_op vhost_reset_device;
 vhost_get_vq_index_op vhost_get_vq_index;
+vhost_set_vring_enable_op vhost_set_vring_enable;
 vhost_set_dev_enable_op vhost_set_dev_enable;
 vhost_requires_shm_log_op vhost_requires_shm_log;
 vhost_migration_done_op vhost_migration_done;
-- 
2.32.0




[PATCH 1/8] docs: vhost-user: add VHOST_USER_RESET_VRING message

2022-08-26 Thread Kangjie Xu
To support the reset operation for an individual virtqueue,
we introduce a new message VHOST_USER_RESET_VRING. This
message is submitted by the front-end to reset an individual
virtqueue to initial states in the back-end. The reply is
needed to ensure that the reset operation is complete.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 docs/interop/vhost-user.rst | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index 3f18ab424e..ce7991b9d3 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1422,6 +1422,16 @@ Front-end message types
   query the back-end for its device status as defined in the Virtio
   specification.
 
+``VHOST_USER_RESET_VRING``
+  :id: 41
+  :equivalent ioctl: N/A
+  :request payload: vring state description
+  :reply payload: ``u64``
+
+  When the feature ``VIRTIO_F_RING_RESET`` feature has been successfully
+  negotiated, this message is submitted by the front-end to reset an
+  individual virtqueue to initial states in the back-end. It will ask
+  for a reply to ensure the virtqueue is successfully reset in the back-end.
 
 Back-end message types
 --
-- 
2.32.0




[PATCH 0/8] Support VIRTIO_F_RING_RESET for vhost-user in virtio pci-modern

2022-08-26 Thread Kangjie Xu
This patch set is based on the patch set that supports VIRTIO_F_RING_RESET for 
vhost-kernel:

https://lore.kernel.org/qemu-devel/cover.1661414345.git.kangjie...@linux.alibaba.com/T/

The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function for vhost-user in QEMU. It consists 
of several parts:
Patch 1: docs about vhost-user message VHOST_USER_RESET_VRING.
Patch 2: rename vhost_set_vring_enable to vhost_set_dev_enable.
Patches 3-4: support in vhost-user module.
Patches 5-6: support in vhost-net module.
Patch 7: support in virtio-net module.
Patch 8: add feature negotitation support.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

The detailed process is listed below:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> vhost_net_virtqueue_reset() [vhost-net]
-> vhost_user_reset_vring() [vhost-user]
-> send VHOST_USER_RESET_VRING to the device
-> vhost_virtqueue_unmap()
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> virtio_queue_enable() [virtio]
-> virtio_net_queue_enable() [virtio-net]
-> vhost_net_virtqueue_restart() [vhost-net]
-> vhost_virtqueue_start()
-> vhost_user_set_vring_enable [vhost-user]
-> send VHOST_USER_SET_VRING_ENABLE to the device
-> set enabled, reset status of vq.

Test environment:
Qemu: QEMU emulator version 7.0.50
Guest: 5.19.0-rc3 (With vq reset support)
DPDK: 22.07-rc1 (With vq reset support)
Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

The drvier can resize the virtio queue, then virtio queue reset function 
should
be triggered.

The default is split mode, modify Qemu virtio-net to add PACKED feature to 
test packed mode.

Guest Kernel Patch:

https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

DPDK Patch:

https://github.com/middaywords/dpdk/compare/72206323a5dd3182b13f61b25a64abdddfee595c...eabadfac7953da66bc10ffb8284b490d09bb7ec7

changelog:(based the series 
https://lore.kernel.org/qemu-devel/cover.1658141552.git.kangjie...@linux.alibaba.com/T/#t)
1. rename vhost_set_vring_enable to vhost_set_dev_enable.
2. add vhost-user message VHOST_USER_RESET_VRING
3. remove restart/reset functions of virtqueue in vhost module.

Kangjie Xu (8):
  docs: vhost-user: add VHOST_USER_RESET_VRING message
  net: virtio: rename vhost_set_vring_enable to vhost_set_dev_enable
  vhost-user: add op to enable or disable a single vring
  vhost-user: introduce vhost_reset_vring() interface
  vhost-net: vhost-user: update vhost_net_virtqueue_reset()
  vhost-net: vhost-user: update vhost_net_virtqueue_restart()
  virtio-net: vhost-user: update queue_reset and queue_enable
  vhost: vhost-user: enable vq reset feature

 backends/cryptodev-vhost.c| 12 +++---
 docs/interop/vhost-user.rst   | 10 +
 hw/net/vhost_net-stub.c   |  2 +-
 hw/net/vhost_net.c| 34 +---
 hw/net/virtio-net.c   | 10 +++--
 hw/virtio/vhost-user.c| 68 +++
 include/hw/virtio/vhost-backend.h |  8 +++-
 include/net/vhost_net.h   |  2 +-
 8 files changed, 119 insertions(+), 27 deletions(-)

-- 
2.32.0




[PATCH v3 15/15] vhost: vhost-kernel: enable vq reset feature

2022-08-25 Thread Kangjie Xu
Add virtqueue reset feature for vhost-kernel.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 0716f6cd96..74c5147d6e 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -46,6 +46,7 @@ static const int kernel_feature_bits[] = {
 VIRTIO_NET_F_MTU,
 VIRTIO_F_IOMMU_PLATFORM,
 VIRTIO_F_RING_PACKED,
+VIRTIO_F_RING_RESET,
 VIRTIO_NET_F_HASH_REPORT,
 VHOST_INVALID_FEATURE_BIT
 };
-- 
2.32.0




[PATCH v3 14/15] virtio-net: support queue_enable

2022-08-25 Thread Kangjie Xu
Support queue_enable in vhost-kernel scenario. It can be called when
a vq reset operation has been performed and the vq is restared.

It should be noted that we can restart the vq when the vhost has
already started. When launching a new vhost device, the vhost is not
started and all vqs are not initalized until VIRTIO_PCI_COMMON_STATUS
is written. Thus, we should use vhost_started to differentiate the
two cases: vq reset and device start.

Currently it only supports vhost-kernel.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/virtio-net.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index d774a3e652..7817206596 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -557,6 +557,26 @@ static void virtio_net_queue_reset(VirtIODevice *vdev, 
uint32_t queue_index)
 flush_or_purge_queued_packets(nc);
 }
 
+static void virtio_net_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtIONet *n = VIRTIO_NET(vdev);
+NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+int r;
+
+if (!nc->peer || !vdev->vhost_started) {
+return;
+}
+
+if (get_vhost_net(nc->peer) &&
+nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+r = vhost_net_virtqueue_restart(vdev, nc, queue_index);
+if (r < 0) {
+error_report("unable to restart vhost net virtqueue: %d, "
+"when resetting the queue", queue_index);
+}
+}
+}
+
 static void virtio_net_reset(VirtIODevice *vdev)
 {
 VirtIONet *n = VIRTIO_NET(vdev);
@@ -3802,6 +3822,7 @@ static void virtio_net_class_init(ObjectClass *klass, 
void *data)
 vdc->bad_features = virtio_net_bad_features;
 vdc->reset = virtio_net_reset;
 vdc->queue_reset = virtio_net_queue_reset;
+vdc->queue_enable = virtio_net_queue_enable;
 vdc->set_status = virtio_net_set_status;
 vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
 vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
-- 
2.32.0




[PATCH v3 00/15] Support VIRTIO_F_RING_RESET for virtio-net, vhost-net kernel in virtio pci-modern

2022-08-25 Thread Kangjie Xu
The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-11 support vq reset and vq restart for vhost-kernel.
3. Patches 12-14 support vq reset and vq restart for virtio-net.
5. Patch 15 enables the vq reset feature for vhost-kernel.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

Since this patch set involves multiple modules and seems a bit messy, we 
briefly describe the
calling process for different modes below.
virtio-net:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> set enabled, reset status of vq.

vhost-kernel:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> vhost_net_virtqueue_stop() [vhost-net]
-> vhost_net_set_backend() [vhost]
-> vhost_virtqueue_unmap()
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> virtio_queue_enable() [virtio]
-> virtio_net_queue_enable() [virtio-net]
-> vhost_net_virtqueue_restart() [vhost-net]
-> vhost_virtqueue_start() [vhost]
-> vhost_net_set_backend()
-> set enabled, reset status of vq.


Test environment and method:
Host: 5.19.0-rc3 (With vq reset support)
Qemu: QEMU emulator version 7.0.50
Guest: 5.19.0-rc3 (With vq reset support)
Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

The drvier can resize the virtio queue, then virtio queue reset function 
should
be triggered.

The default is split mode, modify Qemu virtio-net to add PACKED feature to 
test packed mode.

Guest Kernel Patch:

https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

Host Kernel Patch:

https://github.com/middaywords/linux/commit/a845098f0df6b8bdf7e1e5db57af6ebd1c8eaf47

Looking forward to your review and comments. Thanks.

changelog:
v3:
  1. Remove support for vhost-user in this series and refactor the code.
  2. Rename 'vhost_net_virtqueue_stop' to 'vhost_net_virtqueue_reset'.
  3. Make PCI transport ready before device ready when queue_enabled is set to 
true.
  3. Add some comments.

v2:
  1. Add support for vhost-net kernel scenario.
  2. Add a new vhost-user message VHOST_USER_RESET_VRING.
  3. Add migration compatibility for virtqueue reset.

Kangjie Xu (10):
  virtio: introduce virtio_queue_enable()
  virtio: core: vq reset feature negotation support
  virtio-pci: support queue enable
  vhost: extract the logic of unmapping the vrings and desc
  vhost: expose vhost_virtqueue_start()
  vhost-net: vhost-kernel: introduce vhost_net_virtqueue_reset()
  vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()
  virtio-net: introduce flush_or_purge_queued_packets()
  virtio-net: support queue_enable
  vhost: vhost-kernel: enable vq reset feature

Xuan Zhuo (5):
  virtio: sync relevant definitions with linux
  virtio: introduce __virtio_queue_reset()
  virtio: introduce virtio_queue_reset()
  virtio-pci: support queue reset
  virtio-net: support queue reset

 hw/core/machine.c |  1 +
 hw/net/vhost_net.c| 75 +++
 hw/net/virtio-net.c   | 56 --
 hw/virtio/vhost.c | 28 ---
 hw/virtio/virtio-pci.c| 16 
 hw/virtio/virtio.c| 62 +++
 include/hw/virtio/vhost.h |  5 ++
 include/hw/virtio/virtio-pci.h|  5 ++
 include/hw/virtio/virtio.h|  8 +-
 include/net/vhost_net.h   |  4 +
 .../standard-headers/linux/virtio_config.h|  5 ++
 include/standard-headers/linux/virtio_pci.h   |  2 +
 12 files changed, 234 insertions(+), 33 deletions(-)

-- 
2.32.0




[PATCH v3 02/15] virtio: introduce __virtio_queue_reset()

2022-08-25 Thread Kangjie Xu
From: Xuan Zhuo 

Separate the logic of vq reset. This logic will be called directly
later.

Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/virtio.c | 37 +
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 5d607aeaa0..67d54832a9 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2019,6 +2019,26 @@ static enum virtio_device_endian 
virtio_current_cpu_endian(void)
 }
 }
 
+static void __virtio_queue_reset(VirtIODevice *vdev, uint32_t i)
+{
+vdev->vq[i].vring.desc = 0;
+vdev->vq[i].vring.avail = 0;
+vdev->vq[i].vring.used = 0;
+vdev->vq[i].last_avail_idx = 0;
+vdev->vq[i].shadow_avail_idx = 0;
+vdev->vq[i].used_idx = 0;
+vdev->vq[i].last_avail_wrap_counter = true;
+vdev->vq[i].shadow_avail_wrap_counter = true;
+vdev->vq[i].used_wrap_counter = true;
+virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
+vdev->vq[i].signalled_used = 0;
+vdev->vq[i].signalled_used_valid = false;
+vdev->vq[i].notification = true;
+vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
+vdev->vq[i].inuse = 0;
+virtio_virtqueue_reset_region_cache(>vq[i]);
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
@@ -2050,22 +2070,7 @@ void virtio_reset(void *opaque)
 virtio_notify_vector(vdev, vdev->config_vector);
 
 for(i = 0; i < VIRTIO_QUEUE_MAX; i++) {
-vdev->vq[i].vring.desc = 0;
-vdev->vq[i].vring.avail = 0;
-vdev->vq[i].vring.used = 0;
-vdev->vq[i].last_avail_idx = 0;
-vdev->vq[i].shadow_avail_idx = 0;
-vdev->vq[i].used_idx = 0;
-vdev->vq[i].last_avail_wrap_counter = true;
-vdev->vq[i].shadow_avail_wrap_counter = true;
-vdev->vq[i].used_wrap_counter = true;
-virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
-vdev->vq[i].signalled_used = 0;
-vdev->vq[i].signalled_used_valid = false;
-vdev->vq[i].notification = true;
-vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
-vdev->vq[i].inuse = 0;
-virtio_virtqueue_reset_region_cache(>vq[i]);
+__virtio_queue_reset(vdev, i);
 }
 }
 
-- 
2.32.0




[PATCH v3 13/15] virtio-net: support queue reset

2022-08-25 Thread Kangjie Xu
From: Xuan Zhuo 

virtio-net and vhost-kernel implement queue reset.
Queued packets in the corresponding queue pair are flushed
or purged.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
 hw/net/virtio-net.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 27b59c0ad6..d774a3e652 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -540,6 +540,23 @@ static RxFilterInfo 
*virtio_net_query_rxfilter(NetClientState *nc)
 return info;
 }
 
+static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtIONet *n = VIRTIO_NET(vdev);
+NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+
+if (!nc->peer) {
+return;
+}
+
+if (get_vhost_net(nc->peer) &&
+nc->peer->info->type == NET_CLIENT_DRIVER_TAP) {
+vhost_net_virtqueue_reset(vdev, nc, queue_index);
+}
+
+flush_or_purge_queued_packets(nc);
+}
+
 static void virtio_net_reset(VirtIODevice *vdev)
 {
 VirtIONet *n = VIRTIO_NET(vdev);
@@ -3784,6 +3801,7 @@ static void virtio_net_class_init(ObjectClass *klass, 
void *data)
 vdc->set_features = virtio_net_set_features;
 vdc->bad_features = virtio_net_bad_features;
 vdc->reset = virtio_net_reset;
+vdc->queue_reset = virtio_net_queue_reset;
 vdc->set_status = virtio_net_set_status;
 vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
 vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
-- 
2.32.0




[PATCH v3 07/15] virtio-pci: support queue enable

2022-08-25 Thread Kangjie Xu
PCI devices support device specific vq enable.

Based on this function, the driver can re-enable the virtqueue after the
virtqueue is reset.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/virtio-pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 79b9e641dd..a53b5d9f1e 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1342,6 +1342,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
proxy->vqs[vdev->queue_sel].used[0]);
 proxy->vqs[vdev->queue_sel].enabled = 1;
 proxy->vqs[vdev->queue_sel].reset = 0;
+virtio_queue_enable(vdev, vdev->queue_sel);
 } else {
 virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val);
 }
-- 
2.32.0




[PATCH v3 05/15] virtio: core: vq reset feature negotation support

2022-08-25 Thread Kangjie Xu
A a new command line parameter "queue_reset" is added.

Meanwhile, the vq reset feature is disabled for pre-7.1 machines.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/core/machine.c  | 1 +
 include/hw/virtio/virtio.h | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index a673302cce..8b22b4647f 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -43,6 +43,7 @@
 GlobalProperty hw_compat_7_0[] = {
 { "arm-gicv3-common", "force-8-bit-prio", "on" },
 { "nvme-ns", "eui64-default", "on"},
+{ "virtio-device", "queue_reset", "false" },
 };
 const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
 
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 085997d8f3..ed3ecbef80 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -295,7 +295,9 @@ typedef struct VirtIORNGConf VirtIORNGConf;
 DEFINE_PROP_BIT64("iommu_platform", _state, _field, \
   VIRTIO_F_IOMMU_PLATFORM, false), \
 DEFINE_PROP_BIT64("packed", _state, _field, \
-  VIRTIO_F_RING_PACKED, false)
+  VIRTIO_F_RING_PACKED, false), \
+DEFINE_PROP_BIT64("queue_reset", _state, _field, \
+  VIRTIO_F_RING_RESET, true)
 
 hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
 bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n);
-- 
2.32.0




[PATCH v3 10/15] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_reset()

2022-08-25 Thread Kangjie Xu
Introduce vhost_virtqueue_reset(), which can reset the specific
virtqueue in the device. Then it will unmap vrings and the desc
of the virtqueue.

Here we do not reuse the vhost_net_stop_one() or vhost_dev_stop(),
because they work at queue pair level. We do not use
vhost_virtqueue_stop() because it may stop the device in the
backend.

This patch only considers the case of vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c  | 22 ++
 include/net/vhost_net.h |  2 ++
 2 files changed, 24 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index ccac5b7a64..be51be98b3 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -514,3 +514,25 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
 
 return vhost_ops->vhost_net_set_mtu(>dev, mtu);
 }
+
+void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
+   int vq_index)
+{
+VHostNetState *net = get_vhost_net(nc->peer);
+const VhostOps *vhost_ops = net->dev.vhost_ops;
+struct vhost_vring_file file = { .fd = -1 };
+int idx;
+
+/* should only be called after backend is connected */
+assert(vhost_ops);
+
+idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.index = idx;
+int r = vhost_net_set_backend(>dev, );
+assert(r >= 0);
+}
+
+vhost_virtqueue_unmap(>dev, vdev, net->dev.vqs + idx, idx);
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 387e913e4e..85d85a4957 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -48,4 +48,6 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net);
 
 int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
 
+void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
+   int vq_index);
 #endif
-- 
2.32.0




[PATCH v3 04/15] virtio: introduce virtio_queue_enable()

2022-08-25 Thread Kangjie Xu
Introduce the interface queue_enable() in VirtioDeviceClass and the
fucntion virtio_queue_enable() in virtio, it can be called when
VIRTIO_PCI_COMMON_Q_ENABLE is written and related virtqueue can be
started. It only supports the devices of virtio 1 or later. The
not-supported devices can only start the virtqueue when DRIVER_OK.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/virtio.c | 14 ++
 include/hw/virtio/virtio.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 0e9d41366f..141f18c633 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2050,6 +2050,20 @@ void virtio_queue_reset(VirtIODevice *vdev, uint32_t 
queue_index)
 __virtio_queue_reset(vdev, queue_index);
 }
 
+void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+
+if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+error_report("queue_enable is only suppported in devices of virtio "
+ "1.0 or later.");
+}
+
+if (k->queue_enable) {
+k->queue_enable(vdev, queue_index);
+}
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 879394299b..085997d8f3 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -131,6 +131,7 @@ struct VirtioDeviceClass {
 void (*reset)(VirtIODevice *vdev);
 void (*set_status)(VirtIODevice *vdev, uint8_t val);
 void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index);
+void (*queue_enable)(VirtIODevice *vdev, uint32_t queue_index);
 /* For transitional devices, this is a bitmap of features
  * that are only exposed on the legacy interface but not
  * the modern one.
@@ -270,6 +271,7 @@ int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, 
int n,
 int virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
 void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index);
+void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index);
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint64_t val);
 
-- 
2.32.0




[PATCH v3 03/15] virtio: introduce virtio_queue_reset()

2022-08-25 Thread Kangjie Xu
From: Xuan Zhuo 

Introduce a new interface function virtio_queue_reset() to implement
reset for vq.

Add a new callback to VirtioDeviceClass for queue reset operation for
each child device.

Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/virtio.c | 11 +++
 include/hw/virtio/virtio.h |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 67d54832a9..0e9d41366f 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2039,6 +2039,17 @@ static void __virtio_queue_reset(VirtIODevice *vdev, 
uint32_t i)
 virtio_virtqueue_reset_region_cache(>vq[i]);
 }
 
+void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+
+if (k->queue_reset) {
+k->queue_reset(vdev, queue_index);
+}
+
+__virtio_queue_reset(vdev, queue_index);
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index db1c0ddf6b..879394299b 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -130,6 +130,7 @@ struct VirtioDeviceClass {
 void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
 void (*reset)(VirtIODevice *vdev);
 void (*set_status)(VirtIODevice *vdev, uint8_t val);
+void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index);
 /* For transitional devices, this is a bitmap of features
  * that are only exposed on the legacy interface but not
  * the modern one.
@@ -268,6 +269,7 @@ int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, 
int n,
   MemoryRegion *mr, bool assign);
 int virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
+void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index);
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint64_t val);
 
-- 
2.32.0




[PATCH v3 08/15] vhost: extract the logic of unmapping the vrings and desc

2022-08-25 Thread Kangjie Xu
Introduce vhost_virtqueue_unmap() to ummap the vrings and desc
of a virtqueue.

The function will be re-used when resetting a virtqueue.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
Acked-by: Jason Wang 
---
 hw/virtio/vhost.c | 20 ++--
 include/hw/virtio/vhost.h |  3 +++
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index f758f177bb..2419521c36 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1201,6 +1201,19 @@ fail_alloc_desc:
 return r;
 }
 
+void vhost_virtqueue_unmap(struct vhost_dev *dev,
+   struct VirtIODevice *vdev,
+   struct vhost_virtqueue *vq,
+   unsigned idx)
+{
+vhost_memory_unmap(dev, vq->used, virtio_queue_get_used_size(vdev, idx),
+   1, virtio_queue_get_used_size(vdev, idx));
+vhost_memory_unmap(dev, vq->avail, virtio_queue_get_avail_size(vdev, idx),
+   0, virtio_queue_get_avail_size(vdev, idx));
+vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx),
+   0, virtio_queue_get_desc_size(vdev, idx));
+}
+
 static void vhost_virtqueue_stop(struct vhost_dev *dev,
 struct VirtIODevice *vdev,
 struct vhost_virtqueue *vq,
@@ -1239,12 +1252,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
 vhost_vq_index);
 }
 
-vhost_memory_unmap(dev, vq->used, virtio_queue_get_used_size(vdev, idx),
-   1, virtio_queue_get_used_size(vdev, idx));
-vhost_memory_unmap(dev, vq->avail, virtio_queue_get_avail_size(vdev, idx),
-   0, virtio_queue_get_avail_size(vdev, idx));
-vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx),
-   0, virtio_queue_get_desc_size(vdev, idx));
+vhost_virtqueue_unmap(dev, vdev, vq, idx);
 }
 
 static void vhost_eventfd_add(MemoryListener *listener,
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index a346f23d13..d9adbca584 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -279,6 +279,9 @@ int vhost_net_set_backend(struct vhost_dev *hdev,
 
 int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write);
 
+void vhost_virtqueue_unmap(struct vhost_dev *dev, struct VirtIODevice *vdev,
+   struct vhost_virtqueue *vq, unsigned idx);
+
 void vhost_dev_reset_inflight(struct vhost_inflight *inflight);
 void vhost_dev_free_inflight(struct vhost_inflight *inflight);
 void vhost_dev_save_inflight(struct vhost_inflight *inflight, QEMUFile *f);
-- 
2.32.0




[PATCH v3 01/15] virtio: sync relevant definitions with linux

2022-08-25 Thread Kangjie Xu
From: Xuan Zhuo 

This is updated using scripts/update-linux-headers.sh.

Added VIRTIO_F_RING_RESET, VIRTIO_PCI_COMMON_Q_RESET. It came from here:
https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

Add VIRTIO_PCI_COMMON_Q_NDATA, which comes from here:
https://github.com/oasis-tcs/virtio-spec/issues/89

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
 include/standard-headers/linux/virtio_config.h | 5 +
 include/standard-headers/linux/virtio_pci.h| 2 ++
 2 files changed, 7 insertions(+)

diff --git a/include/standard-headers/linux/virtio_config.h 
b/include/standard-headers/linux/virtio_config.h
index 7acd8d4abc..47a7eef5e4 100644
--- a/include/standard-headers/linux/virtio_config.h
+++ b/include/standard-headers/linux/virtio_config.h
@@ -96,4 +96,9 @@
  * Does the device support Single Root I/O Virtualization?
  */
 #define VIRTIO_F_SR_IOV37
+
+/*
+ * This feature indicates that the driver can reset a queue individually.
+ */
+#define VIRTIO_F_RING_RESET40
 #endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/standard-headers/linux/virtio_pci.h 
b/include/standard-headers/linux/virtio_pci.h
index db7a8e2fcb..be912cfc95 100644
--- a/include/standard-headers/linux/virtio_pci.h
+++ b/include/standard-headers/linux/virtio_pci.h
@@ -202,6 +202,8 @@ struct virtio_pci_cfg_cap {
 #define VIRTIO_PCI_COMMON_Q_AVAILHI44
 #define VIRTIO_PCI_COMMON_Q_USEDLO 48
 #define VIRTIO_PCI_COMMON_Q_USEDHI 52
+#define VIRTIO_PCI_COMMON_Q_NDATA  56
+#define VIRTIO_PCI_COMMON_Q_RESET  58
 
 #endif /* VIRTIO_PCI_NO_MODERN */
 
-- 
2.32.0




[PATCH v3 12/15] virtio-net: introduce flush_or_purge_queued_packets()

2022-08-25 Thread Kangjie Xu
Introduce the fucntion flush_or_purge_queued_packets(), it will be
used in device reset and virtqueue reset. Therefore, we extract the
common logic as a new function.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/virtio-net.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index dd0d056fde..27b59c0ad6 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -118,6 +118,16 @@ static int vq2q(int queue_index)
 return queue_index / 2;
 }
 
+static void flush_or_purge_queued_packets(NetClientState *nc)
+{
+if (!nc->peer) {
+return;
+}
+
+qemu_flush_or_purge_queued_packets(nc->peer, true);
+assert(!virtio_net_get_subqueue(nc)->async_tx.elem);
+}
+
 /* TODO
  * - we could suppress RX interrupt if we were so inclined.
  */
@@ -560,12 +570,7 @@ static void virtio_net_reset(VirtIODevice *vdev)
 
 /* Flush any async TX */
 for (i = 0;  i < n->max_queue_pairs; i++) {
-NetClientState *nc = qemu_get_subqueue(n->nic, i);
-
-if (nc->peer) {
-qemu_flush_or_purge_queued_packets(nc->peer, true);
-assert(!virtio_net_get_subqueue(nc)->async_tx.elem);
-}
+flush_or_purge_queued_packets(qemu_get_subqueue(n->nic, i));
 }
 }
 
-- 
2.32.0




[PATCH v3 06/15] virtio-pci: support queue reset

2022-08-25 Thread Kangjie Xu
From: Xuan Zhuo 

PCI devices support vq reset.

Based on this function, the driver can adjust the size of the ring, and
quickly recycle the buffer in the ring.

The migration of the virtio devices will not happen during a reset
operation. This is becuase the global iothread lock is held. Migration
thread also needs the lock. As a result, when migration of virtio
devices starts, the 'reset' status of VirtIOPCIQueue will always be 0.
Thus, we do not need to add it in vmstate_virtio_pci_modern_queue_state.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
 hw/virtio/virtio-pci.c | 15 +++
 include/hw/virtio/virtio-pci.h |  5 +
 2 files changed, 20 insertions(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index a50c5a57d7..79b9e641dd 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1251,6 +1251,9 @@ static uint64_t virtio_pci_common_read(void *opaque, 
hwaddr addr,
 case VIRTIO_PCI_COMMON_Q_USEDHI:
 val = proxy->vqs[vdev->queue_sel].used[1];
 break;
+case VIRTIO_PCI_COMMON_Q_RESET:
+val = proxy->vqs[vdev->queue_sel].reset;
+break;
 default:
 val = 0;
 }
@@ -1338,6 +1341,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
 proxy->vqs[vdev->queue_sel].enabled = 1;
+proxy->vqs[vdev->queue_sel].reset = 0;
 } else {
 virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val);
 }
@@ -1360,6 +1364,16 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
 case VIRTIO_PCI_COMMON_Q_USEDHI:
 proxy->vqs[vdev->queue_sel].used[1] = val;
 break;
+case VIRTIO_PCI_COMMON_Q_RESET:
+if (val == 1) {
+proxy->vqs[vdev->queue_sel].reset = 1;
+
+virtio_queue_reset(vdev, vdev->queue_sel);
+
+proxy->vqs[vdev->queue_sel].reset = 0;
+proxy->vqs[vdev->queue_sel].enabled = 0;
+}
+break;
 default:
 break;
 }
@@ -1954,6 +1968,7 @@ static void virtio_pci_reset(DeviceState *qdev)
 
 for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
 proxy->vqs[i].enabled = 0;
+proxy->vqs[i].reset = 0;
 proxy->vqs[i].num = 0;
 proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
 proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
index 2446dcd9ae..938799e8f6 100644
--- a/include/hw/virtio/virtio-pci.h
+++ b/include/hw/virtio/virtio-pci.h
@@ -117,6 +117,11 @@ typedef struct VirtIOPCIRegion {
 typedef struct VirtIOPCIQueue {
   uint16_t num;
   bool enabled;
+  /*
+   * No need to migrate the reset status, because it is always 0
+   * when the migration starts.
+   */
+  bool reset;
   uint32_t desc[2];
   uint32_t avail[2];
   uint32_t used[2];
-- 
2.32.0




[PATCH v3 11/15] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()

2022-08-25 Thread Kangjie Xu
Introduce vhost_net_virtqueue_restart(), which can restart the
specific virtqueue when the vhost net started running before.
If it fails to restart the virtqueue, the device will be stopped.

Here we do not reuse vhost_net_start_one() or vhost_dev_start()
because they work at queue pair level. The mem table and features
do not change, so we can call the vhost_virtqueue_start() to
restart a specific queue.

This patch only considers the case of vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c  | 52 +
 include/net/vhost_net.h |  2 ++
 2 files changed, 54 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index be51be98b3..0716f6cd96 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -536,3 +536,55 @@ void vhost_net_virtqueue_reset(VirtIODevice *vdev, 
NetClientState *nc,
 
 vhost_virtqueue_unmap(>dev, vdev, net->dev.vqs + idx, idx);
 }
+
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+int vq_index)
+{
+VHostNetState *net = get_vhost_net(nc->peer);
+const VhostOps *vhost_ops = net->dev.vhost_ops;
+struct vhost_vring_file file = { };
+int idx, r;
+
+if (!net->dev.started) {
+return 0;
+}
+
+/* should only be called after backend is connected */
+assert(vhost_ops);
+
+idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+r = vhost_virtqueue_start(>dev,
+  vdev,
+  net->dev.vqs + idx,
+  net->dev.vq_index + idx);
+if (r < 0) {
+goto err_start;
+}
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.index = idx;
+file.fd = net->backend;
+r = vhost_net_set_backend(>dev, );
+if (r < 0) {
+r = -errno;
+goto err_start;
+}
+}
+
+return 0;
+
+err_start:
+error_report("Error when restarting the queue.");
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.fd = -1;
+file.index = idx;
+int r = vhost_net_set_backend(>dev, );
+assert(r >= 0);
+}
+
+vhost_dev_stop(>dev, vdev);
+
+return r;
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 85d85a4957..40b9a40074 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -50,4 +50,6 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
 
 void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
int vq_index);
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+int vq_index);
 #endif
-- 
2.32.0




[PATCH v3 09/15] vhost: expose vhost_virtqueue_start()

2022-08-25 Thread Kangjie Xu
Expose vhost_virtqueue_start(), we need to use it when restarting a
virtqueue.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 8 
 include/hw/virtio/vhost.h | 2 ++
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 2419521c36..8bf9ed952e 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1081,10 +1081,10 @@ out:
 return ret;
 }
 
-static int vhost_virtqueue_start(struct vhost_dev *dev,
-struct VirtIODevice *vdev,
-struct vhost_virtqueue *vq,
-unsigned idx)
+int vhost_virtqueue_start(struct vhost_dev *dev,
+  struct VirtIODevice *vdev,
+  struct vhost_virtqueue *vq,
+  unsigned idx)
 {
 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
 VirtioBusState *vbus = VIRTIO_BUS(qbus);
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index d9adbca584..7b4ffc522b 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -279,6 +279,8 @@ int vhost_net_set_backend(struct vhost_dev *hdev,
 
 int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write);
 
+int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev,
+  struct vhost_virtqueue *vq, unsigned idx);
 void vhost_virtqueue_unmap(struct vhost_dev *dev, struct VirtIODevice *vdev,
struct vhost_virtqueue *vq, unsigned idx);
 
-- 
2.32.0




Re: [PATCH v2 07/24] virtio-pci: support queue enable

2022-08-24 Thread Kangjie Xu



在 2022/8/25 10:52, Jason Wang 写道:

On Wed, Aug 24, 2022 at 7:27 PM Kangjie Xu  wrote:


在 2022/8/24 16:59, Jason Wang 写道:


在 2022/8/23 16:20, Kangjie Xu 写道:


在 2022/8/23 15:44, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

PCI devices support vq enable.



Nit: it might be "support device specific vq enable"


Get it.


Based on this function, the driver can re-enable the virtqueue after the
virtqueue is reset.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
   hw/virtio/virtio-pci.c | 1 +
   1 file changed, 1 insertion(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index ec8e92052f..3d560e45ad 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1335,6 +1335,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
proxy->vqs[vdev->queue_sel].avail[0],
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
+virtio_queue_enable(vdev, vdev->queue_sel);
   proxy->vqs[vdev->queue_sel].enabled = 1;
   proxy->vqs[vdev->queue_sel].reset = 0;



Any reason we do it before the assignment of 1? It probably means the device 
specific method can't depend on virtio_queue_enabled()?

Thanks

Sorry, I don't get why device specific method can't depend on 
virtio_queue_enabled().



I meant if the device specific method call virtio_queue_enabled() it will 
return false in this case, is this intended?

Yes, I intend it to behave in this way.



Before virtio_queue_enable() is done, virtqueue should always be not ready and 
disabled.

Otherwise, If we put it after the assignment of enabled to 1, the virtqueue may 
be accessed illegally and may cause panic, because the virtqueue is still being 
intialized and being configured.



How? Shouldn't we make transport ready before making device virtqueue(device) 
ready?

Thanks

I am not experienced in this field, could you tell me why we should make the 
transport ready first?

That's a must for the device to work.

E.g for PCI device, I can't image the device is ready to work before
PCI is ready.


I make the transport ready later than making device ready for two aspects:

1. In QEMU, the virtio_queue_enabled() is used only when we start the 
device/queue pair (vhost_dev_start_one), or reading VIRTIO_PCI_COMMON_Q_ENABLE. 
These two operations and resetting the queue will be synchronized using 
iothread lock, so we do not need to worry about the case currently.

Note that virtio_queue_enabled() is an exported helper, you can't
assume how it will be used in the future.


2. Suppose we use virtio_queue_enabled() or access the enabled status 
asynchronously, and we make the transport ready first.

After enabled set to true, and before virtio_queue_enable() is finished, 
somewhere  that call virtio_queue_enabled()  or access the enabled status of 
VirtIOPCIQueue. Then the caller will consider the virtqueue as enabled(enabled 
= true in VirtIOPCIQueue). The caller might access the virtqueue(access avail 
ring / desc table). But I think the access here is illegal because the 
virtqueue might still be unintialized status.


How can this happen, won't we call device specific method after we set
queue_enabled as true? It's the charge of the device specific method
to synchronize the necessary external I/O in this case.

Thanks


I get your point.

You are right. I realized that I ignored the external I/O.

Will fix it.

Thanks




Thus, from my perspective, to prevent illegal access, we need to make transport 
ready after virtio_queue_enable().

Thanks



Thanks


   } else {






Re: [PATCH v2 07/24] virtio-pci: support queue enable

2022-08-24 Thread Kangjie Xu


在 2022/8/24 16:59, Jason Wang 写道:


在 2022/8/23 16:20, Kangjie Xu 写道:


在 2022/8/23 15:44, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

PCI devices support vq enable.



Nit: it might be "support device specific vq enable"



Get it.


Based on this function, the driver can re-enable the virtqueue 
after the

virtqueue is reset.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/virtio-pci.c | 1 +
  1 file changed, 1 insertion(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index ec8e92052f..3d560e45ad 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1335,6 +1335,7 @@ static void virtio_pci_common_write(void 
*opaque, hwaddr addr,

proxy->vqs[vdev->queue_sel].avail[0],
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
+    virtio_queue_enable(vdev, vdev->queue_sel);
  proxy->vqs[vdev->queue_sel].enabled = 1;
  proxy->vqs[vdev->queue_sel].reset = 0;



Any reason we do it before the assignment of 1? It probably means 
the device specific method can't depend on virtio_queue_enabled()?


Thanks

Sorry, I don't get why device specific method can't depend on 
virtio_queue_enabled().



I meant if the device specific method call virtio_queue_enabled() it 
will return false in this case, is this intended?



Yes, I intend it to behave in this way.




Before virtio_queue_enable() is done, virtqueue should always be not 
ready and disabled.


Otherwise, If we put it after the assignment of enabled to 1, the 
virtqueue may be accessed illegally and may cause panic, because the 
virtqueue is still being intialized and being configured.



How? Shouldn't we make transport ready before making device 
virtqueue(device) ready?


Thanks

I am not experienced in this field, could you tell me why we should make 
the transport ready first?


I make the transport ready later than making device ready for two aspects:

1. In QEMU, the virtio_queue_enabled() is used only when we start the 
device/queue pair (vhost_dev_start_one), or reading 
VIRTIO_PCI_COMMON_Q_ENABLE. These two operations and resetting the queue 
will *be synchronized* using iothread lock, so we do not need to worry 
about the case currently.


2. Suppose we use virtio_queue_enabled() or access the enabled status 
asynchronously, and we make the transport ready first.


After enabled set to true, and before virtio_queue_enable() is finished, 
somewhere  that call virtio_queue_enabled()  or access the enabled 
status of VirtIOPCIQueue. Then the caller will consider the virtqueue as 
enabled(enabled = true in VirtIOPCIQueue). The caller might access the 
virtqueue(access avail ring / desc table). But I think *the access here 
is illegal* because the virtqueue might still be *unintialized* status.


Thus, from my perspective, to prevent illegal access, we need to make 
transport ready after virtio_queue_enable().


Thanks





Thanks




  } else {


Re: [PATCH v2 15/24] vhost-user: add op to enable or disable a single vring

2022-08-24 Thread Kangjie Xu



在 2022/8/24 17:02, Jason Wang 写道:


在 2022/8/24 11:09, Kangjie Xu 写道:


在 2022/8/24 10:53, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

The interface to set enable status for a single vring is lacked in
VhostOps, since the vhost_set_vring_enable_op will manipulate all
virtqueues in a device.

Resetting a single vq will rely on this interface.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/vhost-user.c    | 26 +++---
  include/hw/virtio/vhost-backend.h |  3 +++
  2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 56033f7a92..8307976cda 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1199,6 +1199,22 @@ static int vhost_user_set_vring_base(struct 
vhost_dev *dev,

  return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
  }
  +static int vhost_user_set_single_vring_enable(struct vhost_dev 
*dev,

+  int index,
+  int enable)
+{
+    if (index < dev->vq_index || index >= dev->vq_index + 
dev->nvqs) {

+    return -EINVAL;
+    }
+
+    struct vhost_vring_state state = {
+    .index = index,
+    .num   = enable,
+    };
+
+    return vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+}
+
  static int vhost_user_set_vring_enable(struct vhost_dev *dev, int 
enable)

  {
  int i;
@@ -1208,13 +1224,8 @@ static int 
vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)

  }
    for (i = 0; i < dev->nvqs; ++i) {
-    int ret;
-    struct vhost_vring_state state = {
-    .index = dev->vq_index + i,
-    .num   = enable,
-    };
-
-    ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, 
);



Then I'd squash this into previous patch or re-roder to let this 
patch (vhost_user_set_single_vring_enable()) to be first.


Thanks


Sorry, I don't get why we should re-order them, since these two 
patches are independent.



I meant it's not good to introduce some codes in patch 14 but delete 
them in patch 15 (the above part for example).


Thanks


I get your point, but in fact, it seems that the deleded codes here in 
patch 15 do not appear in patch 14


Patch 14 is about vhost_user_reset_vring(), patch 15 is about 
vhost_user_set_vring_enable().


Thanks.



Thanks

+    int ret = vhost_user_set_single_vring_enable(dev, 
dev->vq_index + i,

+ enable);
  if (ret < 0) {
  /*
   * Restoring the previous state is likely infeasible, 
as well as

@@ -2668,6 +2679,7 @@ const VhostOps user_ops = {
  .vhost_reset_vring = vhost_user_reset_vring,
  .vhost_reset_device = vhost_user_reset_device,
  .vhost_get_vq_index = vhost_user_get_vq_index,
+    .vhost_set_single_vring_enable = 
vhost_user_set_single_vring_enable,

  .vhost_set_vring_enable = vhost_user_set_vring_enable,
  .vhost_requires_shm_log = vhost_user_requires_shm_log,
  .vhost_migration_done = vhost_user_migration_done,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h

index f23bf71a8d..38f6b752ff 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -83,6 +83,8 @@ typedef int (*vhost_reset_vring_op)(struct 
vhost_dev *dev,

  struct vhost_vring_state *ring);
  typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
  typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int 
idx);
+typedef int (*vhost_set_single_vring_enable_op)(struct vhost_dev 
*dev,
+    int index, int 
enable);

  typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
   int enable);
  typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
@@ -158,6 +160,7 @@ typedef struct VhostOps {
  vhost_reset_device_op vhost_reset_device;
  vhost_reset_vring_op vhost_reset_vring;
  vhost_get_vq_index_op vhost_get_vq_index;
+    vhost_set_single_vring_enable_op vhost_set_single_vring_enable;
  vhost_set_vring_enable_op vhost_set_vring_enable;
  vhost_requires_shm_log_op vhost_requires_shm_log;
  vhost_migration_done_op vhost_migration_done;






Re: [PATCH v2 18/24] vhost-net: vhost-user: update vhost_net_virtqueue_stop()

2022-08-24 Thread Kangjie Xu



在 2022/8/24 17:04, Jason Wang 写道:


在 2022/8/24 12:57, Kangjie Xu 写道:


在 2022/8/24 12:05, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Update vhost_net_virtqueue_stop() for vhost-user scenario.



Let's explain why it is needed now or why it doesn't cause any issue 
or it's a bug fix or not.


Thanks


This patch is to suppport vq reset for vhost-user.

We need this simply because the behavior of vhost_ops->get_vq_index() 
is different in vhost-user and vhost-kernel.


vhost_user_get_vq_index(dev, idx) simply returns "idx".

vhost_kernel_get_vq_index(dev, idx) returns "idx - dev->vq_index".

Thanks



Let's add them in the change-log in the next version.

Sorry, i don't get what to be changed here, could you explain it?


But the question still, is this a bug fix (requires a Fixes tag)? If 
not why do we need this now?


Thanks


Actually, it is not a bugfix, it is simply intended to support vhost-user.

Because vhost_ops->get_vq_index returns different values for 
vhost-kernel and vhost-user.


To align vhost-kernel and vhost-user and reuse the following code,

    vhost_dev_virtqueue_stop(>dev, vdev, idx);

we process the 'idx' here for vhost-user specifically.

Thanks.









Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/net/vhost_net.c | 4 
  1 file changed, 4 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 2ab67e875e..c0d408f3b4 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -533,6 +533,10 @@ void vhost_net_virtqueue_stop(VirtIODevice 
*vdev, NetClientState *nc,

  assert(r >= 0);
  }
  +    if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+    idx = idx - net->dev.vq_index;
+    }
+
  vhost_dev_virtqueue_stop(>dev, vdev, idx);
  }






Re: [PATCH v2 12/24] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()

2022-08-24 Thread Kangjie Xu



在 2022/8/24 17:01, Jason Wang 写道:


在 2022/8/24 10:53, Kangjie Xu 写道:


在 2022/8/24 10:44, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Introduce vhost_net_virtqueue_restart(), which can restart the
virtqueue when the vhost net started running before. If it fails
to restart the virtqueue, the device will be stopped.

This patch only considers the case for vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 



I would explain why current 
vhost_net_start_one()/vhost_net_stop_one() can't work. Is it because 
it works at queue pair level? If yes can we restructure the code and 
try to reuse ?


Thanks

Because vhost_net_start_one()/vhost_net_stop_one() works at device 
level.


The queue pair level start/stop are vhost_virtqueue_start() and 
vhost_virtqueue_stop().


What we can reuse is the vhost_virtqueue_start(). 
vhost_virtqueue_stop() cannot be reused because it will destroy device.



Let's add this in the changelog or a comment in the code.

Thanks



Will fix.

Thanks.



I think we do not need to restructure because we've already had an 
abstraction vhost_virtqueue_start().


Thanks.




---
  hw/net/vhost_net.c  | 48 
+

  include/net/vhost_net.h |  2 ++
  2 files changed, 50 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index aa60dd901c..2ab67e875e 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -535,3 +535,51 @@ void vhost_net_virtqueue_stop(VirtIODevice 
*vdev, NetClientState *nc,

    vhost_dev_virtqueue_stop(>dev, vdev, idx);
  }
+
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState 
*nc,

+    int vq_index)
+{
+    VHostNetState *net = get_vhost_net(nc->peer);
+    const VhostOps *vhost_ops = net->dev.vhost_ops;
+    struct vhost_vring_file file = { };
+    int idx, r;
+
+    if (!net->dev.started) {
+    return 0;
+    }
+
+    assert(vhost_ops);
+
+    idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+    r = vhost_dev_virtqueue_restart(>dev, vdev, idx);
+    if (r < 0) {
+    goto err_start;
+    }
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.index = idx;
+    file.fd = net->backend;
+    r = vhost_net_set_backend(>dev, );
+    if (r < 0) {
+    r = -errno;
+    goto err_start;
+    }
+    }
+
+    return 0;
+
+err_start:
+    error_report("Error when restarting the queue.");
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.fd = -1;
+    file.index = idx;
+    int r = vhost_net_set_backend(>dev, );
+    assert(r >= 0);
+    }
+
+    vhost_dev_stop(>dev, vdev);
+
+    return r;
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 9b3aaf3814..e11a297380 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -50,4 +50,6 @@ int vhost_net_set_mtu(struct vhost_net *net, 
uint16_t mtu);
    void vhost_net_virtqueue_stop(VirtIODevice *vdev, 
NetClientState *nc,

    int vq_index);
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState 
*nc,

+    int vq_index);
  #endif






Re: [PATCH v2 17/24] vhost: vhost-user: update vhost_dev_virtqueue_restart()

2022-08-23 Thread Kangjie Xu



在 2022/8/24 12:03, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Update vhost_dev_virtqueue_restart() for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/vhost.c | 26 ++
  1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index a0d6824353..bd90cfe13a 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1937,11 +1937,29 @@ int vhost_dev_virtqueue_restart(struct 
vhost_dev *hdev, VirtIODevice *vdev,

  int idx)
  {
  const VhostOps *vhost_ops = hdev->vhost_ops;
+    int r;
    assert(vhost_ops);
  -    return vhost_virtqueue_start(hdev,
- vdev,
- hdev->vqs + idx,
- hdev->vq_index + idx);
+    r = vhost_virtqueue_start(hdev,
+  vdev,
+  hdev->vqs + idx,
+  hdev->vq_index + idx);
+    if (r < 0) {
+    goto err_start;
+    }
+
+    if (vhost_ops->vhost_set_single_vring_enable) {
+    r = vhost_ops->vhost_set_single_vring_enable(hdev,
+ hdev->vq_index + idx,
+ 1);



Rethink about the name, I think the current names is kind of confusing:

    .vhost_set_single_vring_enable = 
vhost_user_set_single_vring_enable,

    .vhost_set_vring_enable = vhost_user_set_vring_enable,

I wonder if it's better:

1) rename vhost_set_vring_enable to vhost_set_dev_enable()

then we can

2) use vhost_set_vring_enable() for per vq enabling?

Thanks



I agree. It looks better, I will refactor this part.

Thanks.


+    if (r < 0) {
+    goto err_start;
+    }
+    }
+
+    return 0;
+
+err_start:
+    return r;
  }




Re: [PATCH v2 16/24] vhost: vhost-user: update vhost_dev_virtqueue_stop()

2022-08-23 Thread Kangjie Xu


在 2022/8/24 11:56, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Update vhost_dev_virtqueue_stop() for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/vhost.c | 19 +++
  1 file changed, 19 insertions(+)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index fc3f550c76..a0d6824353 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1908,10 +1908,29 @@ int vhost_net_set_backend(struct vhost_dev 
*hdev,
  void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, VirtIODevice 
*vdev,

    int idx)
  {
+    const VhostOps *vhost_ops = hdev->vhost_ops;
+    struct vhost_vring_state state;
+    int r;
+
+    assert(vhost_ops);
+
+    if (vhost_ops->vhost_reset_vring) {
+    state.index = hdev->vq_index + idx;
+    r = vhost_ops->vhost_reset_vring(hdev, );
+    if (r < 0) {
+    goto err_queue_reset;
+    }
+    }
+



So this worries me:

1) having two similar functions

vhost_virtqueue_stop()

and

vhost_dev_virtqueue_stop()

It can easily confuse the people who want stop the device.

I think we need rename vhost_dev_virtqueue_stop() to 
vhost_virqtueue_reset() since it has different semantic compared to stop:


1) stop means the virtqueue state is reserved, e.g the index could be 
synced via get_vring_base()

2) reset means the virqtueue state is lost

Thanks



Totally agree, will fix.

Thanks


  vhost_virtqueue_unmap(hdev,
    vdev,
    hdev->vqs + idx,
    idx);
+
+    return;
+
+err_queue_reset:
+    error_report("Error when stopping the qeuue.");
  }
    int vhost_dev_virtqueue_restart(struct vhost_dev *hdev, 
VirtIODevice *vdev,

Re: [PATCH v2 18/24] vhost-net: vhost-user: update vhost_net_virtqueue_stop()

2022-08-23 Thread Kangjie Xu



在 2022/8/24 12:05, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Update vhost_net_virtqueue_stop() for vhost-user scenario.



Let's explain why it is needed now or why it doesn't cause any issue 
or it's a bug fix or not.


Thanks


This patch is to suppport vq reset for vhost-user.

We need this simply because the behavior of vhost_ops->get_vq_index() is 
different in vhost-user and vhost-kernel.


vhost_user_get_vq_index(dev, idx) simply returns "idx".

vhost_kernel_get_vq_index(dev, idx) returns "idx - dev->vq_index".

Thanks





Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/net/vhost_net.c | 4 
  1 file changed, 4 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 2ab67e875e..c0d408f3b4 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -533,6 +533,10 @@ void vhost_net_virtqueue_stop(VirtIODevice 
*vdev, NetClientState *nc,

  assert(r >= 0);
  }
  +    if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+    idx = idx - net->dev.vq_index;
+    }
+
  vhost_dev_virtqueue_stop(>dev, vdev, idx);
  }




Re: [PATCH v2 11/24] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_stop()

2022-08-23 Thread Kangjie Xu



在 2022/8/24 10:40, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Introduce vhost_virtqueue_stop(), which can reset the virtqueue
in the device. Then it will unmap vrings and the desc of the
virtqueue.

This patch only considers the case for vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/net/vhost_net.c  | 21 +
  include/net/vhost_net.h |  2 ++
  2 files changed, 23 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index ccac5b7a64..aa60dd901c 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -514,3 +514,24 @@ int vhost_net_set_mtu(struct vhost_net *net, 
uint16_t mtu)

    return vhost_ops->vhost_net_set_mtu(>dev, mtu);
  }
+
+void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState *nc,
+  int vq_index)
+{
+    VHostNetState *net = get_vhost_net(nc->peer);
+    const VhostOps *vhost_ops = net->dev.vhost_ops;
+    struct vhost_vring_file file = { .fd = -1 };
+    int idx;
+
+    assert(vhost_ops);
+
+    idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.index = idx;
+    int r = vhost_net_set_backend(>dev, );
+    assert(r >= 0);
+    }



Let's have a vhost_ops here instead of open code it.

Thanks

I double-checked it, vhost_net_set_backend is already a wrapper of 
vhost_ops->vhost_net_set_backend().


It seems that, to further simplify it, we can only add idx and fd to the 
parameter list of vhost_net_set_backend().


Thanks




+
+    vhost_dev_virtqueue_stop(>dev, vdev, idx);
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 387e913e4e..9b3aaf3814 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -48,4 +48,6 @@ uint64_t vhost_net_get_acked_features(VHostNetState 
*net);

    int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
  +void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState *nc,
+  int vq_index);
  #endif




Re: [PATCH v2 15/24] vhost-user: add op to enable or disable a single vring

2022-08-23 Thread Kangjie Xu



在 2022/8/24 10:53, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

The interface to set enable status for a single vring is lacked in
VhostOps, since the vhost_set_vring_enable_op will manipulate all
virtqueues in a device.

Resetting a single vq will rely on this interface.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/vhost-user.c    | 26 +++---
  include/hw/virtio/vhost-backend.h |  3 +++
  2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 56033f7a92..8307976cda 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1199,6 +1199,22 @@ static int vhost_user_set_vring_base(struct 
vhost_dev *dev,

  return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
  }
  +static int vhost_user_set_single_vring_enable(struct vhost_dev *dev,
+  int index,
+  int enable)
+{
+    if (index < dev->vq_index || index >= dev->vq_index + dev->nvqs) {
+    return -EINVAL;
+    }
+
+    struct vhost_vring_state state = {
+    .index = index,
+    .num   = enable,
+    };
+
+    return vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+}
+
  static int vhost_user_set_vring_enable(struct vhost_dev *dev, int 
enable)

  {
  int i;
@@ -1208,13 +1224,8 @@ static int vhost_user_set_vring_enable(struct 
vhost_dev *dev, int enable)

  }
    for (i = 0; i < dev->nvqs; ++i) {
-    int ret;
-    struct vhost_vring_state state = {
-    .index = dev->vq_index + i,
-    .num   = enable,
-    };
-
-    ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, 
);



Then I'd squash this into previous patch or re-roder to let this patch 
(vhost_user_set_single_vring_enable()) to be first.


Thanks


Sorry, I don't get why we should re-order them, since these two patches 
are independent.


Thanks

+    int ret = vhost_user_set_single_vring_enable(dev, 
dev->vq_index + i,

+ enable);
  if (ret < 0) {
  /*
   * Restoring the previous state is likely infeasible, 
as well as

@@ -2668,6 +2679,7 @@ const VhostOps user_ops = {
  .vhost_reset_vring = vhost_user_reset_vring,
  .vhost_reset_device = vhost_user_reset_device,
  .vhost_get_vq_index = vhost_user_get_vq_index,
+    .vhost_set_single_vring_enable = 
vhost_user_set_single_vring_enable,

  .vhost_set_vring_enable = vhost_user_set_vring_enable,
  .vhost_requires_shm_log = vhost_user_requires_shm_log,
  .vhost_migration_done = vhost_user_migration_done,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h

index f23bf71a8d..38f6b752ff 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -83,6 +83,8 @@ typedef int (*vhost_reset_vring_op)(struct 
vhost_dev *dev,

  struct vhost_vring_state *ring);
  typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
  typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
+typedef int (*vhost_set_single_vring_enable_op)(struct vhost_dev *dev,
+    int index, int enable);
  typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
   int enable);
  typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
@@ -158,6 +160,7 @@ typedef struct VhostOps {
  vhost_reset_device_op vhost_reset_device;
  vhost_reset_vring_op vhost_reset_vring;
  vhost_get_vq_index_op vhost_get_vq_index;
+    vhost_set_single_vring_enable_op vhost_set_single_vring_enable;
  vhost_set_vring_enable_op vhost_set_vring_enable;
  vhost_requires_shm_log_op vhost_requires_shm_log;
  vhost_migration_done_op vhost_migration_done;




Re: [PATCH v2 14/24] vhost-user: introduce vhost_reset_vring() interface

2022-08-23 Thread Kangjie Xu



在 2022/8/24 10:50, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Introduce the interface vhost_reset_vring(). The interface is a wrapper
to send a VHOST_USER_RESET_VRING message to the back-end. It will reset
an individual vring in the back-end. Meanwhile, it will wait for a reply
to ensure the reset has been completed.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/vhost-user.c    | 41 +++
  include/hw/virtio/vhost-backend.h |  3 +++
  2 files changed, 44 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 75b8df21a4..56033f7a92 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -126,6 +126,7 @@ typedef enum VhostUserRequest {
  VHOST_USER_GET_MAX_MEM_SLOTS = 36,
  VHOST_USER_ADD_MEM_REG = 37,
  VHOST_USER_REM_MEM_REG = 38,
+    VHOST_USER_RESET_VRING = 41,
  VHOST_USER_MAX
  } VhostUserRequest;
  @@ -1498,6 +1499,45 @@ static int 
vhost_user_get_max_memslots(struct vhost_dev *dev,

  return 0;
  }
  +static int vhost_user_reset_vring(struct vhost_dev *dev,
+  struct vhost_vring_state *ring)
+{
+    int ret;
+    VhostUserMsg msg = {
+    .hdr.request = VHOST_USER_RESET_VRING,
+    .hdr.flags = VHOST_USER_VERSION,



Do we need VHOST_USER_NEED_REPLY_MASK here?

Other looks good.

Thanks

No, it works the same as vhost_user_get_features() or 
vhost_user_get_vring_base().


Thanks




+    .payload.state = *ring,
+    .hdr.size = sizeof(msg.payload.state),
+    };
+
+    if (!virtio_has_feature(dev->acked_features, 
VIRTIO_F_RING_RESET)) {

+    return -ENOTSUP;
+    }
+
+    ret = vhost_user_write(dev, , NULL, 0);
+    if (ret < 0) {
+    return ret;
+    }
+
+    ret = vhost_user_read(dev, );
+    if (ret < 0) {
+    return ret;
+    }
+
+    if (msg.hdr.request != VHOST_USER_RESET_VRING) {
+    error_report("Received unexpected msg type. Expected %d 
received %d",

+ VHOST_USER_RESET_VRING, msg.hdr.request);
+    return -EPROTO;
+    }
+
+    if (msg.hdr.size != sizeof(msg.payload.state)) {
+    error_report("Received bad msg size.");
+    return -EPROTO;
+    }
+
+    return 0;
+}
+
  static int vhost_user_reset_device(struct vhost_dev *dev)
  {
  VhostUserMsg msg = {
@@ -2625,6 +2665,7 @@ const VhostOps user_ops = {
  .vhost_set_features = vhost_user_set_features,
  .vhost_get_features = vhost_user_get_features,
  .vhost_set_owner = vhost_user_set_owner,
+    .vhost_reset_vring = vhost_user_reset_vring,
  .vhost_reset_device = vhost_user_reset_device,
  .vhost_get_vq_index = vhost_user_get_vq_index,
  .vhost_set_vring_enable = vhost_user_set_vring_enable,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h

index eab46d7f0b..f23bf71a8d 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -79,6 +79,8 @@ typedef int (*vhost_get_features_op)(struct 
vhost_dev *dev,

   uint64_t *features);
  typedef int (*vhost_set_backend_cap_op)(struct vhost_dev *dev);
  typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
+typedef int (*vhost_reset_vring_op)(struct vhost_dev *dev,
+    struct vhost_vring_state *ring);
  typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
  typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
  typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
@@ -154,6 +156,7 @@ typedef struct VhostOps {
  vhost_set_backend_cap_op vhost_set_backend_cap;
  vhost_set_owner_op vhost_set_owner;
  vhost_reset_device_op vhost_reset_device;
+    vhost_reset_vring_op vhost_reset_vring;
  vhost_get_vq_index_op vhost_get_vq_index;
  vhost_set_vring_enable_op vhost_set_vring_enable;
  vhost_requires_shm_log_op vhost_requires_shm_log;




Re: [PATCH v2 12/24] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()

2022-08-23 Thread Kangjie Xu



在 2022/8/24 10:44, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Introduce vhost_net_virtqueue_restart(), which can restart the
virtqueue when the vhost net started running before. If it fails
to restart the virtqueue, the device will be stopped.

This patch only considers the case for vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 



I would explain why current vhost_net_start_one()/vhost_net_stop_one() 
can't work. Is it because it works at queue pair level? If yes can we 
restructure the code and try to reuse ?


Thanks


Because vhost_net_start_one()/vhost_net_stop_one() works at device level.

The queue pair level start/stop are vhost_virtqueue_start() and 
vhost_virtqueue_stop().


What we can reuse is the vhost_virtqueue_start(). vhost_virtqueue_stop() 
cannot be reused because it will destroy device.


I think we do not need to restructure because we've already had an 
abstraction vhost_virtqueue_start().


Thanks.




---
  hw/net/vhost_net.c  | 48 +
  include/net/vhost_net.h |  2 ++
  2 files changed, 50 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index aa60dd901c..2ab67e875e 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -535,3 +535,51 @@ void vhost_net_virtqueue_stop(VirtIODevice 
*vdev, NetClientState *nc,

    vhost_dev_virtqueue_stop(>dev, vdev, idx);
  }
+
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+    int vq_index)
+{
+    VHostNetState *net = get_vhost_net(nc->peer);
+    const VhostOps *vhost_ops = net->dev.vhost_ops;
+    struct vhost_vring_file file = { };
+    int idx, r;
+
+    if (!net->dev.started) {
+    return 0;
+    }
+
+    assert(vhost_ops);
+
+    idx =  vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+    r = vhost_dev_virtqueue_restart(>dev, vdev, idx);
+    if (r < 0) {
+    goto err_start;
+    }
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.index = idx;
+    file.fd = net->backend;
+    r = vhost_net_set_backend(>dev, );
+    if (r < 0) {
+    r = -errno;
+    goto err_start;
+    }
+    }
+
+    return 0;
+
+err_start:
+    error_report("Error when restarting the queue.");
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.fd = -1;
+    file.index = idx;
+    int r = vhost_net_set_backend(>dev, );
+    assert(r >= 0);
+    }
+
+    vhost_dev_stop(>dev, vdev);
+
+    return r;
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 9b3aaf3814..e11a297380 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -50,4 +50,6 @@ int vhost_net_set_mtu(struct vhost_net *net, 
uint16_t mtu);
    void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState 
*nc,

    int vq_index);
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+    int vq_index);
  #endif




Re: [PATCH v2 11/24] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_stop()

2022-08-23 Thread Kangjie Xu


在 2022/8/24 10:40, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Introduce vhost_virtqueue_stop(), which can reset the virtqueue
in the device. Then it will unmap vrings and the desc of the
virtqueue.

This patch only considers the case for vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/net/vhost_net.c  | 21 +
  include/net/vhost_net.h |  2 ++
  2 files changed, 23 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index ccac5b7a64..aa60dd901c 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -514,3 +514,24 @@ int vhost_net_set_mtu(struct vhost_net *net, 
uint16_t mtu)

    return vhost_ops->vhost_net_set_mtu(>dev, mtu);
  }
+
+void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState *nc,
+  int vq_index)
+{
+    VHostNetState *net = get_vhost_net(nc->peer);
+    const VhostOps *vhost_ops = net->dev.vhost_ops;
+    struct vhost_vring_file file = { .fd = -1 };
+    int idx;
+
+    assert(vhost_ops);
+
+    idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+    file.index = idx;
+    int r = vhost_net_set_backend(>dev, );
+    assert(r >= 0);
+    }



Let's have a vhost_ops here instead of open code it.

Thanks


I share your view.

Thanks




+
+    vhost_dev_virtqueue_stop(>dev, vdev, idx);
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 387e913e4e..9b3aaf3814 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -48,4 +48,6 @@ uint64_t vhost_net_get_acked_features(VHostNetState 
*net);

    int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
  +void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState *nc,
+  int vq_index);
  #endif

Re: [PATCH v2 10/24] vhost: introduce vhost_dev_virtqueue_restart()

2022-08-23 Thread Kangjie Xu



在 2022/8/24 10:37, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Introduce vhost_dev_virtqueue_restart(), which can restart the
virtqueue when the vhost has already started running.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/vhost.c | 13 +
  include/hw/virtio/vhost.h |  2 ++
  2 files changed, 15 insertions(+)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 1bca9ff48d..fc3f550c76 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1913,3 +1913,16 @@ void vhost_dev_virtqueue_stop(struct vhost_dev 
*hdev, VirtIODevice *vdev,

    hdev->vqs + idx,
    idx);
  }
+
+int vhost_dev_virtqueue_restart(struct vhost_dev *hdev, VirtIODevice 
*vdev,

+    int idx)
+{
+    const VhostOps *vhost_ops = hdev->vhost_ops;
+
+    assert(vhost_ops);



So we had the comment like:

    /* should only be called after backend is connected */

in vhost_virtqueue_mask().

If this assert has the same reason, let's add a comment here.



Get it.

+
+    return vhost_virtqueue_start(hdev,
+ vdev,
+ hdev->vqs + idx,
+ hdev->vq_index + idx);



So it just a wrapper of vhost_virtqueue_start(), any value to have a 
re-start wrapper?


Thanks

Because in subsequent patches, to support vhost-user, we will add 
vhost_ops->vhost_set_single_vring_enable() in this function.


Thanks.




+}
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 574888440c..b3394b6348 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -291,4 +291,6 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, 
uint16_t queue_size,
    void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, 
VirtIODevice *vdev,

    int idx);
+int vhost_dev_virtqueue_restart(struct vhost_dev *hdev, VirtIODevice 
*vdev,

+    int idx);
  #endif




Re: [PATCH v2 07/24] virtio-pci: support queue enable

2022-08-23 Thread Kangjie Xu



在 2022/8/23 15:44, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

PCI devices support vq enable.



Nit: it might be "support device specific vq enable"



Get it.


Based on this function, the driver can re-enable the virtqueue after the
virtqueue is reset.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/virtio-pci.c | 1 +
  1 file changed, 1 insertion(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index ec8e92052f..3d560e45ad 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1335,6 +1335,7 @@ static void virtio_pci_common_write(void 
*opaque, hwaddr addr,

proxy->vqs[vdev->queue_sel].avail[0],
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
+    virtio_queue_enable(vdev, vdev->queue_sel);
  proxy->vqs[vdev->queue_sel].enabled = 1;
  proxy->vqs[vdev->queue_sel].reset = 0;



Any reason we do it before the assignment of 1? It probably means the 
device specific method can't depend on virtio_queue_enabled()?


Thanks

Sorry, I don't get why device specific method can't depend on 
virtio_queue_enabled().


Before virtio_queue_enable() is done, virtqueue should always be not 
ready and disabled.


Otherwise, If we put it after the assignment of enabled to 1, the 
virtqueue may be accessed illegally and may cause panic, because the 
virtqueue is still being intialized and being configured.


Thanks




  } else {




Re: [PATCH v2 09/24] vhost: introduce vhost_dev_virtqueue_stop()

2022-08-23 Thread Kangjie Xu



在 2022/8/23 15:52, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

Introduce vhost_dev_virtqueue_stop(), which can ummap the
vrings and the desc of it.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/virtio/vhost.c | 9 +
  include/hw/virtio/vhost.h | 3 +++
  2 files changed, 12 insertions(+)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index e467dfc7bc..1bca9ff48d 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1904,3 +1904,12 @@ int vhost_net_set_backend(struct vhost_dev *hdev,
    return -ENOSYS;
  }
+
+void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, VirtIODevice 
*vdev,

+  int idx)
+{
+    vhost_virtqueue_unmap(hdev,
+  vdev,
+  hdev->vqs + idx,
+  idx);



So I think the unmap is not sufficient, we need backend specific 
support. E.g for vhost kernel, need a SET_BACKEND here?


Thanks

But SET_BACKEND of vhost-net needs a parameter fd in vhost_vring_file: 
that is net->backend of VHostNetState.


If we add the fd parameter or struct vhost_vring_file to 
vhost_dev_virtqueue_stop/restart, it exposes some implementation details 
in the parameter list.


And that seems not good? So I put SET_BACKEND in the vhost-net module. 
The workflow is similar to vhost_net_start_one().


Thanks




+}
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index a346f23d13..574888440c 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -288,4 +288,7 @@ int vhost_dev_set_inflight(struct vhost_dev *dev,
 struct vhost_inflight *inflight);
  int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size,
 struct vhost_inflight *inflight);
+
+void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, VirtIODevice 
*vdev,

+  int idx);
  #endif




Re: [PATCH v2 06/24] virtio-pci: support queue reset

2022-08-23 Thread Kangjie Xu



在 2022/8/23 15:40, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

From: Xuan Zhuo 

PCI devices support vq reset.

Based on this function, the driver can adjust the size of the ring, and
quickly recycle the buffer in the ring.

The migration of the virtio devices will not happen during a reset
operation. This is becuase the global iothread lock is held. Migration
thread also needs the lock. As a result, we do not need to migrate the
reset state of VirtIOPCIQueue.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
  hw/virtio/virtio-pci.c | 19 +++
  include/hw/virtio/virtio-pci.h |  1 +
  2 files changed, 20 insertions(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 45327f0b31..ec8e92052f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1246,6 +1246,9 @@ static uint64_t virtio_pci_common_read(void 
*opaque, hwaddr addr,

  case VIRTIO_PCI_COMMON_Q_USEDHI:
  val = proxy->vqs[vdev->queue_sel].used[1];
  break;
+    case VIRTIO_PCI_COMMON_Q_RESET:
+    val = proxy->vqs[vdev->queue_sel].reset;
+    break;
  default:
  val = 0;
  }
@@ -1333,6 +1336,7 @@ static void virtio_pci_common_write(void 
*opaque, hwaddr addr,

((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
  proxy->vqs[vdev->queue_sel].enabled = 1;
+    proxy->vqs[vdev->queue_sel].reset = 0;
  } else {
  virtio_error(vdev, "wrong value for queue_enable 
%"PRIx64, val);

  }
@@ -1355,6 +1359,20 @@ static void virtio_pci_common_write(void 
*opaque, hwaddr addr,

  case VIRTIO_PCI_COMMON_Q_USEDHI:
  proxy->vqs[vdev->queue_sel].used[1] = val;
  break;
+    case VIRTIO_PCI_COMMON_Q_RESET:
+    if (val == 1) {
+    /*
+ * With the global iothread lock taken, the migration 
will not

+ * happen until the virtqueue reset is done.
+ */



This comment applies to all other common cfg operation as well, So it 
looks not necessary?



Get it.




+ proxy->vqs[vdev->queue_sel].reset = 1;
+
+    virtio_queue_reset(vdev, vdev->queue_sel);
+
+    proxy->vqs[vdev->queue_sel].reset = 0;
+    proxy->vqs[vdev->queue_sel].enabled = 0;
+    }
+    break;
  default:
  break;
  }
@@ -1950,6 +1968,7 @@ static void virtio_pci_reset(DeviceState *qdev)
    for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
  proxy->vqs[i].enabled = 0;
+    proxy->vqs[i].reset = 0;
  proxy->vqs[i].num = 0;
  proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
  proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
diff --git a/include/hw/virtio/virtio-pci.h 
b/include/hw/virtio/virtio-pci.h

index 2446dcd9ae..e9290e2b94 100644
--- a/include/hw/virtio/virtio-pci.h
+++ b/include/hw/virtio/virtio-pci.h
@@ -117,6 +117,7 @@ typedef struct VirtIOPCIRegion {
  typedef struct VirtIOPCIQueue {
    uint16_t num;
    bool enabled;
+  bool reset;



Do we need to migrate this?

Thanks

I think we do not need to migrate this because we hold the global 
iothread lock when virtqueue reset is triggered. The migration of these 
device states also needs this lock.


On the other hand, the 'reset' state of virtqueue is same(is 0) before 
and after the process of resetting a virtqueue.


Thus, the migration will not happen when we are resetting a virtqueue 
and we do not to migrate it.


Thanks




    uint32_t desc[2];
    uint32_t avail[2];
    uint32_t used[2];




Re: [PATCH v2 05/24] virtio: core: vq reset feature negotation support

2022-08-23 Thread Kangjie Xu



在 2022/8/23 15:34, Jason Wang 写道:


在 2022/8/16 09:06, Kangjie Xu 写道:

A a new command line parameter "queue_reset" is added.

Meanwhile, the vq reset feature is disabled for pre-7.1 machines.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
  hw/core/machine.c  | 1 +
  include/hw/virtio/virtio.h | 4 +++-
  2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index a673302cce..8b22b4647f 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -43,6 +43,7 @@
  GlobalProperty hw_compat_7_0[] = {
  { "arm-gicv3-common", "force-8-bit-prio", "on" },
  { "nvme-ns", "eui64-default", "on"},
+    { "virtio-device", "queue_reset", "false" },



7.1 is about to release so we need to do it for pre-7.2.

Thanks

The current version is 7.0.92, should I wait until 7.1 to be released 
and submit my patch after that? or just add hw_compat_7_1[] and related 
support.


Thanks




  };
  const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
  diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 085997d8f3..ed3ecbef80 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -295,7 +295,9 @@ typedef struct VirtIORNGConf VirtIORNGConf;
  DEFINE_PROP_BIT64("iommu_platform", _state, _field, \
    VIRTIO_F_IOMMU_PLATFORM, false), \
  DEFINE_PROP_BIT64("packed", _state, _field, \
-  VIRTIO_F_RING_PACKED, false)
+  VIRTIO_F_RING_PACKED, false), \
+    DEFINE_PROP_BIT64("queue_reset", _state, _field, \
+  VIRTIO_F_RING_RESET, true)
    hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
  bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n);




Re: [PATCH 00/24] Support VIRTIO_F_RING_RESET for virtio-net, vhost-user, vhost-kernel in virtio pci-modern

2022-08-22 Thread Kangjie Xu
Forgot to append changelog for v2 in the cover letter, so I add it in 
this email.



changelog:

1. Add support for vhost-net scenario

2. Add a new vhost-user message VHOST_USER_RESET_VRING

3. Add migration compatibility for virtqueue reset


Looking forward to your review and comments to this patch set, thanks. :)


Best regards,

Kangjie

在 2022/8/16 09:06, Kangjie Xu 写道:

The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

 https://github.com/oasis-tcs/virtio-spec/issues/124
 https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-12 support vq stop and vq restart for vhost-kernel.
3. Patches 13-19 support vq stop and vq restart for vhost-user.
4. Patches 20-22 support vq reset and re-enable for virtio-net.
5. Patches 23-24 enable the vq reset feature for vhost-kernel and vhost-user.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

Since this patch set involves multiple modules and seems a bit messy, we 
briefly describe the
calling process for different modes below.
virtio-net:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> set enabled, reset status of vq.

vhost-kernel:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> vhost_net_virtqueue_stop() [vhost-net]
 -> vhost_net_set_backend() [vhost]
 -> vhost_dev_virtqueue_stop()
 -> vhost_virtqueue_unmap()
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> virtio_queue_enable() [virtio]
 -> virtio_net_queue_enable() [virtio-net]
 -> vhost_net_virtqueue_restart() [vhost-net]
 -> vhost_dev_virtqueue_restart() [vhost]
 -> vhost_virtqueue_start()
 -> vhost_net_set_backend()
 -> set enabled, reset status of vq.

vhost-user:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> vhost_net_virtqueue_stop() [vhost-net]
 -> vhost_dev_virtqueue_stop() [vhost]
 -> vhost_user_reset_vring() [vhost-user]
 -> send VHOST_USER_RESET_VRING to the device
 -> vhost_virtqueue_unmap()
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> virtio_queue_enable() [virtio]
 -> virtio_net_queue_enable() [virtio-net]
 -> vhost_net_virtqueue_restart() [vhost-net]
 -> vhost_dev_virtqueue_restart() [vhost]
 -> vhost_virtqueue_start()
 -> vhost_user_set_single_vring_enable [vhost-user]
 -> send VHOST_USER_SET_VRING_ENABLE to the device
 -> set enabled, reset status of vq.


Test environment:
 Host: 5.19.0-rc3 (With vq reset support)
 Qemu: QEMU emulator version 7.0.50
 Guest: 5.19.0-rc3 (With vq reset support)
 DPDK: 22.07-rc1 (With vq reset support)
 Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

 The drvier can resize the virtio queue, then virtio queue reset function 
should
 be triggered.

 The default is split mode, modify Qemu virtio-net to add PACKED feature to
 test packed mode.

Guest Kernel Patch:
 
https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

DPDK Patch:
 
https://github.com/middaywords/dpdk/compare/72206323a5dd3182b13f61b25a64abdddfee595c...eabadfac7953da66bc10ffb8284b490d09bb7ec7

Host Kernel Patch:
 
https://github.com/middaywords/linux/commit/19a91e0d7167b2031e46078c6215c213b89cb2c3

Looking forward to your review and comments. Thanks.

Kangjie Xu (19):
   virtio: introduce virtio_queue_enable()
   virtio: core: vq reset feature negotation support
   virtio-pci: support queue enable
   vhost: extract the logic of unmapping the vrings and desc
   vhost: introduce vhost_dev_virtqueue_stop()
   vhost: introduce vhost_dev_virtqueue_restart()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_stop()
   vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()
   docs: vhost-user: add VHOST_USER_RESET_VRING message
   vhost-user: introduce vhost_reset_vring() interface
   vhost-

Re: [PATCH 00/24] Support VIRTIO_F_RING_RESET for virtio-net, vhost-user, vhost-kernel in virtio pci-modern

2022-08-17 Thread Kangjie Xu



在 2022/8/16 14:22, Michael S. Tsirkin 写道:

On Tue, Aug 16, 2022 at 02:15:57PM +0800, Xuan Zhuo wrote:

On Tue, 16 Aug 2022 02:14:10 -0400, "Michael S. Tsirkin"  
wrote:

On Tue, Aug 16, 2022 at 09:06:12AM +0800, Kangjie Xu wrote:

The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

 https://github.com/oasis-tcs/virtio-spec/issues/124
 https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-12 support vq stop and vq restart for vhost-kernel.
3. Patches 13-19 support vq stop and vq restart for vhost-user.
4. Patches 20-22 support vq reset and re-enable for virtio-net.
5. Patches 23-24 enable the vq reset feature for vhost-kernel and vhost-user.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

Since this patch set involves multiple modules and seems a bit messy, we 
briefly describe the
calling process for different modes below.
virtio-net:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> set enabled, reset status of vq.

vhost-kernel:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> vhost_net_virtqueue_stop() [vhost-net]
 -> vhost_net_set_backend() [vhost]
 -> vhost_dev_virtqueue_stop()
 -> vhost_virtqueue_unmap()
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> virtio_queue_enable() [virtio]
 -> virtio_net_queue_enable() [virtio-net]
 -> vhost_net_virtqueue_restart() [vhost-net]
 -> vhost_dev_virtqueue_restart() [vhost]
 -> vhost_virtqueue_start()
 -> vhost_net_set_backend()
 -> set enabled, reset status of vq.

vhost-user:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
 -> virtio_queue_reset() [virtio]
 -> virtio_net_queue_reset() [virtio-net]
 -> vhost_net_virtqueue_stop() [vhost-net]
 -> vhost_dev_virtqueue_stop() [vhost]
 -> vhost_user_reset_vring() [vhost-user]
 -> send VHOST_USER_RESET_VRING to the device
 -> vhost_virtqueue_unmap()
 -> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
 -> virtio_queue_enable() [virtio]
 -> virtio_net_queue_enable() [virtio-net]
 -> vhost_net_virtqueue_restart() [vhost-net]
 -> vhost_dev_virtqueue_restart() [vhost]
 -> vhost_virtqueue_start()
 -> vhost_user_set_single_vring_enable [vhost-user]
 -> send VHOST_USER_SET_VRING_ENABLE to the device
 -> set enabled, reset status of vq.


Test environment:
 Host: 5.19.0-rc3 (With vq reset support)
 Qemu: QEMU emulator version 7.0.50
 Guest: 5.19.0-rc3 (With vq reset support)
 DPDK: 22.07-rc1 (With vq reset support)
 Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

 The drvier can resize the virtio queue, then virtio queue reset function 
should
 be triggered.

 The default is split mode, modify Qemu virtio-net to add PACKED feature to
 test packed mode.

legacy mode testing?


legacy does not support vq reset.

Thanks.

yes but did it break with all these code changes?


For pci legacy mode, we tested resizing the vq using 'ethtool -G', it 
reported an error code -ENOENT because the transport did not support the 
vq reset feature.


We also tested the connectivity and performance in pci legacy mode using 
iperf 3.9. We placed a client in the host and a server in the guest, or 
swapped the them.


In all the cases, the connectivity did not break down. The performance 
was about the same with all our code changes.


Thanks.


Guest Kernel Patch:
 
https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

DPDK Patch:
 
https://github.com/middaywords/dpdk/compare/72206323a5dd3182b13f61b25a64abdddfee595c...eabadfac7953da66bc10ffb8284b490d09bb7ec7

Host Kernel Patch:
 
https://github.com/middaywords/linux/commit/19a91e0d7167b2031e46078c6215c213b89cb2c3

Looking forward to your review and comments. Thanks.

Kangjie Xu (19):
   virtio: introduce virtio_queue_enable()
   virtio: core: vq reset feature negotation support
   v

[PATCH v2 19/24] vhost-net: vhost-user: update vhost_net_virtqueue_restart()

2022-08-15 Thread Kangjie Xu
Update vhost_net_virtqueue_restart() for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index c0d408f3b4..778081e54a 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -556,6 +556,10 @@ int vhost_net_virtqueue_restart(VirtIODevice *vdev, 
NetClientState *nc,
 
 idx =  vhost_ops->vhost_get_vq_index(>dev, vq_index);
 
+if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+idx = idx - net->dev.vq_index;
+}
+
 r = vhost_dev_virtqueue_restart(>dev, vdev, idx);
 if (r < 0) {
 goto err_start;
-- 
2.32.0




[PATCH v2 20/24] virtio-net: introduce flush_or_purge_queued_packets()

2022-08-15 Thread Kangjie Xu
Introduce the fucntion flush_or_purge_queued_packets(), it will be
used in device reset and virtqueue reset. Therefore, we extract the
common logic as a new function.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/virtio-net.c | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index dd0d056fde..27b59c0ad6 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -118,6 +118,16 @@ static int vq2q(int queue_index)
 return queue_index / 2;
 }
 
+static void flush_or_purge_queued_packets(NetClientState *nc)
+{
+if (!nc->peer) {
+return;
+}
+
+qemu_flush_or_purge_queued_packets(nc->peer, true);
+assert(!virtio_net_get_subqueue(nc)->async_tx.elem);
+}
+
 /* TODO
  * - we could suppress RX interrupt if we were so inclined.
  */
@@ -560,12 +570,7 @@ static void virtio_net_reset(VirtIODevice *vdev)
 
 /* Flush any async TX */
 for (i = 0;  i < n->max_queue_pairs; i++) {
-NetClientState *nc = qemu_get_subqueue(n->nic, i);
-
-if (nc->peer) {
-qemu_flush_or_purge_queued_packets(nc->peer, true);
-assert(!virtio_net_get_subqueue(nc)->async_tx.elem);
-}
+flush_or_purge_queued_packets(qemu_get_subqueue(n->nic, i));
 }
 }
 
-- 
2.32.0




[PATCH v2 24/24] vhost: vhost-user: enable vq reset feature

2022-08-15 Thread Kangjie Xu
Add virtqueue reset feature for vhost-user.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 9ea160e4e9..5bc89f2842 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -74,6 +74,7 @@ static const int user_feature_bits[] = {
 VIRTIO_NET_F_MTU,
 VIRTIO_F_IOMMU_PLATFORM,
 VIRTIO_F_RING_PACKED,
+VIRTIO_F_RING_RESET,
 VIRTIO_NET_F_RSS,
 VIRTIO_NET_F_HASH_REPORT,
 
-- 
2.32.0




[PATCH v2 18/24] vhost-net: vhost-user: update vhost_net_virtqueue_stop()

2022-08-15 Thread Kangjie Xu
Update vhost_net_virtqueue_stop() for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 2ab67e875e..c0d408f3b4 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -533,6 +533,10 @@ void vhost_net_virtqueue_stop(VirtIODevice *vdev, 
NetClientState *nc,
 assert(r >= 0);
 }
 
+if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
+idx = idx - net->dev.vq_index;
+}
+
 vhost_dev_virtqueue_stop(>dev, vdev, idx);
 }
 
-- 
2.32.0




[PATCH v2 21/24] virtio-net: support queue reset

2022-08-15 Thread Kangjie Xu
From: Xuan Zhuo 

virtio-net, vhost-kernel, vhost-user implement queue reset.
Queued packets in the corresponding queue pair are flushed
or purged.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
 hw/net/virtio-net.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 27b59c0ad6..e2989487ec 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -540,6 +540,24 @@ static RxFilterInfo 
*virtio_net_query_rxfilter(NetClientState *nc)
 return info;
 }
 
+static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtIONet *n = VIRTIO_NET(vdev);
+NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+
+if (!nc->peer) {
+return;
+}
+
+if (get_vhost_net(nc->peer) &&
+((nc->peer->info->type == NET_CLIENT_DRIVER_TAP) ||
+ (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER))) {
+vhost_net_virtqueue_stop(vdev, nc, queue_index);
+}
+
+flush_or_purge_queued_packets(nc);
+}
+
 static void virtio_net_reset(VirtIODevice *vdev)
 {
 VirtIONet *n = VIRTIO_NET(vdev);
@@ -3784,6 +3802,7 @@ static void virtio_net_class_init(ObjectClass *klass, 
void *data)
 vdc->set_features = virtio_net_set_features;
 vdc->bad_features = virtio_net_bad_features;
 vdc->reset = virtio_net_reset;
+vdc->queue_reset = virtio_net_queue_reset;
 vdc->set_status = virtio_net_set_status;
 vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
 vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
-- 
2.32.0




[PATCH v2 16/24] vhost: vhost-user: update vhost_dev_virtqueue_stop()

2022-08-15 Thread Kangjie Xu
Update vhost_dev_virtqueue_stop() for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index fc3f550c76..a0d6824353 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1908,10 +1908,29 @@ int vhost_net_set_backend(struct vhost_dev *hdev,
 void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
   int idx)
 {
+const VhostOps *vhost_ops = hdev->vhost_ops;
+struct vhost_vring_state state;
+int r;
+
+assert(vhost_ops);
+
+if (vhost_ops->vhost_reset_vring) {
+state.index = hdev->vq_index + idx;
+r = vhost_ops->vhost_reset_vring(hdev, );
+if (r < 0) {
+goto err_queue_reset;
+}
+}
+
 vhost_virtqueue_unmap(hdev,
   vdev,
   hdev->vqs + idx,
   idx);
+
+return;
+
+err_queue_reset:
+error_report("Error when stopping the qeuue.");
 }
 
 int vhost_dev_virtqueue_restart(struct vhost_dev *hdev, VirtIODevice *vdev,
-- 
2.32.0




[PATCH v2 22/24] virtio-net: support queue_enable

2022-08-15 Thread Kangjie Xu
virtio-net: support queue_enable for vhost

Support queue_enable in vhost scenario. It can be called when
a vq reset operation is performed and the vq will be restared.

It should be noted that we can restart the vq when the vhost has
already started. When launching a new vhost-user device, the vhost
is not started and all vqs are not initalized until
VIRTIO_PCI_COMMON_STATUS is written. Thus, we should use vhost_started
to differentiate the two cases: vq reset and device start.

Currently it only supports vhost-user and vhost-kernel.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/virtio-net.c | 22 ++
 1 file changed, 22 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index e2989487ec..ba216f7b84 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -558,6 +558,27 @@ static void virtio_net_queue_reset(VirtIODevice *vdev, 
uint32_t queue_index)
 flush_or_purge_queued_packets(nc);
 }
 
+static void virtio_net_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtIONet *n = VIRTIO_NET(vdev);
+NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index));
+int r;
+
+if (!nc->peer || !vdev->vhost_started) {
+return;
+}
+
+if (get_vhost_net(nc->peer) &&
+((nc->peer->info->type == NET_CLIENT_DRIVER_TAP) ||
+ (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER))) {
+r = vhost_net_virtqueue_restart(vdev, nc, queue_index);
+if (r < 0) {
+error_report("unable to restart vhost net virtqueue: %d, "
+"when resetting the queue", queue_index);
+}
+}
+}
+
 static void virtio_net_reset(VirtIODevice *vdev)
 {
 VirtIONet *n = VIRTIO_NET(vdev);
@@ -3803,6 +3824,7 @@ static void virtio_net_class_init(ObjectClass *klass, 
void *data)
 vdc->bad_features = virtio_net_bad_features;
 vdc->reset = virtio_net_reset;
 vdc->queue_reset = virtio_net_queue_reset;
+vdc->queue_enable = virtio_net_queue_enable;
 vdc->set_status = virtio_net_set_status;
 vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
 vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
-- 
2.32.0




[PATCH v2 14/24] vhost-user: introduce vhost_reset_vring() interface

2022-08-15 Thread Kangjie Xu
Introduce the interface vhost_reset_vring(). The interface is a wrapper
to send a VHOST_USER_RESET_VRING message to the back-end. It will reset
an individual vring in the back-end. Meanwhile, it will wait for a reply
to ensure the reset has been completed.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost-user.c| 41 +++
 include/hw/virtio/vhost-backend.h |  3 +++
 2 files changed, 44 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 75b8df21a4..56033f7a92 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -126,6 +126,7 @@ typedef enum VhostUserRequest {
 VHOST_USER_GET_MAX_MEM_SLOTS = 36,
 VHOST_USER_ADD_MEM_REG = 37,
 VHOST_USER_REM_MEM_REG = 38,
+VHOST_USER_RESET_VRING = 41,
 VHOST_USER_MAX
 } VhostUserRequest;
 
@@ -1498,6 +1499,45 @@ static int vhost_user_get_max_memslots(struct vhost_dev 
*dev,
 return 0;
 }
 
+static int vhost_user_reset_vring(struct vhost_dev *dev,
+  struct vhost_vring_state *ring)
+{
+int ret;
+VhostUserMsg msg = {
+.hdr.request = VHOST_USER_RESET_VRING,
+.hdr.flags = VHOST_USER_VERSION,
+.payload.state = *ring,
+.hdr.size = sizeof(msg.payload.state),
+};
+
+if (!virtio_has_feature(dev->acked_features, VIRTIO_F_RING_RESET)) {
+return -ENOTSUP;
+}
+
+ret = vhost_user_write(dev, , NULL, 0);
+if (ret < 0) {
+return ret;
+}
+
+ret = vhost_user_read(dev, );
+if (ret < 0) {
+return ret;
+}
+
+if (msg.hdr.request != VHOST_USER_RESET_VRING) {
+error_report("Received unexpected msg type. Expected %d received %d",
+ VHOST_USER_RESET_VRING, msg.hdr.request);
+return -EPROTO;
+}
+
+if (msg.hdr.size != sizeof(msg.payload.state)) {
+error_report("Received bad msg size.");
+return -EPROTO;
+}
+
+return 0;
+}
+
 static int vhost_user_reset_device(struct vhost_dev *dev)
 {
 VhostUserMsg msg = {
@@ -2625,6 +2665,7 @@ const VhostOps user_ops = {
 .vhost_set_features = vhost_user_set_features,
 .vhost_get_features = vhost_user_get_features,
 .vhost_set_owner = vhost_user_set_owner,
+.vhost_reset_vring = vhost_user_reset_vring,
 .vhost_reset_device = vhost_user_reset_device,
 .vhost_get_vq_index = vhost_user_get_vq_index,
 .vhost_set_vring_enable = vhost_user_set_vring_enable,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h
index eab46d7f0b..f23bf71a8d 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -79,6 +79,8 @@ typedef int (*vhost_get_features_op)(struct vhost_dev *dev,
  uint64_t *features);
 typedef int (*vhost_set_backend_cap_op)(struct vhost_dev *dev);
 typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
+typedef int (*vhost_reset_vring_op)(struct vhost_dev *dev,
+struct vhost_vring_state *ring);
 typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
 typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
 typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
@@ -154,6 +156,7 @@ typedef struct VhostOps {
 vhost_set_backend_cap_op vhost_set_backend_cap;
 vhost_set_owner_op vhost_set_owner;
 vhost_reset_device_op vhost_reset_device;
+vhost_reset_vring_op vhost_reset_vring;
 vhost_get_vq_index_op vhost_get_vq_index;
 vhost_set_vring_enable_op vhost_set_vring_enable;
 vhost_requires_shm_log_op vhost_requires_shm_log;
-- 
2.32.0




[PATCH v2 15/24] vhost-user: add op to enable or disable a single vring

2022-08-15 Thread Kangjie Xu
The interface to set enable status for a single vring is lacked in
VhostOps, since the vhost_set_vring_enable_op will manipulate all
virtqueues in a device.

Resetting a single vq will rely on this interface.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost-user.c| 26 +++---
 include/hw/virtio/vhost-backend.h |  3 +++
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 56033f7a92..8307976cda 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1199,6 +1199,22 @@ static int vhost_user_set_vring_base(struct vhost_dev 
*dev,
 return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
 }
 
+static int vhost_user_set_single_vring_enable(struct vhost_dev *dev,
+  int index,
+  int enable)
+{
+if (index < dev->vq_index || index >= dev->vq_index + dev->nvqs) {
+return -EINVAL;
+}
+
+struct vhost_vring_state state = {
+.index = index,
+.num   = enable,
+};
+
+return vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+}
+
 static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
 {
 int i;
@@ -1208,13 +1224,8 @@ static int vhost_user_set_vring_enable(struct vhost_dev 
*dev, int enable)
 }
 
 for (i = 0; i < dev->nvqs; ++i) {
-int ret;
-struct vhost_vring_state state = {
-.index = dev->vq_index + i,
-.num   = enable,
-};
-
-ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, );
+int ret = vhost_user_set_single_vring_enable(dev, dev->vq_index + i,
+ enable);
 if (ret < 0) {
 /*
  * Restoring the previous state is likely infeasible, as well as
@@ -2668,6 +2679,7 @@ const VhostOps user_ops = {
 .vhost_reset_vring = vhost_user_reset_vring,
 .vhost_reset_device = vhost_user_reset_device,
 .vhost_get_vq_index = vhost_user_get_vq_index,
+.vhost_set_single_vring_enable = vhost_user_set_single_vring_enable,
 .vhost_set_vring_enable = vhost_user_set_vring_enable,
 .vhost_requires_shm_log = vhost_user_requires_shm_log,
 .vhost_migration_done = vhost_user_migration_done,
diff --git a/include/hw/virtio/vhost-backend.h 
b/include/hw/virtio/vhost-backend.h
index f23bf71a8d..38f6b752ff 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -83,6 +83,8 @@ typedef int (*vhost_reset_vring_op)(struct vhost_dev *dev,
 struct vhost_vring_state *ring);
 typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
 typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
+typedef int (*vhost_set_single_vring_enable_op)(struct vhost_dev *dev,
+int index, int enable);
 typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
  int enable);
 typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
@@ -158,6 +160,7 @@ typedef struct VhostOps {
 vhost_reset_device_op vhost_reset_device;
 vhost_reset_vring_op vhost_reset_vring;
 vhost_get_vq_index_op vhost_get_vq_index;
+vhost_set_single_vring_enable_op vhost_set_single_vring_enable;
 vhost_set_vring_enable_op vhost_set_vring_enable;
 vhost_requires_shm_log_op vhost_requires_shm_log;
 vhost_migration_done_op vhost_migration_done;
-- 
2.32.0




[PATCH v2 11/24] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_stop()

2022-08-15 Thread Kangjie Xu
Introduce vhost_virtqueue_stop(), which can reset the virtqueue
in the device. Then it will unmap vrings and the desc of the
virtqueue.

This patch only considers the case for vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c  | 21 +
 include/net/vhost_net.h |  2 ++
 2 files changed, 23 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index ccac5b7a64..aa60dd901c 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -514,3 +514,24 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
 
 return vhost_ops->vhost_net_set_mtu(>dev, mtu);
 }
+
+void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState *nc,
+  int vq_index)
+{
+VHostNetState *net = get_vhost_net(nc->peer);
+const VhostOps *vhost_ops = net->dev.vhost_ops;
+struct vhost_vring_file file = { .fd = -1 };
+int idx;
+
+assert(vhost_ops);
+
+idx = vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.index = idx;
+int r = vhost_net_set_backend(>dev, );
+assert(r >= 0);
+}
+
+vhost_dev_virtqueue_stop(>dev, vdev, idx);
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 387e913e4e..9b3aaf3814 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -48,4 +48,6 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net);
 
 int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
 
+void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState *nc,
+  int vq_index);
 #endif
-- 
2.32.0




[PATCH v2 17/24] vhost: vhost-user: update vhost_dev_virtqueue_restart()

2022-08-15 Thread Kangjie Xu
Update vhost_dev_virtqueue_restart() for vhost-user scenario.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 26 ++
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index a0d6824353..bd90cfe13a 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1937,11 +1937,29 @@ int vhost_dev_virtqueue_restart(struct vhost_dev *hdev, 
VirtIODevice *vdev,
 int idx)
 {
 const VhostOps *vhost_ops = hdev->vhost_ops;
+int r;
 
 assert(vhost_ops);
 
-return vhost_virtqueue_start(hdev,
- vdev,
- hdev->vqs + idx,
- hdev->vq_index + idx);
+r = vhost_virtqueue_start(hdev,
+  vdev,
+  hdev->vqs + idx,
+  hdev->vq_index + idx);
+if (r < 0) {
+goto err_start;
+}
+
+if (vhost_ops->vhost_set_single_vring_enable) {
+r = vhost_ops->vhost_set_single_vring_enable(hdev,
+ hdev->vq_index + idx,
+ 1);
+if (r < 0) {
+goto err_start;
+}
+}
+
+return 0;
+
+err_start:
+return r;
 }
-- 
2.32.0




[PATCH v2 12/24] vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()

2022-08-15 Thread Kangjie Xu
Introduce vhost_net_virtqueue_restart(), which can restart the
virtqueue when the vhost net started running before. If it fails
to restart the virtqueue, the device will be stopped.

This patch only considers the case for vhost-kernel, when
NetClientDriver is NET_CLIENT_DRIVER_TAP.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c  | 48 +
 include/net/vhost_net.h |  2 ++
 2 files changed, 50 insertions(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index aa60dd901c..2ab67e875e 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -535,3 +535,51 @@ void vhost_net_virtqueue_stop(VirtIODevice *vdev, 
NetClientState *nc,
 
 vhost_dev_virtqueue_stop(>dev, vdev, idx);
 }
+
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+int vq_index)
+{
+VHostNetState *net = get_vhost_net(nc->peer);
+const VhostOps *vhost_ops = net->dev.vhost_ops;
+struct vhost_vring_file file = { };
+int idx, r;
+
+if (!net->dev.started) {
+return 0;
+}
+
+assert(vhost_ops);
+
+idx =  vhost_ops->vhost_get_vq_index(>dev, vq_index);
+
+r = vhost_dev_virtqueue_restart(>dev, vdev, idx);
+if (r < 0) {
+goto err_start;
+}
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.index = idx;
+file.fd = net->backend;
+r = vhost_net_set_backend(>dev, );
+if (r < 0) {
+r = -errno;
+goto err_start;
+}
+}
+
+return 0;
+
+err_start:
+error_report("Error when restarting the queue.");
+
+if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
+file.fd = -1;
+file.index = idx;
+int r = vhost_net_set_backend(>dev, );
+assert(r >= 0);
+}
+
+vhost_dev_stop(>dev, vdev);
+
+return r;
+}
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index 9b3aaf3814..e11a297380 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -50,4 +50,6 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
 
 void vhost_net_virtqueue_stop(VirtIODevice *vdev, NetClientState *nc,
   int vq_index);
+int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
+int vq_index);
 #endif
-- 
2.32.0




[PATCH v2 10/24] vhost: introduce vhost_dev_virtqueue_restart()

2022-08-15 Thread Kangjie Xu
Introduce vhost_dev_virtqueue_restart(), which can restart the
virtqueue when the vhost has already started running.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 13 +
 include/hw/virtio/vhost.h |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 1bca9ff48d..fc3f550c76 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1913,3 +1913,16 @@ void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, 
VirtIODevice *vdev,
   hdev->vqs + idx,
   idx);
 }
+
+int vhost_dev_virtqueue_restart(struct vhost_dev *hdev, VirtIODevice *vdev,
+int idx)
+{
+const VhostOps *vhost_ops = hdev->vhost_ops;
+
+assert(vhost_ops);
+
+return vhost_virtqueue_start(hdev,
+ vdev,
+ hdev->vqs + idx,
+ hdev->vq_index + idx);
+}
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 574888440c..b3394b6348 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -291,4 +291,6 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t 
queue_size,
 
 void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
   int idx);
+int vhost_dev_virtqueue_restart(struct vhost_dev *hdev, VirtIODevice *vdev,
+int idx);
 #endif
-- 
2.32.0




[PATCH v2 09/24] vhost: introduce vhost_dev_virtqueue_stop()

2022-08-15 Thread Kangjie Xu
Introduce vhost_dev_virtqueue_stop(), which can ummap the
vrings and the desc of it.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 9 +
 include/hw/virtio/vhost.h | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index e467dfc7bc..1bca9ff48d 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1904,3 +1904,12 @@ int vhost_net_set_backend(struct vhost_dev *hdev,
 
 return -ENOSYS;
 }
+
+void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
+  int idx)
+{
+vhost_virtqueue_unmap(hdev,
+  vdev,
+  hdev->vqs + idx,
+  idx);
+}
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index a346f23d13..574888440c 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -288,4 +288,7 @@ int vhost_dev_set_inflight(struct vhost_dev *dev,
struct vhost_inflight *inflight);
 int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size,
struct vhost_inflight *inflight);
+
+void vhost_dev_virtqueue_stop(struct vhost_dev *hdev, VirtIODevice *vdev,
+  int idx);
 #endif
-- 
2.32.0




[PATCH v2 02/24] virtio: introduce __virtio_queue_reset()

2022-08-15 Thread Kangjie Xu
From: Xuan Zhuo 

Separate the logic of vq reset. This logic will be called directly
later.

Signed-off-by: Xuan Zhuo 
---
 hw/virtio/virtio.c | 37 +
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 5d607aeaa0..67d54832a9 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2019,6 +2019,26 @@ static enum virtio_device_endian 
virtio_current_cpu_endian(void)
 }
 }
 
+static void __virtio_queue_reset(VirtIODevice *vdev, uint32_t i)
+{
+vdev->vq[i].vring.desc = 0;
+vdev->vq[i].vring.avail = 0;
+vdev->vq[i].vring.used = 0;
+vdev->vq[i].last_avail_idx = 0;
+vdev->vq[i].shadow_avail_idx = 0;
+vdev->vq[i].used_idx = 0;
+vdev->vq[i].last_avail_wrap_counter = true;
+vdev->vq[i].shadow_avail_wrap_counter = true;
+vdev->vq[i].used_wrap_counter = true;
+virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
+vdev->vq[i].signalled_used = 0;
+vdev->vq[i].signalled_used_valid = false;
+vdev->vq[i].notification = true;
+vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
+vdev->vq[i].inuse = 0;
+virtio_virtqueue_reset_region_cache(>vq[i]);
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
@@ -2050,22 +2070,7 @@ void virtio_reset(void *opaque)
 virtio_notify_vector(vdev, vdev->config_vector);
 
 for(i = 0; i < VIRTIO_QUEUE_MAX; i++) {
-vdev->vq[i].vring.desc = 0;
-vdev->vq[i].vring.avail = 0;
-vdev->vq[i].vring.used = 0;
-vdev->vq[i].last_avail_idx = 0;
-vdev->vq[i].shadow_avail_idx = 0;
-vdev->vq[i].used_idx = 0;
-vdev->vq[i].last_avail_wrap_counter = true;
-vdev->vq[i].shadow_avail_wrap_counter = true;
-vdev->vq[i].used_wrap_counter = true;
-virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
-vdev->vq[i].signalled_used = 0;
-vdev->vq[i].signalled_used_valid = false;
-vdev->vq[i].notification = true;
-vdev->vq[i].vring.num = vdev->vq[i].vring.num_default;
-vdev->vq[i].inuse = 0;
-virtio_virtqueue_reset_region_cache(>vq[i]);
+__virtio_queue_reset(vdev, i);
 }
 }
 
-- 
2.32.0




[PATCH v2 05/24] virtio: core: vq reset feature negotation support

2022-08-15 Thread Kangjie Xu
A a new command line parameter "queue_reset" is added.

Meanwhile, the vq reset feature is disabled for pre-7.1 machines.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/core/machine.c  | 1 +
 include/hw/virtio/virtio.h | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index a673302cce..8b22b4647f 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -43,6 +43,7 @@
 GlobalProperty hw_compat_7_0[] = {
 { "arm-gicv3-common", "force-8-bit-prio", "on" },
 { "nvme-ns", "eui64-default", "on"},
+{ "virtio-device", "queue_reset", "false" },
 };
 const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
 
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 085997d8f3..ed3ecbef80 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -295,7 +295,9 @@ typedef struct VirtIORNGConf VirtIORNGConf;
 DEFINE_PROP_BIT64("iommu_platform", _state, _field, \
   VIRTIO_F_IOMMU_PLATFORM, false), \
 DEFINE_PROP_BIT64("packed", _state, _field, \
-  VIRTIO_F_RING_PACKED, false)
+  VIRTIO_F_RING_PACKED, false), \
+DEFINE_PROP_BIT64("queue_reset", _state, _field, \
+  VIRTIO_F_RING_RESET, true)
 
 hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
 bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n);
-- 
2.32.0




[PATCH v2 08/24] vhost: extract the logic of unmapping the vrings and desc

2022-08-15 Thread Kangjie Xu
Introduce vhost_virtqueue_unmap() to ummap the vrings and desc
of a virtqueue.

The function will be used later.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/vhost.c | 20 ++--
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 0827d631c0..e467dfc7bc 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1197,6 +1197,19 @@ fail_alloc_desc:
 return r;
 }
 
+static void vhost_virtqueue_unmap(struct vhost_dev *dev,
+  struct VirtIODevice *vdev,
+  struct vhost_virtqueue *vq,
+  unsigned idx)
+{
+vhost_memory_unmap(dev, vq->used, virtio_queue_get_used_size(vdev, idx),
+   1, virtio_queue_get_used_size(vdev, idx));
+vhost_memory_unmap(dev, vq->avail, virtio_queue_get_avail_size(vdev, idx),
+   0, virtio_queue_get_avail_size(vdev, idx));
+vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx),
+   0, virtio_queue_get_desc_size(vdev, idx));
+}
+
 static void vhost_virtqueue_stop(struct vhost_dev *dev,
 struct VirtIODevice *vdev,
 struct vhost_virtqueue *vq,
@@ -1235,12 +1248,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
 vhost_vq_index);
 }
 
-vhost_memory_unmap(dev, vq->used, virtio_queue_get_used_size(vdev, idx),
-   1, virtio_queue_get_used_size(vdev, idx));
-vhost_memory_unmap(dev, vq->avail, virtio_queue_get_avail_size(vdev, idx),
-   0, virtio_queue_get_avail_size(vdev, idx));
-vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx),
-   0, virtio_queue_get_desc_size(vdev, idx));
+vhost_virtqueue_unmap(dev, vdev, vq, idx);
 }
 
 static void vhost_eventfd_add(MemoryListener *listener,
-- 
2.32.0




[PATCH v2 01/24] virtio: sync relevant definitions with linux

2022-08-15 Thread Kangjie Xu
From: Xuan Zhuo 

This is updated using scripts/update-linux-headers.sh.

Added VIRTIO_F_RING_RESET, VIRTIO_PCI_COMMON_Q_RESET. It came from here:
https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

Add VIRTIO_PCI_COMMON_Q_NDATA, which comes from here:
https://github.com/oasis-tcs/virtio-spec/issues/89

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
 include/standard-headers/linux/virtio_config.h | 5 +
 include/standard-headers/linux/virtio_pci.h| 2 ++
 2 files changed, 7 insertions(+)

diff --git a/include/standard-headers/linux/virtio_config.h 
b/include/standard-headers/linux/virtio_config.h
index 7acd8d4abc..47a7eef5e4 100644
--- a/include/standard-headers/linux/virtio_config.h
+++ b/include/standard-headers/linux/virtio_config.h
@@ -96,4 +96,9 @@
  * Does the device support Single Root I/O Virtualization?
  */
 #define VIRTIO_F_SR_IOV37
+
+/*
+ * This feature indicates that the driver can reset a queue individually.
+ */
+#define VIRTIO_F_RING_RESET40
 #endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/standard-headers/linux/virtio_pci.h 
b/include/standard-headers/linux/virtio_pci.h
index db7a8e2fcb..be912cfc95 100644
--- a/include/standard-headers/linux/virtio_pci.h
+++ b/include/standard-headers/linux/virtio_pci.h
@@ -202,6 +202,8 @@ struct virtio_pci_cfg_cap {
 #define VIRTIO_PCI_COMMON_Q_AVAILHI44
 #define VIRTIO_PCI_COMMON_Q_USEDLO 48
 #define VIRTIO_PCI_COMMON_Q_USEDHI 52
+#define VIRTIO_PCI_COMMON_Q_NDATA  56
+#define VIRTIO_PCI_COMMON_Q_RESET  58
 
 #endif /* VIRTIO_PCI_NO_MODERN */
 
-- 
2.32.0




[PATCH v2 23/24] vhost: vhost-kernel: enable vq reset feature

2022-08-15 Thread Kangjie Xu
Add virtqueue reset feature for vhost-kernel.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/net/vhost_net.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 778081e54a..9ea160e4e9 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -46,6 +46,7 @@ static const int kernel_feature_bits[] = {
 VIRTIO_NET_F_MTU,
 VIRTIO_F_IOMMU_PLATFORM,
 VIRTIO_F_RING_PACKED,
+VIRTIO_F_RING_RESET,
 VIRTIO_NET_F_HASH_REPORT,
 VHOST_INVALID_FEATURE_BIT
 };
-- 
2.32.0




[PATCH v2 06/24] virtio-pci: support queue reset

2022-08-15 Thread Kangjie Xu
From: Xuan Zhuo 

PCI devices support vq reset.

Based on this function, the driver can adjust the size of the ring, and
quickly recycle the buffer in the ring.

The migration of the virtio devices will not happen during a reset
operation. This is becuase the global iothread lock is held. Migration
thread also needs the lock. As a result, we do not need to migrate the
reset state of VirtIOPCIQueue.

Signed-off-by: Xuan Zhuo 
Signed-off-by: Kangjie Xu 
---
 hw/virtio/virtio-pci.c | 19 +++
 include/hw/virtio/virtio-pci.h |  1 +
 2 files changed, 20 insertions(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 45327f0b31..ec8e92052f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1246,6 +1246,9 @@ static uint64_t virtio_pci_common_read(void *opaque, 
hwaddr addr,
 case VIRTIO_PCI_COMMON_Q_USEDHI:
 val = proxy->vqs[vdev->queue_sel].used[1];
 break;
+case VIRTIO_PCI_COMMON_Q_RESET:
+val = proxy->vqs[vdev->queue_sel].reset;
+break;
 default:
 val = 0;
 }
@@ -1333,6 +1336,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
 proxy->vqs[vdev->queue_sel].enabled = 1;
+proxy->vqs[vdev->queue_sel].reset = 0;
 } else {
 virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val);
 }
@@ -1355,6 +1359,20 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
 case VIRTIO_PCI_COMMON_Q_USEDHI:
 proxy->vqs[vdev->queue_sel].used[1] = val;
 break;
+case VIRTIO_PCI_COMMON_Q_RESET:
+if (val == 1) {
+/*
+ * With the global iothread lock taken, the migration will not
+ * happen until the virtqueue reset is done.
+ */
+proxy->vqs[vdev->queue_sel].reset = 1;
+
+virtio_queue_reset(vdev, vdev->queue_sel);
+
+proxy->vqs[vdev->queue_sel].reset = 0;
+proxy->vqs[vdev->queue_sel].enabled = 0;
+}
+break;
 default:
 break;
 }
@@ -1950,6 +1968,7 @@ static void virtio_pci_reset(DeviceState *qdev)
 
 for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
 proxy->vqs[i].enabled = 0;
+proxy->vqs[i].reset = 0;
 proxy->vqs[i].num = 0;
 proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
 proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
index 2446dcd9ae..e9290e2b94 100644
--- a/include/hw/virtio/virtio-pci.h
+++ b/include/hw/virtio/virtio-pci.h
@@ -117,6 +117,7 @@ typedef struct VirtIOPCIRegion {
 typedef struct VirtIOPCIQueue {
   uint16_t num;
   bool enabled;
+  bool reset;
   uint32_t desc[2];
   uint32_t avail[2];
   uint32_t used[2];
-- 
2.32.0




[PATCH 00/24] Support VIRTIO_F_RING_RESET for virtio-net, vhost-user, vhost-kernel in virtio pci-modern

2022-08-15 Thread Kangjie Xu
The virtio queue reset function has already been defined in the virtio spec 1.2.
The relevant virtio spec information is here:

https://github.com/oasis-tcs/virtio-spec/issues/124
https://github.com/oasis-tcs/virtio-spec/issues/139

This patch set is to support this function in QEMU. It consists of several 
parts:
1. Patches 1-7 are the basic interfaces for vq reset in virtio and virtio-pci.
2. Patches 8-12 support vq stop and vq restart for vhost-kernel.
3. Patches 13-19 support vq stop and vq restart for vhost-user.
4. Patches 20-22 support vq reset and re-enable for virtio-net.
5. Patches 23-24 enable the vq reset feature for vhost-kernel and vhost-user.

The process of virtqueue reset can be concluded as:
1. The virtqueue is disabled when VIRTIO_PCI_COMMON_Q_RESET is written.
2. Then the virtqueue can be optionally restarted(re-enabled).

Since this patch set involves multiple modules and seems a bit messy, we 
briefly describe the
calling process for different modes below.
virtio-net:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> set enabled, reset status of vq.

vhost-kernel:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> vhost_net_virtqueue_stop() [vhost-net]
-> vhost_net_set_backend() [vhost]
-> vhost_dev_virtqueue_stop()
-> vhost_virtqueue_unmap()
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> virtio_queue_enable() [virtio]
-> virtio_net_queue_enable() [virtio-net]
-> vhost_net_virtqueue_restart() [vhost-net]
-> vhost_dev_virtqueue_restart() [vhost]
-> vhost_virtqueue_start()
-> vhost_net_set_backend()
-> set enabled, reset status of vq.

vhost-user:
1. VIRTIO_PCI_COMMON_Q_RESET is written [virtio-pci]
-> virtio_queue_reset() [virtio]
-> virtio_net_queue_reset() [virtio-net]
-> vhost_net_virtqueue_stop() [vhost-net]
-> vhost_dev_virtqueue_stop() [vhost]
-> vhost_user_reset_vring() [vhost-user]
-> send VHOST_USER_RESET_VRING to the device
-> vhost_virtqueue_unmap()
-> __virtio_queue_reset()
2. VIRTIO_PCI_COMMON_Q_ENABLE is written [virtio-pci]
-> virtio_queue_enable() [virtio]
-> virtio_net_queue_enable() [virtio-net]
-> vhost_net_virtqueue_restart() [vhost-net]
-> vhost_dev_virtqueue_restart() [vhost]
-> vhost_virtqueue_start()
-> vhost_user_set_single_vring_enable [vhost-user]
-> send VHOST_USER_SET_VRING_ENABLE to the device
-> set enabled, reset status of vq.


Test environment:
Host: 5.19.0-rc3 (With vq reset support)
Qemu: QEMU emulator version 7.0.50
Guest: 5.19.0-rc3 (With vq reset support)
DPDK: 22.07-rc1 (With vq reset support)
Test Cmd: ethtool -g eth1; ethtool -G eth1 rx $1 tx $2; ethtool -g eth1;

The drvier can resize the virtio queue, then virtio queue reset function 
should
be triggered.

The default is split mode, modify Qemu virtio-net to add PACKED feature to 
test packed mode.

Guest Kernel Patch:

https://lore.kernel.org/bpf/20220801063902.129329-1-xuanz...@linux.alibaba.com/

DPDK Patch:

https://github.com/middaywords/dpdk/compare/72206323a5dd3182b13f61b25a64abdddfee595c...eabadfac7953da66bc10ffb8284b490d09bb7ec7

Host Kernel Patch:

https://github.com/middaywords/linux/commit/19a91e0d7167b2031e46078c6215c213b89cb2c3

Looking forward to your review and comments. Thanks.

Kangjie Xu (19):
  virtio: introduce virtio_queue_enable()
  virtio: core: vq reset feature negotation support
  virtio-pci: support queue enable
  vhost: extract the logic of unmapping the vrings and desc
  vhost: introduce vhost_dev_virtqueue_stop()
  vhost: introduce vhost_dev_virtqueue_restart()
  vhost-net: vhost-kernel: introduce vhost_net_virtqueue_stop()
  vhost-net: vhost-kernel: introduce vhost_net_virtqueue_restart()
  docs: vhost-user: add VHOST_USER_RESET_VRING message
  vhost-user: introduce vhost_reset_vring() interface
  vhost-user: add op to enable or disable a single vring
  vhost: vhost-user: update vhost_dev_virtqueue_stop()
  vhost: vhost-user: update vhost_dev_virtqueue_restart()
  vhost-net: vhost-user: update vhost_net_virtqueue_stop()
  vhost-net: vhost-user: update vhost_net_virtqueue_restart()
  virtio-net: introduce flush_or_purge_queued_packets()
  virtio-net: support queue_enable
  vhost: vhost-kernel: enable vq reset feature
  vhost: vhost

[PATCH v2 03/24] virtio: introduce virtio_queue_reset()

2022-08-15 Thread Kangjie Xu
From: Xuan Zhuo 

Introduce a new interface function virtio_queue_reset() to implement
reset for vq.

Add a new callback to VirtioDeviceClass for queue reset operation for
each child device.

Signed-off-by: Xuan Zhuo 
---
 hw/virtio/virtio.c | 11 +++
 include/hw/virtio/virtio.h |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 67d54832a9..0e9d41366f 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2039,6 +2039,17 @@ static void __virtio_queue_reset(VirtIODevice *vdev, 
uint32_t i)
 virtio_virtqueue_reset_region_cache(>vq[i]);
 }
 
+void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+
+if (k->queue_reset) {
+k->queue_reset(vdev, queue_index);
+}
+
+__virtio_queue_reset(vdev, queue_index);
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index db1c0ddf6b..879394299b 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -130,6 +130,7 @@ struct VirtioDeviceClass {
 void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
 void (*reset)(VirtIODevice *vdev);
 void (*set_status)(VirtIODevice *vdev, uint8_t val);
+void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index);
 /* For transitional devices, this is a bitmap of features
  * that are only exposed on the legacy interface but not
  * the modern one.
@@ -268,6 +269,7 @@ int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, 
int n,
   MemoryRegion *mr, bool assign);
 int virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
+void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index);
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint64_t val);
 
-- 
2.32.0




[PATCH v2 13/24] docs: vhost-user: add VHOST_USER_RESET_VRING message

2022-08-15 Thread Kangjie Xu
To support the reset operation for an individual virtqueue,
we introduce a new message VHOST_USER_RESET_VRING. This
message is submitted by the front-end to reset an individual
virtqueue to initial states in the back-end. The reply is
needed to ensure that the reset operation is complete.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 docs/interop/vhost-user.rst | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index 3f18ab424e..ce7991b9d3 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1422,6 +1422,16 @@ Front-end message types
   query the back-end for its device status as defined in the Virtio
   specification.
 
+``VHOST_USER_RESET_VRING``
+  :id: 41
+  :equivalent ioctl: N/A
+  :request payload: vring state description
+  :reply payload: ``u64``
+
+  When the feature ``VIRTIO_F_RING_RESET`` feature has been successfully
+  negotiated, this message is submitted by the front-end to reset an
+  individual virtqueue to initial states in the back-end. It will ask
+  for a reply to ensure the virtqueue is successfully reset in the back-end.
 
 Back-end message types
 --
-- 
2.32.0




[PATCH v2 04/24] virtio: introduce virtio_queue_enable()

2022-08-15 Thread Kangjie Xu
Introduce the interface queue_enable() in VirtioDeviceClass and the
fucntion virtio_queue_enable() in virtio, it can be called when
VIRTIO_PCI_COMMON_Q_ENABLE is written and related virtqueue can be
started. It only supports the devices of virtio 1 or later. The
not-supported devices can only start the virtqueue when DRIVER_OK.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/virtio.c | 14 ++
 include/hw/virtio/virtio.h |  2 ++
 2 files changed, 16 insertions(+)

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 0e9d41366f..141f18c633 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2050,6 +2050,20 @@ void virtio_queue_reset(VirtIODevice *vdev, uint32_t 
queue_index)
 __virtio_queue_reset(vdev, queue_index);
 }
 
+void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index)
+{
+VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+
+if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+error_report("queue_enable is only suppported in devices of virtio "
+ "1.0 or later.");
+}
+
+if (k->queue_enable) {
+k->queue_enable(vdev, queue_index);
+}
+}
+
 void virtio_reset(void *opaque)
 {
 VirtIODevice *vdev = opaque;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 879394299b..085997d8f3 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -131,6 +131,7 @@ struct VirtioDeviceClass {
 void (*reset)(VirtIODevice *vdev);
 void (*set_status)(VirtIODevice *vdev, uint8_t val);
 void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index);
+void (*queue_enable)(VirtIODevice *vdev, uint32_t queue_index);
 /* For transitional devices, this is a bitmap of features
  * that are only exposed on the legacy interface but not
  * the modern one.
@@ -270,6 +271,7 @@ int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, 
int n,
 int virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
 void virtio_queue_reset(VirtIODevice *vdev, uint32_t queue_index);
+void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index);
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint64_t val);
 
-- 
2.32.0




[PATCH v2 07/24] virtio-pci: support queue enable

2022-08-15 Thread Kangjie Xu
PCI devices support vq enable.

Based on this function, the driver can re-enable the virtqueue after the
virtqueue is reset.

Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
 hw/virtio/virtio-pci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index ec8e92052f..3d560e45ad 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1335,6 +1335,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr 
addr,
proxy->vqs[vdev->queue_sel].avail[0],
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
+virtio_queue_enable(vdev, vdev->queue_sel);
 proxy->vqs[vdev->queue_sel].enabled = 1;
 proxy->vqs[vdev->queue_sel].reset = 0;
 } else {
-- 
2.32.0




Re: [PATCH 08/16] vhost: add op to enable or disable a single vring

2022-07-28 Thread Kangjie Xu



在 2022/7/28 10:41, Jason Wang 写道:

On Wed, Jul 27, 2022 at 3:05 PM Kangjie Xu  wrote:


在 2022/7/27 12:55, Jason Wang 写道:

On Tue, Jul 26, 2022 at 2:39 PM Kangjie Xu  wrote:

在 2022/7/26 11:49, Jason Wang 写道:

在 2022/7/18 19:17, Kangjie Xu 写道:

The interface to set enable status for a single vring is lacked in
VhostOps, since the vhost_set_vring_enable_op will manipulate all
virtqueues in a device.

Resetting a single vq will rely on this interface. It requires a
reply to indicate that the reset operation is finished, so the
parameter, wait_for_reply, is added.

The wait reply seems to be a implementation specific thing. Can we
hide it?

Thanks


I do not hide wait_for_reply here because when stopping the queue, a
reply is needed to ensure that the message has been processed and queue
has been disabled.

This needs to be done at vhost-backend level instead of the general vhost code.

E.g vhost-kernel or vDPA is using ioctl() which is synchronous.

Yeah, I understand your concerns, will fix it in the next version.

When restarting the queue, we do not need a reply, which is the same as
what qemu does in vhost_dev_start().

So I add this parameter to distinguish the two cases.

I think one alternative implementation is to add a interface in
VhostOps: queue_reset(). In this way details can be hidden. What do you
think of this solution? Does it look better?

Let me ask it differently, under which case can we call this function
with wait_for_reply = false?

Thanks

Cases when we do not need to wait until that the reply has been
processed. Actually in dev_start(), or dev_stop(),

But we don't need to send virtqueue reset requests in those cases?


You're right, we don't need to do this in those cases.

Thanks


they do not wait for
replies when enabling/disabling vqs.

Specifically, vhost_set_vring_enable() will call it with wait_for_reply
= false.

In our vq reset scenario, it should be synchronous because the driver
need to modify queues after the device stop using the vq in the backend.
Undefined errors will occur If the device is still using the queue when
the driver is making modifications to it,

Back to our implementation, we will not expose this parameter in the
next version.

Ok.

Thanks


Thanks.


Thanks


Signed-off-by: Kangjie Xu 
Signed-off-by: Xuan Zhuo 
---
include/hw/virtio/vhost-backend.h | 4 
1 file changed, 4 insertions(+)

diff --git a/include/hw/virtio/vhost-backend.h
b/include/hw/virtio/vhost-backend.h
index eab46d7f0b..7bddd1e9a0 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -81,6 +81,9 @@ typedef int (*vhost_set_backend_cap_op)(struct
vhost_dev *dev);
typedef int (*vhost_set_owner_op)(struct vhost_dev *dev);
typedef int (*vhost_reset_device_op)(struct vhost_dev *dev);
typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx);
+typedef int (*vhost_set_single_vring_enable_op)(struct vhost_dev *dev,
+int index, int enable,
+bool wait_for_reply);
typedef int (*vhost_set_vring_enable_op)(struct vhost_dev *dev,
 int enable);
typedef bool (*vhost_requires_shm_log_op)(struct vhost_dev *dev);
@@ -155,6 +158,7 @@ typedef struct VhostOps {
vhost_set_owner_op vhost_set_owner;
vhost_reset_device_op vhost_reset_device;
vhost_get_vq_index_op vhost_get_vq_index;
+vhost_set_single_vring_enable_op vhost_set_single_vring_enable;
vhost_set_vring_enable_op vhost_set_vring_enable;
vhost_requires_shm_log_op vhost_requires_shm_log;
vhost_migration_done_op vhost_migration_done;




  1   2   >