]> git.baikalelectronics.ru Git - kernel.git/commitdiff
vhost_net: avoid tx queue stuck when sendmsg fails
authorYunjian Wang <wangyunjian@huawei.com>
Fri, 15 Jan 2021 04:46:20 +0000 (12:46 +0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 19 Jan 2021 19:13:30 +0000 (11:13 -0800)
Currently the driver doesn't drop a packet which can't be sent by tun
(e.g bad packet). In this case, the driver will always process the
same packet lead to the tx queue stuck.

To fix this issue:
1. in the case of persistent failure (e.g bad packet), the driver
   can skip this descriptor by ignoring the error.
2. in the case of transient failure (e.g -ENOBUFS, -EAGAIN and -ENOMEM),
   the driver schedules the worker to try again.

Signed-off-by: Yunjian Wang <wangyunjian@huawei.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Link: https://lore.kernel.org/r/1610685980-38608-1-git-send-email-wangyunjian@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/vhost/net.c

index 3b744031ec8f2daa2518b1a1e79d86d2ad5a6879..df82b124170ec9b3dc8b6e574dc27011b868e4e2 100644 (file)
@@ -828,14 +828,15 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
                                msg.msg_flags &= ~MSG_MORE;
                }
 
-               /* TODO: Check specific error and bomb out unless ENOBUFS? */
                err = sock->ops->sendmsg(sock, &msg, len);
                if (unlikely(err < 0)) {
-                       vhost_discard_vq_desc(vq, 1);
-                       vhost_net_enable_vq(net, vq);
-                       break;
-               }
-               if (err != len)
+                       if (err == -EAGAIN || err == -ENOMEM || err == -ENOBUFS) {
+                               vhost_discard_vq_desc(vq, 1);
+                               vhost_net_enable_vq(net, vq);
+                               break;
+                       }
+                       pr_debug("Fail to send packet: err %d", err);
+               } else if (unlikely(err != len))
                        pr_debug("Truncated TX packet: len %d != %zd\n",
                                 err, len);
 done:
@@ -924,7 +925,6 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
                        msg.msg_flags &= ~MSG_MORE;
                }
 
-               /* TODO: Check specific error and bomb out unless ENOBUFS? */
                err = sock->ops->sendmsg(sock, &msg, len);
                if (unlikely(err < 0)) {
                        if (zcopy_used) {
@@ -933,11 +933,13 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
                                nvq->upend_idx = ((unsigned)nvq->upend_idx - 1)
                                        % UIO_MAXIOV;
                        }
-                       vhost_discard_vq_desc(vq, 1);
-                       vhost_net_enable_vq(net, vq);
-                       break;
-               }
-               if (err != len)
+                       if (err == -EAGAIN || err == -ENOMEM || err == -ENOBUFS) {
+                               vhost_discard_vq_desc(vq, 1);
+                               vhost_net_enable_vq(net, vq);
+                               break;
+                       }
+                       pr_debug("Fail to send packet: err %d", err);
+               } else if (unlikely(err != len))
                        pr_debug("Truncated TX packet: "
                                 " len %d != %zd\n", err, len);
                if (!zcopy_used)