net: rename skb_unshare() to skb_unclone_full()

skb_unshare() only copies cloned skbs. A shared skb that is not a clone
comes back unchanged, which the name doesn't suggest. The loopback
selftest hooks got caught by this and hit BUG_ON(skb_shared()).

Rename it to skb_unclone_full(). Like skb_unclone() it only acts on
clones, but it copies the whole skb, not just the head.

Suggested-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Ioana Ciornei <ioana.ciornei@nxp.com> # dpaa2
Link: https://patch.msgid.link/20261015-nb-skb-unclone-full-v1-1-0dfbf01f60f2@tipi-net.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Nicolai Buchwitz 2026-10-15 10:16:38 +02:00 committed by Jakub Kicinski
parent 985e325058
commit 258c3ae4a4
16 changed files with 34 additions and 31 deletions

View File

@ -44,7 +44,7 @@ static int xgbe_test_loopback_validate(struct sk_buff *skb,
struct iphdr *ih;
int eat;
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb)
goto out;

View File

@ -1418,9 +1418,9 @@ static netdev_tx_t __dpaa2_eth_tx(struct sk_buff *skb,
/* We'll be holding a back-reference to the skb until Tx Confirmation;
* we don't want that overwritten by a concurrent Tx with a cloned skb.
*/
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (unlikely(!skb)) {
/* skb_unshare() has already freed the skb */
/* skb_unclone_full() has already freed the skb */
percpu_stats->tx_dropped++;
return NETDEV_TX_OK;
}

View File

@ -1276,9 +1276,9 @@ static netdev_tx_t dpaa2_switch_port_tx(struct sk_buff *skb,
}
/* We'll be holding a back-reference to the skb until Tx confirmation */
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (unlikely(!skb)) {
/* skb_unshare() has already freed the skb */
/* skb_unclone_full() has already freed the skb */
net_err_ratelimited("%s: Error copying the socket buffer\n", net_dev->name);
goto err_exit;
}

View File

@ -2117,7 +2117,7 @@ dma_addr_t otx2_dma_map_skb_frag(struct otx2_nic *pfvf,
/* Crypto hardware need write permission for ipsec crypto offload */
if (unlikely(xfrm_offload(skb))) {
dir = DMA_BIDIRECTIONAL;
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
}
/* First segment is always skb->data */

View File

@ -920,7 +920,7 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
proto = tpriv->svlan ? ETH_P_8021AD : ETH_P_8021Q;
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb)
goto out;

View File

@ -644,7 +644,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
return ERR_PTR(-ENOMEM);
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb) {
macsec_txsa_put(tx_sa);
return ERR_PTR(-ENOMEM);
@ -953,7 +953,7 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
aead_request_set_crypt(req, sg, sg, len, iv);
aead_request_set_ad(req, macsec_hdr_len(macsec_skb_cb(skb)->has_sci));
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb) {
aead_request_free(req);
return ERR_PTR(-ENOMEM);
@ -1159,7 +1159,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
if (hdr->eth.h_proto != htons(ETH_P_MACSEC))
return handle_not_macsec(skb);
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
*pskb = skb;
if (!skb)
return RX_HANDLER_CONSUMED;

View File

@ -427,8 +427,8 @@ static inline int __vlan_insert_tag(struct sk_buff *skb,
* Inserts the VLAN tag into @skb as part of the payload at offset mac_len
* Returns a VLAN tagged skb. This might change skb->head.
*
* Following the skb_unshare() example, in case of error, the calling function
* doesn't have to worry about freeing the original skb.
* Following the skb_unclone_full() example, in case of error, the calling
* function doesn't have to worry about freeing the original skb.
*
* Does not change skb->protocol so this function can be used during receive.
*
@ -458,8 +458,8 @@ static inline struct sk_buff *vlan_insert_inner_tag(struct sk_buff *skb,
* Inserts the VLAN tag into @skb as part of the payload
* Returns a VLAN tagged skb. This might change skb->head.
*
* Following the skb_unshare() example, in case of error, the calling function
* doesn't have to worry about freeing the original skb.
* Following the skb_unclone_full() example, in case of error, the calling
* function doesn't have to worry about freeing the original skb.
*
* Does not change skb->protocol so this function can be used during receive.
*
@ -480,8 +480,8 @@ static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
* Inserts the VLAN tag into @skb as part of the payload
* Returns a VLAN tagged skb. This might change skb->head.
*
* Following the skb_unshare() example, in case of error, the calling function
* doesn't have to worry about freeing the original skb.
* Following the skb_unclone_full() example, in case of error, the calling
* function doesn't have to worry about freeing the original skb.
*
* Return: modified @skb on success, NULL on error (@skb is freed).
*/
@ -524,8 +524,8 @@ static inline void __vlan_hwaccel_copy_tag(struct sk_buff *dst, const struct sk_
*
* Pushes the VLAN tag from @skb->vlan_tci inside to the payload.
*
* Following the skb_unshare() example, in case of error, the calling function
* doesn't have to worry about freeing the original skb.
* Following the skb_unclone_full() example, in case of error, the calling
* function doesn't have to worry about freeing the original skb.
*/
static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
{

View File

@ -2131,14 +2131,14 @@ static inline struct sk_buff *skb_share_check(struct sk_buff *skb, gfp_t pri)
}
/*
* Copy shared buffers into a new sk_buff. We effectively do COW on
* Copy cloned buffers into a new sk_buff. We effectively do COW on
* packets to handle cases where we have a local reader and forward
* and a couple of other messy ones. The normal one is tcpdumping
* a packet that's being forwarded.
*/
/**
* skb_unshare - make a copy of a shared buffer
* skb_unclone_full - make a private copy of a cloned buffer
* @skb: buffer to check
* @pri: priority for memory allocation
*
@ -2148,10 +2148,13 @@ static inline struct sk_buff *skb_share_check(struct sk_buff *skb, gfp_t pri)
* the original buffer is returned. When called with a spinlock held or
* from interrupt state @pri must be %GFP_ATOMIC
*
* Unlike skb_unclone(), the paged data is copied as well. A buffer with
* skb->users > 1 that is not a clone is returned as is, use
* skb_share_check() for that case.
*
* %NULL is returned on a memory allocation failure.
*/
static inline struct sk_buff *skb_unshare(struct sk_buff *skb,
gfp_t pri)
static inline struct sk_buff *skb_unclone_full(struct sk_buff *skb, gfp_t pri)
{
might_sleep_if(gfpflags_allow_blocking(pri));
if (skb_cloned(skb)) {

View File

@ -515,7 +515,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
/* We must take a copy of the skb before we modify/replace the ipv6
* header as the header could be used elsewhere
*/
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb)
return NET_XMIT_DROP;

View File

@ -64,7 +64,7 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
return 0;
}
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb)
return 0;

View File

@ -294,7 +294,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *wdev,
*/
if (lowpan_is_frag1(*skb_network_header(skb)) ||
lowpan_is_iphc(*skb_network_header(skb))) {
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb)
goto out;
}

View File

@ -279,7 +279,7 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
return NET_XMIT_DROP;
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb)
return NET_XMIT_DROP;
}

