]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 7 Dec 2019 12:24:33 +0000 (13:24 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 7 Dec 2019 12:24:33 +0000 (13:24 +0100)
added patches:
fuse-verify-attributes.patch
fuse-verify-nlink.patch
sched-fair-scale-bandwidth-quota-and-period-without-losing-quota-period-ratio-precision.patch
tcp-exit-if-nothing-to-retransmit-on-rto-timeout.patch

queue-4.14/fuse-verify-attributes.patch [new file with mode: 0644]
queue-4.14/fuse-verify-nlink.patch [new file with mode: 0644]
queue-4.14/media-coda-fix-memory-corruption-in-case-more-than-3.patch [deleted file]
queue-4.14/sched-fair-scale-bandwidth-quota-and-period-without-losing-quota-period-ratio-precision.patch [new file with mode: 0644]
queue-4.14/series
queue-4.14/tcp-exit-if-nothing-to-retransmit-on-rto-timeout.patch [new file with mode: 0644]

diff --git a/queue-4.14/fuse-verify-attributes.patch b/queue-4.14/fuse-verify-attributes.patch
new file mode 100644 (file)
index 0000000..5129c01
--- /dev/null
@@ -0,0 +1,121 @@
+From eb59bd17d2fa6e5e84fba61a5ebdea984222e6d5 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Tue, 12 Nov 2019 11:49:04 +0100
+Subject: fuse: verify attributes
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+commit eb59bd17d2fa6e5e84fba61a5ebdea984222e6d5 upstream.
+
+If a filesystem returns negative inode sizes, future reads on the file were
+causing the cpu to spin on truncate_pagecache.
+
+Create a helper to validate the attributes.  This now does two things:
+
+ - check the file mode
+ - check if the file size fits in i_size without overflowing
+
+Reported-by: Arijit Banerjee <arijit@rubrik.com>
+Fixes: d8a5ba45457e ("[PATCH] FUSE - core")
+Cc: <stable@vger.kernel.org> # v2.6.14
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/fuse/dir.c    |   24 +++++++++++++++++-------
+ fs/fuse/fuse_i.h |    2 ++
+ 2 files changed, 19 insertions(+), 7 deletions(-)
+
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -234,7 +234,8 @@ static int fuse_dentry_revalidate(struct
+               kfree(forget);
+               if (ret == -ENOMEM)
+                       goto out;
+-              if (ret || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
++              if (ret || fuse_invalid_attr(&outarg.attr) ||
++                  (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
+                       goto invalid;
+               forget_all_cached_acls(inode);
+@@ -297,6 +298,12 @@ int fuse_valid_type(int m)
+               S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
+ }
++bool fuse_invalid_attr(struct fuse_attr *attr)
++{
++      return !fuse_valid_type(attr->mode) ||
++              attr->size > LLONG_MAX;
++}
++
+ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
+                    struct fuse_entry_out *outarg, struct inode **inode)
+ {
+@@ -328,7 +335,7 @@ int fuse_lookup_name(struct super_block
+       err = -EIO;
+       if (!outarg->nodeid)
+               goto out_put_forget;
+-      if (!fuse_valid_type(outarg->attr.mode))
++      if (fuse_invalid_attr(&outarg->attr))
+               goto out_put_forget;
+       *inode = fuse_iget(sb, outarg->nodeid, outarg->generation,
+@@ -451,7 +458,8 @@ static int fuse_create_open(struct inode
+               goto out_free_ff;
+       err = -EIO;
+-      if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
++      if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) ||
++          fuse_invalid_attr(&outentry.attr))
+               goto out_free_ff;
+       ff->fh = outopen.fh;
+@@ -557,7 +565,7 @@ static int create_new_entry(struct fuse_
+               goto out_put_forget_req;
+       err = -EIO;
+-      if (invalid_nodeid(outarg.nodeid))
++      if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr))
+               goto out_put_forget_req;
+       if ((outarg.attr.mode ^ mode) & S_IFMT)
+@@ -911,7 +919,8 @@ static int fuse_do_getattr(struct inode
+       args.out.args[0].value = &outarg;
+       err = fuse_simple_request(fc, &args);
+       if (!err) {
+-              if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
++              if (fuse_invalid_attr(&outarg.attr) ||
++                  (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
+                       make_bad_inode(inode);
+                       err = -EIO;
+               } else {
+@@ -1215,7 +1224,7 @@ static int fuse_direntplus_link(struct f
+       if (invalid_nodeid(o->nodeid))
+               return -EIO;
+-      if (!fuse_valid_type(o->attr.mode))
++      if (fuse_invalid_attr(&o->attr))
+               return -EIO;
+       fc = get_fuse_conn(dir);
+@@ -1692,7 +1701,8 @@ int fuse_do_setattr(struct dentry *dentr
+               goto error;
+       }
+-      if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
++      if (fuse_invalid_attr(&outarg.attr) ||
++          (inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
+               make_bad_inode(inode);
+               err = -EIO;
+               goto error;
+--- a/fs/fuse/fuse_i.h
++++ b/fs/fuse/fuse_i.h
+@@ -896,6 +896,8 @@ void fuse_ctl_remove_conn(struct fuse_co
+  */
+ int fuse_valid_type(int m);
++bool fuse_invalid_attr(struct fuse_attr *attr);
++
+ /**
+  * Is current process allowed to perform filesystem operation?
+  */
diff --git a/queue-4.14/fuse-verify-nlink.patch b/queue-4.14/fuse-verify-nlink.patch
new file mode 100644 (file)
index 0000000..eed1e48
--- /dev/null
@@ -0,0 +1,32 @@
+From c634da718db9b2fac201df2ae1b1b095344ce5eb Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Tue, 12 Nov 2019 11:49:04 +0100
+Subject: fuse: verify nlink
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+commit c634da718db9b2fac201df2ae1b1b095344ce5eb upstream.
+
+When adding a new hard link, make sure that i_nlink doesn't overflow.
+
+Fixes: ac45d61357e8 ("fuse: fix nlink after unlink")
+Cc: <stable@vger.kernel.org> # v3.4
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/fuse/dir.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/fuse/dir.c
++++ b/fs/fuse/dir.c
+@@ -830,7 +830,8 @@ static int fuse_link(struct dentry *entr
+               spin_lock(&fc->lock);
+               fi->attr_version = ++fc->attr_version;
+-              inc_nlink(inode);
++              if (likely(inode->i_nlink < UINT_MAX))
++                      inc_nlink(inode);
+               spin_unlock(&fc->lock);
+               fuse_invalidate_attr(inode);
+               fuse_update_ctime(inode);
diff --git a/queue-4.14/media-coda-fix-memory-corruption-in-case-more-than-3.patch b/queue-4.14/media-coda-fix-memory-corruption-in-case-more-than-3.patch
deleted file mode 100644 (file)
index 3e6b2a8..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-From 0139af208d3499abd38af388a359691015e605a3 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Nov 2018 05:40:54 -0500
-Subject: media: coda: fix memory corruption in case more than 32 instances are
- opened
-
-From: Philipp Zabel <p.zabel@pengutronix.de>
-
-[ Upstream commit 649cfc2bdfeeb98ff7d8fdff0af3f8fb9c8da50f ]
-
-The ffz() return value is undefined if the instance mask does not
-contain any zeros. If it returned 32, the following set_bit would
-corrupt the debugfs_root pointer.
-Switch to IDA for context index allocation. This also removes the
-artificial 32 instance limit for all except CodaDx6.
-
-Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-Signed-off-by: Hans Verkuil <hansverk@cisco.com>
-Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/media/platform/coda/coda-common.c | 26 +++++++++--------------
- drivers/media/platform/coda/coda.h        |  3 ++-
- 2 files changed, 12 insertions(+), 17 deletions(-)
-
-diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
-index 5b87c488ee111..ab5d00a4eb342 100644
---- a/drivers/media/platform/coda/coda-common.c
-+++ b/drivers/media/platform/coda/coda-common.c
-@@ -17,6 +17,7 @@
- #include <linux/firmware.h>
- #include <linux/gcd.h>
- #include <linux/genalloc.h>
-+#include <linux/idr.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/irq.h>
-@@ -1931,17 +1932,6 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
-       return coda_queue_init(priv, dst_vq);
- }
--static int coda_next_free_instance(struct coda_dev *dev)
--{
--      int idx = ffz(dev->instance_mask);
--
--      if ((idx < 0) ||
--          (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
--              return -EBUSY;
--
--      return idx;
--}
--
- /*
-  * File operations
-  */
-@@ -1950,7 +1940,8 @@ static int coda_open(struct file *file)
- {
-       struct video_device *vdev = video_devdata(file);
-       struct coda_dev *dev = video_get_drvdata(vdev);
--      struct coda_ctx *ctx = NULL;
-+      struct coda_ctx *ctx;
-+      unsigned int max = ~0;
-       char *name;
-       int ret;
-       int idx;
-@@ -1959,12 +1950,13 @@ static int coda_open(struct file *file)
-       if (!ctx)
-               return -ENOMEM;
--      idx = coda_next_free_instance(dev);
-+      if (dev->devtype->product == CODA_DX6)
-+              max = CODADX6_MAX_INSTANCES - 1;
-+      idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL);
-       if (idx < 0) {
-               ret = idx;
-               goto err_coda_max;
-       }
--      set_bit(idx, &dev->instance_mask);
-       name = kasprintf(GFP_KERNEL, "context%d", idx);
-       if (!name) {
-@@ -2072,8 +2064,8 @@ err_clk_per:
- err_pm_get:
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
--      clear_bit(ctx->idx, &dev->instance_mask);
- err_coda_name_init:
-+      ida_free(&dev->ida, ctx->idx);
- err_coda_max:
-       kfree(ctx);
-       return ret;
-@@ -2115,7 +2107,7 @@ static int coda_release(struct file *file)
-       pm_runtime_put_sync(&dev->plat_dev->dev);
-       v4l2_fh_del(&ctx->fh);
-       v4l2_fh_exit(&ctx->fh);
--      clear_bit(ctx->idx, &dev->instance_mask);
-+      ida_free(&dev->ida, ctx->idx);
-       if (ctx->ops->release)
-               ctx->ops->release(ctx);
-       debugfs_remove_recursive(ctx->debugfs_entry);
-@@ -2558,6 +2550,7 @@ static int coda_probe(struct platform_device *pdev)
-       mutex_init(&dev->dev_mutex);
-       mutex_init(&dev->coda_mutex);
-+      ida_init(&dev->ida);
-       dev->debugfs_root = debugfs_create_dir("coda", NULL);
-       if (!dev->debugfs_root)
-@@ -2645,6 +2638,7 @@ static int coda_remove(struct platform_device *pdev)
-       coda_free_aux_buf(dev, &dev->tempbuf);
-       coda_free_aux_buf(dev, &dev->workbuf);
-       debugfs_remove_recursive(dev->debugfs_root);
-+      ida_destroy(&dev->ida);
-       return 0;
- }
-diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
-index 389a882cc3dab..2b187f83e5447 100644
---- a/drivers/media/platform/coda/coda.h
-+++ b/drivers/media/platform/coda/coda.h
-@@ -16,6 +16,7 @@
- #define __CODA_H__
- #include <linux/debugfs.h>
-+#include <linux/idr.h>
- #include <linux/irqreturn.h>
- #include <linux/mutex.h>
- #include <linux/kfifo.h>
-@@ -94,7 +95,7 @@ struct coda_dev {
-       struct workqueue_struct *workqueue;
-       struct v4l2_m2m_dev     *m2m_dev;
-       struct list_head        instances;
--      unsigned long           instance_mask;
-+      struct ida              ida;
-       struct dentry           *debugfs_root;
- };
--- 
-2.20.1
-
diff --git a/queue-4.14/sched-fair-scale-bandwidth-quota-and-period-without-losing-quota-period-ratio-precision.patch b/queue-4.14/sched-fair-scale-bandwidth-quota-and-period-without-losing-quota-period-ratio-precision.patch
new file mode 100644 (file)
index 0000000..3122d5d
--- /dev/null
@@ -0,0 +1,107 @@
+From 4929a4e6faa0f13289a67cae98139e727f0d4a97 Mon Sep 17 00:00:00 2001
+From: Xuewei Zhang <xueweiz@google.com>
+Date: Thu, 3 Oct 2019 17:12:43 -0700
+Subject: sched/fair: Scale bandwidth quota and period without losing quota/period ratio precision
+
+From: Xuewei Zhang <xueweiz@google.com>
+
+commit 4929a4e6faa0f13289a67cae98139e727f0d4a97 upstream.
+
+The quota/period ratio is used to ensure a child task group won't get
+more bandwidth than the parent task group, and is calculated as:
+
+  normalized_cfs_quota() = [(quota_us << 20) / period_us]
+
+If the quota/period ratio was changed during this scaling due to
+precision loss, it will cause inconsistency between parent and child
+task groups.
+
+See below example:
+
+A userspace container manager (kubelet) does three operations:
+
+ 1) Create a parent cgroup, set quota to 1,000us and period to 10,000us.
+ 2) Create a few children cgroups.
+ 3) Set quota to 1,000us and period to 10,000us on a child cgroup.
+
+These operations are expected to succeed. However, if the scaling of
+147/128 happens before step 3, quota and period of the parent cgroup
+will be changed:
+
+  new_quota: 1148437ns,   1148us
+ new_period: 11484375ns, 11484us
+
+And when step 3 comes in, the ratio of the child cgroup will be
+104857, which will be larger than the parent cgroup ratio (104821),
+and will fail.
+
+Scaling them by a factor of 2 will fix the problem.
+
+Tested-by: Phil Auld <pauld@redhat.com>
+Signed-off-by: Xuewei Zhang <xueweiz@google.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Acked-by: Phil Auld <pauld@redhat.com>
+Cc: Anton Blanchard <anton@ozlabs.org>
+Cc: Ben Segall <bsegall@google.com>
+Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
+Cc: Juri Lelli <juri.lelli@redhat.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Mel Gorman <mgorman@suse.de>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Steven Rostedt <rostedt@goodmis.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Vincent Guittot <vincent.guittot@linaro.org>
+Fixes: 2e8e19226398 ("sched/fair: Limit sched_cfs_period_timer() loop to avoid hard lockup")
+Link: https://lkml.kernel.org/r/20191004001243.140897-1-xueweiz@google.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ kernel/sched/fair.c |   34 +++++++++++++++++++++-------------
+ 1 file changed, 21 insertions(+), 13 deletions(-)
+
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -4655,20 +4655,28 @@ static enum hrtimer_restart sched_cfs_pe
+               if (++count > 3) {
+                       u64 new, old = ktime_to_ns(cfs_b->period);
+-                      new = (old * 147) / 128; /* ~115% */
+-                      new = min(new, max_cfs_quota_period);
++                      /*
++                       * Grow period by a factor of 2 to avoid losing precision.
++                       * Precision loss in the quota/period ratio can cause __cfs_schedulable
++                       * to fail.
++                       */
++                      new = old * 2;
++                      if (new < max_cfs_quota_period) {
++                              cfs_b->period = ns_to_ktime(new);
++                              cfs_b->quota *= 2;
+-                      cfs_b->period = ns_to_ktime(new);
+-
+-                      /* since max is 1s, this is limited to 1e9^2, which fits in u64 */
+-                      cfs_b->quota *= new;
+-                      cfs_b->quota = div64_u64(cfs_b->quota, old);
+-
+-                      pr_warn_ratelimited(
+-        "cfs_period_timer[cpu%d]: period too short, scaling up (new cfs_period_us %lld, cfs_quota_us = %lld)\n",
+-                              smp_processor_id(),
+-                              div_u64(new, NSEC_PER_USEC),
+-                                div_u64(cfs_b->quota, NSEC_PER_USEC));
++                              pr_warn_ratelimited(
++      "cfs_period_timer[cpu%d]: period too short, scaling up (new cfs_period_us = %lld, cfs_quota_us = %lld)\n",
++                                      smp_processor_id(),
++                                      div_u64(new, NSEC_PER_USEC),
++                                      div_u64(cfs_b->quota, NSEC_PER_USEC));
++                      } else {
++                              pr_warn_ratelimited(
++      "cfs_period_timer[cpu%d]: period too short, but cannot scale up without losing precision (cfs_period_us = %lld, cfs_quota_us = %lld)\n",
++                                      smp_processor_id(),
++                                      div_u64(old, NSEC_PER_USEC),
++                                      div_u64(cfs_b->quota, NSEC_PER_USEC));
++                      }
+                       /* reset count so we don't come right back in here */
+                       count = 0;
index 9b08654e6f9090b76cf52b422e8bc222cdfba06d..f0b79ce655679e9c98e4dffb8ada98869410cd18 100644 (file)
@@ -56,7 +56,6 @@ math-emu-soft-fp.h-_fp_round_zero-cast-0-to-void-to-.patch
 rtc-max8997-fix-the-returned-value-in-case-of-error-.patch
 rtc-dt-binding-abx80x-fix-resistance-scale.patch
 arm-dts-exynos-use-samsung-soc-specific-compatible-f.patch
-media-coda-fix-memory-corruption-in-case-more-than-3.patch
 media-pulse8-cec-return-0-when-invalidating-the-logi.patch
 media-cec-report-vendor-id-after-initialization.patch
 dmaengine-coh901318-fix-a-double-lock-bug.patch
@@ -121,3 +120,7 @@ usb-mtu3-fix-dbginfo-in-qmu_tx_zlp_error_handler.patch
 arm-dts-sunxi-fix-pmu-compatible-strings.patch
 media-vimc-fix-start-stream-when-link-is-disabled.patch
 net-aquantia-fix-rss-table-and-key-sizes.patch
+tcp-exit-if-nothing-to-retransmit-on-rto-timeout.patch
+sched-fair-scale-bandwidth-quota-and-period-without-losing-quota-period-ratio-precision.patch
+fuse-verify-nlink.patch
+fuse-verify-attributes.patch
diff --git a/queue-4.14/tcp-exit-if-nothing-to-retransmit-on-rto-timeout.patch b/queue-4.14/tcp-exit-if-nothing-to-retransmit-on-rto-timeout.patch
new file mode 100644 (file)
index 0000000..50767aa
--- /dev/null
@@ -0,0 +1,74 @@
+From edumazet@google.com  Sat Dec  7 12:55:03 2019
+From: Eric Dumazet <edumazet@google.com>
+Date: Fri,  6 Dec 2019 10:20:16 -0800
+Subject: tcp: exit if nothing to retransmit on RTO timeout
+To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: "David S . Miller" <davem@davemloft.net>, netdev <netdev@vger.kernel.org>,  Eric Dumazet <edumazet@google.com>, Eric Dumazet <eric.dumazet@gmail.com>,  Yuchung Cheng <ycheng@google.com>, Neal Cardwell <ncardwell@google.com>,  Soheil Hassas Yeganeh <soheil@google.com>
+Message-ID: <20191206182016.137529-1-edumazet@google.com>
+
+From: Eric Dumazet <edumazet@google.com>
+
+Two upstream commits squashed together for v4.14 stable :
+
+ commit 88f8598d0a302a08380eadefd09b9f5cb1c4c428 upstream.
+
+  Previously TCP only warns if its RTO timer fires and the
+  retransmission queue is empty, but it'll cause null pointer
+  reference later on. It's better to avoid such catastrophic failure
+  and simply exit with a warning.
+
+Squashed with "tcp: refactor tcp_retransmit_timer()" :
+
+ commit 0d580fbd2db084a5c96ee9c00492236a279d5e0f upstream.
+
+  It appears linux-4.14 stable needs a backport of commit
+  88f8598d0a30 ("tcp: exit if nothing to retransmit on RTO timeout")
+
+  Since tcp_rtx_queue_empty() is not in pre 4.15 kernels,
+  let's refactor tcp_retransmit_timer() to only use tcp_rtx_queue_head()
+
+Signed-off-by: Yuchung Cheng <ycheng@google.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Neal Cardwell <ncardwell@google.com>
+Reviewed-by: Soheil Hassas Yeganeh <soheil@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/tcp_timer.c |   10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/net/ipv4/tcp_timer.c
++++ b/net/ipv4/tcp_timer.c
+@@ -413,6 +413,7 @@ void tcp_retransmit_timer(struct sock *s
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct net *net = sock_net(sk);
+       struct inet_connection_sock *icsk = inet_csk(sk);
++      struct sk_buff *skb;
+       if (tp->fastopen_rsk) {
+               WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
+@@ -423,10 +424,13 @@ void tcp_retransmit_timer(struct sock *s
+                */
+               return;
+       }
++
+       if (!tp->packets_out)
+-              goto out;
++              return;
+-      WARN_ON(tcp_write_queue_empty(sk));
++      skb = tcp_rtx_queue_head(sk);
++      if (WARN_ON_ONCE(!skb))
++              return;
+       tp->tlp_high_seq = 0;
+@@ -459,7 +463,7 @@ void tcp_retransmit_timer(struct sock *s
+                       goto out;
+               }
+               tcp_enter_loss(sk);
+-              tcp_retransmit_skb(sk, tcp_write_queue_head(sk), 1);
++              tcp_retransmit_skb(sk, skb, 1);
+               __sk_dst_reset(sk);
+               goto out_reset_timer;
+       }