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:
commit
54e3f3e302
6 changed files with 82 additions and 12 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue