This is the 5.4.55 stable release

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAl8kSvEACgkQONu9yGCS
 aT52hg//TXqmLGJiUw/sx0fULFuJqdkaiyhQXFbLz6WZUWGUxNlpD8qC6GbLPe0t
 jZSkUB02iHXgVaTxaN9oefixwRSG/NWLl3cbE4enpjhTpmMIQ5BStEH+AJmZKYLF
 9e/zTVHsynUneTskLgukoKInEuqtg9XS473jBgQS724RZA/LI5BfNquMoENtyj/E
 xbwZK9wol1DzSYAs5QQ93WesUothxvLA1dlAuqzQ2mq9zevWSz+nVSgsT1kYNUfd
 LpZ1AdRbxMlsNLToUd+lkZ21ZxHw7i58KhbyZr5fbQbzqr5NmP33F4qbSplwOSX6
 WsdpkET/GaZgOY9yw41KYG8vv9tMYnXYuxyYc2xgxhnU/dmItKQ1bxnFzJODNbnc
 8FglncvuN0daJdDOTxBWUoLLotiqUVPBWa4i1sPQlPRGN9m1PBe5KpSUH7U1wK5f
 8nHFP6KU0DKaFLHaVF2aSfWlX3r5gR66wSc5RWwNBjiOr8pLIBWeb06CpH7BwQhl
 9xzvYW++4NgqaAz6jKZJ0XEZZKY8nJRs1SoUYRQRk8MKhYpHB7SlVMDvrjs9i3gt
 wGGwohYBcwczh1i7MRRkodusj0g+1D6Tr4EEdH/NhIcL0yd9eZrnv7noQCS6HZlD
 BFfS0vPMQU/JHQL7G/vdN+73eDdnRFZjbClwnDrsRTJL5NDfqM0=
 =jer2
 -----END PGP SIGNATURE-----

Merge 5.4.55 into android11-5.4

Changes in 5.4.55
	AX.25: Fix out-of-bounds read in ax25_connect()
	AX.25: Prevent out-of-bounds read in ax25_sendmsg()
	dev: Defer free of skbs in flush_backlog
	drivers/net/wan/x25_asy: Fix to make it work
	ip6_gre: fix null-ptr-deref in ip6gre_init_net()
	net-sysfs: add a newline when printing 'tx_timeout' by sysfs
	net: udp: Fix wrong clean up for IS_UDPLITE macro
	qrtr: orphan socket in qrtr_release()
	rtnetlink: Fix memory(net_device) leak when ->newlink fails
	rxrpc: Fix sendmsg() returning EPIPE due to recvmsg() returning ENODATA
	tcp: allow at most one TLP probe per flight
	AX.25: Prevent integer overflows in connect and sendmsg
	sctp: shrink stream outq only when new outcnt < old outcnt
	sctp: shrink stream outq when fails to do addstream reconf
	udp: Copy has_conns in reuseport_grow().
	udp: Improve load balancing for SO_REUSEPORT.
	regmap: debugfs: check count when read regmap file
	PM: wakeup: Show statistics for deleted wakeup sources again
	Revert "dpaa_eth: fix usage as DSA master, try 3"
	Linux 5.4.55

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I776630d05a9d6a34f76719cb3d2fb6b9790d643b
This commit is contained in:
Greg Kroah-Hartman 2020-08-01 11:46:55 +02:00
commit 53b501f197
20 changed files with 102 additions and 55 deletions

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
VERSION = 5 VERSION = 5
PATCHLEVEL = 4 PATCHLEVEL = 4
SUBLEVEL = 54 SUBLEVEL = 55
EXTRAVERSION = EXTRAVERSION =
NAME = Kleptomaniac Octopus NAME = Kleptomaniac Octopus

View File

@ -1124,6 +1124,9 @@ static void *wakeup_sources_stats_seq_next(struct seq_file *m,
break; break;
} }
if (!next_ws)
print_wakeup_source_stats(m, &deleted_ws);
return next_ws; return next_ws;
} }

View File

