From e3f85dd1ebc00eac8440be845a281cf1cfa298a0 Mon Sep 17 00:00:00 2001
From: Ksawlii <ksawery.blaszczak@proton.me>
Date: Sun, 24 Nov 2024 00:23:41 +0100
Subject: [PATCH] Revert "gro: remove rcu_read_lock/rcu_read_unlock from
 gro_receive handlers"

This reverts commit c35b04ae631df11e6491fd2e7017e621c4ed97a0.
---
 drivers/net/geneve.c   |  5 ++++-
 net/8021q/vlan_core.c  |  5 ++++-
 net/ethernet/eth.c     |  5 ++++-
 net/ipv4/af_inet.c     | 12 ++++++++----
 net/ipv4/fou.c         | 12 +++++++++---
 net/ipv4/gre_offload.c |  9 ++++++---
 net/ipv4/udp_offload.c |  2 ++
 net/ipv6/ip6_offload.c |  6 +++++-
 net/ipv6/udp_offload.c |  2 ++
 9 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 17989688f..af35361a3 100755
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -528,15 +528,18 @@ static struct sk_buff *geneve_gro_receive(struct sock *sk,
 
 	type = gh->proto_type;
 
+	rcu_read_lock();
 	ptype = gro_find_receive_by_type(type);
 	if (!ptype)
-		goto out;
+		goto out_unlock;
 
 	skb_gro_pull(skb, gh_len);
 	skb_gro_postpull_rcsum(skb, gh, gh_len);
 	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 	flush = 0;
 
+out_unlock:
+	rcu_read_unlock();
 out:
 	skb_gro_flush_final(skb, pp, flush);
 
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index ff0d3fc82..43aea97c5 100755
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -482,9 +482,10 @@ static struct sk_buff *vlan_gro_receive(struct list_head *head,
 
 	type = vhdr->h_vlan_encapsulated_proto;
 
+	rcu_read_lock();
 	ptype = gro_find_receive_by_type(type);
 	if (!ptype)
-		goto out;
+		goto out_unlock;
 
 	flush = 0;
 
@@ -503,6 +504,8 @@ static struct sk_buff *vlan_gro_receive(struct list_head *head,
 	skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
 	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 
+out_unlock:
+	rcu_read_unlock();
 out:
 	skb_gro_flush_final(skb, pp, flush);
 
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 79c242b0b..c3669a0b7 100755
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -430,16 +430,19 @@ struct sk_buff *eth_gro_receive(struct list_head *head, struct sk_buff *skb)
 
 	type = eh->h_proto;
 
+	rcu_read_lock();
 	ptype = gro_find_receive_by_type(type);
 	if (ptype == NULL) {
 		flush = 1;
-		goto out;
+		goto out_unlock;
 	}
 
 	skb_gro_pull(skb, sizeof(*eh));
 	skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
 	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 
+out_unlock:
+	rcu_read_unlock();
 out:
 	skb_gro_flush_final(skb, pp, flush);
 
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 0e0b9e23d..6f2db5ac2 100755
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1473,18 +1473,19 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb)
 
 	proto = iph->protocol;
 
+	rcu_read_lock();
 	ops = rcu_dereference(inet_offloads[proto]);
 	if (!ops || !ops->callbacks.gro_receive)
-		goto out;
+		goto out_unlock;
 
 	if (*(u8 *)iph != 0x45)
-		goto out;
+		goto out_unlock;
 
 	if (ip_is_fragment(iph))
-		goto out;
+		goto out_unlock;
 
 	if (unlikely(ip_fast_csum((u8 *)iph, 5)))
-		goto out;
+		goto out_unlock;
 
 	id = ntohl(*(__be32 *)&iph->id);
 	flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF));
@@ -1561,6 +1562,9 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb)
 	pp = indirect_call_gro_receive(tcp4_gro_receive, udp4_gro_receive,
 				       ops->callbacks.gro_receive, head, skb);
 
+out_unlock:
+	rcu_read_unlock();
+
 out:
 	skb_gro_flush_final(skb, pp, flush);
 
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 5aacc75e4..8fcbc6258 100755
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -246,14 +246,17 @@ static struct sk_buff *fou_gro_receive(struct sock *sk,
 	/* Flag this frame as already having an outer encap header */
 	NAPI_GRO_CB(skb)->is_fou = 1;
 
+	rcu_read_lock();
 	offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
 	ops = rcu_dereference(offloads[proto]);
 	if (!ops || !ops->callbacks.gro_receive)
-		goto out;
+		goto out_unlock;
 
 	pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
 
-out:
+out_unlock:
+	rcu_read_unlock();
+
 	return pp;
 }
 
