--- /dev/null
+From stable-bounces@linux.kernel.org Wed Aug 1 23:37:02 2007
+From: Christian Lamparter <chunkeey@web.de>
+Date: Thu, 2 Aug 2007 15:36:50 +0900
+Subject: Add a PCI ID for santa rosa's PATA controller.
+To: stable@kernel.org
+Cc: linux-ide@vger.kernel.org, Jeff Garzik <jeff@garzik.org>
+Message-ID: <20070802063650.GK13674@htj.dyndns.org>
+Content-Disposition: inline
+
+
+From: Christian Lamparter <chunkeey@web.de>
+
+This is commit c1e6f28cc5de37dcd113b9668a185c0b9334ba8a which is
+merged during 23-rc1 window. Considering the popularity of these
+chips, I think including it in -stable release would be good idea.
+
+Signed-off-by: Christian Lamparter <chunkeey@web.de>
+Signed-off-by: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/ata/ata_piix.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/ata/ata_piix.c
++++ b/drivers/ata/ata_piix.c
+@@ -200,6 +200,8 @@ static const struct pci_device_id piix_p
+ /* ICH7/7-R (i945, i975) UDMA 100*/
+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
++ /* ICH8 Mobile PATA Controller */
++ { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+
+ /* NOTE: The following PCI ids must be kept in sync with the
+ * list in drivers/pci/quirks.c.
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:34:14 2007
+From: David Miller <davem@davemloft.net>
+Date: Wed, 18 Jul 2007 02:34:05 -0700 (PDT)
+Subject: Fix deadlocks in sparc serial console.
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.023405.58454422.davem@davemloft.net>
+
+
+From: David S. Miller <davem@davemloft.net>
+
+Subject: [PATCH] [SERIAL]: Fix console write locking in sparc drivers.
+
+Mirror the logic in 8250 for proper console write locking
+when SYSRQ is triggered or an OOPS is in progress.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/sunhv.c | 30 ++++++++++++++++++++++++++----
+ drivers/serial/sunsab.c | 19 ++++++++++++++-----
+ drivers/serial/sunsu.c | 14 ++++++++++++++
+ drivers/serial/sunzilog.c | 17 ++++++++++++++---
+ 4 files changed, 68 insertions(+), 12 deletions(-)
+
+--- a/drivers/serial/sunhv.c
++++ b/drivers/serial/sunhv.c
+@@ -440,8 +440,16 @@ static void sunhv_console_write_paged(st
+ {
+ struct uart_port *port = sunhv_port;
+ unsigned long flags;
++ int locked = 1;
++
++ local_irq_save(flags);
++ if (port->sysrq) {
++ locked = 0;
++ } else if (oops_in_progress) {
++ locked = spin_trylock(&port->lock);
++ } else
++ spin_lock(&port->lock);
+
+- spin_lock_irqsave(&port->lock, flags);
+ while (n > 0) {
+ unsigned long ra = __pa(con_write_page);
+ unsigned long page_bytes;
+@@ -469,7 +477,10 @@ static void sunhv_console_write_paged(st
+ ra += written;
+ }
+ }
+- spin_unlock_irqrestore(&port->lock, flags);
++
++ if (locked)
++ spin_unlock(&port->lock);
++ local_irq_restore(flags);
+ }
+
+ static inline void sunhv_console_putchar(struct uart_port *port, char c)
+@@ -488,7 +499,15 @@ static void sunhv_console_write_bychar(s
+ {
+ struct uart_port *port = sunhv_port;
+ unsigned long flags;
+- int i;
++ int i, locked = 1;
++
++ local_irq_save(flags);
++ if (port->sysrq) {
++ locked = 0;
++ } else if (oops_in_progress) {
++ locked = spin_trylock(&port->lock);
++ } else
++ spin_lock(&port->lock);
+
+ spin_lock_irqsave(&port->lock, flags);
+ for (i = 0; i < n; i++) {
+@@ -496,7 +515,10 @@ static void sunhv_console_write_bychar(s
+ sunhv_console_putchar(port, '\r');
+ sunhv_console_putchar(port, *s++);
+ }
+- spin_unlock_irqrestore(&port->lock, flags);
++
++ if (locked)
++ spin_unlock(&port->lock);
++ local_irq_restore(flags);
+ }
+
+ static struct console sunhv_console = {
+--- a/drivers/serial/sunsab.c
++++ b/drivers/serial/sunsab.c
+@@ -860,22 +860,31 @@ static int num_channels;
+ static void sunsab_console_putchar(struct uart_port *port, int c)
+ {
+ struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&up->port.lock, flags);
+
+ sunsab_tec_wait(up);
+ writeb(c, &up->regs->w.tic);
+-
+- spin_unlock_irqrestore(&up->port.lock, flags);
+ }
+
+ static void sunsab_console_write(struct console *con, const char *s, unsigned n)
+ {
+ struct uart_sunsab_port *up = &sunsab_ports[con->index];
++ unsigned long flags;
++ int locked = 1;
++
++ local_irq_save(flags);
++ if (up->port.sysrq) {
++ locked = 0;
++ } else if (oops_in_progress) {
++ locked = spin_trylock(&up->port.lock);
++ } else
++ spin_lock(&up->port.lock);
+
+ uart_console_write(&up->port, s, n, sunsab_console_putchar);
+ sunsab_tec_wait(up);
++
++ if (locked)
++ spin_unlock(&up->port.lock);
++ local_irq_restore(flags);
+ }
+
+ static int sunsab_console_setup(struct console *con, char *options)
+--- a/drivers/serial/sunsu.c
++++ b/drivers/serial/sunsu.c
+@@ -1288,7 +1288,17 @@ static void sunsu_console_write(struct c
+ unsigned int count)
+ {
+ struct uart_sunsu_port *up = &sunsu_ports[co->index];
++ unsigned long flags;
+ unsigned int ier;
++ int locked = 1;
++
++ local_irq_save(flags);
++ if (up->port.sysrq) {
++ locked = 0;
++ } else if (oops_in_progress) {
++ locked = spin_trylock(&up->port.lock);
++ } else
++ spin_lock(&up->port.lock);
+
+ /*
+ * First save the UER then disable the interrupts
+@@ -1304,6 +1314,10 @@ static void sunsu_console_write(struct c
+ */
+ wait_for_xmitr(up);
+ serial_out(up, UART_IER, ier);
++
++ if (locked)
++ spin_unlock(&up->port.lock);
++ local_irq_restore(flags);
+ }
+
+ /*
+--- a/drivers/serial/sunzilog.c
++++ b/drivers/serial/sunzilog.c
+@@ -9,7 +9,7 @@
+ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
+ * work there.
+ *
+- * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net)
++ * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
+ */
+
+ #include <linux/module.h>
+@@ -1151,11 +1151,22 @@ sunzilog_console_write(struct console *c
+ {
+ struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
+ unsigned long flags;
++ int locked = 1;
++
++ local_irq_save(flags);
++ if (up->port.sysrq) {
++ locked = 0;
++ } else if (oops_in_progress) {
++ locked = spin_trylock(&up->port.lock);
++ } else
++ spin_lock(&up->port.lock);
+
+- spin_lock_irqsave(&up->port.lock, flags);
+ uart_console_write(&up->port, s, count, sunzilog_putchar);
+ udelay(2);
+- spin_unlock_irqrestore(&up->port.lock, flags);
++
++ if (locked)
++ spin_unlock(&up->port.lock);
++ local_irq_restore(flags);
+ }
+
+ static int __init sunzilog_console_setup(struct console *con, char *options)
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:51:26 2007
+From: Dmitry Butskoy <dmitry@butskoy.name>
+Date: Wed, 18 Jul 2007 02:51:17 -0700 (PDT)
+Subject: Fix error queue socket lookup in ipv6
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.025117.94556618.davem@davemloft.net>
+
+From: Dmitry Butskoy <dmitry@butskoy.name>
+
+[IPV6]: MSG_ERRQUEUE messages do not pass to connected raw sockets
+
+From: Dmitry Butskoy <dmitry@butskoy.name>
+
+Taken from http://bugzilla.kernel.org/show_bug.cgi?id=8747
+
+Problem Description:
+
+It is related to the possibility to obtain MSG_ERRQUEUE messages from the udp
+and raw sockets, both connected and unconnected.
+
+There is a little typo in net/ipv6/icmp.c code, which prevents such messages
+to be delivered to the errqueue of the correspond raw socket, when the socket
+is CONNECTED. The typo is due to swap of local/remote addresses.
+
+Consider __raw_v6_lookup() function from net/ipv6/raw.c. When a raw socket is
+looked up usual way, it is something like:
+
+sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);
+
+where "daddr" is a destination address of the incoming packet (IOW our local
+address), "saddr" is a source address of the incoming packet (the remote end).
+
+But when the raw socket is looked up for some icmp error report, in
+net/ipv6/icmp.c:icmpv6_notify() , daddr/saddr are obtained from the echoed
+fragment of the "bad" packet, i.e. "daddr" is the original destination
+address of that packet, "saddr" is our local address. Hence, for
+icmpv6_notify() must use "saddr, daddr" in its arguments, not "daddr, saddr"
+...
+
+Steps to reproduce:
+
+Create some raw socket, connect it to an address, and cause some error
+situation: f.e. set ttl=1 where the remote address is more than 1 hop to reach.
+Set IPV6_RECVERR .
+Then send something and wait for the error (f.e. poll() with POLLERR|POLLIN).
+You should receive "time exceeded" icmp message (because of "ttl=1"), but the
+socket do not receive it.
+
+If you do not connect your raw socket, you will receive MSG_ERRQUEUE
+successfully. (The reason is that for unconnected socket there are no actual
+checks for local/remote addresses).
+
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv6/icmp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/ipv6/icmp.c
++++ b/net/ipv6/icmp.c
+@@ -604,7 +604,7 @@ static void icmpv6_notify(struct sk_buff
+
+ read_lock(&raw_v6_lock);
+ if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) {
+- while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr,
++ while ((sk = __raw_v6_lookup(sk, nexthdr, saddr, daddr,
+ IP6CB(skb)->iif))) {
+ rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
+ sk = sk_next(sk);
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:26:40 2007
+From: Patrick McHardy <kaber@trash.net>
+Date: Wed, 18 Jul 2007 02:26:27 -0700 (PDT)
+Subject: Fix IPCOMP crashes.
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.022627.107251288.davem@davemloft.net>
+
+
+From: Patrick McHardy <kaber@trash.net>
+
+[XFRM]: Fix crash introduced by struct dst_entry reordering
+
+XFRM expects xfrm_dst->u.next to be same pointer as dst->next, which
+was broken by the dst_entry reordering in commit 1e19e02c~, causing
+an oops in xfrm_bundle_ok when walking the bundle upwards.
+
+Kill xfrm_dst->u.next and change the only user to use dst->next instead.
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/net/xfrm.h | 1 -
+ net/xfrm/xfrm_policy.c | 2 +-
+ 2 files changed, 1 insertion(+), 2 deletions(-)
+
+--- a/include/net/xfrm.h
++++ b/include/net/xfrm.h
+@@ -577,7 +577,6 @@ static inline int xfrm_sec_ctx_match(str
+ struct xfrm_dst
+ {
+ union {
+- struct xfrm_dst *next;
+ struct dst_entry dst;
+ struct rtable rt;
+ struct rt6_info rt6;
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -2141,7 +2141,7 @@ int xfrm_bundle_ok(struct xfrm_policy *p
+ if (last == first)
+ break;
+
+- last = last->u.next;
++ last = (struct xfrm_dst *)last->u.dst.next;
+ last->child_mtu_cached = mtu;
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:52:38 2007
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+Date: Wed, 18 Jul 2007 02:52:33 -0700 (PDT)
+Subject: Fix ipv6 link down handling.
+To: stable@kernel.org
+Message-ID: <20070718.025233.118626637.davem@davemloft.net>
+
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+
+[IPV6]: Call inet6addr_chain notifiers on link down
+
+Currently if the link is brought down via ip link or ifconfig down,
+the inet6addr_chain notifiers are not called even though all
+the addresses are removed from the interface. This caused SCTP
+to add duplicate addresses to it's list.
+
+Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv6/addrconf.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -2472,6 +2472,7 @@ static int addrconf_ifdown(struct net_de
+ write_unlock_bh(&idev->lock);
+
+ __ipv6_ifa_notify(RTM_DELADDR, ifa);
++ atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
+ in6_ifa_put(ifa);
+
+ write_lock_bh(&idev->lock);
--- /dev/null
+From stable-bounces@linux.kernel.org Tue Jul 24 21:44:03 2007
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Tue, 24 Jul 2007 21:43:58 -0700 (PDT)
+Subject: Fix ipv6 tunnel endianness bug.
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070724.214358.35664196.davem@davemloft.net>
+
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+[IPV6]: endianness bug in ip6_tunnel
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv6/ip6_tunnel.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -962,8 +962,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, str
+ dsfield = ipv4_get_dsfield(iph);
+
+ if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+- fl.fl6_flowlabel |= ntohl(((__u32)iph->tos << IPV6_TCLASS_SHIFT)
+- & IPV6_TCLASS_MASK);
++ fl.fl6_flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
++ & IPV6_TCLASS_MASK;
+
+ err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
+ if (err != 0) {
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:45:30 2007
+From: Ingo Molnar <mingo@elte.hu>
+Date: Wed, 18 Jul 2007 02:45:14 -0700 (PDT)
+Subject: Fix rfkill IRQ flags.
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.024514.71553572.davem@davemloft.net>
+
+From: Ingo Molnar <mingo@elte.hu>
+
+[RFKILL]: fix net/rfkill/rfkill-input.c bug on 64-bit systems
+
+Subject: [patch] net/input: fix net/rfkill/rfkill-input.c bug on 64-bit systems
+
+this recent commit:
+
+ commit cf4328cd949c2086091c62c5685f1580fe9b55e4
+ Author: Ivo van Doorn <IvDoorn@gmail.com>
+ Date: Mon May 7 00:34:20 2007 -0700
+
+ [NET]: rfkill: add support for input key to control wireless radio
+
+added this 64-bit bug:
+
+ ....
+ unsigned int flags;
+
+ spin_lock_irqsave(&task->lock, flags);
+ ....
+
+irq 'flags' must be unsigned long, not unsigned int. The -rt tree has
+strict checks about this on 64-bit so this triggered a build failure.
+
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/rfkill/rfkill-input.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/rfkill/rfkill-input.c
++++ b/net/rfkill/rfkill-input.c
+@@ -55,7 +55,7 @@ static void rfkill_task_handler(struct w
+
+ static void rfkill_schedule_toggle(struct rfkill_task *task)
+ {
+- unsigned int flags;
++ unsigned long flags;
+
+ spin_lock_irqsave(&task->lock, flags);
+
--- /dev/null
+From stable-bounces@linux.kernel.org Tue Jul 24 21:44:55 2007
+From: Alexander Shmelev <ashmelev@task.sun.mcst.ru>
+Date: Tue, 24 Jul 2007 21:44:48 -0700 (PDT)
+Subject: Fix sparc32 memset()
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070724.214448.38711437.davem@davemloft.net>
+
+From: Alexander Shmelev <ashmelev@task.sun.mcst.ru>
+
+[SPARC32]: Fix bug in sparc optimized memset.
+
+Sparc optimized memset (arch/sparc/lib/memset.S) does not fill last
+byte of the memory area, if area size is less than 8 bytes and start
+address is not word (4-bytes) aligned.
+
+Here is code chunk where bug located:
+/* %o0 - memory address, %o1 - size, %g3 - value */
+8:
+ add %o0, 1, %o0
+ subcc %o1, 1, %o1
+ bne,a 8b
+ stb %g3, [%o0 - 1]
+
+This code should write byte every loop iteration, but last time delay
+instruction stb is not executed because branch instruction sets
+"annul" bit.
+
+Patch replaces bne,a by bne instruction.
+
+Error can be reproduced by simple kernel module:
+
+--------------------
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <string.h>
+
+static void do_memset(void **p, int size)
+{
+ memset(p, 0x00, size);
+}
+
+static int __init memset_test_init(void)
+{
+ char fooc[8];
+ int *fooi;
+ memset(fooc, 0xba, sizeof(fooc));
+
+ do_memset((void**)(fooc + 3), 1);
+
+ fooi = (int*) fooc;
+ printk("%08X %08X\n", fooi[0], fooi[1]);
+
+ return -1;
+}
+
+static void __exit memset_test_cleanup(void)
+{
+ return;
+}
+
+module_init(memset_test_init);
+module_exit(memset_test_cleanup);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+------------------------
+
+Signed-off-by: Alexander Shmelev <ashmelev@task.sun.mcst.ru>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/sparc/lib/memset.S | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/sparc/lib/memset.S
++++ b/arch/sparc/lib/memset.S
+@@ -162,7 +162,7 @@ __bzero:
+ 8:
+ add %o0, 1, %o0
+ subcc %o1, 1, %o1
+- bne,a 8b
++ bne 8b
+ EX(stb %g3, [%o0 - 1], add %o1, 1)
+ 0:
+ retl
--- /dev/null
+From stable-bounces@linux.kernel.org Tue Jul 24 21:45:49 2007
+From: Mark Fortescue <mark@mtfhpc.demon.co.uk>
+Date: Tue, 24 Jul 2007 21:45:44 -0700 (PDT)
+Subject: Fix sparc32 udelay() rounding errors.
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070724.214544.35015303.davem@davemloft.net>
+
+
+From: Mark Fortescue <mark@mtfhpc.demon.co.uk>
+
+[SPARC32]: Fix rounding errors in ndelay/udelay implementation.
+
+__ndelay and __udelay have not been delayung >= specified time.
+The problem with __ndelay has been tacked down to the rounding of the
+multiplier constant. By changing this, delays > app 18us are correctly
+calculated.
+The problem with __udelay has also been tracked down to rounding issues.
+Changing the multiplier constant (to match that used in sparc64) corrects
+for large delays and adding in a rounding constant corrects for trunctaion
+errors in the claculations.
+Many short delays will return without looping. This is not an error as there
+is the fixed delay of doing all the maths to calculate the loop count.
+
+Signed-off-by: Mark Fortescue <mark@mtfhpc.demon.co.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/sparc/kernel/entry.S | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/arch/sparc/kernel/entry.S
++++ b/arch/sparc/kernel/entry.S
+@@ -1749,8 +1749,8 @@ fpload:
+ __ndelay:
+ save %sp, -STACKFRAME_SZ, %sp
+ mov %i0, %o0
+- call .umul
+- mov 0x1ad, %o1 ! 2**32 / (1 000 000 000 / HZ)
++ call .umul ! round multiplier up so large ns ok
++ mov 0x1ae, %o1 ! 2**32 / (1 000 000 000 / HZ)
+ call .umul
+ mov %i1, %o1 ! udelay_val
+ ba delay_continue
+@@ -1760,11 +1760,17 @@ __ndelay:
+ __udelay:
+ save %sp, -STACKFRAME_SZ, %sp
+ mov %i0, %o0
+- sethi %hi(0x10c6), %o1
++ sethi %hi(0x10c7), %o1 ! round multiplier up so large us ok
+ call .umul
+- or %o1, %lo(0x10c6), %o1 ! 2**32 / 1 000 000
++ or %o1, %lo(0x10c7), %o1 ! 2**32 / 1 000 000
+ call .umul
+ mov %i1, %o1 ! udelay_val
++ sethi %hi(0x028f4b62), %l0 ! Add in rounding constant * 2**32,
++ or %g0, %lo(0x028f4b62), %l0
++ addcc %o0, %l0, %o0 ! 2**32 * 0.009 999
++ bcs,a 3f
++ add %o1, 0x01, %o1
++3:
+ call .umul
+ mov HZ, %o0 ! >>32 earlier for wider range
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:32:46 2007
+From: Patrick McHardy <kaber@trash.net>
+Date: Wed, 18 Jul 2007 02:32:39 -0700 (PDT)
+Subject: Fix TC deadlock.
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.023239.13770405.davem@davemloft.net>
+
+
+From: Patrick McHardy <kaber@trash.net>
+
+[NET_SCHED]: Revert "avoid transmit softirq on watchdog wakeup" optimization
+
+As noticed by Ranko Zivojnovic <ranko@spidernet.net>, calling qdisc_run
+from the timer handler can result in deadlock:
+
+> CPU#0
+>
+> qdisc_watchdog() fires and gets dev->queue_lock
+> qdisc_run()...qdisc_restart()...
+> -> releases dev->queue_lock and enters dev_hard_start_xmit()
+>
+> CPU#1
+>
+> tc del qdisc dev ...
+> qdisc_graft()...dev_graft_qdisc()...dev_deactivate()...
+> -> grabs dev->queue_lock ...
+>
+> qdisc_reset()...{cbq,hfsc,htb,netem,tbf}_reset()...qdisc_watchdog_cancel()...
+> -> hrtimer_cancel() - waiting for the qdisc_watchdog() to exit, while still
+> holding dev->queue_lock
+>
+> CPU#0
+>
+> dev_hard_start_xmit() returns ...
+> -> wants to get dev->queue_lock(!)
+>
+> DEADLOCK!
+
+The entire optimization is a bit questionable IMO, it moves potentially
+large parts of NET_TX_SOFTIRQ work to TIMER_SOFTIRQ/HRTIMER_SOFTIRQ,
+which kind of defeats the separation of them.
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Acked-by: Ranko Zivojnovic <ranko@spidernet.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/sched/sch_api.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/net/sched/sch_api.c
++++ b/net/sched/sch_api.c
+@@ -290,11 +290,7 @@ static enum hrtimer_restart qdisc_watchd
+
+ wd->qdisc->flags &= ~TCQ_F_THROTTLED;
+ smp_wmb();
+- if (spin_trylock(&dev->queue_lock)) {
+- qdisc_run(dev);
+- spin_unlock(&dev->queue_lock);
+- } else
+- netif_schedule(dev);
++ netif_schedule(dev);
+
+ return HRTIMER_NORESTART;
+ }
--- /dev/null
+From stable-bounces@linux.kernel.org Tue Jul 24 21:47:13 2007
+From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+Date: Tue, 24 Jul 2007 21:47:05 -0700 (PDT)
+Subject: Fix TCP IPV6 MD5 bug.
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070724.214705.15264479.davem@davemloft.net>
+
+From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+
+[TCPv6] MD5SIG: Ensure to reset allocation count to avoid panic.
+
+After clearing all passwords for IPv6 peers, we need to
+set allocation count to zero as well as we free the storage.
+Otherwise, we panic when a user trys to (re)add a password.
+
+Discovered and fixed by MIYAJIMA Mitsuharu <miyajima.mitsuharu@anchor.jp>.
+
+Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv6/tcp_ipv6.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -644,6 +644,7 @@ static int tcp_v6_md5_do_del(struct sock
+ if (tp->md5sig_info->entries6 == 0) {
+ kfree(tp->md5sig_info->keys6);
+ tp->md5sig_info->keys6 = NULL;
++ tp->md5sig_info->alloced6 = 0;
+
+ tcp_free_md5sig_pool();
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:49:56 2007
+From: Ranko Zivojnovic <ranko@spidernet.net>
+Date: Wed, 18 Jul 2007 02:49:48 -0700 (PDT)
+Subject: gen estimator deadlock fix
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.024948.123972595.davem@davemloft.net>
+
+From: Ranko Zivojnovic <ranko@spidernet.net>
+
+[NET]: gen_estimator deadlock fix
+
+-Fixes ABBA deadlock noted by Patrick McHardy <kaber@trash.net>:
+
+> There is at least one ABBA deadlock, est_timer() does:
+> read_lock(&est_lock)
+> spin_lock(e->stats_lock) (which is dev->queue_lock)
+>
+> and qdisc_destroy calls htb_destroy under dev->queue_lock, which
+> calls htb_destroy_class, then gen_kill_estimator and this
+> write_locks est_lock.
+
+To fix the ABBA deadlock the rate estimators are now kept on an rcu list.
+
+-The est_lock changes the use from protecting the list to protecting
+the update to the 'bstat' pointer in order to avoid NULL dereferencing.
+
+-The 'interval' member of the gen_estimator structure removed as it is
+not needed.
+
+Signed-off-by: Ranko Zivojnovic <ranko@spidernet.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/core/gen_estimator.c | 81 ++++++++++++++++++++++++++++-------------------
+ 1 file changed, 49 insertions(+), 32 deletions(-)
+
+--- a/net/core/gen_estimator.c
++++ b/net/core/gen_estimator.c
+@@ -79,27 +79,27 @@
+
+ struct gen_estimator
+ {
+- struct gen_estimator *next;
++ struct list_head list;
+ struct gnet_stats_basic *bstats;
+ struct gnet_stats_rate_est *rate_est;
+ spinlock_t *stats_lock;
+- unsigned interval;
+ int ewma_log;
+ u64 last_bytes;
+ u32 last_packets;
+ u32 avpps;
+ u32 avbps;
++ struct rcu_head e_rcu;
+ };
+
+ struct gen_estimator_head
+ {
+ struct timer_list timer;
+- struct gen_estimator *list;
++ struct list_head list;
+ };
+
+ static struct gen_estimator_head elist[EST_MAX_INTERVAL+1];
+
+-/* Estimator array lock */
++/* Protects against NULL dereference */
+ static DEFINE_RWLOCK(est_lock);
+
+ static void est_timer(unsigned long arg)
+@@ -107,13 +107,17 @@ static void est_timer(unsigned long arg)
+ int idx = (int)arg;
+ struct gen_estimator *e;
+
+- read_lock(&est_lock);
+- for (e = elist[idx].list; e; e = e->next) {
++ rcu_read_lock();
++ list_for_each_entry_rcu(e, &elist[idx].list, list) {
+ u64 nbytes;
+ u32 npackets;
+ u32 rate;
+
+ spin_lock(e->stats_lock);
++ read_lock(&est_lock);
++ if (e->bstats == NULL)
++ goto skip;
++
+ nbytes = e->bstats->bytes;
+ npackets = e->bstats->packets;
+ rate = (nbytes - e->last_bytes)<<(7 - idx);
+@@ -125,12 +129,14 @@ static void est_timer(unsigned long arg)
+ e->last_packets = npackets;
+ e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
+ e->rate_est->pps = (e->avpps+0x1FF)>>10;
++skip:
++ read_unlock(&est_lock);
+ spin_unlock(e->stats_lock);
+ }
+
+- if (elist[idx].list != NULL)
++ if (!list_empty(&elist[idx].list))
+ mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+- read_unlock(&est_lock);
++ rcu_read_unlock();
+ }
+
+ /**
+@@ -147,12 +153,17 @@ static void est_timer(unsigned long arg)
+ * &rate_est with the statistics lock grabed during this period.
+ *
+ * Returns 0 on success or a negative error code.
++ *
++ * NOTE: Called under rtnl_mutex
+ */
+ int gen_new_estimator(struct gnet_stats_basic *bstats,
+- struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct rtattr *opt)
++ struct gnet_stats_rate_est *rate_est,
++ spinlock_t *stats_lock,
++ struct rtattr *opt)
+ {
+ struct gen_estimator *est;
+ struct gnet_estimator *parm = RTA_DATA(opt);
++ int idx;
+
+ if (RTA_PAYLOAD(opt) < sizeof(*parm))
+ return -EINVAL;
+@@ -164,7 +175,7 @@ int gen_new_estimator(struct gnet_stats_
+ if (est == NULL)
+ return -ENOBUFS;
+
+- est->interval = parm->interval + 2;
++ idx = parm->interval + 2;
+ est->bstats = bstats;
+ est->rate_est = rate_est;
+ est->stats_lock = stats_lock;
+@@ -174,20 +185,25 @@ int gen_new_estimator(struct gnet_stats_
+ est->last_packets = bstats->packets;
+ est->avpps = rate_est->pps<<10;
+
+- est->next = elist[est->interval].list;
+- if (est->next == NULL) {
+- init_timer(&elist[est->interval].timer);
+- elist[est->interval].timer.data = est->interval;
+- elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
+- elist[est->interval].timer.function = est_timer;
+- add_timer(&elist[est->interval].timer);
++ if (!elist[idx].timer.function) {
++ INIT_LIST_HEAD(&elist[idx].list);
++ setup_timer(&elist[idx].timer, est_timer, idx);
+ }
+- write_lock_bh(&est_lock);
+- elist[est->interval].list = est;
+- write_unlock_bh(&est_lock);
++
++ if (list_empty(&elist[idx].list))
++ mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
++
++ list_add_rcu(&est->list, &elist[idx].list);
+ return 0;
+ }
+
++static void __gen_kill_estimator(struct rcu_head *head)
++{
++ struct gen_estimator *e = container_of(head,
++ struct gen_estimator, e_rcu);
++ kfree(e);
++}
++
+ /**
+ * gen_kill_estimator - remove a rate estimator
+ * @bstats: basic statistics
+@@ -195,31 +211,32 @@ int gen_new_estimator(struct gnet_stats_
+ *
+ * Removes the rate estimator specified by &bstats and &rate_est
+ * and deletes the timer.
++ *
++ * NOTE: Called under rtnl_mutex
+ */
+ void gen_kill_estimator(struct gnet_stats_basic *bstats,
+ struct gnet_stats_rate_est *rate_est)
+ {
+ int idx;
+- struct gen_estimator *est, **pest;
++ struct gen_estimator *e, *n;
+
+ for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
+- int killed = 0;
+- pest = &elist[idx].list;
+- while ((est=*pest) != NULL) {
+- if (est->rate_est != rate_est || est->bstats != bstats) {
+- pest = &est->next;
++
++ /* Skip non initialized indexes */
++ if (!elist[idx].timer.function)
++ continue;
++
++ list_for_each_entry_safe(e, n, &elist[idx].list, list) {
++ if (e->rate_est != rate_est || e->bstats != bstats)
+ continue;
+- }
+
+ write_lock_bh(&est_lock);
+- *pest = est->next;
++ e->bstats = NULL;
+ write_unlock_bh(&est_lock);
+
+- kfree(est);
+- killed++;
++ list_del_rcu(&e->list);
++ call_rcu(&e->e_rcu, __gen_kill_estimator);
+ }
+- if (killed && elist[idx].list == NULL)
+- del_timer(&elist[idx].timer);
+ }
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:48:50 2007
+From: Patrick McHardy <kaber@trash.net>
+Date: Wed, 18 Jul 2007 02:48:43 -0700 (PDT)
+Subject: gen estimator timer unload race
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.024843.85819931.davem@davemloft.net>
+
+From: Patrick McHardy <kaber@trash.net>
+
+[NET]: Fix gen_estimator timer removal race
+
+As noticed by Jarek Poplawski <jarkao2@o2.pl>, the timer removal in
+gen_kill_estimator races with the timer function rearming the timer.
+
+Check whether the timer list is empty before rearming the timer
+in the timer function to fix this.
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Acked-by: Jarek Poplawski <jarkao2@o2.pl>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/core/gen_estimator.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/net/core/gen_estimator.c
++++ b/net/core/gen_estimator.c
+@@ -128,7 +128,8 @@ static void est_timer(unsigned long arg)
+ spin_unlock(e->stats_lock);
+ }
+
+- mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
++ if (elist[idx].list != NULL)
++ mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+ read_unlock(&est_lock);
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:37:12 2007
+From: Adrian Bunk <bunk@stusta.de>
+Date: Wed, 18 Jul 2007 02:37:05 -0700 (PDT)
+Subject: Missing header include in ipt_iprange.h
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.023705.45875793.davem@davemloft.net>
+
+From: Adrian Bunk <bunk@stusta.de>
+
+[NETFILTER]: ipt_iprange.h must #include <linux/types.h>
+
+ipt_iprange.h must #include <linux/types.h> since it uses __be32.
+
+This patch fixes kernel Bugzilla #7604.
+
+Signed-off-by: Adrian Bunk <bunk@stusta.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/netfilter_ipv4/ipt_iprange.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/include/linux/netfilter_ipv4/ipt_iprange.h
++++ b/include/linux/netfilter_ipv4/ipt_iprange.h
+@@ -1,6 +1,8 @@
+ #ifndef _IPT_IPRANGE_H
+ #define _IPT_IPRANGE_H
+
++#include <linux/types.h>
++
+ #define IPRANGE_SRC 0x01 /* Match source IP address */
+ #define IPRANGE_DST 0x02 /* Match destination IP address */
+ #define IPRANGE_SRC_INV 0x10 /* Negate the condition */
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:54:27 2007
+From: Satyam Sharma <ssatyam@cse.iitk.ac.in>
+Date: Wed, 18 Jul 2007 02:54:19 -0700 (PDT)
+Subject: Netpoll leak
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.025419.108809166.davem@davemloft.net>
+
+From: Satyam Sharma <ssatyam@cse.iitk.ac.in>
+
+[NETPOLL]: Fix a leak-n-bug in netpoll_cleanup()
+
+93ec2c723e3f8a216dde2899aeb85c648672bc6b applied excessive duct tape to
+the netpoll beast's netpoll_cleanup(), thus substituting one leak with
+another, and opening up a little buglet :-)
+
+net_device->npinfo (netpoll_info) is a shared and refcounted object and
+cannot simply be set NULL the first time netpoll_cleanup() is called.
+Otherwise, further netpoll_cleanup()'s see np->dev->npinfo == NULL and
+become no-ops, thus leaking. And it's a bug too: the first call to
+netpoll_cleanup() would thus (annoyingly) "disable" other (still alive)
+netpolls too. Maybe nobody noticed this because netconsole (only user
+of netpoll) never supported multiple netpoll objects earlier.
+
+This is a trivial and obvious one-line fixlet.
+
+Signed-off-by: Satyam Sharma <ssatyam@cse.iitk.ac.in>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/core/netpoll.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/core/netpoll.c
++++ b/net/core/netpoll.c
+@@ -781,7 +781,6 @@ void netpoll_cleanup(struct netpoll *np)
+ spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+ }
+
+- np->dev->npinfo = NULL;
+ if (atomic_dec_and_test(&npinfo->refcnt)) {
+ skb_queue_purge(&npinfo->arp_tx);
+ skb_queue_purge(&npinfo->txq);
+@@ -794,6 +793,7 @@ void netpoll_cleanup(struct netpoll *np)
+ kfree_skb(skb);
+ }
+ kfree(npinfo);
++ np->dev->npinfo = NULL;
+ }
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:44:24 2007
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+Date: Wed, 18 Jul 2007 02:44:12 -0700 (PDT)
+Subject: SCTP scope_id handling fix
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.024412.35506936.davem@davemloft.net>
+
+From: Vlad Yasevich <vladislav.yasevich@hp.com>
+
+SCTP: Add scope_id validation for link-local binds
+
+SCTP currently permits users to bind to link-local addresses,
+but doesn't verify that the scope id specified at bind matches
+the interface that the address is configured on. It was report
+that this can hang a system.
+
+Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/sctp/ipv6.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -875,6 +875,10 @@ static int sctp_inet6_send_verify(struct
+ dev = dev_get_by_index(addr->v6.sin6_scope_id);
+ if (!dev)
+ return 0;
++ if (!ipv6_chk_addr(&addr->v6.sin6_addr, dev, 0)) {
++ dev_put(dev);
++ return 0;
++ }
+ dev_put(dev);
+ }
+ af = opt->pf->af;
--- /dev/null
+usb-cdc-acm-fix-sysfs-attribute-registration-bug.patch
+tcp-frto-retransmit-bug-fix.patch
+fix-tc-deadlock.patch
+fix-ipcomp-crashes.patch
+fix-deadlocks-in-sparc-serial-console.patch
+add-a-pci-id-for-santa-rosa-s-pata-controller.patch
+missing-header-include-in-ipt_iprange.h.patch
+sctp-scope_id-handling-fix.patch
+fix-rfkill-irq-flags.patch
+gen-estimator-timer-unload-race.patch
+gen-estimator-deadlock-fix.patch
+fix-error-queue-socket-lookup-in-ipv6.patch
+fix-ipv6-link-down-handling.patch
+netpoll-leak.patch
+sparc64-bootup-assembler-bug.patch
+fix-ipv6-tunnel-endianness-bug.patch
+fix-sparc32-memset.patch
+fix-sparc32-udelay-rounding-errors.patch
+fix-tcp-ipv6-md5-bug.patch
--- /dev/null
+From stable-bounces@linux.kernel.org Thu Jul 19 22:06:23 2007
+From: David Miller <davem@davemloft.net>
+Date: Thu, 19 Jul 2007 22:06:09 -0700 (PDT)
+Subject: Sparc64 bootup assembler bug
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070719.220609.112621863.davem@davemloft.net>
+
+
+From: David S. Miller <davem@davemloft.net>
+
+[SPARC64]: Fix two year old bug in early bootup asm.
+
+We try to fetch the CIF entry pointer from %o4, but that
+can get clobbered by the early OBP calls. It is saved
+in %l7 already, so actually this "mov %o4, %l7" can just
+be completely removed with no other changes.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/sparc64/kernel/head.S | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/sparc64/kernel/head.S
++++ b/arch/sparc64/kernel/head.S
+@@ -458,7 +458,6 @@ tlb_fixup_done:
+ or %g6, %lo(init_thread_union), %g6
+ ldx [%g6 + TI_TASK], %g4
+ mov %sp, %l6
+- mov %o4, %l7
+
+ wr %g0, ASI_P, %asi
+ mov 1, %g1
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jul 18 02:30:56 2007
+From: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
+Date: Wed, 18 Jul 2007 02:30:41 -0700 (PDT)
+Subject: TCP FRTO retransmit bug fix
+To: stable@kernel.org
+Cc: bunk@stusta.de
+Message-ID: <20070718.023041.52167051.davem@davemloft.net>
+
+From: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
+
+[TCP]: Verify the presence of RETRANS bit when leaving FRTO
+
+For yet unknown reason, something cleared SACKED_RETRANS bit
+underneath FRTO.
+
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/ipv4/tcp_input.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -1398,7 +1398,9 @@ static void tcp_enter_frto_loss(struct s
+ * waiting for the first ACK and did not get it)...
+ */
+ if ((tp->frto_counter == 1) && !(flag&FLAG_DATA_ACKED)) {
+- tp->retrans_out += tcp_skb_pcount(skb);
++ /* For some reason this R-bit might get cleared? */
++ if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
++ tp->retrans_out += tcp_skb_pcount(skb);
+ /* ...enter this if branch just for the first segment */
+ flag |= FLAG_DATA_ACKED;
+ } else {
--- /dev/null
+From stable-bounces@linux.kernel.org Thu Aug 2 10:29:26 2007
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Thu, 2 Aug 2007 13:29:10 -0400 (EDT)
+Subject: USB: cdc-acm: fix sysfs attribute registration bug
+To: Greg KH <greg@kroah.com>, <stable@kernel.org>
+Cc: Oliver Neukum <oliver@neukum.name>, "A. Kalten" <akalten@comcast.net>
+Message-ID: <Pine.LNX.4.44L0.0708021324230.2573-100000@iolanthe.rowland.org>
+
+
+This patch (as950) fixes a bug in the cdc-acm driver. It doesn't keep
+track of which interface (control or data) the sysfs attributes get
+registered for, and as a result, during disconnect it will sometimes
+attempt to remove the attributes from the wrong interface. The
+left-over attributes can cause a crash later on, particularly if the driver
+module has been unloaded.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+CC: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/cdc-acm.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -919,6 +919,10 @@ skip_normal_probe:
+ return -EINVAL;
+ }
+ }
++
++ /* Accept probe requests only for the control interface */
++ if (intf != control_interface)
++ return -ENODEV;
+
+ if (usb_interface_claimed(data_interface)) { /* valid in this context */
+ dev_dbg(&intf->dev,"The data interface isn't available");
+@@ -1107,10 +1111,12 @@ static void acm_disconnect(struct usb_in
+ return;
+ }
+ if (acm->country_codes){
+- device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
+- device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
++ device_remove_file(&acm->control->dev,
++ &dev_attr_wCountryCodes);
++ device_remove_file(&acm->control->dev,
++ &dev_attr_iCountryCodeRelDate);
+ }
+- device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
++ device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
+ acm->dev = NULL;
+ usb_set_intfdata(acm->control, NULL);
+ usb_set_intfdata(acm->data, NULL);