@ -227,6 +227,9 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
if (*ppos < 0 || !count) if (*ppos < 0 || !count)
return -EINVAL; return -EINVAL;
if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
count = PAGE_SIZE << (MAX_ORDER - 1);
buf = kmalloc(count, GFP_KERNEL); buf = kmalloc(count, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
@ -371,6 +374,9 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file,
if (*ppos < 0 || !count) if (*ppos < 0 || !count)
return -EINVAL; return -EINVAL;
if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
count = PAGE_SIZE << (MAX_ORDER - 1);
buf = kmalloc(count, GFP_KERNEL); buf = kmalloc(count, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;

View File

@ -2802,7 +2802,7 @@ static int dpaa_eth_probe(struct platform_device *pdev)
} }
/* Do this here, so we can be verbose early */ /* Do this here, so we can be verbose early */
SET_NETDEV_DEV(net_dev, dev->parent); SET_NETDEV_DEV(net_dev, dev);
dev_set_drvdata(dev, net_dev); dev_set_drvdata(dev, net_dev);
priv = netdev_priv(net_dev); priv = netdev_priv(net_dev);

View File

@ -183,7 +183,7 @@ static inline void x25_asy_unlock(struct x25_asy *sl)
netif_wake_queue(sl->dev); netif_wake_queue(sl->dev);
} }
/* Send one completely decapsulated IP datagram to the IP layer. */ /* Send an LAPB frame to the LAPB module to process. */
static void x25_asy_bump(struct x25_asy *sl) static void x25_asy_bump(struct x25_asy *sl)
{ {
@ -195,13 +195,12 @@ static void x25_asy_bump(struct x25_asy *sl)
count = sl->rcount; count = sl->rcount;
dev->stats.rx_bytes += count; dev->stats.rx_bytes += count;
skb = dev_alloc_skb(count+1); skb = dev_alloc_skb(count);
if (skb == NULL) { if (skb == NULL) {
netdev_warn(sl->dev, "memory squeeze, dropping packet\n"); netdev_warn(sl->dev, "memory squeeze, dropping packet\n");
dev->stats.rx_dropped++; dev->stats.rx_dropped++;
return; return;
} }
skb_push(skb, 1); /* LAPB internal control */
skb_put_data(skb, sl->rbuff, count); skb_put_data(skb, sl->rbuff, count);
skb->protocol = x25_type_trans(skb, sl->dev); skb->protocol = x25_type_trans(skb, sl->dev);
err = lapb_data_received(skb->dev, skb); err = lapb_data_received(skb->dev, skb);
@ -209,7 +208,6 @@ static void x25_asy_bump(struct x25_asy *sl)
kfree_skb(skb); kfree_skb(skb);
printk(KERN_DEBUG "x25_asy: data received err - %d\n", err); printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
} else { } else {
netif_rx(skb);
dev->stats.rx_packets++; dev->stats.rx_packets++;
} }
} }
@ -356,12 +354,21 @@ static netdev_tx_t x25_asy_xmit(struct sk_buff *skb,
*/ */
/* /*
* Called when I frame data arrives. We did the work above - throw it * Called when I frame data arrive. We add a pseudo header for upper
* at the net layer. * layers and pass it to upper layers.
*/ */
static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
{ {
if (skb_cow(skb, 1)) {
kfree_skb(skb);
return NET_RX_DROP;
}
skb_push(skb, 1);
skb->data[0] = X25_IFACE_DATA;
skb->protocol = x25_type_trans(skb, dev);
return netif_rx(skb); return netif_rx(skb);
} }
@ -657,7 +664,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
switch (s) { switch (s) {
case X25_END: case X25_END:
if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
sl->rcount > 2) sl->rcount >= 2)
x25_asy_bump(sl); x25_asy_bump(sl);
clear_bit(SLF_ESCAPE, &sl->flags); clear_bit(SLF_ESCAPE, &sl->flags);
sl->rcount = 0; sl->rcount = 0;

View File

@ -216,6 +216,8 @@ struct tcp_sock {
} rack; } rack;
u16 advmss; /* Advertised MSS */ u16 advmss; /* Advertised MSS */
u8 compressed_ack; u8 compressed_ack;
u8 tlp_retrans:1, /* TLP is a retransmission */
unused_1:7;
u32 chrono_start; /* Start time in jiffies of a TCP chrono */ u32 chrono_start; /* Start time in jiffies of a TCP chrono */
u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */ u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */
u8 chrono_type:2, /* current chronograph type */ u8 chrono_type:2, /* current chronograph type */
@ -238,7 +240,7 @@ struct tcp_sock {
save_syn:1, /* Save headers of SYN packet */ save_syn:1, /* Save headers of SYN packet */
is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */ is_cwnd_limited:1,/* forward progress limited by snd_cwnd? */
syn_smc:1; /* SYN includes SMC */ syn_smc:1; /* SYN includes SMC */
u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ u32 tlp_high_seq; /* snd_nxt at the time of TLP */
u32 tcp_tx_delay; /* delay (in usec) added to TX packets */ u32 tcp_tx_delay; /* delay (in usec) added to TX packets */
u64 tcp_wstamp_ns; /* departure time for next sent data packet */ u64 tcp_wstamp_ns; /* departure time for next sent data packet */

View File

@ -1187,7 +1187,10 @@ static int __must_check ax25_connect(struct socket *sock,
if (addr_len > sizeof(struct sockaddr_ax25) && if (addr_len > sizeof(struct sockaddr_ax25) &&
fsa->fsa_ax25.sax25_ndigis != 0) { fsa->fsa_ax25.sax25_ndigis != 0) {
/* Valid number of digipeaters ? */ /* Valid number of digipeaters ? */
if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) { if (fsa->fsa_ax25.sax25_ndigis < 1 ||
fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS ||
addr_len < sizeof(struct sockaddr_ax25) +
sizeof(ax25_address) * fsa->fsa_ax25.sax25_ndigis) {
err = -EINVAL; err = -EINVAL;
goto out_release; goto out_release;
} }
@ -1507,7 +1510,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax; struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
/* Valid number of digipeaters ? */ /* Valid number of digipeaters ? */
if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) { if (usax->sax25_ndigis < 1 ||
usax->sax25_ndigis > AX25_MAX_DIGIS ||
addr_len < sizeof(struct sockaddr_ax25) +
sizeof(ax25_address) * usax->sax25_ndigis) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }

View File

@ -5229,7 +5229,7 @@ static void flush_backlog(struct work_struct *work)
skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) { skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) {
if (skb->dev->reg_state == NETREG_UNREGISTERING) { if (skb->dev->reg_state == NETREG_UNREGISTERING) {
__skb_unlink(skb, &sd->input_pkt_queue); __skb_unlink(skb, &sd->input_pkt_queue);
kfree_skb(skb); dev_kfree_skb_irq(skb);
input_queue_head_incr(sd); input_queue_head_incr(sd);
} }
} }

