Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-convert-to-skb_dstref_steal-and-skb_dstref_restore'

Stanislav Fomichev says:

====================
net: Convert to skb_dstref_steal and skb_dstref_restore

To diagnose and prevent issues similar to [0], emit warning
(CONFIG_DEBUG_NET) from skb_dst_set and skb_dst_set_noref when
overwriting non-null reference-counted entry. Two new helpers
are added to handle special cases where the entry needs to be
reset and restored: skb_dstref_steal/skb_dstref_restore. The bulk of
the patches in the series converts manual _skb_refst manipulations
to these new helpers.

0: https://lore.kernel.org/netdev/20250723224625.1340224-1-sdf@fomichev.me/T/#u
====================

Link: https://patch.msgid.link/20250818154032.3173645-1-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+72 -20
+5 -5
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
··· 171 171 struct sk_buff *skb; 172 172 173 173 while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { 174 - skb_dst_set(skb, (void *)NULL); 174 + skb_dstref_steal(skb); 175 175 kfree_skb(skb); 176 176 } 177 177 } ··· 194 194 struct sk_buff *skb; 195 195 196 196 while ((skb = __skb_dequeue(&tlsk->sk_recv_queue)) != NULL) { 197 - skb_dst_set(skb, NULL); 197 + skb_dstref_steal(skb); 198 198 kfree_skb(skb); 199 199 } 200 200 } ··· 1734 1734 pr_err("can't find conn. for hwtid %u.\n", hwtid); 1735 1735 return -EINVAL; 1736 1736 } 1737 - skb_dst_set(skb, NULL); 1737 + skb_dstref_steal(skb); 1738 1738 process_cpl_msg(chtls_recv_data, sk, skb); 1739 1739 return 0; 1740 1740 } ··· 1786 1786 pr_err("can't find conn. for hwtid %u.\n", hwtid); 1787 1787 return -EINVAL; 1788 1788 } 1789 - skb_dst_set(skb, NULL); 1789 + skb_dstref_steal(skb); 1790 1790 process_cpl_msg(chtls_recv_pdu, sk, skb); 1791 1791 return 0; 1792 1792 } ··· 1855 1855 pr_err("can't find conn. for hwtid %u.\n", hwtid); 1856 1856 return -EINVAL; 1857 1857 } 1858 - skb_dst_set(skb, NULL); 1858 + skb_dstref_steal(skb); 1859 1859 process_cpl_msg(chtls_rx_hdr, sk, skb); 1860 1860 1861 1861 return 0;
+2 -2
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.h
··· 171 171 172 172 static inline void chtls_free_skb(struct sock *sk, struct sk_buff *skb) 173 173 { 174 - skb_dst_set(skb, NULL); 174 + skb_dstref_steal(skb); 175 175 __skb_unlink(skb, &sk->sk_receive_queue); 176 176 __kfree_skb(skb); 177 177 } 178 178 179 179 static inline void chtls_kfree_skb(struct sock *sk, struct sk_buff *skb) 180 180 { 181 - skb_dst_set(skb, NULL); 181 + skb_dstref_steal(skb); 182 182 __skb_unlink(skb, &sk->sk_receive_queue); 183 183 kfree_skb(skb); 184 184 }
+1 -1
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c
··· 1434 1434 continue; 1435 1435 found_ok_skb: 1436 1436 if (!skb->len) { 1437 - skb_dst_set(skb, NULL); 1437 + skb_dstref_steal(skb); 1438 1438 __skb_unlink(skb, &sk->sk_receive_queue); 1439 1439 kfree_skb(skb); 1440 1440
+1 -2
drivers/staging/octeon/ethernet-tx.c
··· 346 346 * The skbuff will be reused without ever being freed. We must 347 347 * cleanup a bunch of core things. 348 348 */ 349 - dst_release(skb_dst(skb)); 350 - skb_dst_set(skb, NULL); 349 + skb_dst_drop(skb); 351 350 skb_ext_reset(skb); 352 351 nf_reset_ct(skb); 353 352 skb_reset_redirect(skb);
+41
include/linux/skbuff.h
··· 1159 1159 return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK); 1160 1160 } 1161 1161 1162 + static inline void skb_dst_check_unset(struct sk_buff *skb) 1163 + { 1164 + DEBUG_NET_WARN_ON_ONCE((skb->_skb_refdst & SKB_DST_PTRMASK) && 1165 + !(skb->_skb_refdst & SKB_DST_NOREF)); 1166 + } 1167 + 1168 + /** 1169 + * skb_dstref_steal() - return current dst_entry value and clear it 1170 + * @skb: buffer 1171 + * 1172 + * Resets skb dst_entry without adjusting its reference count. Useful in 1173 + * cases where dst_entry needs to be temporarily reset and restored. 1174 + * Note that the returned value cannot be used directly because it 1175 + * might contain SKB_DST_NOREF bit. 1176 + * 1177 + * When in doubt, prefer skb_dst_drop() over skb_dstref_steal() to correctly 1178 + * handle dst_entry reference counting. 1179 + * 1180 + * Returns: original skb dst_entry. 1181 + */ 1182 + static inline unsigned long skb_dstref_steal(struct sk_buff *skb) 1183 + { 1184 + unsigned long refdst = skb->_skb_refdst; 1185 + 1186 + skb->_skb_refdst = 0; 1187 + return refdst; 1188 + } 1189 + 1190 + /** 1191 + * skb_dstref_restore() - restore skb dst_entry removed via skb_dstref_steal() 1192 + * @skb: buffer 1193 + * @refdst: dst entry from a call to skb_dstref_steal() 1194 + */ 1195 + static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst) 1196 + { 1197 + skb_dst_check_unset(skb); 1198 + skb->_skb_refdst = refdst; 1199 + } 1200 + 1162 1201 /** 1163 1202 * skb_dst_set - sets skb dst 1164 1203 * @skb: buffer ··· 1208 1169 */ 1209 1170 static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) 1210 1171 { 1172 + skb_dst_check_unset(skb); 1211 1173 skb->slow_gro |= !!dst; 1212 1174 skb->_skb_refdst = (unsigned long)dst; 1213 1175 } ··· 1225 1185 */ 1226 1186 static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst) 1227 1187 { 1188 + skb_dst_check_unset(skb); 1228 1189 WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); 1229 1190 skb->slow_gro |= !!dst; 1230 1191 skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
+4 -3
net/ipv4/icmp.c
··· 544 544 goto relookup_failed; 545 545 } 546 546 /* Ugh! */ 547 - orefdst = skb_in->_skb_refdst; /* save old refdst */ 548 - skb_dst_set(skb_in, NULL); 547 + orefdst = skb_dstref_steal(skb_in); 549 548 err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, 550 549 dscp, rt2->dst.dev) ? -EINVAL : 0; 551 550 552 551 dst_release(&rt2->dst); 553 552 rt2 = skb_rtable(skb_in); 554 - skb_in->_skb_refdst = orefdst; /* restore old refdst */ 553 + /* steal dst entry from skb_in, don't drop refcnt */ 554 + skb_dstref_steal(skb_in); 555 + skb_dstref_restore(skb_in, orefdst); 555 556 } 556 557 557 558 if (err)
+2 -3
net/ipv4/ip_options.c
··· 615 615 } 616 616 memcpy(&nexthop, &optptr[srrptr-1], 4); 617 617 618 - orefdst = skb->_skb_refdst; 619 - skb_dst_set(skb, NULL); 618 + orefdst = skb_dstref_steal(skb); 620 619 err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph), 621 620 dev) ? -EINVAL : 0; 622 621 rt2 = skb_rtable(skb); 623 622 if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { 624 623 skb_dst_drop(skb); 625 - skb->_skb_refdst = orefdst; 624 + skb_dstref_restore(skb, orefdst); 626 625 return -EINVAL; 627 626 } 628 627 refdst_drop(orefdst);
+4 -1
net/ipv4/netfilter.c
··· 65 65 if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && 66 66 xfrm_decode_session(net, skb, flowi4_to_flowi(&fl4), AF_INET) == 0) { 67 67 struct dst_entry *dst = skb_dst(skb); 68 - skb_dst_set(skb, NULL); 68 + /* ignore return value from skb_dstref_steal, xfrm_lookup takes 69 + * care of dropping the refcnt if needed. 70 + */ 71 + skb_dstref_steal(skb); 69 72 dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), sk, 0); 70 73 if (IS_ERR(dst)) 71 74 return PTR_ERR(dst);
+4 -1
net/ipv6/netfilter.c
··· 63 63 #ifdef CONFIG_XFRM 64 64 if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 65 65 xfrm_decode_session(net, skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) { 66 - skb_dst_set(skb, NULL); 66 + /* ignore return value from skb_dstref_steal, xfrm_lookup takes 67 + * care of dropping the refcnt if needed. 68 + */ 69 + skb_dstref_steal(skb); 67 70 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0); 68 71 if (IS_ERR(dst)) 69 72 return PTR_ERR(dst);
+8 -2
net/xfrm/xfrm_policy.c
··· 3881 3881 } 3882 3882 3883 3883 skb_dst_force(skb); 3884 - if (!skb_dst(skb)) { 3884 + dst = skb_dst(skb); 3885 + if (!dst) { 3885 3886 XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); 3886 3887 return 0; 3887 3888 } 3888 3889 3889 - dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE); 3890 + /* ignore return value from skb_dstref_steal, xfrm_lookup takes 3891 + * care of dropping the refcnt if needed. 3892 + */ 3893 + skb_dstref_steal(skb); 3894 + 3895 + dst = xfrm_lookup(net, dst, &fl, NULL, XFRM_LOOKUP_QUEUE); 3890 3896 if (IS_ERR(dst)) { 3891 3897 res = 0; 3892 3898 dst = NULL;