summary refs log tree commit diff
path: root/drivers/uio
diff options
context:
space:
mode:
authorZhaolong Zhang <zhangzl2013@126.com>2018-11-16 18:21:51 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-11-27 11:19:10 +0100
commitb5570ca7c475bffbc5fc2e9af994dc6d249eb13e (patch)
tree789278e2d7ff374f34261e140d9ef54a2042777d /drivers/uio
parent3b1ad360acad6052c2568f891bb3d0f3f057016f (diff)
downloadlinux-b5570ca7c475bffbc5fc2e9af994dc6d249eb13e.tar.gz
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>
Diffstat (limited to 'drivers/uio')
-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;