View File

@ -396,7 +396,7 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb)
* this will free the skb; callers can no longer access it
* safely.
*/
key->reasm_head = skb_unshare(skb, GFP_ATOMIC);
key->reasm_head = skb_unclone_full(skb, GFP_ATOMIC);
if (!key->reasm_head)
return -ENOMEM;

View File

@ -460,7 +460,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff **to_free)
{
struct netem_sched_data *q = qdisc_priv(sch);
/* We don't fill cb now as skb_unshare() may invalidate it */
/* We don't fill cb now as skb_unclone_full() may invalidate it */
struct netem_skb_cb *cb;
struct sk_buff *skb2 = NULL;
struct sk_buff *segs = NULL;
@ -528,7 +528,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
qdisc_skb_cb(skb)->pkt_len = skb->len;
}
skb = skb_unshare(skb, GFP_ATOMIC);
skb = skb_unclone_full(skb, GFP_ATOMIC);
if (unlikely(!skb)) {
WRITE_ONCE(q->allocation_errors, q->allocation_errors + 1);
qdisc_qstats_drop(sch);

View File

@ -339,7 +339,7 @@ struct sctp_ulpevent *sctp_make_reassembled_event(struct net *net,
if (skb_cloned(f_frag)) {
/* This is a cloned skb, we can't just modify
* the frag_list. We need a new skb to do that.
* Instead of calling skb_unshare(), we'll do it
* Instead of calling skb_unclone_full(), we'll do it
* ourselves since we need to delay the free.
*/
new = skb_copy(f_frag, GFP_ATOMIC);

View File

@ -145,7 +145,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
if (skb_has_frag_list(frag) && __skb_linearize(frag))
goto err;
*buf = NULL;
frag = skb_unshare(frag, GFP_ATOMIC);
frag = skb_unclone_full(frag, GFP_ATOMIC);
if (unlikely(!frag))
goto err;
head = *headbuf = frag;