Commit 5a5df594 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[NETLINK]: Unshare SKB, as necessary, in netlink_trim()

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0e91e70f
...@@ -660,7 +660,7 @@ void netlink_detachskb(struct sock *sk, struct sk_buff *skb) ...@@ -660,7 +660,7 @@ void netlink_detachskb(struct sock *sk, struct sk_buff *skb)
sock_put(sk); 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; int delta;
...@@ -668,10 +668,20 @@ static inline void netlink_trim(struct sk_buff *skb, int allocation) ...@@ -668,10 +668,20 @@ static inline void netlink_trim(struct sk_buff *skb, int allocation)
delta = skb->end - skb->tail; delta = skb->end - skb->tail;
if (delta * 2 < skb->truesize) if (delta * 2 < skb->truesize)
return; return skb;
if (pskb_expand_head(skb, 0, -delta, allocation))
return; if (skb_shared(skb)) {
skb->truesize -= delta; 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) int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)
...@@ -680,7 +690,7 @@ int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock ...@@ -680,7 +690,7 @@ int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock
int err; int err;
long timeo; long timeo;
netlink_trim(skb, gfp_any()); skb = netlink_trim(skb, gfp_any());
timeo = sock_sndtimeo(ssk, nonblock); timeo = sock_sndtimeo(ssk, nonblock);
retry: retry:
...@@ -778,6 +788,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -778,6 +788,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
struct hlist_node *node; struct hlist_node *node;
struct sock *sk; struct sock *sk;
skb = netlink_trim(skb, allocation);
info.exclude_sk = ssk; info.exclude_sk = ssk;
info.pid = pid; info.pid = pid;
info.group = group; info.group = group;
...@@ -788,8 +800,6 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -788,8 +800,6 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
info.skb = skb; info.skb = skb;
info.skb2 = NULL; info.skb2 = NULL;
netlink_trim(skb, allocation);
/* While we sleep in clone, do not allow to change socket list */ /* While we sleep in clone, do not allow to change socket list */
netlink_lock_table(); netlink_lock_table();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment