]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
.29 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Mon, 4 May 2009 23:08:50 +0000 (16:08 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 4 May 2009 23:08:50 +0000 (16:08 -0700)
queue-2.6.29/acpi-revert-conflicting-workaround-for-bios-w-mangled-prt-entries.patch [new file with mode: 0644]
queue-2.6.29/powerpc-sanitize-stack-pointer-in-signal-handling-code.patch [new file with mode: 0644]
queue-2.6.29/series
queue-2.6.29/usb-serial-fix-lifetime-and-locking-problems.patch [new file with mode: 0644]

diff --git a/queue-2.6.29/acpi-revert-conflicting-workaround-for-bios-w-mangled-prt-entries.patch b/queue-2.6.29/acpi-revert-conflicting-workaround-for-bios-w-mangled-prt-entries.patch
new file mode 100644 (file)
index 0000000..7b4ec1c
--- /dev/null
@@ -0,0 +1,91 @@
+From lenb@kernel.org  Mon May  4 16:01:55 2009
+From: Zhang Rui <rui.zhang@intel.com>
+Date: Fri, 01 May 2009 11:12:41 -0400 (EDT)
+Subject: ACPI: Revert conflicting workaround for BIOS w/ mangled PRT entries
+To: stable@kernel.org
+Cc: linux-acpi@vger.kernel.org, tmb@mandriva.org
+Message-ID: <alpine.LFD.2.00.0905011106130.6437@localhost.localdomain>
+
+
+From: Zhang Rui <rui.zhang@intel.com>
+
+upstream 82babbb3887e234c995626e4121d411ea9070ca5
+backported to 2.6.29.2
+
+2f894ef9c8b36a35d80709bedca276d2fc691941
+in Linux-2.6.21 worked around BIOS with mangled _PRT entries:
+http://bugzilla.kernel.org/show_bug.cgi?id=6859
+
+d0e184abc5983281ef189db2c759d65d56eb1b80
+worked around the same issue via ACPICA, and shipped in 2.6.27.
+
+Unfortunately the two workarounds conflict:
+http://bugzilla.kernel.org/show_bug.cgi?id=12270
+
+So revert the Linux specific one.
+
+Signed-off-by: Zhang Rui <rui.zhang@intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/acpi/acpica/rscreate.c |   27 ++-------------------------
+ 1 file changed, 2 insertions(+), 25 deletions(-)
+
+--- a/drivers/acpi/acpica/rscreate.c
++++ b/drivers/acpi/acpica/rscreate.c
+@@ -191,8 +191,6 @@ acpi_rs_create_pci_routing_table(union a
+       user_prt = ACPI_CAST_PTR(struct acpi_pci_routing_table, buffer);
+       for (index = 0; index < number_of_elements; index++) {
+-              int source_name_index = 2;
+-              int source_index_index = 3;
+               /*
+                * Point user_prt past this current structure
+@@ -261,27 +259,6 @@ acpi_rs_create_pci_routing_table(union a
+                       return_ACPI_STATUS(AE_BAD_DATA);
+               }
+-              /*
+-               * If BIOS erroneously reversed the _PRT source_name and source_index,
+-               * then reverse them back.
+-               */
+-              if (ACPI_GET_OBJECT_TYPE(sub_object_list[3]) !=
+-                  ACPI_TYPE_INTEGER) {
+-                      if (acpi_gbl_enable_interpreter_slack) {
+-                              source_name_index = 3;
+-                              source_index_index = 2;
+-                              printk(KERN_WARNING
+-                                     "ACPI: Handling Garbled _PRT entry\n");
+-                      } else {
+-                              ACPI_ERROR((AE_INFO,
+-                                          "(PRT[%X].source_index) Need Integer, found %s",
+-                                          index,
+-                                          acpi_ut_get_object_type_name
+-                                          (sub_object_list[3])));
+-                              return_ACPI_STATUS(AE_BAD_DATA);
+-                      }
+-              }
+-
+               user_prt->pin = (u32) obj_desc->integer.value;
+               /*
+@@ -305,7 +282,7 @@ acpi_rs_create_pci_routing_table(union a
+                * 3) Third subobject: Dereference the PRT.source_name
+                * The name may be unresolved (slack mode), so allow a null object
+                */
+-              obj_desc = sub_object_list[source_name_index];
++              obj_desc = sub_object_list[2];
+               if (obj_desc) {
+                       switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
+                       case ACPI_TYPE_LOCAL_REFERENCE:
+@@ -379,7 +356,7 @@ acpi_rs_create_pci_routing_table(union a
+               /* 4) Fourth subobject: Dereference the PRT.source_index */
+-              obj_desc = sub_object_list[source_index_index];
++              obj_desc = sub_object_list[3];
+               if (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER) {
+                       ACPI_ERROR((AE_INFO,
+                                   "(PRT[%X].SourceIndex) Need Integer, found %s",
diff --git a/queue-2.6.29/powerpc-sanitize-stack-pointer-in-signal-handling-code.patch b/queue-2.6.29/powerpc-sanitize-stack-pointer-in-signal-handling-code.patch
new file mode 100644 (file)
index 0000000..0dae4ce
--- /dev/null
@@ -0,0 +1,126 @@
+From jwboyer@linux.vnet.ibm.com  Mon May  4 16:02:51 2009
+From: Josh Boyer <jwboyer@linux.vnet.ibm.com>
+Date: Tue, 28 Apr 2009 11:15:59 -0400
+Subject: powerpc: Sanitize stack pointer in signal handling code
+To: stable@kernel.org
+Cc: benh@kernel.crashing.org
+Message-ID: <20090428151559.GC5281@yoda.jdub.homelinux.org>
+Content-Disposition: inline
+
+From: Josh Boyer <jwboyer@linux.vnet.ibm.com>
+
+This has been backported to 2.6.29.x from commit efbda86098 in Linus' tree
+
+On powerpc64 machines running 32-bit userspace, we can get garbage bits in the
+stack pointer passed into the kernel.  Most places handle this correctly, but
+the signal handling code uses the passed value directly for allocating signal
+stack frames.
+
+This fixes the issue by introducing a get_clean_sp function that returns a
+sanitized stack pointer.  For 32-bit tasks on a 64-bit kernel, the stack
+pointer is masked correctly.  In all other cases, the stack pointer is simply
+returned.
+
+Additionally, we pass an 'is_32' parameter to get_sigframe now in order to
+get the properly sanitized stack.  The callers are know to be 32 or 64-bit
+statically.
+
+Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
+Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/powerpc/include/asm/processor.h |   19 +++++++++++++++++++
+ arch/powerpc/kernel/signal.c         |    4 ++--
+ arch/powerpc/kernel/signal.h         |    2 +-
+ arch/powerpc/kernel/signal_32.c      |    4 ++--
+ arch/powerpc/kernel/signal_64.c      |    2 +-
+ 5 files changed, 25 insertions(+), 6 deletions(-)
+
+--- a/arch/powerpc/include/asm/processor.h
++++ b/arch/powerpc/include/asm/processor.h
+@@ -313,6 +313,25 @@ static inline void prefetchw(const void 
+ #define HAVE_ARCH_PICK_MMAP_LAYOUT
+ #endif
++#ifdef CONFIG_PPC64
++static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
++{
++      unsigned long sp;
++
++      if (is_32)
++              sp = regs->gpr[1] & 0x0ffffffffUL;
++      else
++              sp = regs->gpr[1];
++
++      return sp;
++}
++#else
++static inline unsigned long get_clean_sp(struct pt_regs *regs, int is_32)
++{
++      return regs->gpr[1];
++}
++#endif
++
+ #endif /* __KERNEL__ */
+ #endif /* __ASSEMBLY__ */
+ #endif /* _ASM_POWERPC_PROCESSOR_H */
+--- a/arch/powerpc/kernel/signal_32.c
++++ b/arch/powerpc/kernel/signal_32.c
+@@ -836,7 +836,7 @@ int handle_rt_signal32(unsigned long sig
+       /* Set up Signal Frame */
+       /* Put a Real Time Context onto stack */
+-      rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
++      rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf), 1);
+       addr = rt_sf;
+       if (unlikely(rt_sf == NULL))
+               goto badframe;
+@@ -1182,7 +1182,7 @@ int handle_signal32(unsigned long sig, s
+       unsigned long newsp = 0;
+       /* Set up Signal Frame */
+-      frame = get_sigframe(ka, regs, sizeof(*frame));
++      frame = get_sigframe(ka, regs, sizeof(*frame), 1);
+       if (unlikely(frame == NULL))
+               goto badframe;
+       sc = (struct sigcontext __user *) &frame->sctx;
+--- a/arch/powerpc/kernel/signal_64.c
++++ b/arch/powerpc/kernel/signal_64.c
+@@ -402,7 +402,7 @@ int handle_rt_signal64(int signr, struct
+       unsigned long newsp = 0;
+       long err = 0;
+-      frame = get_sigframe(ka, regs, sizeof(*frame));
++      frame = get_sigframe(ka, regs, sizeof(*frame), 0);
+       if (unlikely(frame == NULL))
+               goto badframe;
+--- a/arch/powerpc/kernel/signal.c
++++ b/arch/powerpc/kernel/signal.c
+@@ -26,12 +26,12 @@ int show_unhandled_signals = 0;
+  * Allocate space for the signal frame
+  */
+ void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+-                         size_t frame_size)
++                         size_t frame_size, int is_32)
+ {
+         unsigned long oldsp, newsp;
+         /* Default to using normal stack */
+-        oldsp = regs->gpr[1];
++        oldsp = get_clean_sp(regs, is_32);
+       /* Check for alt stack */
+       if ((ka->sa.sa_flags & SA_ONSTACK) &&
+--- a/arch/powerpc/kernel/signal.h
++++ b/arch/powerpc/kernel/signal.h
+@@ -15,7 +15,7 @@
+ extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags);
+ extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+-                                size_t frame_size);
++                                size_t frame_size, int is_32);
+ extern void restore_sigmask(sigset_t *set);
+ extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
index 3341e8dc8fb9f13f38b85b5ec09becafcd0a64d5..d67c88646cfa3b9605bab0b4613037ccf250b90a 100644 (file)
@@ -28,3 +28,6 @@ mm-fix-committed_as-underflow-on-large-nr_cpus-environment.patch
 pagemap-require-aligned-length-non-null-reads-of-proc-pid-pagemap.patch
 kbuild-fix-module.markers-permission-error-under-cygwin.patch
 ptrace-ptrace_attach-fix-the-usage-of-cred_exec_mutex.patch
+usb-serial-fix-lifetime-and-locking-problems.patch
+acpi-revert-conflicting-workaround-for-bios-w-mangled-prt-entries.patch
+powerpc-sanitize-stack-pointer-in-signal-handling-code.patch
diff --git a/queue-2.6.29/usb-serial-fix-lifetime-and-locking-problems.patch b/queue-2.6.29/usb-serial-fix-lifetime-and-locking-problems.patch
new file mode 100644 (file)
index 0000000..a2ca022
--- /dev/null
@@ -0,0 +1,279 @@
+From stern@rowland.harvard.edu  Mon May  4 16:00:35 2009
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 4 May 2009 11:30:32 -0400 (EDT)
+Subject: USB: serial: fix lifetime and locking problems
+To: stable@kernel.org
+Message-ID: <Pine.LNX.4.44L0.0905041130110.6437-100000@iolanthe.rowland.org>
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+This is commit 2d93148ab6988cad872e65d694c95e8944e1b626 back-ported to
+2.6.29.
+
+This patch (as1229-3) fixes a few lifetime and locking problems in the
+usb-serial driver.  The main symptom is that an invalid kevent is
+created when the serial device is unplugged while a connection is
+active.
+
+       Ports should be unregistered when device is disconnected,
+       not when the parent usb_serial structure is deallocated.
+
+       Each open file should hold a reference to the corresponding
+       port structure, and the reference should be released when
+       the file is closed.
+
+       serial->disc_mutex should be acquired in serial_open(), to
+       resolve the classic race between open and disconnect.
+
+       serial_close() doesn't need to hold both serial->disc_mutex
+       and port->mutex at the same time.
+
+       Release the subdriver's module reference only after releasing
+       all the other references, in case one of the release routines
+       needs to invoke some code in the subdriver module.
+
+       Replace a call to flush_scheduled_work() (which is prone to
+       deadlocks) with cancel_work_sync().  Also, add a call to
+       cancel_work_sync() in the disconnect routine.
+
+       Reduce the scope of serial->disc_mutex in serial_disconnect().
+       The only place it really needs to protect is where the
+       "disconnected" flag is set.
+
+       Call the shutdown method from within serial_disconnect()
+       instead of destroy_serial(), because some subdrivers expect
+       the port data structures still to be in existence when
+       their shutdown method runs.
+
+This fixes the bug reported in
+
+       http://bugs.freedesktop.org/show_bug.cgi?id=20703
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+
+---
+ drivers/usb/serial/usb-serial.c |   99 +++++++++++++++++++++++++++-------------
+ 1 file changed, 68 insertions(+), 31 deletions(-)
+
+--- a/drivers/usb/serial/usb-serial.c
++++ b/drivers/usb/serial/usb-serial.c
+@@ -136,22 +136,10 @@ static void destroy_serial(struct kref *
+       dbg("%s - %s", __func__, serial->type->description);
+-      serial->type->shutdown(serial);
+-
+       /* return the minor range that this device had */
+       if (serial->minor != SERIAL_TTY_NO_MINOR)
+               return_serial(serial);
+-      for (i = 0; i < serial->num_ports; ++i)
+-              serial->port[i]->port.count = 0;
+-
+-      /* the ports are cleaned up and released in port_release() */
+-      for (i = 0; i < serial->num_ports; ++i)
+-              if (serial->port[i]->dev.parent != NULL) {
+-                      device_unregister(&serial->port[i]->dev);
+-                      serial->port[i] = NULL;
+-              }
+-
+       /* If this is a "fake" port, we have to clean it up here, as it will
+        * not get cleaned up in port_release() as it was never registered with
+        * the driver core */
+@@ -186,7 +174,7 @@ static int serial_open (struct tty_struc
+       struct usb_serial *serial;
+       struct usb_serial_port *port;
+       unsigned int portNumber;
+-      int retval;
++      int retval = 0;
+       dbg("%s", __func__);
+@@ -197,16 +185,24 @@ static int serial_open (struct tty_struc
+               return -ENODEV;
+       }
++      mutex_lock(&serial->disc_mutex);
+       portNumber = tty->index - serial->minor;
+       port = serial->port[portNumber];
+-      if (!port) {
++      if (!port || serial->disconnected)
+               retval = -ENODEV;
+-              goto bailout_kref_put;
+-      }
++      else
++              get_device(&port->dev);
++      /*
++       * Note: Our locking order requirement does not allow port->mutex
++       * to be acquired while serial->disc_mutex is held.
++       */
++      mutex_unlock(&serial->disc_mutex);
++      if (retval)
++              goto bailout_serial_put;
+       if (mutex_lock_interruptible(&port->mutex)) {
+               retval = -ERESTARTSYS;
+-              goto bailout_kref_put;
++              goto bailout_port_put;
+       }
+       ++port->port.count;
+@@ -226,14 +222,20 @@ static int serial_open (struct tty_struc
+                       goto bailout_mutex_unlock;
+               }
+-              retval = usb_autopm_get_interface(serial->interface);
++              mutex_lock(&serial->disc_mutex);
++              if (serial->disconnected)
++                      retval = -ENODEV;
++              else
++                      retval = usb_autopm_get_interface(serial->interface);
+               if (retval)
+                       goto bailout_module_put;
++
+               /* only call the device specific open if this
+                * is the first time the port is opened */
+               retval = serial->type->open(tty, port, filp);
+               if (retval)
+                       goto bailout_interface_put;
++              mutex_unlock(&serial->disc_mutex);
+       }
+       mutex_unlock(&port->mutex);
+@@ -242,13 +244,16 @@ static int serial_open (struct tty_struc
+ bailout_interface_put:
+       usb_autopm_put_interface(serial->interface);
+ bailout_module_put:
++      mutex_unlock(&serial->disc_mutex);
+       module_put(serial->type->driver.owner);
+ bailout_mutex_unlock:
+       port->port.count = 0;
+       tty->driver_data = NULL;
+       tty_port_tty_set(&port->port, NULL);
+       mutex_unlock(&port->mutex);
+-bailout_kref_put:
++bailout_port_put:
++      put_device(&port->dev);
++bailout_serial_put:
+       usb_serial_put(serial);
+       return retval;
+ }
+@@ -256,6 +261,9 @@ bailout_kref_put:
+ static void serial_close(struct tty_struct *tty, struct file *filp)
+ {
+       struct usb_serial_port *port = tty->driver_data;
++      struct usb_serial *serial;
++      struct module *owner;
++      int count;
+       if (!port)
+               return;
+@@ -263,6 +271,8 @@ static void serial_close(struct tty_stru
+       dbg("%s - port %d", __func__, port->number);
+       mutex_lock(&port->mutex);
++      serial = port->serial;
++      owner = serial->type->driver.owner;
+       if (port->port.count == 0) {
+               mutex_unlock(&port->mutex);
+@@ -275,7 +285,7 @@ static void serial_close(struct tty_stru
+                * this before we drop the port count. The call is protected
+                * by the port mutex
+                */
+-              port->serial->type->close(tty, port, filp);
++              serial->type->close(tty, port, filp);
+       if (port->port.count == (port->console ? 2 : 1)) {
+               struct tty_struct *tty = tty_port_tty_get(&port->port);
+@@ -289,17 +299,23 @@ static void serial_close(struct tty_stru
+               }
+       }
+-      if (port->port.count == 1) {
+-              mutex_lock(&port->serial->disc_mutex);
+-              if (!port->serial->disconnected)
+-                      usb_autopm_put_interface(port->serial->interface);
+-              mutex_unlock(&port->serial->disc_mutex);
+-              module_put(port->serial->type->driver.owner);
+-      }
+       --port->port.count;
+-
++      count = port->port.count;
+       mutex_unlock(&port->mutex);
+-      usb_serial_put(port->serial);
++      put_device(&port->dev);
++
++      /* Mustn't dereference port any more */
++      if (count == 0) {
++              mutex_lock(&serial->disc_mutex);
++              if (!serial->disconnected)
++                      usb_autopm_put_interface(serial->interface);
++              mutex_unlock(&serial->disc_mutex);
++      }
++      usb_serial_put(serial);
++
++      /* Mustn't dereference serial any more */
++      if (count == 0)
++              module_put(owner);
+ }
+ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
+@@ -548,7 +564,13 @@ static void kill_traffic(struct usb_seri
+ static void port_free(struct usb_serial_port *port)
+ {
++      /*
++       * Stop all the traffic before cancelling the work, so that
++       * nobody will restart it by calling usb_serial_port_softint.
++       */
+       kill_traffic(port);
++      cancel_work_sync(&port->work);
++
+       usb_free_urb(port->read_urb);
+       usb_free_urb(port->write_urb);
+       usb_free_urb(port->interrupt_in_urb);
+@@ -557,7 +579,6 @@ static void port_free(struct usb_serial_
+       kfree(port->bulk_out_buffer);
+       kfree(port->interrupt_in_buffer);
+       kfree(port->interrupt_out_buffer);
+-      flush_scheduled_work();         /* port->work */
+       kfree(port);
+ }
+@@ -1042,6 +1063,12 @@ void usb_serial_disconnect(struct usb_in
+       usb_set_intfdata(interface, NULL);
+       /* must set a flag, to signal subdrivers */
+       serial->disconnected = 1;
++      mutex_unlock(&serial->disc_mutex);
++
++      /* Unfortunately, many of the sub-drivers expect the port structures
++       * to exist when their shutdown method is called, so we have to go
++       * through this awkward two-step unregistration procedure.
++       */
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = serial->port[i];
+               if (port) {
+@@ -1051,11 +1078,21 @@ void usb_serial_disconnect(struct usb_in
+                               tty_kref_put(tty);
+                       }
+                       kill_traffic(port);
++                      cancel_work_sync(&port->work);
++                      device_del(&port->dev);
+               }
+       }
++      serial->type->shutdown(serial);
++      for (i = 0; i < serial->num_ports; ++i) {
++              port = serial->port[i];
++              if (port) {
++                      put_device(&port->dev);
++                      serial->port[i] = NULL;
++              }
++      }
++
+       /* let the last holder of this object
+        * cause it to be cleaned up */
+-      mutex_unlock(&serial->disc_mutex);
+       usb_serial_put(serial);
+       dev_info(dev, "device disconnected\n");
+ }