summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/core/skbuff.c6
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv6/ip6_output.c4
3 files changed, 9 insertions, 5 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 40796b8bf820..e5bfd42fd083 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1001,7 +1001,11 @@ struct ubuf_info *sock_zerocopy_realloc(struct sock *sk, size_t size,
uarg->len++;
uarg->bytelen = bytelen;
atomic_set(&sk->sk_zckey, ++next);
- sock_zerocopy_get(uarg);
+
+ /* no extra ref when appending to datagram (MSG_MORE) */
+ if (sk->sk_type == SOCK_STREAM)
+ sock_zerocopy_get(uarg);
+
return uarg;
}
}
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index e8bb2e85c5a4..ac770940adb9 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -883,7 +883,7 @@ static int __ip_append_data(struct sock *sk,
int csummode = CHECKSUM_NONE;
struct rtable *rt = (struct rtable *)cork->dst;
unsigned int wmem_alloc_delta = 0;
- bool paged, extra_uref;
+ bool paged, extra_uref = false;
u32 tskey = 0;
skb = skb_peek_tail(queue);
@@ -923,7 +923,7 @@ static int __ip_append_data(struct sock *sk,
uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
if (!uarg)
return -ENOBUFS;
- extra_uref = true;
+ extra_uref = !skb; /* only extra ref if !MSG_MORE */
if (rt->dst.dev->features & NETIF_F_SG &&
csummode == CHECKSUM_PARTIAL) {
paged = true;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e71227390bec..de16c2e343ef 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1269,7 +1269,7 @@ static int __ip6_append_data(struct sock *sk,
int csummode = CHECKSUM_NONE;
unsigned int maxnonfragsize, headersize;
unsigned int wmem_alloc_delta = 0;
- bool paged, extra_uref;
+ bool paged, extra_uref = false;
skb = skb_peek_tail(queue);
if (!skb) {
@@ -1338,7 +1338,7 @@ emsgsize:
uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
if (!uarg)
return -ENOBUFS;
- extra_uref = true;
+ extra_uref = !skb; /* only extra ref if !MSG_MORE */
if (rt->dst.dev->features & NETIF_F_SG &&
csummode == CHECKSUM_PARTIAL) {
paged = true;