Skip to content

Commit f1638fc

Browse files
committed
Merge tag 'tty-4.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver fixes from Greg KH: "Here are some tty and serial driver fixes for 4.11-rc4. One of these fix a long-standing issue in the ldisc code that was found by Dmitry Vyukov with his great fuzzing work. The other fixes resolve other reported issues, and there is one revert of a patch in 4.11-rc1 that wasn't correct. All of these have been in linux-next for a while with no reported issues" * tag 'tty-4.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: tty: fix data race in tty_ldisc_ref_wait() tty: don't panic on OOM in tty_set_ldisc() Revert "tty: serial: pl011: add ttyAMA for matching pl011 console" tty: acpi/spcr: QDF2400 E44 checks for wrong OEM revision serial: 8250_dw: Fix breakage when HAVE_CLK=n serial: 8250_dw: Honor clk_round_rate errors in dw8250_set_termios
2 parents 53b4d59 + a4a3e06 commit f1638fc

File tree

4 files changed

+30
-75
lines changed

4 files changed

+30
-75
lines changed

drivers/acpi/spcr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static bool qdf2400_erratum_44_present(struct acpi_table_header *h)
3030
return true;
3131

3232
if (!memcmp(h->oem_table_id, "QDF2400 ", ACPI_OEM_TABLE_ID_SIZE) &&
33-
h->oem_revision == 0)
33+
h->oem_revision == 1)
3434
return true;
3535

3636
return false;

