summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhaolong Zhang <zhangzl2013@126.com>2018-11-16 13:21:51 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-11-27 13:19:10 +0300
commitb5570ca7c475bffbc5fc2e9af994dc6d249eb13e (patch)
tree789278e2d7ff374f34261e140d9ef54a2042777d
parent3b1ad360acad6052c2568f891bb3d0f3f057016f (diff)
downloadlinux-b5570ca7c475bffbc5fc2e9af994dc6d249eb13e.tar.xz
uio: dismiss waiters on device unregistration
When the device is unregistered, it should wake up the blocking waiters. Otherwise, they will sleep forever. Signed-off-by: Zhaolong Zhang <zhangzl2013@126.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/uio/uio.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 0a357db4b31b..131342280b46 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -569,20 +569,20 @@ static ssize_t uio_read(struct file *filep, char __user *buf,
ssize_t retval = 0;
s32 event_count;
- mutex_lock(&idev->info_lock);
- if (!idev->info || !idev->info->irq)
- retval = -EIO;
- mutex_unlock(&idev->info_lock);
-
- if (retval)
- return retval;
-
if (count != sizeof(s32))
return -EINVAL;
add_wait_queue(&idev->wait, &wait);
do {
+ mutex_lock(&idev->info_lock);
+ if (!idev->info || !idev->info->irq) {
+ retval = -EIO;
+ mutex_unlock(&idev->info_lock);
+ break;
+ }
+ mutex_unlock(&idev->info_lock);
+
set_current_state(TASK_INTERRUPTIBLE);
event_count = atomic_read(&idev->event);
@@ -1017,6 +1017,9 @@ void uio_unregister_device(struct uio_info *info)
idev->info = NULL;
mutex_unlock(&idev->info_lock);
+ wake_up_interruptible(&idev->wait);
+ kill_fasync(&idev->async_queue, SIGIO, POLL_HUP);
+
device_unregister(&idev->dev);
return;