--- linux-2.6/net/netlink/af_netlink.c.orig 2005-01-16 17:46:49.000000000 +1100 +++ linux-2.6/net/netlink/af_netlink.c 2005-01-16 19:00:51.000000000 +1100 @@ -660,7 +660,7 @@ sock_put(sk); } -static inline void netlink_trim(struct sk_buff *skb, int allocation) +static inline struct sk_buff *netlink_trim(struct sk_buff *skb, int allocation) { int delta; @@ -668,10 +668,20 @@ delta = skb->end - skb->tail; if (delta * 2 < skb->truesize) - return; - if (pskb_expand_head(skb, 0, -delta, allocation)) - return; - skb->truesize -= delta; + return skb; + + if (skb_shared(skb)) { + struct sk_buff *nskb = skb_clone(skb, allocation); + if (!nskb) + return skb; + kfree_skb(skb); + skb = nskb; + } + + if (!pskb_expand_head(skb, 0, -delta, allocation)) + skb->truesize -= delta; + + return skb; } int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock) @@ -680,7 +690,7 @@ int err; long timeo; - netlink_trim(skb, gfp_any()); + skb = netlink_trim(skb, gfp_any()); timeo = sock_sndtimeo(ssk, nonblock); retry: @@ -788,7 +798,7 @@ info.skb = skb; info.skb2 = NULL; - netlink_trim(skb, allocation); + skb = netlink_trim(skb, allocation); /* While we sleep in clone, do not allow to change socket list */