View File

@ -1036,7 +1036,7 @@ static ssize_t tx_timeout_show(struct netdev_queue *queue, char *buf)
trans_timeout = queue->trans_timeout; trans_timeout = queue->trans_timeout;
spin_unlock_irq(&queue->_xmit_lock); spin_unlock_irq(&queue->_xmit_lock);
return sprintf(buf, "%lu", trans_timeout); return sprintf(buf, fmt_ulong, trans_timeout);
} }
static unsigned int get_netdev_queue_index(struct netdev_queue *queue) static unsigned int get_netdev_queue_index(struct netdev_queue *queue)

View File

@ -3231,7 +3231,8 @@ replay:
*/ */
if (err < 0) { if (err < 0) {
/* If device is not registered at all, free it now */ /* If device is not registered at all, free it now */
if (dev->reg_state == NETREG_UNINITIALIZED) if (dev->reg_state == NETREG_UNINITIALIZED ||
dev->reg_state == NETREG_UNREGISTERED)
free_netdev(dev); free_netdev(dev);
goto out; goto out;
} }

View File

@ -112,6 +112,7 @@ static struct sock_reuseport *reuseport_grow(struct sock_reuseport *reuse)
more_reuse->prog = reuse->prog; more_reuse->prog = reuse->prog;
more_reuse->reuseport_id = reuse->reuseport_id; more_reuse->reuseport_id = reuse->reuseport_id;
more_reuse->bind_inany = reuse->bind_inany; more_reuse->bind_inany = reuse->bind_inany;
more_reuse->has_conns = reuse->has_conns;
memcpy(more_reuse->socks, reuse->socks, memcpy(more_reuse->socks, reuse->socks,
reuse->num_socks * sizeof(struct sock *)); reuse->num_socks * sizeof(struct sock *));

