| From db7d4d7f40215843000cb9d441c9149fd42ea36b Mon Sep 17 00:00:00 2001 |
| From: Alex Williamson <alex.williamson@redhat.com> |
| Date: Fri, 1 May 2015 16:31:41 -0600 |
| Subject: vfio: Fix runaway interruptible timeout |
| |
| From: Alex Williamson <alex.williamson@redhat.com> |
| |
| commit db7d4d7f40215843000cb9d441c9149fd42ea36b upstream. |
| |
| Commit 13060b64b819 ("vfio: Add and use device request op for vfio |
| bus drivers") incorrectly makes use of an interruptible timeout. |
| When interrupted, the signal remains pending resulting in subsequent |
| timeouts occurring instantly. This makes the loop spin at a much |
| higher rate than intended. |
| |
| Instead of making this completely non-interruptible, we can change |
| this into a sort of interruptible-once behavior and use the "once" |
| to log debug information. The driver API doesn't allow us to abort |
| and return an error code. |
| |
| Signed-off-by: Alex Williamson <alex.williamson@redhat.com> |
| Fixes: 13060b64b819 |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/vfio/vfio.c | 21 ++++++++++++++++++--- |
| 1 file changed, 18 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/vfio/vfio.c |
| +++ b/drivers/vfio/vfio.c |
| @@ -711,6 +711,8 @@ void *vfio_del_group_dev(struct device * |
| void *device_data = device->device_data; |
| struct vfio_unbound_dev *unbound; |
| unsigned int i = 0; |
| + long ret; |
| + bool interrupted = false; |
| |
| /* |
| * The group exists so long as we have a device reference. Get |
| @@ -756,9 +758,22 @@ void *vfio_del_group_dev(struct device * |
| |
| vfio_device_put(device); |
| |
| - } while (wait_event_interruptible_timeout(vfio.release_q, |
| - !vfio_dev_present(group, dev), |
| - HZ * 10) <= 0); |
| + if (interrupted) { |
| + ret = wait_event_timeout(vfio.release_q, |
| + !vfio_dev_present(group, dev), HZ * 10); |
| + } else { |
| + ret = wait_event_interruptible_timeout(vfio.release_q, |
| + !vfio_dev_present(group, dev), HZ * 10); |
| + if (ret == -ERESTARTSYS) { |
| + interrupted = true; |
| + dev_warn(dev, |
| + "Device is currently in use, task" |
| + " \"%s\" (%d) " |
| + "blocked until device is released", |
| + current->comm, task_pid_nr(current)); |
| + } |
| + } |
| + } while (ret <= 0); |
| |
| vfio_group_put(group); |
| |