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

[NETLINK]: Yield in netlink_broadcast when congested.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ff517ce2
...@@ -593,7 +593,7 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff ...@@ -593,7 +593,7 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff
skb_set_owner_r(skb, sk); skb_set_owner_r(skb, sk);
skb_queue_tail(&sk->sk_receive_queue, skb); skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk, skb->len); sk->sk_data_ready(sk, skb->len);
return 0; return atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf;
} }
return -1; return -1;
} }
...@@ -606,6 +606,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -606,6 +606,8 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
struct sk_buff *skb2 = NULL; struct sk_buff *skb2 = NULL;
int protocol = ssk->sk_protocol; int protocol = ssk->sk_protocol;
int failure = 0, delivered = 0; int failure = 0, delivered = 0;
int congested = 0;
int val;
netlink_trim(skb, allocation); netlink_trim(skb, allocation);
...@@ -640,9 +642,10 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -640,9 +642,10 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
netlink_overrun(sk); netlink_overrun(sk);
/* Clone failed. Notify ALL listeners. */ /* Clone failed. Notify ALL listeners. */
failure = 1; failure = 1;
} else if (netlink_broadcast_deliver(sk, skb2)) { } else if ((val = netlink_broadcast_deliver(sk, skb2)) < 0) {
netlink_overrun(sk); netlink_overrun(sk);
} else { } else {
congested |= val;
delivered = 1; delivered = 1;
skb2 = NULL; skb2 = NULL;
} }
...@@ -655,8 +658,11 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -655,8 +658,11 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
kfree_skb(skb2); kfree_skb(skb2);
kfree_skb(skb); kfree_skb(skb);
if (delivered) if (delivered) {
if (congested && (allocation & __GFP_WAIT))
yield();
return 0; return 0;
}
if (failure) if (failure)
return -ENOBUFS; return -ENOBUFS;
return -ESRCH; return -ESRCH;
......
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