Skip to content

Commit

Permalink
Merge tag 'tty-4.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
torvalds committed Feb 1, 2016
2 parents 8c4e378 + 6c55d9b commit 54e3f3e
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 12 deletions.
5 changes: 4 additions & 1 deletion drivers/staging/speakup/selection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down
7 changes: 2 additions & 5 deletions drivers/tty/n_tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
29 changes: 29 additions & 0 deletions drivers/tty/serial/8250/8250_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
*/
Expand Down
44 changes: 38 additions & 6 deletions drivers/tty/tty_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions drivers/tty/tty_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions include/linux/tty.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 54e3f3e

Please sign in to comment.