]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
more .25 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Fri, 13 Jun 2008 20:51:14 +0000 (13:51 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 13 Jun 2008 20:51:14 +0000 (13:51 -0700)
queue-2.6.25/cciss-add-new-hardware-support.patch [new file with mode: 0644]
queue-2.6.25/forcedeth-msi-interrupts.patch [new file with mode: 0644]
queue-2.6.25/hgafb-resource-management-fix.patch [new file with mode: 0644]
queue-2.6.25/ib-umem-avoid-sign-problems-when-demoting-npages-to-integer.patch [new file with mode: 0644]
queue-2.6.25/mmc-wbsd-initialize-tasklets-before-requesting-interrupt.patch [new file with mode: 0644]
queue-2.6.25/series
queue-2.6.25/tcp-fix-inconsistency-source.patch [new file with mode: 0644]

diff --git a/queue-2.6.25/cciss-add-new-hardware-support.patch b/queue-2.6.25/cciss-add-new-hardware-support.patch
new file mode 100644 (file)
index 0000000..9c6f62c
--- /dev/null
@@ -0,0 +1,103 @@
+From stable-bounces@linux.kernel.org Thu Jun 12 19:40:41 2008
+From: Mike Miller <mike.miller@hp.com>
+Date: Fri, 13 Jun 2008 02:40:19 GMT
+Subject: cciss: add new hardware support
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200806130240.m5D2eJb2031185@hera.kernel.org>
+
+From: Mike Miller <mike.miller@hp.com>
+
+commit 24aac480e76c6f5d1391ac05c5e9c0eb9b0cd302 upstream
+Date: Thu, 12 Jun 2008 15:21:34 -0700
+Subject: cciss: add new hardware support
+
+Add support for the next generation of HP Smart Array SAS/SATA
+controllers.  Shipping date is late Fall 2008.
+
+Bump the driver version to 3.6.20 to reflect the new hardware support from
+patch 1 of this set.
+
+Signed-off-by: Mike Miller <mike.miller@hp.com>
+Cc: Jens Axboe <jens.axboe@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/cciss.txt |    5 +++++
+ drivers/block/cciss.c   |   21 ++++++++++++++++-----
+ include/linux/pci_ids.h |    1 +
+ 3 files changed, 22 insertions(+), 5 deletions(-)
+
+--- a/Documentation/cciss.txt
++++ b/Documentation/cciss.txt
+@@ -21,6 +21,11 @@ This driver is known to work with the fo
+       * SA E200
+       * SA E200i
+       * SA E500
++      * SA P212
++      * SA P410
++      * SA P410i
++      * SA P411
++      * SA P812
+ Detecting drive failures:
+ -------------------------
+--- a/drivers/block/cciss.c
++++ b/drivers/block/cciss.c
+@@ -53,15 +53,16 @@
+ #include <linux/scatterlist.h>
+ #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
+-#define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
+-#define DRIVER_VERSION CCISS_DRIVER_VERSION(3,6,14)
++#define DRIVER_NAME "HP CISS Driver (v 3.6.20)"
++#define DRIVER_VERSION CCISS_DRIVER_VERSION(3, 6, 20)
+ /* Embedded module documentation macros - see modules.h */
+ MODULE_AUTHOR("Hewlett-Packard Company");
+-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 3.6.14");
++MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
+ MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
+-                      " SA6i P600 P800 P400 P400i E200 E200i E500");
+-MODULE_VERSION("3.6.14");
++                      " SA6i P600 P800 P400 P400i E200 E200i E500 P700m"
++                      " Smart Array G2 Series SAS/SATA Controllers");
++MODULE_VERSION("3.6.20");
+ MODULE_LICENSE("GPL");
+ #include "cciss_cmd.h"
+@@ -90,6 +91,11 @@ static const struct pci_device_id cciss_
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3237},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x323D},
++      {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3241},
++      {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3243},
++      {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3245},
++      {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3247},
++      {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3249},
+       {PCI_VENDOR_ID_HP,     PCI_ANY_ID,      PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
+       {0,}
+@@ -123,6 +129,11 @@ static struct board_type products[] = {
+       {0x3215103C, "Smart Array E200i", &SA5_access, 120},
+       {0x3237103C, "Smart Array E500", &SA5_access, 512},
+       {0x323D103C, "Smart Array P700m", &SA5_access, 512},
++      {0x3241103C, "Smart Array P212", &SA5_access, 384},
++      {0x3243103C, "Smart Array P410", &SA5_access, 384},
++      {0x3245103C, "Smart Array P410i", &SA5_access, 384},
++      {0x3247103C, "Smart Array P411", &SA5_access, 384},
++      {0x3249103C, "Smart Array P812", &SA5_access, 384},
+       {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120},
+ };
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -716,6 +716,7 @@
+ #define PCI_DEVICE_ID_HP_CISSA                0x3220
+ #define PCI_DEVICE_ID_HP_CISSC                0x3230
+ #define PCI_DEVICE_ID_HP_CISSD                0x3238
++#define PCI_DEVICE_ID_HP_CISSE                0x323a
+ #define PCI_DEVICE_ID_HP_ZX2_IOC      0x4031
+ #define PCI_VENDOR_ID_PCTECH          0x1042
diff --git a/queue-2.6.25/forcedeth-msi-interrupts.patch b/queue-2.6.25/forcedeth-msi-interrupts.patch
new file mode 100644 (file)
index 0000000..c7e6023
--- /dev/null
@@ -0,0 +1,78 @@
+From stable-bounces@linux.kernel.org Wed Jun 11 17:20:39 2008
+From: Ayaz Abdulla <aabdulla@nvidia.com>
+Date: Thu, 12 Jun 2008 00:20:18 GMT
+Subject: forcedeth: msi interrupts
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200806120020.m5C0KIPP018517@hera.kernel.org>
+
+From: Ayaz Abdulla <aabdulla@nvidia.com>
+
+commit 4db0ee176e256444695ee2d7b004552e82fec987 upstream
+
+Add a workaround for lost MSI interrupts.  There is a race condition in
+the HW in which future interrupts could be missed.  The workaround is to
+toggle the MSI irq mask.
+
+Added cleanup based on comments from Andrew Morton.
+
+Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
+Cc: Manfred Spraul <manfred@colorfullife.com>
+Cc: Jeff Garzik <jeff@garzik.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/forcedeth.c |   20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+--- a/drivers/net/forcedeth.c
++++ b/drivers/net/forcedeth.c
+@@ -3111,6 +3111,20 @@ static void nv_link_irq(struct net_devic
+       dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);
+ }
++static void nv_msi_workaround(struct fe_priv *np)
++{
++
++      /* Need to toggle the msi irq mask within the ethernet device,
++       * otherwise, future interrupts will not be detected.
++       */
++      if (np->msi_flags & NV_MSI_ENABLED) {
++              u8 __iomem *base = np->base;
++
++              writel(0, base + NvRegMSIIrqMask);
++              writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
++      }
++}
++
+ static irqreturn_t nv_nic_irq(int foo, void *data)
+ {
+       struct net_device *dev = (struct net_device *) data;
+@@ -3133,6 +3147,8 @@ static irqreturn_t nv_nic_irq(int foo, v
+               if (!(events & np->irqmask))
+                       break;
++              nv_msi_workaround(np);
++
+               spin_lock(&np->lock);
+               nv_tx_done(dev);
+               spin_unlock(&np->lock);
+@@ -3248,6 +3264,8 @@ static irqreturn_t nv_nic_irq_optimized(
+               if (!(events & np->irqmask))
+                       break;
++              nv_msi_workaround(np);
++
+               spin_lock(&np->lock);
+               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+               spin_unlock(&np->lock);
+@@ -3588,6 +3606,8 @@ static irqreturn_t nv_nic_irq_test(int f
+       if (!(events & NVREG_IRQ_TIMER))
+               return IRQ_RETVAL(0);
++      nv_msi_workaround(np);
++
+       spin_lock(&np->lock);
+       np->intr_test = 1;
+       spin_unlock(&np->lock);
diff --git a/queue-2.6.25/hgafb-resource-management-fix.patch b/queue-2.6.25/hgafb-resource-management-fix.patch
new file mode 100644 (file)
index 0000000..4a6f8d9
--- /dev/null
@@ -0,0 +1,87 @@
+From stable-bounces@linux.kernel.org Thu Jun 12 19:40:46 2008
+From: Krzysztof Helt <krzysztof.h1@wp.pl>
+Date: Fri, 13 Jun 2008 02:40:28 GMT
+Subject: hgafb: resource management fix
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200806130240.m5D2eSbU031209@hera.kernel.org>
+
+From: Krzysztof Helt <krzysztof.h1@wp.pl>
+
+commit 630c270183133ac25bef8c8d726ac448df9b169a upstream
+Date: Thu, 12 Jun 2008 15:21:29 -0700
+Subject: hgafb: resource management fix
+
+Release ports which are requested during detection which are not freed if
+there is no hga card.  Otherwise there is a crash during cat /proc/ioports
+command.
+
+Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/hgafb.c |   26 +++++++++++++++-----------
+ 1 file changed, 15 insertions(+), 11 deletions(-)
+
+--- a/drivers/video/hgafb.c
++++ b/drivers/video/hgafb.c
+@@ -279,7 +279,7 @@ static void hga_blank(int blank_mode)
+ static int __init hga_card_detect(void)
+ {
+-      int count=0;
++      int count = 0;
+       void __iomem *p, *q;
+       unsigned short p_save, q_save;
+@@ -303,20 +303,18 @@ static int __init hga_card_detect(void)
+       writew(0x55aa, p); if (readw(p) == 0x55aa) count++;
+       writew(p_save, p);
+-      if (count != 2) {
+-              return 0;
+-      }
++      if (count != 2)
++              goto error;
+       /* Ok, there is definitely a card registering at the correct
+        * memory location, so now we do an I/O port test.
+        */
+       
+-      if (!test_hga_b(0x66, 0x0f)) {      /* cursor low register */
+-              return 0;
+-      }
+-      if (!test_hga_b(0x99, 0x0f)) {     /* cursor low register */
+-              return 0;
+-      }
++      if (!test_hga_b(0x66, 0x0f))        /* cursor low register */
++              goto error;
++
++      if (!test_hga_b(0x99, 0x0f))     /* cursor low register */
++              goto error;
+       /* See if the card is a Hercules, by checking whether the vsync
+        * bit of the status register is changing.  This test lasts for
+@@ -331,7 +329,7 @@ static int __init hga_card_detect(void)
+       }
+       if (p_save == q_save) 
+-              return 0;
++              goto error;
+       switch (inb_p(HGA_STATUS_PORT) & 0x70) {
+               case 0x10:
+@@ -348,6 +346,12 @@ static int __init hga_card_detect(void)
+                       break;
+       }
+       return 1;
++error:
++      if (release_io_ports)
++              release_region(0x3b0, 12);
++      if (release_io_port)
++              release_region(0x3bf, 1);
++      return 0;
+ }
+ /**
diff --git a/queue-2.6.25/ib-umem-avoid-sign-problems-when-demoting-npages-to-integer.patch b/queue-2.6.25/ib-umem-avoid-sign-problems-when-demoting-npages-to-integer.patch
new file mode 100644 (file)
index 0000000..92e11af
--- /dev/null
@@ -0,0 +1,56 @@
+From stable-bounces@linux.kernel.org Mon Jun  9 19:35:22 2008
+From: Roland Dreier <rolandd@cisco.com>
+Date: Tue, 10 Jun 2008 02:35:12 GMT
+Subject: IB/umem: Avoid sign problems when demoting npages to integer
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200806100235.m5A2ZCn6017093@hera.kernel.org>
+
+From: Roland Dreier <rolandd@cisco.com>
+
+commit 8079ffa0e18baaf2940e52e0c118eef420a473a4 upstream
+
+On a 64-bit architecture, if ib_umem_get() is called with a size value
+that is so big that npages is negative when cast to int, then the
+length of the page list passed to get_user_pages(), namely
+
+       min_t(int, npages, PAGE_SIZE / sizeof (struct page *))
+
+will be negative, and get_user_pages() will immediately return 0 (at
+least since 900cf086, "Be more robust about bad arguments in
+get_user_pages()").  This leads to an infinite loop in ib_umem_get(),
+since the code boils down to:
+
+       while (npages) {
+               ret = get_user_pages(...);
+               npages -= ret;
+       }
+
+Fix this by taking the minimum as unsigned longs, so that the value of
+npages is never truncated.
+
+The impact of this bug isn't too severe, since the value of npages is
+checked against RLIMIT_MEMLOCK, so a process would need to have an
+astronomical limit or have CAP_IPC_LOCK to be able to trigger this,
+and such a process could already cause lots of mischief.  But it does
+let buggy userspace code cause a kernel lock-up; for example I hit
+this with code that passes a negative value into a memory registartion
+function where it is promoted to a huge u64 value.
+
+Signed-off-by: Roland Dreier <rolandd@cisco.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/infiniband/core/umem.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/infiniband/core/umem.c
++++ b/drivers/infiniband/core/umem.c
+@@ -144,7 +144,7 @@ struct ib_umem *ib_umem_get(struct ib_uc
+       ret = 0;
+       while (npages) {
+               ret = get_user_pages(current, current->mm, cur_base,
+-                                   min_t(int, npages,
++                                   min_t(unsigned long, npages,
+                                          PAGE_SIZE / sizeof (struct page *)),
+                                    1, !umem->writable, page_list, vma_list);
diff --git a/queue-2.6.25/mmc-wbsd-initialize-tasklets-before-requesting-interrupt.patch b/queue-2.6.25/mmc-wbsd-initialize-tasklets-before-requesting-interrupt.patch
new file mode 100644 (file)
index 0000000..b60f3dc
--- /dev/null
@@ -0,0 +1,66 @@
+From stable-bounces@linux.kernel.org Thu Jun 12 19:40:37 2008
+From: Chuck Ebbert <cebbert@redhat.com>
+Date: Fri, 13 Jun 2008 02:40:16 GMT
+Subject: mmc: wbsd: initialize tasklets before requesting interrupt
+To: jejb@kernel.org, stable@kernel.org
+Message-ID: <200806130240.m5D2eG1P031162@hera.kernel.org>
+
+From: Chuck Ebbert <cebbert@redhat.com>
+
+commit cef33400d0349fb24b6f8b7dea79b66e3144fd8b upstream
+
+With CONFIG_DEBUG_SHIRQ set we will get an interrupt as soon as we
+allocate one.  Tasklets may be scheduled in the interrupt handler but they
+will be initialized after the handler returns, causing a BUG() in
+kernel/softirq.c when they run.
+
+Should fix this Fedora bug report:
+https://bugzilla.redhat.com/show_bug.cgi?id=449817
+
+Signed-off-by: Chuck Ebbert <cebbert@redhat.com>
+Acked-by: Pierre Ossman <drzeus@drzeus.cx>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/mmc/host/wbsd.c |   21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+--- a/drivers/mmc/host/wbsd.c
++++ b/drivers/mmc/host/wbsd.c
+@@ -1457,17 +1457,7 @@ static int __devinit wbsd_request_irq(st
+       int ret;
+       /*
+-       * Allocate interrupt.
+-       */
+-
+-      ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
+-      if (ret)
+-              return ret;
+-
+-      host->irq = irq;
+-
+-      /*
+-       * Set up tasklets.
++       * Set up tasklets. Must be done before requesting interrupt.
+        */
+       tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
+                       (unsigned long)host);
+@@ -1480,6 +1470,15 @@ static int __devinit wbsd_request_irq(st
+       tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
+                       (unsigned long)host);
++      /*
++       * Allocate interrupt.
++       */
++      ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
++      if (ret)
++              return ret;
++
++      host->irq = irq;
++
+       return 0;
+ }
index a9610071ab577fa1a6d52ffc256a9da89eee6fb3..bc301ce63d43522a514c01de241ce01ae67a00e9 100644 (file)
@@ -31,3 +31,9 @@ tcp-fix-skb-vs-fack_count-out-of-sync-condition.patch
 tcp-frto-fix-fallback-to-conventional-recovery.patch
 tcp-frto-sack-variant-is-errorneously-used-with-newreno.patch
 tcp-frto-work-around-inorder-receivers.patch
+mmc-wbsd-initialize-tasklets-before-requesting-interrupt.patch
+cciss-add-new-hardware-support.patch
+hgafb-resource-management-fix.patch
+forcedeth-msi-interrupts.patch
+tcp-fix-inconsistency-source.patch
+ib-umem-avoid-sign-problems-when-demoting-npages-to-integer.patch
diff --git a/queue-2.6.25/tcp-fix-inconsistency-source.patch b/queue-2.6.25/tcp-fix-inconsistency-source.patch
new file mode 100644 (file)
index 0000000..5951091
--- /dev/null
@@ -0,0 +1,99 @@
+From e193474d6d5658f0bd4429226d64ffb1493e38fa Mon Sep 17 00:00:00 2001
+From: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
+Date: Tue, 10 Jun 2008 15:37:34 -0700
+Subject: tcp: Fix inconsistency source (CA_Open only when !tcp_left_out(tp))
+Message-Id: <20080610.153918.57440222.davem@davemloft.net>
+
+From: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
+
+[ upstream commit: 8aca6cb1179ed9bef9351028c8d8af852903eae2 ]
+
+It is possible that this skip path causes TCP to end up into an
+invalid state where ca_state was left to CA_Open while some
+segments already came into sacked_out. If next valid ACK doesn't
+contain new SACK information TCP fails to enter into
+tcp_fastretrans_alert(). Thus at least high_seq is set
+incorrectly to a too high seqno because some new data segments
+could be sent in between (and also, limited transmit is not
+being correctly invoked there). Reordering in both directions
+can easily cause this situation to occur.
+
+I guess we would want to use tcp_moderate_cwnd(tp) there as well
+as it may be possible to use this to trigger oversized burst to
+network by sending an old ACK with huge amount of SACK info, but
+I'm a bit unsure about its effects (mainly to FlightSize), so to
+be on the safe side I just currently fixed it minimally to keep
+TCP's state consistent (obviously, such nasty ACKs have been
+possible this far). Though it seems that FlightSize is already
+underestimated by some amount, so probably on the long term we
+might want to trigger recovery there too, if appropriate, to make
+FlightSize calculation to resemble reality at the time when the
+losses where discovered (but such change scares me too much now
+and requires some more thinking anyway how to do that as it
+likely involves some code shuffling).
+
+This bug was found by Brian Vowell while running my TCP debug
+patch to find cause of another TCP issue (fackets_out
+miscount).
+
+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 |   29 +++++++++++++++++++----------
+ 1 file changed, 19 insertions(+), 10 deletions(-)
+
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -2469,6 +2469,20 @@ static inline void tcp_complete_cwr(stru
+       tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR);
+ }
++static void tcp_try_keep_open(struct sock *sk)
++{
++      struct tcp_sock *tp = tcp_sk(sk);
++      int state = TCP_CA_Open;
++
++      if (tcp_left_out(tp) || tp->retrans_out || tp->undo_marker)
++              state = TCP_CA_Disorder;
++
++      if (inet_csk(sk)->icsk_ca_state != state) {
++              tcp_set_ca_state(sk, state);
++              tp->high_seq = tp->snd_nxt;
++      }
++}
++
+ static void tcp_try_to_open(struct sock *sk, int flag)
+ {
+       struct tcp_sock *tp = tcp_sk(sk);
+@@ -2482,15 +2496,7 @@ static void tcp_try_to_open(struct sock 
+               tcp_enter_cwr(sk, 1);
+       if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
+-              int state = TCP_CA_Open;
+-
+-              if (tcp_left_out(tp) || tp->retrans_out || tp->undo_marker)
+-                      state = TCP_CA_Disorder;
+-
+-              if (inet_csk(sk)->icsk_ca_state != state) {
+-                      tcp_set_ca_state(sk, state);
+-                      tp->high_seq = tp->snd_nxt;
+-              }
++              tcp_try_keep_open(sk);
+               tcp_moderate_cwnd(tp);
+       } else {
+               tcp_cwnd_down(sk, flag);
+@@ -3296,8 +3302,11 @@ no_queue:
+       return 1;
+ old_ack:
+-      if (TCP_SKB_CB(skb)->sacked)
++      if (TCP_SKB_CB(skb)->sacked) {
+               tcp_sacktag_write_queue(sk, skb, prior_snd_una);
++              if (icsk->icsk_ca_state == TCP_CA_Open)
++                      tcp_try_keep_open(sk);
++      }
+ uninteresting_ack:
+       SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);