x86-hyper-v-register-clocksource-only-if-its-advertised.patch
alsa-ali5451-remove-irq-enabling-in-pointer-callback.patch
alsa-rme32.c-irq-enabling-after-spin_lock_irq.patch
+tty-prevent-deadlock-in-n_gsm-driver.patch
+tty-set_termios-set_termiox-should-not-return-eintr.patch
+usb-serial-fix-null-pointer-dereferences-on-disconnect.patch
--- /dev/null
+From 4d9b109060f690f5c835130ff54165ae157b3087 Mon Sep 17 00:00:00 2001
+From: Dirkjan Bussink <d.bussink@gmail.com>
+Date: Wed, 30 Jan 2013 11:44:50 +0100
+Subject: tty: Prevent deadlock in n_gsm driver
+
+From: Dirkjan Bussink <d.bussink@gmail.com>
+
+commit 4d9b109060f690f5c835130ff54165ae157b3087 upstream.
+
+This change fixes a deadlock when the multiplexer is closed while there
+are still client side ports open.
+
+When the multiplexer is closed and there are active tty's it tries to
+close them with tty_vhangup. This has a problem though, because
+tty_vhangup needs the tty_lock. This patch changes it to unlock the
+tty_lock before attempting the hangup and relocks afterwards. The
+additional call to tty_port_tty_set is needed because otherwise the
+port stays active because of the reference counter.
+
+This change also exposed another problem that other code paths don't
+expect that the multiplexer could have been closed. This patch also adds
+checks for these cases in the gsmtty_ class of function that could be
+called.
+
+The documentation explicitly states that "first close all virtual ports
+before closing the physical port" but we've found this to not always
+reality in our field situations. The GPRS / UTMS modem sometimes crashes
+and needs a power cycle in that case which means cleanly shutting down
+everything is not always possible. This change makes it much more robust
+for our situation where at least the system is recoverable with this patch
+and doesn't hang in a deadlock situation inside the kernel.
+
+The patch is against the long term support kernel (3.4.27) and should
+apply cleanly to more recent branches. Tested with a Telit GE864-QUADV2
+and Telit HE910 modem.
+
+Signed-off-by: Dirkjan Bussink <dirkjan.bussink@nedap.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/n_gsm.c | 42 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 41 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/n_gsm.c
++++ b/drivers/tty/n_gsm.c
+@@ -1692,6 +1692,8 @@ static inline void dlci_put(struct gsm_d
+ kref_put(&dlci->ref, gsm_dlci_free);
+ }
+
++static void gsm_destroy_network(struct gsm_dlci *dlci);
++
+ /**
+ * gsm_dlci_release - release DLCI
+ * @dlci: DLCI to destroy
+@@ -1705,9 +1707,19 @@ static void gsm_dlci_release(struct gsm_
+ {
+ struct tty_struct *tty = tty_port_tty_get(&dlci->port);
+ if (tty) {
++ mutex_lock(&dlci->mutex);
++ gsm_destroy_network(dlci);
++ mutex_unlock(&dlci->mutex);
++
++ /* tty_vhangup needs the tty_lock, so unlock and
++ relock after doing the hangup. */
++ tty_unlock();
+ tty_vhangup(tty);
++ tty_lock();
++ tty_port_tty_set(&dlci->port, NULL);
+ tty_kref_put(tty);
+ }
++ dlci->state = DLCI_CLOSED;
+ dlci_put(dlci);
+ }
+
+@@ -2933,6 +2945,8 @@ static void gsmtty_close(struct tty_stru
+
+ if (dlci == NULL)
+ return;
++ if (dlci->state == DLCI_CLOSED)
++ return;
+ mutex_lock(&dlci->mutex);
+ gsm_destroy_network(dlci);
+ mutex_unlock(&dlci->mutex);
+@@ -2951,6 +2965,8 @@ out:
+ static void gsmtty_hangup(struct tty_struct *tty)
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return;
+ tty_port_hangup(&dlci->port);
+ gsm_dlci_begin_close(dlci);
+ }
+@@ -2958,9 +2974,12 @@ static void gsmtty_hangup(struct tty_str
+ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
+ int len)
+ {
++ int sent;
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return -EINVAL;
+ /* Stuff the bytes into the fifo queue */
+- int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
++ sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
+ /* Need to kick the channel */
+ gsm_dlci_data_kick(dlci);
+ return sent;
+@@ -2969,18 +2988,24 @@ static int gsmtty_write(struct tty_struc
+ static int gsmtty_write_room(struct tty_struct *tty)
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return -EINVAL;
+ return TX_SIZE - kfifo_len(dlci->fifo);
+ }
+
+ static int gsmtty_chars_in_buffer(struct tty_struct *tty)
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return -EINVAL;
+ return kfifo_len(dlci->fifo);
+ }
+
+ static void gsmtty_flush_buffer(struct tty_struct *tty)
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return;
+ /* Caution needed: If we implement reliable transport classes
+ then the data being transmitted can't simply be junked once
+ it has first hit the stack. Until then we can just blow it
+@@ -2999,6 +3024,8 @@ static void gsmtty_wait_until_sent(struc
+ static int gsmtty_tiocmget(struct tty_struct *tty)
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return -EINVAL;
+ return dlci->modem_rx;
+ }
+
+@@ -3008,6 +3035,8 @@ static int gsmtty_tiocmset(struct tty_st
+ struct gsm_dlci *dlci = tty->driver_data;
+ unsigned int modem_tx = dlci->modem_tx;
+
++ if (dlci->state == DLCI_CLOSED)
++ return -EINVAL;
+ modem_tx &= ~clear;
+ modem_tx |= set;
+
+@@ -3026,6 +3055,8 @@ static int gsmtty_ioctl(struct tty_struc
+ struct gsm_netconfig nc;
+ int index;
+
++ if (dlci->state == DLCI_CLOSED)
++ return -EINVAL;
+ switch (cmd) {
+ case GSMIOC_ENABLE_NET:
+ if (copy_from_user(&nc, (void __user *)arg, sizeof(nc)))
+@@ -3052,6 +3083,9 @@ static int gsmtty_ioctl(struct tty_struc
+
+ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
+ {
++ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return;
+ /* For the moment its fixed. In actual fact the speed information
+ for the virtual channel can be propogated in both directions by
+ the RPN control message. This however rapidly gets nasty as we
+@@ -3063,6 +3097,8 @@ static void gsmtty_set_termios(struct tt
+ static void gsmtty_throttle(struct tty_struct *tty)
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return;
+ if (tty->termios->c_cflag & CRTSCTS)
+ dlci->modem_tx &= ~TIOCM_DTR;
+ dlci->throttled = 1;
+@@ -3073,6 +3109,8 @@ static void gsmtty_throttle(struct tty_s
+ static void gsmtty_unthrottle(struct tty_struct *tty)
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
++ if (dlci->state == DLCI_CLOSED)
++ return;
+ if (tty->termios->c_cflag & CRTSCTS)
+ dlci->modem_tx |= TIOCM_DTR;
+ dlci->throttled = 0;
+@@ -3084,6 +3122,8 @@ static int gsmtty_break_ctl(struct tty_s
+ {
+ struct gsm_dlci *dlci = tty->driver_data;
+ int encode = 0; /* Off */
++ if (dlci->state == DLCI_CLOSED)
++ return -EINVAL;
+
+ if (state == -1) /* "On indefinitely" - we can't encode this
+ properly */
--- /dev/null
+From 183d95cdd834381c594d3aa801c1f9f9c0c54fa9 Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Tue, 29 Jan 2013 20:07:41 +0100
+Subject: tty: set_termios/set_termiox should not return -EINTR
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit 183d95cdd834381c594d3aa801c1f9f9c0c54fa9 upstream.
+
+See https://bugzilla.redhat.com/show_bug.cgi?id=904907
+read command causes bash to abort with double free or corruption (out).
+
+A simple test-case from Roman:
+
+ // Compile the reproducer and send sigchld ti that process.
+ // EINTR occurs even if SA_RESTART flag is set.
+
+ void handler(int sig)
+ {
+ }
+
+ main()
+ {
+ struct sigaction act;
+ act.sa_handler = handler;
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGCHLD, &act, 0);
+ struct termio ttp;
+ ioctl(0, TCGETA, &ttp);
+ while(1)
+ {
+ if (ioctl(0, TCSETAW, ttp) < 0)
+ {
+ if (errno == EINTR)
+ {
+ fprintf(stderr, "BUG!"); return(1);
+ }
+ }
+ }
+ }
+
+Change set_termios/set_termiox to return -ERESTARTSYS to fix this
+particular problem.
+
+I didn't dare to change other EINTR's in drivers/tty/, but they look
+equally wrong.
+
+Reported-by: Roman Rakus <rrakus@redhat.com>
+Reported-by: Lingzhu Xiang <lxiang@redhat.com>
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Cc: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/tty_ioctl.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/tty/tty_ioctl.c
++++ b/drivers/tty/tty_ioctl.c
+@@ -617,7 +617,7 @@ static int set_termios(struct tty_struct
+ if (opt & TERMIOS_WAIT) {
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+- return -EINTR;
++ return -ERESTARTSYS;
+ }
+
+ tty_set_termios(tty, &tmp_termios);
+@@ -684,7 +684,7 @@ static int set_termiox(struct tty_struct
+ if (opt & TERMIOS_WAIT) {
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+- return -EINTR;
++ return -ERESTARTSYS;
+ }
+
+ mutex_lock(&tty->termios_mutex);
--- /dev/null
+From b2ca699076573c94fee9a73cb0d8645383b602a0 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Wed, 13 Feb 2013 17:53:28 +0100
+Subject: USB: serial: fix null-pointer dereferences on disconnect
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit b2ca699076573c94fee9a73cb0d8645383b602a0 upstream.
+
+Make sure serial-driver dtr_rts is called with disc_mutex held after
+checking the disconnected flag.
+
+Due to a bug in the tty layer, dtr_rts may get called after a device has
+been disconnected and the tty-device unregistered. Some drivers have had
+individual checks for disconnect to make sure the disconnected interface
+was not accessed, but this should really be handled in usb-serial core
+(at least until the long-standing tty-bug has been fixed).
+
+Note that the problem has been made more acute with commit 0998d0631001
+("device-core: Ensure drvdata = NULL when no driver is bound") as the
+port data is now also NULL when dtr_rts is called resulting in further
+oopses.
+
+Reported-by: Chris Ruehl <chris.ruehl@gtsys.com.hk>
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ftdi_sio.c | 20 +++++++++-----------
+ drivers/usb/serial/mct_u232.c | 22 +++++++++-------------
+ drivers/usb/serial/sierra.c | 8 +-------
+ drivers/usb/serial/ssu100.c | 19 ++++++++-----------
+ drivers/usb/serial/usb-serial.c | 14 ++++++++++++--
+ drivers/usb/serial/usb_wwan.c | 8 +++-----
+ 6 files changed, 42 insertions(+), 49 deletions(-)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -1919,24 +1919,22 @@ static void ftdi_dtr_rts(struct usb_seri
+ {
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+- mutex_lock(&port->serial->disc_mutex);
+- if (!port->serial->disconnected) {
+- /* Disable flow control */
+- if (!on && usb_control_msg(port->serial->dev,
++ /* Disable flow control */
++ if (!on) {
++ if (usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, priv->interface, NULL, 0,
+ WDR_TIMEOUT) < 0) {
+- dev_err(&port->dev, "error from flowcontrol urb\n");
++ dev_err(&port->dev, "error from flowcontrol urb\n");
+ }
+- /* drop RTS and DTR */
+- if (on)
+- set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+- else
+- clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ }
+- mutex_unlock(&port->serial->disc_mutex);
++ /* drop RTS and DTR */
++ if (on)
++ set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
++ else
++ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ }
+
+ /*
+--- a/drivers/usb/serial/mct_u232.c
++++ b/drivers/usb/serial/mct_u232.c
+@@ -514,19 +514,15 @@ static void mct_u232_dtr_rts(struct usb_
+ unsigned int control_state;
+ struct mct_u232_private *priv = usb_get_serial_port_data(port);
+
+- mutex_lock(&port->serial->disc_mutex);
+- if (!port->serial->disconnected) {
+- /* drop DTR and RTS */
+- spin_lock_irq(&priv->lock);
+- if (on)
+- priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+- else
+- priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+- control_state = priv->control_state;
+- spin_unlock_irq(&priv->lock);
+- mct_u232_set_modem_ctrl(port->serial, control_state);
+- }
+- mutex_unlock(&port->serial->disc_mutex);
++ spin_lock_irq(&priv->lock);
++ if (on)
++ priv->control_state |= TIOCM_DTR | TIOCM_RTS;
++ else
++ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
++ control_state = priv->control_state;
++ spin_unlock_irq(&priv->lock);
++
++ mct_u232_set_modem_ctrl(port->serial, control_state);
+ }
+
+ static void mct_u232_close(struct usb_serial_port *port)
+--- a/drivers/usb/serial/sierra.c
++++ b/drivers/usb/serial/sierra.c
+@@ -890,19 +890,13 @@ static int sierra_open(struct tty_struct
+
+ static void sierra_dtr_rts(struct usb_serial_port *port, int on)
+ {
+- struct usb_serial *serial = port->serial;
+ struct sierra_port_private *portdata;
+
+ portdata = usb_get_serial_port_data(port);
+ portdata->rts_state = on;
+ portdata->dtr_state = on;
+
+- if (serial->dev) {
+- mutex_lock(&serial->disc_mutex);
+- if (!serial->disconnected)
+- sierra_send_setup(port);
+- mutex_unlock(&serial->disc_mutex);
+- }
++ sierra_send_setup(port);
+ }
+
+ static int sierra_startup(struct usb_serial *serial)
+--- a/drivers/usb/serial/ssu100.c
++++ b/drivers/usb/serial/ssu100.c
+@@ -532,19 +532,16 @@ static void ssu100_dtr_rts(struct usb_se
+
+ dbg("%s\n", __func__);
+
+- mutex_lock(&port->serial->disc_mutex);
+- if (!port->serial->disconnected) {
+- /* Disable flow control */
+- if (!on &&
+- ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
++ /* Disable flow control */
++ if (!on) {
++ if (ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
+ dev_err(&port->dev, "error from flowcontrol urb\n");
+- /* drop RTS and DTR */
+- if (on)
+- set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
+- else
+- clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
+ }
+- mutex_unlock(&port->serial->disc_mutex);
++ /* drop RTS and DTR */
++ if (on)
++ set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
++ else
++ clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
+ }
+
+ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -699,10 +699,20 @@ static int serial_carrier_raised(struct
+ static void serial_dtr_rts(struct tty_port *port, int on)
+ {
+ struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
+- struct usb_serial_driver *drv = p->serial->type;
++ struct usb_serial *serial = p->serial;
++ struct usb_serial_driver *drv = serial->type;
+
+- if (drv->dtr_rts)
++ if (!drv->dtr_rts)
++ return;
++ /*
++ * Work-around bug in the tty-layer which can result in dtr_rts
++ * being called after a disconnect (and tty_unregister_device
++ * has returned). Remove once bug has been squashed.
++ */
++ mutex_lock(&serial->disc_mutex);
++ if (!serial->disconnected)
+ drv->dtr_rts(p, on);
++ mutex_unlock(&serial->disc_mutex);
+ }
+
+ static const struct tty_port_operations serial_port_ops = {
+--- a/drivers/usb/serial/usb_wwan.c
++++ b/drivers/usb/serial/usb_wwan.c
+@@ -41,7 +41,6 @@ static bool debug;
+
+ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
+ {
+- struct usb_serial *serial = port->serial;
+ struct usb_wwan_port_private *portdata;
+
+ struct usb_wwan_intf_private *intfdata;
+@@ -54,12 +53,11 @@ void usb_wwan_dtr_rts(struct usb_serial_
+ return;
+
+ portdata = usb_get_serial_port_data(port);
+- mutex_lock(&serial->disc_mutex);
++ /* FIXME: locking */
+ portdata->rts_state = on;
+ portdata->dtr_state = on;
+- if (serial->dev)
+- intfdata->send_setup(port);
+- mutex_unlock(&serial->disc_mutex);
++
++ intfdata->send_setup(port);
+ }
+ EXPORT_SYMBOL(usb_wwan_dtr_rts);
+