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; struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current); 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); tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait); 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_buffer_unlock_exclusive(&vc->port);
tty_ldisc_deref(ld); tty_ldisc_deref(ld);
tty_unref:
tty_kref_put(tty); 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) static void n_tty_check_unthrottle(struct tty_struct *tty)
{ {
if (tty->driver->type == TTY_DRIVER_TYPE_PTY && if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) {
if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
return; return;
if (!tty->count) if (!tty->count)
return; return;
n_tty_kick_worker(tty); n_tty_kick_worker(tty);
n_tty_write_wakeup(tty->link); tty_wakeup(tty->link);
if (waitqueue_active(&tty->link->write_wait))
wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
return; 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_UART1 0x228a
#define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c #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 0x800
#define BYT_PRV_CLK_EN (1 << 0) #define BYT_PRV_CLK_EN (1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT 1 #define BYT_PRV_CLK_M_VAL_SHIFT 1
@ -1461,11 +1464,13 @@ byt_serial_setup(struct serial_private *priv,
switch (pdev->device) { switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_BYT_UART1: case PCI_DEVICE_ID_INTEL_BYT_UART1:
case PCI_DEVICE_ID_INTEL_BSW_UART1: case PCI_DEVICE_ID_INTEL_BSW_UART1:
case PCI_DEVICE_ID_INTEL_BDW_UART1:
rx_param->src_id = 3; rx_param->src_id = 3;
tx_param->dst_id = 2; tx_param->dst_id = 2;
break; break;
case PCI_DEVICE_ID_INTEL_BYT_UART2: case PCI_DEVICE_ID_INTEL_BYT_UART2:
case PCI_DEVICE_ID_INTEL_BSW_UART2: case PCI_DEVICE_ID_INTEL_BSW_UART2:
case PCI_DEVICE_ID_INTEL_BDW_UART2:
rx_param->src_id = 5; rx_param->src_id = 5;
tx_param->dst_id = 4; tx_param->dst_id = 4;
break; break;
@ -2062,6 +2067,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.setup = byt_serial_setup, .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 * ITE
*/ */
@ -5506,6 +5525,16 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt }, 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 * Intel Quark x1000
*/ */

View file

@ -1463,13 +1463,13 @@ static int tty_reopen(struct tty_struct *tty)
{ {
struct tty_driver *driver = tty->driver; struct tty_driver *driver = tty->driver;
if (!tty->count)
return -EIO;
if (driver->type == TTY_DRIVER_TYPE_PTY && if (driver->type == TTY_DRIVER_TYPE_PTY &&
driver->subtype == PTY_TYPE_MASTER) driver->subtype == PTY_TYPE_MASTER)
return -EIO; return -EIO;
if (!tty->count)
return -EAGAIN;
if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
return -EBUSY; return -EBUSY;
@ -2065,7 +2065,12 @@ retry_open:
if (tty) { if (tty) {
mutex_unlock(&tty_mutex); 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() */ /* safe to drop the kref from tty_driver_lookup_tty() */
tty_kref_put(tty); tty_kref_put(tty);
retval = tty_reopen(tty); retval = tty_reopen(tty);
@ -2083,7 +2088,11 @@ retry_open:
if (IS_ERR(tty)) { if (IS_ERR(tty)) {
retval = PTR_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); tty_add_file(tty, filp);
@ -2152,6 +2161,7 @@ retry_open:
return 0; return 0;
err_unlock: err_unlock:
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
err_unref:
/* after locks to avoid deadlock */ /* after locks to avoid deadlock */
if (!IS_ERR_OR_NULL(driver)) if (!IS_ERR_OR_NULL(driver))
tty_driver_kref_put(driver); tty_driver_kref_put(driver);
@ -2648,6 +2658,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
return ret; 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 * send_break - performed time break
* @tty: device to break on * @tty: device to break on
@ -2874,7 +2906,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGSID: case TIOCGSID:
return tiocgsid(tty, real_tty, p); return tiocgsid(tty, real_tty, p);
case TIOCGETD: case TIOCGETD:
return put_user(tty->ldisc->ops->num, (int __user *)p); return tiocgetd(tty, p);
case TIOCSETD: case TIOCSETD:
return tiocsetd(tty, p); return tiocsetd(tty, p);
case TIOCVHANGUP: case TIOCVHANGUP:

View file

@ -19,6 +19,14 @@ void __lockfunc tty_lock(struct tty_struct *tty)
} }
EXPORT_SYMBOL(tty_lock); 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) void __lockfunc tty_unlock(struct tty_struct *tty)
{ {
if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", 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 */ /* tty_mutex.c */
/* functions for preparation of BKL removal */ /* functions for preparation of BKL removal */
extern void __lockfunc tty_lock(struct tty_struct *tty); 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_unlock(struct tty_struct *tty);
extern void __lockfunc tty_lock_slave(struct tty_struct *tty); extern void __lockfunc tty_lock_slave(struct tty_struct *tty);
extern void __lockfunc tty_unlock_slave(struct tty_struct *tty); extern void __lockfunc tty_unlock_slave(struct tty_struct *tty);