Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vhost_net: avoid tx queue stuck when sendmsg fails

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>

authored by

Yunjian Wang and committed by
Jakub Kicinski
dc9c9e72 99d51897

+14 -12
+14 -12
drivers/vhost/net.c
··· 828 828 msg.msg_flags &= ~MSG_MORE; 829 829 } 830 830 831 - /* TODO: Check specific error and bomb out unless ENOBUFS? */ 832 831 err = sock->ops->sendmsg(sock, &msg, len); 833 832 if (unlikely(err < 0)) { 834 - vhost_discard_vq_desc(vq, 1); 835 - vhost_net_enable_vq(net, vq); 836 - break; 837 - } 838 - if (err != len) 833 + if (err == -EAGAIN || err == -ENOMEM || err == -ENOBUFS) { 834 + vhost_discard_vq_desc(vq, 1); 835 + vhost_net_enable_vq(net, vq); 836 + break; 837 + } 838 + pr_debug("Fail to send packet: err %d", err); 839 + } else if (unlikely(err != len)) 839 840 pr_debug("Truncated TX packet: len %d != %zd\n", 840 841 err, len); 841 842 done: ··· 925 924 msg.msg_flags &= ~MSG_MORE; 926 925 } 927 926 928 - /* TODO: Check specific error and bomb out unless ENOBUFS? */ 929 927 err = sock->ops->sendmsg(sock, &msg, len); 930 928 if (unlikely(err < 0)) { 931 929 if (zcopy_used) { ··· 933 933 nvq->upend_idx = ((unsigned)nvq->upend_idx - 1) 934 934 % UIO_MAXIOV; 935 935 } 936 - vhost_discard_vq_desc(vq, 1); 937 - vhost_net_enable_vq(net, vq); 938 - break; 939 - } 940 - if (err != len) 936 + if (err == -EAGAIN || err == -ENOMEM || err == -ENOBUFS) { 937 + vhost_discard_vq_desc(vq, 1); 938 + vhost_net_enable_vq(net, vq); 939 + break; 940 + } 941 + pr_debug("Fail to send packet: err %d", err); 942 + } else if (unlikely(err != len)) 941 943 pr_debug("Truncated TX packet: " 942 944 " len %d != %zd\n", err, len); 943 945 if (!zcopy_used)