Commit d5675bd204efd87a174eeea592de23c4c4e7f908
1 parent
38000a94a9
Exists in
master
and in
20 other branches
vhost: break out of polling loop on error
When ring parsing fails, we currently handle this as ring empty condition. This means that we enable kicks and recheck ring empty: if this not empty, we re-start polling which of course will fail again. Instead, let's return a negative error code and stop polling. Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Showing 3 changed files with 31 additions and 22 deletions Side-by-side Diff
drivers/vhost/net.c
... | ... | @@ -98,7 +98,8 @@ |
98 | 98 | static void handle_tx(struct vhost_net *net) |
99 | 99 | { |
100 | 100 | struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX]; |
101 | - unsigned head, out, in, s; | |
101 | + unsigned out, in, s; | |
102 | + int head; | |
102 | 103 | struct msghdr msg = { |
103 | 104 | .msg_name = NULL, |
104 | 105 | .msg_namelen = 0, |
... | ... | @@ -135,6 +136,9 @@ |
135 | 136 | ARRAY_SIZE(vq->iov), |
136 | 137 | &out, &in, |
137 | 138 | NULL, NULL); |
139 | + /* On error, stop handling until the next kick. */ | |
140 | + if (head < 0) | |
141 | + break; | |
138 | 142 | /* Nothing new? Wait for eventfd to tell us they refilled. */ |
139 | 143 | if (head == vq->num) { |
140 | 144 | wmem = atomic_read(&sock->sk->sk_wmem_alloc); |
... | ... | @@ -192,7 +196,8 @@ |
192 | 196 | static void handle_rx(struct vhost_net *net) |
193 | 197 | { |
194 | 198 | struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; |
195 | - unsigned head, out, in, log, s; | |
199 | + unsigned out, in, log, s; | |
200 | + int head; | |
196 | 201 | struct vhost_log *vq_log; |
197 | 202 | struct msghdr msg = { |
198 | 203 | .msg_name = NULL, |
... | ... | @@ -228,6 +233,9 @@ |
228 | 233 | ARRAY_SIZE(vq->iov), |
229 | 234 | &out, &in, |
230 | 235 | vq_log, &log); |
236 | + /* On error, stop handling until the next kick. */ | |
237 | + if (head < 0) | |
238 | + break; | |
231 | 239 | /* OK, now we need to know about added descriptors. */ |
232 | 240 | if (head == vq->num) { |
233 | 241 | if (unlikely(vhost_enable_notify(vq))) { |
drivers/vhost/vhost.c
... | ... | @@ -873,12 +873,13 @@ |
873 | 873 | * number of output then some number of input descriptors, it's actually two |
874 | 874 | * iovecs, but we pack them into one and note how many of each there were. |
875 | 875 | * |
876 | - * This function returns the descriptor number found, or vq->num (which | |
877 | - * is never a valid descriptor number) if none was found. */ | |
878 | -unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, | |
879 | - struct iovec iov[], unsigned int iov_size, | |
880 | - unsigned int *out_num, unsigned int *in_num, | |
881 | - struct vhost_log *log, unsigned int *log_num) | |
876 | + * This function returns the descriptor number found, or vq->num (which is | |
877 | + * never a valid descriptor number) if none was found. A negative code is | |
878 | + * returned on error. */ | |
879 | +int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, | |
880 | + struct iovec iov[], unsigned int iov_size, | |
881 | + unsigned int *out_num, unsigned int *in_num, | |
882 | + struct vhost_log *log, unsigned int *log_num) | |
882 | 883 | { |
883 | 884 | struct vring_desc desc; |
884 | 885 | unsigned int i, head, found = 0; |
885 | 886 | |
... | ... | @@ -890,13 +891,13 @@ |
890 | 891 | if (get_user(vq->avail_idx, &vq->avail->idx)) { |
891 | 892 | vq_err(vq, "Failed to access avail idx at %p\n", |
892 | 893 | &vq->avail->idx); |
893 | - return vq->num; | |
894 | + return -EFAULT; | |
894 | 895 | } |
895 | 896 | |
896 | 897 | if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) { |
897 | 898 | vq_err(vq, "Guest moved used index from %u to %u", |
898 | 899 | last_avail_idx, vq->avail_idx); |
899 | - return vq->num; | |
900 | + return -EFAULT; | |
900 | 901 | } |
901 | 902 | |
902 | 903 | /* If there's nothing new since last we looked, return invalid. */ |
903 | 904 | |
... | ... | @@ -912,14 +913,14 @@ |
912 | 913 | vq_err(vq, "Failed to read head: idx %d address %p\n", |
913 | 914 | last_avail_idx, |
914 | 915 | &vq->avail->ring[last_avail_idx % vq->num]); |
915 | - return vq->num; | |
916 | + return -EFAULT; | |
916 | 917 | } |
917 | 918 | |
918 | 919 | /* If their number is silly, that's an error. */ |
919 | 920 | if (head >= vq->num) { |
920 | 921 | vq_err(vq, "Guest says index %u > %u is available", |
921 | 922 | head, vq->num); |
922 | - return vq->num; | |
923 | + return -EINVAL; | |
923 | 924 | } |
924 | 925 | |
925 | 926 | /* When we start there are none of either input nor output. */ |
926 | 927 | |
927 | 928 | |
... | ... | @@ -933,19 +934,19 @@ |
933 | 934 | if (i >= vq->num) { |
934 | 935 | vq_err(vq, "Desc index is %u > %u, head = %u", |
935 | 936 | i, vq->num, head); |
936 | - return vq->num; | |
937 | + return -EINVAL; | |
937 | 938 | } |
938 | 939 | if (++found > vq->num) { |
939 | 940 | vq_err(vq, "Loop detected: last one at %u " |
940 | 941 | "vq size %u head %u\n", |
941 | 942 | i, vq->num, head); |
942 | - return vq->num; | |
943 | + return -EINVAL; | |
943 | 944 | } |
944 | 945 | ret = copy_from_user(&desc, vq->desc + i, sizeof desc); |
945 | 946 | if (ret) { |
946 | 947 | vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", |
947 | 948 | i, vq->desc + i); |
948 | - return vq->num; | |
949 | + return -EFAULT; | |
949 | 950 | } |
950 | 951 | if (desc.flags & VRING_DESC_F_INDIRECT) { |
951 | 952 | ret = get_indirect(dev, vq, iov, iov_size, |
... | ... | @@ -954,7 +955,7 @@ |
954 | 955 | if (ret < 0) { |
955 | 956 | vq_err(vq, "Failure detected " |
956 | 957 | "in indirect descriptor at idx %d\n", i); |
957 | - return vq->num; | |
958 | + return ret; | |
958 | 959 | } |
959 | 960 | continue; |
960 | 961 | } |
... | ... | @@ -964,7 +965,7 @@ |
964 | 965 | if (ret < 0) { |
965 | 966 | vq_err(vq, "Translation failure %d descriptor idx %d\n", |
966 | 967 | ret, i); |
967 | - return vq->num; | |
968 | + return ret; | |
968 | 969 | } |
969 | 970 | if (desc.flags & VRING_DESC_F_WRITE) { |
970 | 971 | /* If this is an input descriptor, |
... | ... | @@ -981,7 +982,7 @@ |
981 | 982 | if (*in_num) { |
982 | 983 | vq_err(vq, "Descriptor has out after in: " |
983 | 984 | "idx %d\n", i); |
984 | - return vq->num; | |
985 | + return -EINVAL; | |
985 | 986 | } |
986 | 987 | *out_num += ret; |
987 | 988 | } |
drivers/vhost/vhost.h
... | ... | @@ -120,10 +120,10 @@ |
120 | 120 | int vhost_vq_access_ok(struct vhost_virtqueue *vq); |
121 | 121 | int vhost_log_access_ok(struct vhost_dev *); |
122 | 122 | |
123 | -unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, | |
124 | - struct iovec iov[], unsigned int iov_count, | |
125 | - unsigned int *out_num, unsigned int *in_num, | |
126 | - struct vhost_log *log, unsigned int *log_num); | |
123 | +int vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *, | |
124 | + struct iovec iov[], unsigned int iov_count, | |
125 | + unsigned int *out_num, unsigned int *in_num, | |
126 | + struct vhost_log *log, unsigned int *log_num); | |
127 | 127 | void vhost_discard_vq_desc(struct vhost_virtqueue *); |
128 | 128 | |
129 | 129 | int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len); |