patch "USB: usblp: fix a hang in poll() if disconnected" added to usb-linus
Subsystems (3)
This is a note to let you know that I've just added the patch titled
USB: usblp: fix a hang in poll() if disconnected
to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-linus branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will hopefully also be merged in Linus's tree for the next -rc kernel release.
If you have any questions about this process, please let me know.
From 7f6f181b3e2c4d08f5d693eebe7901a28fab8666 Mon Sep 17 00:00:00 2001
From: Pete Zaitcev <[email protected]>
Date: Wed, 3 Mar 2021 22:10:53 -0600
Subject: USB: usblp: fix a hang in poll() if disconnected
Apparently an application that opens a device and calls select() on it, will hang if the decice is disconnected. It's a little surprising that we had this bug for 15 years, but apparently nobody ever uses select() with a printer: only write() and read(), and those work fine. Well, you can also select() with a timeout.
The fix is modeled after devio.c. A few other drivers check the condition first, then do not add the wait queue in case the device is disconnected. We doubt that's completely race-free. So, this patch adds the process first, then locks properly and checks for the disconnect.
--- drivers/usb/class/usblp.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/usb/class/usblp.c +12 -4
@@ -494,16 +494,24 @@ static int usblp_release(struct inode *inode, struct file *file)/* No kernel lock - fine */ static __poll_t usblp_poll (struct file *file,struct poll_table_struct *wait) { -__poll_t ret; +struct usblp *usblp = file->private_data; +__poll_t ret =0 ;unsigned long flags; -struct usblp *usblp = file->private_data;/* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */ poll_wait (file, &usblp->rwait, wait);poll_wait (file, &usblp->wwait, wait); + +mutex_lock (&usblp->mut); +if (!usblp->present) + ret |=EPOLLHUP ; +mutex_unlock (&usblp->mut); +spin_lock_irqsave (&usblp->lock, flags); - ret = ((usblp->bidir && usblp->rcomplete) ?EPOLLIN |EPOLLRDNORM :0 ) | - ((usblp->no_paper || usblp->wcomplete) ?EPOLLOUT |EPOLLWRNORM :0 ); +if (usblp->bidir && usblp->rcomplete) + ret |=EPOLLIN |EPOLLRDNORM ; +if (usblp->no_paper || usblp->wcomplete) + ret |=EPOLLOUT |EPOLLWRNORM ;spin_unlock_irqrestore (&usblp->lock, flags);return ret; }
Signature · 1 line
2.30.1