TTY/Serial fixes for 4.5-rc2

Here are some small tty/serial driver fixes for 4.5-rc2.
 
 They resolve a number of reported problems (the ioctl one specifically
 has been pointed out by numerous people) and one patch adds some new
 device ids for the 8250_pci driver.  All have been in linux-next
 successfully.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlauWWkACgkQMUfUDdst+ykujQCfUSpPMRs3yagM24SI8ITnbEJQ
 7H0An0utvQBUhgf10WA7trJ+uyzq4SsQ
 =uUEE
 -----END PGP SIGNATURE-----

Merge tag 'tty-4.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are some small tty/serial driver fixes for 4.5-rc2.

  They resolve a number of reported problems (the ioctl one specifically
  has been pointed out by numerous people) and one patch adds some new
  device ids for the 8250_pci driver.  All have been in linux-next
  successfully"

* tag 'tty-4.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: 8250_pci: Add Intel Broadwell ports
  staging/speakup: Use tty_ldisc_ref() for paste kworker
  n_tty: Fix unsafe reference to "other" ldisc
  tty: Fix unsafe ldisc reference via ioctl(TIOCGETD)
  tty: Retry failed reopen if tty teardown in-progress
  tty: Wait interruptibly for tty lock on reopen
This commit is contained in:
Linus Torvalds 2016-01-31 17:09:39 -08:00
commit 54e3f3e302
6 changed files with 82 additions and 12 deletions

View file

@ -142,7 +142,9 @@ static void __speakup_paste_selection(struct work_struct *work)
struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current);
ld = tty_ldisc_ref_wait(tty);
ld = tty_ldisc_ref(tty);
if (!ld)
goto tty_unref;
tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait);
@ -162,6 +164,7 @@ static void __speakup_paste_selection(struct work_struct *work)
tty_buffer_unlock_exclusive(&vc->port);
tty_ldisc_deref(ld);
tty_unref:
tty_kref_put(tty);
}

View file

@ -269,16 +269,13 @@ static void n_tty_check_throttle(struct tty_struct *tty)
static void n_tty_check_unthrottle(struct tty_struct *tty)
{
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) {
if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
return;
if (!tty->count)
return;
n_tty_kick_worker(tty);
n_tty_write_wakeup(tty->link);
if (waitqueue_active(&tty->link->write_wait))
wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
tty_wakeup(tty->link);
return;
}

View file

@ -1379,6 +1379,9 @@ ce4100_serial_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a
#define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c
#define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3
#define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4
#define BYT_PRV_CLK 0x800
#define BYT_PRV_CLK_EN (1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT 1
@ -1461,11 +1464,13 @@ byt_serial_setup(struct serial_private *priv,
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_BYT_UART1:
case PCI_DEVICE_ID_INTEL_BSW_UART1:
case PCI_DEVICE_ID_INTEL_BDW_UART1:
rx_param->src_id = 3;
tx_param->dst_id = 2;
break;
case PCI_DEVICE_ID_INTEL_BYT_UART2:
case PCI_DEVICE_ID_INTEL_BSW_UART2:
case PCI_DEVICE_ID_INTEL_BDW_UART2:
rx_param->src_id = 5;
tx_param->dst_id = 4;
break;
@ -2062,6 +2067,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BDW_UART1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BDW_UART2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
/*
* ITE
*/
@ -5506,6 +5525,16 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
/* Intel Broadwell */
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART1,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART2,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
/*
* Intel Quark x1000
*/

View file

@ -1463,13 +1463,13 @@ static int tty_reopen(struct tty_struct *tty)
{
struct tty_driver *driver = tty->driver;
if (!tty->count)
return -EIO;
if (driver->type == TTY_DRIVER_TYPE_PTY &&
driver->subtype == PTY_TYPE_MASTER)
return -EIO;
if (!tty->count)
return -EAGAIN;
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
return -EBUSY;
@ -2065,7 +2065,12 @@ static int tty_open(struct inode *inode, struct file *filp)
if (tty) {
mutex_unlock(&tty_mutex);
tty_lock(tty);
retval = tty_lock_interruptible(tty);
if (retval) {
if (retval == -EINTR)
retval = -ERESTARTSYS;
goto err_unref;
}
/* safe to drop the kref from tty_driver_lookup_tty() */
tty_kref_put(tty);
retval = tty_reopen(tty);
@ -2083,7 +2088,11 @@ static int tty_open(struct inode *inode, struct file *filp)
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
goto err_file;
if (retval != -EAGAIN || signal_pending(current))
goto err_file;
tty_free_file(filp);
schedule();
goto retry_open;
}
tty_add_file(tty, filp);
@ -2152,6 +2161,7 @@ static int tty_open(struct inode *inode, struct file *filp)
return 0;
err_unlock:
mutex_unlock(&tty_mutex);
err_unref:
/* after locks to avoid deadlock */
if (!IS_ERR_OR_NULL(driver))
tty_driver_kref_put(driver);
@ -2648,6 +2658,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
return ret;
}
/**
* tiocgetd - get line discipline
* @tty: tty device
* @p: pointer to user data
*
* Retrieves the line discipline id directly from the ldisc.
*
* Locking: waits for ldisc reference (in case the line discipline
* is changing or the tty is being hungup)
*/
static int tiocgetd(struct tty_struct *tty, int __user *p)
{
struct tty_ldisc *ld;
int ret;
ld = tty_ldisc_ref_wait(tty);
ret = put_user(ld->ops->num, p);
tty_ldisc_deref(ld);
return ret;
}
/**
* send_break - performed time break
* @tty: device to break on
@ -2874,7 +2906,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
return put_user(tty->ldisc->ops->num, (int __user *)p);
return tiocgetd(tty, p);
case TIOCSETD:
return tiocsetd(tty, p);
case TIOCVHANGUP:

View file

@ -19,6 +19,14 @@ void __lockfunc tty_lock(struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_lock);
int tty_lock_interruptible(struct tty_struct *tty)
{
if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
return -EIO;
tty_kref_get(tty);
return mutex_lock_interruptible(&tty->legacy_mutex);
}
void __lockfunc tty_unlock(struct tty_struct *tty)
{
if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", tty))

View file

@ -649,6 +649,7 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
/* tty_mutex.c */
/* functions for preparation of BKL removal */
extern void __lockfunc tty_lock(struct tty_struct *tty);
extern int tty_lock_interruptible(struct tty_struct *tty);
extern void __lockfunc tty_unlock(struct tty_struct *tty);
extern void __lockfunc tty_lock_slave(struct tty_struct *tty);
extern void __lockfunc tty_unlock_slave(struct tty_struct *tty);