drivers/tty/serial/8250/8250_dw.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,20 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
257257
{
258258
unsigned int baud = tty_termios_baud_rate(termios);
259259
struct dw8250_data *d = p->private_data;
260-
unsigned int rate;
260+
long rate;
261261
int ret;
262262

263263
if (IS_ERR(d->clk) || !old)
264264
goto out;
265265

266266
clk_disable_unprepare(d->clk);
267267
rate = clk_round_rate(d->clk, baud * 16);
268-
ret = clk_set_rate(d->clk, rate);
268+
if (rate < 0)
269+
ret = rate;
270+
else if (rate == 0)
271+
ret = -ENOENT;
272+
else
273+
ret = clk_set_rate(d->clk, rate);
269274
clk_prepare_enable(d->clk);
270275

271276
if (!ret)

drivers/tty/serial/amba-pl011.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2373,7 +2373,7 @@ static int __init pl011_console_match(struct console *co, char *name, int idx,
23732373
if (strcmp(name, "qdf2400_e44") == 0) {
23742374
pr_info_once("UART: Working around QDF2400 SoC erratum 44");
23752375
qdf2400_e44_present = true;
2376-
} else if (strcmp(name, "pl011") != 0 || strcmp(name, "ttyAMA") != 0) {
2376+
} else if (strcmp(name, "pl011") != 0) {
23772377
return -ENODEV;
23782378
}
23792379

drivers/tty/tty_ldisc.c

Lines changed: 21 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,13 @@ const struct file_operations tty_ldiscs_proc_fops = {
271271

272272
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
273273
{
274+
struct tty_ldisc *ld;
275+
274276
ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
275-
if (!tty->ldisc)
277+
ld = tty->ldisc;
278+
if (!ld)
276279
ldsem_up_read(&tty->ldisc_sem);
277-
return tty->ldisc;
280+
return ld;
278281
}
279282
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
280283

@@ -488,41 +491,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
488491
tty_ldisc_debug(tty, "%p: closed\n", ld);
489492
}
490493

491-
/**
492-
* tty_ldisc_restore - helper for tty ldisc change
493-
* @tty: tty to recover
494-
* @old: previous ldisc
495-
*
496-
* Restore the previous line discipline or N_TTY when a line discipline
497-
* change fails due to an open error
498-
*/
499-
500-
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
501-
{
502-
struct tty_ldisc *new_ldisc;
503-
int r;
504-
505-
/* There is an outstanding reference here so this is safe */
506-
old = tty_ldisc_get(tty, old->ops->num);
507-
WARN_ON(IS_ERR(old));
508-
tty->ldisc = old;
509-
tty_set_termios_ldisc(tty, old->ops->num);
510-
if (tty_ldisc_open(tty, old) < 0) {
511-
tty_ldisc_put(old);
512-
/* This driver is always present */
513-
new_ldisc = tty_ldisc_get(tty, N_TTY);
514-
if (IS_ERR(new_ldisc))
515-
panic("n_tty: get");
516-
tty->ldisc = new_ldisc;
517-
tty_set_termios_ldisc(tty, N_TTY);
518-
r = tty_ldisc_open(tty, new_ldisc);
519-
if (r < 0)
520-
panic("Couldn't open N_TTY ldisc for "
521-
"%s --- error %d.",
522-
tty_name(tty), r);
523-
}
524-
}
525-
526494
/**
527495
* tty_set_ldisc - set line discipline
528496
* @tty: the terminal to set
@@ -536,12 +504,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
536504

537505
int tty_set_ldisc(struct tty_struct *tty, int disc)
538506
{
539-
int retval;
540-
struct tty_ldisc *old_ldisc, *new_ldisc;
541-
542-
new_ldisc = tty_ldisc_get(tty, disc);
543-
if (IS_ERR(new_ldisc))
544-
return PTR_ERR(new_ldisc);
507+
int retval, old_disc;
545508

546509
tty_lock(tty);
547510
retval = tty_ldisc_lock(tty, 5 * HZ);
@@ -554,7 +517,8 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
554517
}
555518

556519
/* Check the no-op case */
557-
if (tty->ldisc->ops->num == disc)
520+
old_disc = tty->ldisc->ops->num;
521+
if (old_disc == disc)
558522
goto out;
559523

560524
if (test_bit(TTY_HUPPED, &tty->flags)) {
@@ -563,42 +527,32 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
563527
goto out;
564528
}
565529

566-
old_ldisc = tty->ldisc;
567-
568-
/* Shutdown the old discipline. */
569-
tty_ldisc_close(tty, old_ldisc);
570-
571-
/* Now set up the new line discipline. */
572-
tty->ldisc = new_ldisc;
573-
tty_set_termios_ldisc(tty, disc);
574-
575-
retval = tty_ldisc_open(tty, new_ldisc);
530+
retval = tty_ldisc_reinit(tty, disc);
576531
if (retval < 0) {
577532
/* Back to the old one or N_TTY if we can't */
578-
tty_ldisc_put(new_ldisc);
579-
tty_ldisc_restore(tty, old_ldisc);
533+
if (tty_ldisc_reinit(tty, old_disc) < 0) {
534+
pr_err("tty: TIOCSETD failed, reinitializing N_TTY\n");
535+
if (tty_ldisc_reinit(tty, N_TTY) < 0) {
536+
/* At this point we have tty->ldisc == NULL. */
537+
pr_err("tty: reinitializing N_TTY failed\n");
538+
}
539+
}
580540
}
581541

582-
if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) {
542+
if (tty->ldisc && tty->ldisc->ops->num != old_disc &&
543+
tty->ops->set_ldisc) {
583544
down_read(&tty->termios_rwsem);
584545
tty->ops->set_ldisc(tty);
585546
up_read(&tty->termios_rwsem);
586547
}
587548

588-
/* At this point we hold a reference to the new ldisc and a
589-
reference to the old ldisc, or we hold two references to
590-
the old ldisc (if it was restored as part of error cleanup
591-
above). In either case, releasing a single reference from
592-
the old ldisc is correct. */
593-
new_ldisc = old_ldisc;
594549
out:
595550
tty_ldisc_unlock(tty);
596551

597552
/* Restart the work queue in case no characters kick it off. Safe if
598553
already running */
599554
tty_buffer_restart_work(tty->port);
600555
err:
601-
tty_ldisc_put(new_ldisc); /* drop the extra reference */
602556
tty_unlock(tty);
603557
return retval;
604558
}
@@ -659,10 +613,8 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
659613
int retval;
660614

661615
ld = tty_ldisc_get(tty, disc);
662-
if (IS_ERR(ld)) {
663-
BUG_ON(disc == N_TTY);
616+
if (IS_ERR(ld))
664617
return PTR_ERR(ld);
665-
}
666618

667619
if (tty->ldisc) {
668620
tty_ldisc_close(tty, tty->ldisc);
@@ -674,10 +626,8 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc)
674626
tty_set_termios_ldisc(tty, disc);
675627
retval = tty_ldisc_open(tty, tty->ldisc);
676628
if (retval) {
677-
if (!WARN_ON(disc == N_TTY)) {
678-
tty_ldisc_put(tty->ldisc);
679-
tty->ldisc = NULL;
680-
}
629+
tty_ldisc_put(tty->ldisc);
630+
tty->ldisc = NULL;
681631
}
682632
return retval;
683633
}

0 commit comments

Comments
 (0)