View File

@ -3505,10 +3505,8 @@ static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
} }
} }
/* This routine deals with acks during a TLP episode. /* This routine deals with acks during a TLP episode and ends an episode by
* We mark the end of a TLP episode on receiving TLP dupack or when * resetting tlp_high_seq. Ref: TLP algorithm in draft-ietf-tcpm-rack
* ack is after tlp_high_seq.
* Ref: loss detection algorithm in draft-dukkipati-tcpm-tcp-loss-probe.
*/ */
static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
{ {
@ -3517,7 +3515,10 @@ static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
if (before(ack, tp->tlp_high_seq)) if (before(ack, tp->tlp_high_seq))
return; return;
if (flag & FLAG_DSACKING_ACK) { if (!tp->tlp_retrans) {
/* TLP of new data has been acknowledged */
tp->tlp_high_seq = 0;
} else if (flag & FLAG_DSACKING_ACK) {
/* This DSACK means original and TLP probe arrived; no loss */ /* This DSACK means original and TLP probe arrived; no loss */
tp->tlp_high_seq = 0; tp->tlp_high_seq = 0;
} else if (after(ack, tp->tlp_high_seq)) { } else if (after(ack, tp->tlp_high_seq)) {

View File

@ -2564,6 +2564,11 @@ void tcp_send_loss_probe(struct sock *sk)
int pcount; int pcount;
int mss = tcp_current_mss(sk); int mss = tcp_current_mss(sk);
/* At most one outstanding TLP */
if (tp->tlp_high_seq)
goto rearm_timer;
tp->tlp_retrans = 0;
skb = tcp_send_head(sk); skb = tcp_send_head(sk);
if (skb && tcp_snd_wnd_test(tp, skb, mss)) { if (skb && tcp_snd_wnd_test(tp, skb, mss)) {
pcount = tp->packets_out; pcount = tp->packets_out;
@ -2581,10 +2586,6 @@ void tcp_send_loss_probe(struct sock *sk)
return; return;
} }
/* At most one outstanding TLP retransmission. */
if (tp->tlp_high_seq)
goto rearm_timer;
if (skb_still_in_host_queue(sk, skb)) if (skb_still_in_host_queue(sk, skb))
goto rearm_timer; goto rearm_timer;
@ -2606,10 +2607,12 @@ void tcp_send_loss_probe(struct sock *sk)
if (__tcp_retransmit_skb(sk, skb, 1)) if (__tcp_retransmit_skb(sk, skb, 1))
goto rearm_timer; goto rearm_timer;
tp->tlp_retrans = 1;
probe_sent:
/* Record snd_nxt for loss detection. */ /* Record snd_nxt for loss detection. */
tp->tlp_high_seq = tp->snd_nxt; tp->tlp_high_seq = tp->snd_nxt;
probe_sent:
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPLOSSPROBES); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPLOSSPROBES);
/* Reset s.t. tcp_rearm_rto will restart timer from now */ /* Reset s.t. tcp_rearm_rto will restart timer from now */
inet_csk(sk)->icsk_pending = 0; inet_csk(sk)->icsk_pending = 0;

View File

@ -413,7 +413,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
struct udp_hslot *hslot2, struct udp_hslot *hslot2,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct sock *sk, *result; struct sock *sk, *result, *reuseport_result;
int score, badness; int score, badness;
u32 hash = 0; u32 hash = 0;
@ -423,17 +423,20 @@ static struct sock *udp4_lib_lookup2(struct net *net,
score = compute_score(sk, net, saddr, sport, score = compute_score(sk, net, saddr, sport,
daddr, hnum, dif, sdif); daddr, hnum, dif, sdif);
if (score > badness) { if (score > badness) {
reuseport_result = NULL;
if (sk->sk_reuseport && if (sk->sk_reuseport &&
sk->sk_state != TCP_ESTABLISHED) { sk->sk_state != TCP_ESTABLISHED) {
hash = udp_ehashfn(net, daddr, hnum, hash = udp_ehashfn(net, daddr, hnum,
saddr, sport); saddr, sport);
result = reuseport_select_sock(sk, hash, skb, reuseport_result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr)); sizeof(struct udphdr));
if (result && !reuseport_has_conns(sk, false)) if (reuseport_result && !reuseport_has_conns(sk, false))
return result; return reuseport_result;
} }
result = reuseport_result ? : sk;
badness = score; badness = score;
result = sk;
} }
} }
return result; return result;
@ -2045,7 +2048,7 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
/* /*
* UDP-Lite specific tests, ignored on UDP sockets * UDP-Lite specific tests, ignored on UDP sockets
*/ */
if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) {
/* /*
* MIB statistics other than incrementing the error count are * MIB statistics other than incrementing the error count are

View File

@ -1560,17 +1560,18 @@ static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head)
static int __net_init ip6gre_init_net(struct net *net) static int __net_init ip6gre_init_net(struct net *net)
{ {
struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
struct net_device *ndev;
int err; int err;
if (!net_has_fallback_tunnels(net)) if (!net_has_fallback_tunnels(net))
return 0; return 0;
ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", ndev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0",
NET_NAME_UNKNOWN, NET_NAME_UNKNOWN, ip6gre_tunnel_setup);
ip6gre_tunnel_setup); if (!ndev) {
if (!ign->fb_tunnel_dev) {
err = -ENOMEM; err = -ENOMEM;
goto err_alloc_dev; goto err_alloc_dev;
} }
ign->fb_tunnel_dev = ndev;
dev_net_set(ign->fb_tunnel_dev, net); dev_net_set(ign->fb_tunnel_dev, net);
/* FB netdevice is special: we have one, and only one per netns. /* FB netdevice is special: we have one, and only one per netns.
* Allowing to move it to another netns is clearly unsafe. * Allowing to move it to another netns is clearly unsafe.
@ -1590,7 +1591,7 @@ static int __net_init ip6gre_init_net(struct net *net)
return 0; return 0;
err_reg_dev: err_reg_dev:
free_netdev(ign->fb_tunnel_dev); free_netdev(ndev);
err_alloc_dev: err_alloc_dev:
return err; return err;
} }

View File

@ -148,7 +148,7 @@ static struct sock *udp6_lib_lookup2(struct net *net,
int dif, int sdif, struct udp_hslot *hslot2, int dif, int sdif, struct udp_hslot *hslot2,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct sock *sk, *result; struct sock *sk, *result, *reuseport_result;
int score, badness; int score, badness;
u32 hash = 0; u32 hash = 0;
@ -158,17 +158,20 @@ static struct sock *udp6_lib_lookup2(struct net *net,
score = compute_score(sk, net, saddr, sport, score = compute_score(sk, net, saddr, sport,
daddr, hnum, dif, sdif); daddr, hnum, dif, sdif);
if (score > badness) { if (score > badness) {
reuseport_result = NULL;
if (sk->sk_reuseport && if (sk->sk_reuseport &&
sk->sk_state != TCP_ESTABLISHED) { sk->sk_state != TCP_ESTABLISHED) {
hash = udp6_ehashfn(net, daddr, hnum, hash = udp6_ehashfn(net, daddr, hnum,
saddr, sport); saddr, sport);
result = reuseport_select_sock(sk, hash, skb, reuseport_result = reuseport_select_sock(sk, hash, skb,
sizeof(struct udphdr)); sizeof(struct udphdr));
if (result && !reuseport_has_conns(sk, false)) if (reuseport_result && !reuseport_has_conns(sk, false))
return result; return reuseport_result;
} }
result = sk;
result = reuseport_result ? : sk;
badness = score; badness = score;
} }
} }
@ -643,7 +646,7 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)
/* /*
* UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c).
*/ */
if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) {
if (up->pcrlen == 0) { /* full coverage was set */ if (up->pcrlen == 0) { /* full coverage was set */
net_dbg_ratelimited("UDPLITE6: partial coverage %d while full coverage %d requested\n", net_dbg_ratelimited("UDPLITE6: partial coverage %d while full coverage %d requested\n",

View File

@ -1004,6 +1004,7 @@ static int qrtr_release(struct socket *sock)
sk->sk_state_change(sk); sk->sk_state_change(sk);
sock_set_flag(sk, SOCK_DEAD); sock_set_flag(sk, SOCK_DEAD);
sock_orphan(sk);
sock->sk = NULL; sock->sk = NULL;
if (!sock_flag(sk, SOCK_ZAPPED)) if (!sock_flag(sk, SOCK_ZAPPED))

View File

@ -464,7 +464,7 @@ try_again:
list_empty(&rx->recvmsg_q) && list_empty(&rx->recvmsg_q) &&
rx->sk.sk_state != RXRPC_SERVER_LISTENING) { rx->sk.sk_state != RXRPC_SERVER_LISTENING) {
release_sock(&rx->sk); release_sock(&rx->sk);
return -ENODATA; return -EAGAIN;
} }
if (list_empty(&rx->recvmsg_q)) { if (list_empty(&rx->recvmsg_q)) {

View File

@ -306,7 +306,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
/* this should be in poll */ /* this should be in poll */
sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) if (sk->sk_shutdown & SEND_SHUTDOWN)
return -EPIPE; return -EPIPE;
more = msg->msg_flags & MSG_MORE; more = msg->msg_flags & MSG_MORE;

View File

@ -22,17 +22,11 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
#include <net/sctp/stream_sched.h> #include <net/sctp/stream_sched.h>
/* Migrates chunks from stream queues to new stream queues if needed, static void sctp_stream_shrink_out(struct sctp_stream *stream, __u16 outcnt)
* but not across associations. Also, removes those chunks to streams
* higher than the new max.
*/
static void sctp_stream_outq_migrate(struct sctp_stream *stream,
struct sctp_stream *new, __u16 outcnt)
{ {
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_chunk *ch, *temp; struct sctp_chunk *ch, *temp;
struct sctp_outq *outq; struct sctp_outq *outq;
int i;
asoc = container_of(stream, struct sctp_association, stream); asoc = container_of(stream, struct sctp_association, stream);
outq = &asoc->outqueue; outq = &asoc->outqueue;
@ -56,6 +50,19 @@ static void sctp_stream_outq_migrate(struct sctp_stream *stream,
sctp_chunk_free(ch); sctp_chunk_free(ch);
} }
}
/* Migrates chunks from stream queues to new stream queues if needed,
* but not across associations. Also, removes those chunks to streams
* higher than the new max.
*/
static void sctp_stream_outq_migrate(struct sctp_stream *stream,
struct sctp_stream *new, __u16 outcnt)
{
int i;
if (stream->outcnt > outcnt)
sctp_stream_shrink_out(stream, outcnt);
if (new) { if (new) {
/* Here we actually move the old ext stuff into the new /* Here we actually move the old ext stuff into the new
@ -1038,11 +1045,13 @@ struct sctp_chunk *sctp_process_strreset_resp(
nums = ntohs(addstrm->number_of_streams); nums = ntohs(addstrm->number_of_streams);
number = stream->outcnt - nums; number = stream->outcnt - nums;
if (result == SCTP_STRRESET_PERFORMED) if (result == SCTP_STRRESET_PERFORMED) {
for (i = number; i < stream->outcnt; i++) for (i = number; i < stream->outcnt; i++)
SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
else } else {
sctp_stream_shrink_out(stream, number);
stream->outcnt = number; stream->outcnt = number;
}
*evp = sctp_ulpevent_make_stream_change_event(asoc, flags, *evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
0, nums, GFP_ATOMIC); 0, nums, GFP_ATOMIC);