@@ -435,14 +438,17 @@ next_proto:
 	/* Flag this frame as already having an outer encap header */
 	NAPI_GRO_CB(skb)->is_fou = 1;
 
+	rcu_read_lock();
 	offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
 	ops = rcu_dereference(offloads[proto]);
 	if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
-		goto out;
+		goto out_unlock;
 
 	pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
 	flush = 0;
 
+out_unlock:
+	rcu_read_unlock();
 out:
 	skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
 
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index e9dabf1af..e0a246575 100755
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -158,9 +158,10 @@ static struct sk_buff *gre_gro_receive(struct list_head *head,
 
 	type = greh->protocol;
 
+	rcu_read_lock();
 	ptype = gro_find_receive_by_type(type);
 	if (!ptype)
-		goto out;
+		goto out_unlock;
 
 	grehlen = GRE_HEADER_SECTION;
 
@@ -174,13 +175,13 @@ static struct sk_buff *gre_gro_receive(struct list_head *head,
 	if (skb_gro_header_hard(skb, hlen)) {
 		greh = skb_gro_header_slow(skb, hlen, off);
 		if (unlikely(!greh))
-			goto out;
+			goto out_unlock;
 	}
 
 	/* Don't bother verifying checksum if we're going to flush anyway. */
 	if ((greh->flags & GRE_CSUM) && !NAPI_GRO_CB(skb)->flush) {
 		if (skb_gro_checksum_simple_validate(skb))
-			goto out;
+			goto out_unlock;
 
 		skb_gro_checksum_try_convert(skb, IPPROTO_GRE,
 					     null_compute_pseudo);
@@ -224,6 +225,8 @@ static struct sk_buff *gre_gro_receive(struct list_head *head,
 	pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
 	flush = 0;
 
+out_unlock:
+	rcu_read_unlock();
 out:
 	skb_gro_flush_final(skb, pp, flush);
 
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index b83556937..5fa67c514 100755
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -628,11 +628,13 @@ struct sk_buff *udp4_gro_receive(struct list_head *head, struct sk_buff *skb)
 					     inet_gro_compute_pseudo);
 skip:
 	NAPI_GRO_CB(skb)->is_ipv6 = 0;
+	rcu_read_lock();
 
 	if (static_branch_unlikely(&udp_encap_needed_key))
 		sk = udp4_gro_lookup_skb(skb, uh->source, uh->dest);
 
 	pp = udp_gro_receive(head, skb, uh, sk);
+	rcu_read_unlock();
 	return pp;
 
 flush:
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index f67921e0d..15c8eef1e 100755
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -209,6 +209,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head,
 
 	flush += ntohs(iph->payload_len) != skb_gro_len(skb);
 
+	rcu_read_lock();
 	proto = iph->nexthdr;
 	ops = rcu_dereference(inet6_offloads[proto]);
 	if (!ops || !ops->callbacks.gro_receive) {
@@ -221,7 +222,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head,
 
 		ops = rcu_dereference(inet6_offloads[proto]);
 		if (!ops || !ops->callbacks.gro_receive)
-			goto out;
+			goto out_unlock;
 
 		iph = ipv6_hdr(skb);
 	}
@@ -279,6 +280,9 @@ not_same_flow:
 	pp = indirect_call_gro_receive_l4(tcp6_gro_receive, udp6_gro_receive,
 					 ops->callbacks.gro_receive, head, skb);
 
+out_unlock:
+	rcu_read_unlock();
+
 out:
 	skb_gro_flush_final(skb, pp, flush);
 
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 1107782c0..7752e1e92 100755
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -144,11 +144,13 @@ struct sk_buff *udp6_gro_receive(struct list_head *head, struct sk_buff *skb)
 
 skip:
 	NAPI_GRO_CB(skb)->is_ipv6 = 1;
+	rcu_read_lock();
 
 	if (static_branch_unlikely(&udpv6_encap_needed_key))
 		sk = udp6_gro_lookup_skb(skb, uh->source, uh->dest);
 
 	pp = udp_gro_receive(head, skb, uh, sk);
+	rcu_read_unlock();
 	return pp;
 
 flush: