virtio_net: support tx queue resize
authorXuan Zhuo <xuanzhuo@linux.alibaba.com>
Mon, 1 Aug 2022 06:39:01 +0000 (14:39 +0800)
committerMichael S. Tsirkin <mst@redhat.com>
Thu, 11 Aug 2022 08:25:22 +0000 (04:25 -0400)
This patch implements the resize function of the tx queues.
Based on this function, it is possible to modify the ring num of the
queue.

Inludes fixup:

virtio_net: fix for stuck when change tx ring size with dev down

When dev is set to DOWN state, napi has been disabled, if we modify the
ring size at this time, we should not call napi_disable() again, which
will cause stuck.

And all operations are under the protection of rtnl_lock, so there is no
need to consider concurrency issues.

Message-Id: <20220801063902.129329-42-xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20220811080258.79398-3-xuanzhuo@linux.alibaba.com>
Reported-by: Kangjie Xu <kangjie.xu@linux.alibaba.com>
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/net/virtio_net.c

index 4cf278d..6aa0871 100644 (file)
@@ -135,6 +135,9 @@ struct send_queue {
        struct virtnet_sq_stats stats;
 
        struct napi_struct napi;
+
+       /* Record whether sq is in reset state. */
+       bool reset;
 };
 
 /* Internal representation of a receive virtqueue */
@@ -285,6 +288,7 @@ struct padded_vnet_hdr {
 };
 
 static void virtnet_rq_free_unused_buf(struct virtqueue *vq, void *buf);
+static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
 
 static bool is_xdp_frame(void *ptr)
 {
@@ -1627,6 +1631,11 @@ static void virtnet_poll_cleantx(struct receive_queue *rq)
                return;
 
        if (__netif_tx_trylock(txq)) {
+               if (sq->reset) {
+                       __netif_tx_unlock(txq);
+                       return;
+               }
+
                do {
                        virtqueue_disable_cb(sq->vq);
                        free_old_xmit_skbs(sq, true);
@@ -1897,6 +1906,47 @@ static int virtnet_rx_resize(struct virtnet_info *vi,
        return err;
 }
 
+static int virtnet_tx_resize(struct virtnet_info *vi,
+                            struct send_queue *sq, u32 ring_num)
+{
+       bool running = netif_running(vi->dev);
+       struct netdev_queue *txq;
+       int err, qindex;
+
+       qindex = sq - vi->sq;
+
+       if (running)
+               virtnet_napi_tx_disable(&sq->napi);
+
+       txq = netdev_get_tx_queue(vi->dev, qindex);
+
+       /* 1. wait all ximt complete
+        * 2. fix the race of netif_stop_subqueue() vs netif_start_subqueue()
+        */
+       __netif_tx_lock_bh(txq);
+
+       /* Prevent rx poll from accessing sq. */
+       sq->reset = true;
+
+       /* Prevent the upper layer from trying to send packets. */
+       netif_stop_subqueue(vi->dev, qindex);
+
+       __netif_tx_unlock_bh(txq);
+
+       err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf);
+       if (err)
+               netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err);
+
+       __netif_tx_lock_bh(txq);
+       sq->reset = false;
+       netif_tx_wake_queue(txq);
+       __netif_tx_unlock_bh(txq);
+
+       if (running)
+               virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
+       return err;
+}
+
 /*
  * Send command via the control virtqueue and check status.  Commands
  * supported by the hypervisor, as indicated by feature bits, should