CHROMIUM: virtwl: properly free qentries that are empty If a qentry was received from the device empty, and an ioctl recv is performed on the qentry, the vfd_qentry_free_if_empty call would be skipped over. Because the qentry is still part of the vfd, the ioctl recv would assume there is more data to read and repeat the entire proces, causing a hang. The solution in this change is to always call vfd_qentry_free_if_empty even if the entry is empty so that the entry gets removed from the vfd and the ioctl recv can return or enter a wait queue. BUG=chromium:791724 TEST=test code from BUG Change-Id: Ifb744dff6a56ac104b9f0816dee680461824daba Signed-off-by: Zach Reizner <zachr@google.com> Reviewed-on: https://chromium-review.googlesource.com/974894 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dmitry Torokhov <dtor@chromium.org>
diff --git a/drivers/virtio/virtio_wl.c b/drivers/virtio/virtio_wl.c index 23eba58..9cf76ba 100644 --- a/drivers/virtio/virtio_wl.c +++ b/drivers/virtio/virtio_wl.c
@@ -462,10 +462,6 @@ static ssize_t vfd_out_locked(struct virtwl_vfd *vfd, char __user *buffer, u8 *buf = (u8 *)recv + recv_offset; ssize_t to_read = (ssize_t)qentry->len - (ssize_t)recv_offset; - if (read_count >= len) - break; - if (to_read <= 0) - continue; if (qentry->hdr->type != VIRTIO_WL_CMD_VFD_RECV) continue; @@ -473,9 +469,7 @@ static ssize_t vfd_out_locked(struct virtwl_vfd *vfd, char __user *buffer, to_read = len - read_count; if (copy_to_user(buffer + read_count, buf, to_read)) { - /* return error unless we have some data to return */ - if (read_count == 0) - read_count = -EFAULT; + read_count = -EFAULT; break; } @@ -483,6 +477,9 @@ static ssize_t vfd_out_locked(struct virtwl_vfd *vfd, char __user *buffer, qentry->data_offset += to_read; vfd_qentry_free_if_empty(vfd, qentry); + + if (read_count >= len) + break; } return read_count;