git: 32d1d7fee613 - stable/13 - LinuxKPI: skbuff: fix skb_queue_splice_init()

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Sun, 27 Mar 2022 20:14:04 UTC
The branch stable/13 has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=32d1d7fee61328e65ae944836d1027335ccb979c

commit 32d1d7fee61328e65ae944836d1027335ccb979c
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2022-03-23 17:05:43 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2022-03-27 18:08:53 +0000

    LinuxKPI: skbuff: fix skb_queue_splice_init()
    
    In skb_queue_splice_init() we set a next value and then used that new
    value to further update the remaining linking rather than the original
    value.  Introduce another temporary variable 'n' to hold the original
    value and use that.
    While here rename q and h to from and to as otherwise it was too
    confusing to read.
    
    Also initialize skb->prev and skb->next to point to skb itself if
    for nothing else at least to aid debugging.
    
    Reported by:    phk (panic in iwl_txq_reclaim)
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit 6a8973c3324c0c6c270ae4ad371e50c0ec5761da)
---
 sys/compat/linuxkpi/common/include/linux/skbuff.h | 25 ++++++++++++-----------
 sys/compat/linuxkpi/common/src/linux_skbuff.c     |  2 ++
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index be93032c7561..21ea7ee560e2 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -762,26 +762,27 @@ skb_mark_not_on_list(struct sk_buff *skb)
 }
 
 static inline void
-skb_queue_splice_init(struct sk_buff_head *q, struct sk_buff_head *h)
+skb_queue_splice_init(struct sk_buff_head *from, struct sk_buff_head *to)
 {
-	struct sk_buff *b, *e;
+	struct sk_buff *b, *e, *n;
 
-	SKB_TRACE2(q, h);
+	SKB_TRACE2(from, to);
 
-	if (skb_queue_empty(q))
+	if (skb_queue_empty(from))
 		return;
 
 	/* XXX do we need a barrier around this? */
-	b = q->next;
-	e = q->prev;
+	b = from->next;
+	e = from->prev;
+	n = to->next;
 
-	b->prev = (struct sk_buff *)h;
-	h->next = b;
-	e->next = h->next;
-	h->next->prev = e;
+	b->prev = (struct sk_buff *)to;
+	to->next = b;
+	e->next = n;
+	n->prev = e;
 
-	h->qlen += q->qlen;
-	__skb_queue_head_init(q);
+	to->qlen += from->qlen;
+	__skb_queue_head_init(from);
 }
 
 static inline void
diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c
index 0a4974d74d9d..efb97fa2f126 100644
--- a/sys/compat/linuxkpi/common/src/linux_skbuff.c
+++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c
@@ -86,6 +86,8 @@ linuxkpi_alloc_skb(size_t size, gfp_t gfp)
 	skb->head = skb->data = skb->tail = (uint8_t *)(skb+1);
 	skb->end = skb->head + size;
 
+	skb->prev = skb->next = skb;
+
 	skb->shinfo = (struct skb_shared_info *)(skb->end);
 
 	SKB_TRACE_FMT(skb, "data %p size %zu", skb->data, size);