From: Greg Kroah-Hartman Date: Tue, 18 Nov 2014 17:12:23 +0000 (-0800) Subject: 3.17-stable patches X-Git-Tag: v3.10.61~48 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0921b3313e372801d135c06c4ed772907917f7be;p=thirdparty%2Fkernel%2Fstable-queue.git 3.17-stable patches added patches: gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch inet-frags-fix-a-race-between-inet_evict_bucket-and-inet_frag_kill.patch inet-frags-remove-the-warn_on-from-inet_evict_bucket.patch ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch ipv6-fix-ipv6_pktinfo-with-v4-mapped.patch net-mv643xx_eth-reclaim-tx-skbs-only-when-released-by-the-hw.patch net-ppp-don-t-call-bpf_prog_create-in-ppp_lock.patch net-ptp-fix-time-stamp-matching-logic-for-vlan-packets.patch net-sctp-fix-memory-leak-in-auth-key-management.patch net-sctp-fix-null-pointer-dereference-in-af-from_addr_param-on-malformed-packet.patch netlink-properly-unbind-in-error-conditions.patch sit-use-ipip6_tunnel_init-as-the-ndo_init-function.patch smsc911x-power-up-phydev-before-doing-a-software-reset.patch sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch sunvdc-add-cdrom-and-v1.1-protocol-support.patch sunvdc-compute-vdisk-geometry-from-capacity.patch sunvdc-don-t-call-vd_op_get_vtoc.patch sunvdc-limit-each-sg-segment-to-a-page.patch udptunnel-add-skb_gso_udp_tunnel-during-gro_complete.patch vio-fix-reuse-of-vio_dring-slot.patch vti6-use-vti6_dev_init-as-the-ndo_init-function.patch vxlan-do-not-reuse-sockets-for-a-different-address-family.patch --- diff --git a/queue-3.17/gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch b/queue-3.17/gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch new file mode 100644 index 00000000000..009a96eb57a --- /dev/null +++ b/queue-3.17/gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch @@ -0,0 +1,46 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Steffen Klassert +Date: Mon, 3 Nov 2014 09:19:30 +0100 +Subject: gre6: Move the setting of dev->iflink into the ndo_init functions. + +From: Steffen Klassert + +[ Upstream commit f03eb128e3f4276f46442d14f3b8f864f3775821 ] + +Otherwise it gets overwritten by register_netdev(). + +Signed-off-by: Steffen Klassert +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_gre.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/net/ipv6/ip6_gre.c ++++ b/net/ipv6/ip6_gre.c +@@ -957,8 +957,6 @@ static void ip6gre_tnl_link_config(struc + else + dev->flags &= ~IFF_POINTOPOINT; + +- dev->iflink = p->link; +- + /* Precalculate GRE options length */ + if (t->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) { + if (t->parms.o_flags&GRE_CSUM) +@@ -1268,6 +1266,7 @@ static int ip6gre_tunnel_init(struct net + u64_stats_init(&ip6gre_tunnel_stats->syncp); + } + ++ dev->iflink = tunnel->parms.link; + + return 0; + } +@@ -1477,6 +1476,8 @@ static int ip6gre_tap_init(struct net_de + if (!dev->tstats) + return -ENOMEM; + ++ dev->iflink = tunnel->parms.link; ++ + return 0; + } + diff --git a/queue-3.17/inet-frags-fix-a-race-between-inet_evict_bucket-and-inet_frag_kill.patch b/queue-3.17/inet-frags-fix-a-race-between-inet_evict_bucket-and-inet_frag_kill.patch new file mode 100644 index 00000000000..5704bd23d7a --- /dev/null +++ b/queue-3.17/inet-frags-fix-a-race-between-inet_evict_bucket-and-inet_frag_kill.patch @@ -0,0 +1,62 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Nikolay Aleksandrov +Date: Tue, 28 Oct 2014 10:30:34 +0100 +Subject: inet: frags: fix a race between inet_evict_bucket and inet_frag_kill + +From: Nikolay Aleksandrov + +[ Upstream commit 65ba1f1ec0eff1c25933468e1d238201c0c2cb29 ] + +When the evictor is running it adds some chosen frags to a local list to +be evicted once the chain lock has been released but at the same time +the *frag_queue can be running for some of the same queues and it +may call inet_frag_kill which will wait on the chain lock and +will then delete the queue from the wrong list since it was added in the +eviction one. The fix is simple - check if the queue has the evict flag +set under the chain lock before deleting it, this is safe because the +evict flag is set only under that lock and having the flag set also means +that the queue has been detached from the chain list, so no need to delete +it again. +An important note to make is that we're safe w.r.t refcnt because +inet_frag_kill and inet_evict_bucket will sync on the del_timer operation +where only one of the two can succeed (or if the timer is executing - +none of them), the cases are: +1. inet_frag_kill succeeds in del_timer + - then the timer ref is removed, but inet_evict_bucket will not add + this queue to its expire list but will restart eviction in that chain +2. inet_evict_bucket succeeds in del_timer + - then the timer ref is kept until the evictor "expires" the queue, but + inet_frag_kill will remove the initial ref and will set + INET_FRAG_COMPLETE which will make the frag_expire fn just to remove + its ref. +In the end all of the queue users will do an inet_frag_put and the one +that reaches 0 will free it. The refcount balance should be okay. + +CC: Florian Westphal +CC: Eric Dumazet +CC: Patrick McLean + +Fixes: b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue") +Suggested-by: Eric Dumazet +Reported-by: Patrick McLean +Tested-by: Patrick McLean +Signed-off-by: Nikolay Aleksandrov +Reviewed-by: Florian Westphal +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/inet_fragment.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/ipv4/inet_fragment.c ++++ b/net/ipv4/inet_fragment.c +@@ -285,7 +285,8 @@ static inline void fq_unlink(struct inet + struct inet_frag_bucket *hb; + + hb = get_frag_bucket_locked(fq, f); +- hlist_del(&fq->list); ++ if (!(fq->flags & INET_FRAG_EVICTED)) ++ hlist_del(&fq->list); + spin_unlock(&hb->chain_lock); + } + diff --git a/queue-3.17/inet-frags-remove-the-warn_on-from-inet_evict_bucket.patch b/queue-3.17/inet-frags-remove-the-warn_on-from-inet_evict_bucket.patch new file mode 100644 index 00000000000..74e99f297d6 --- /dev/null +++ b/queue-3.17/inet-frags-remove-the-warn_on-from-inet_evict_bucket.patch @@ -0,0 +1,42 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Nikolay Aleksandrov +Date: Tue, 28 Oct 2014 10:44:01 +0100 +Subject: inet: frags: remove the WARN_ON from inet_evict_bucket + +From: Nikolay Aleksandrov + +[ Upstream commit d70127e8a942364de8dd140fe73893efda363293 ] + +The WARN_ON in inet_evict_bucket can be triggered by a valid case: +inet_frag_kill and inet_evict_bucket can be running in parallel on the +same queue which means that there has been at least one more ref added +by a previous inet_frag_find call, but inet_frag_kill can delete the +timer before inet_evict_bucket which will cause the WARN_ON() there to +trigger since we'll have refcnt!=1. Now, this case is valid because the +queue is being "killed" for some reason (removed from the chain list and +its timer deleted) so it will get destroyed in the end by one of the +inet_frag_put() calls which reaches 0 i.e. refcnt is still valid. + +CC: Florian Westphal +CC: Eric Dumazet +CC: Patrick McLean + +Fixes: b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue") +Reported-by: Patrick McLean +Signed-off-by: Nikolay Aleksandrov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/inet_fragment.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/net/ipv4/inet_fragment.c ++++ b/net/ipv4/inet_fragment.c +@@ -146,7 +146,6 @@ evict_again: + atomic_inc(&fq->refcnt); + spin_unlock(&hb->chain_lock); + del_timer_sync(&fq->timer); +- WARN_ON(atomic_read(&fq->refcnt) != 1); + inet_frag_put(fq, f); + goto evict_again; + } diff --git a/queue-3.17/ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch b/queue-3.17/ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch new file mode 100644 index 00000000000..758b0cb051f --- /dev/null +++ b/queue-3.17/ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch @@ -0,0 +1,60 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Steffen Klassert +Date: Mon, 3 Nov 2014 09:19:27 +0100 +Subject: ip6_tunnel: Use ip6_tnl_dev_init as the ndo_init function. + +From: Steffen Klassert + +[ Upstream commit 6c6151daaf2d8dc2046d9926539feed5f66bf74e ] + +ip6_tnl_dev_init() sets the dev->iflink via a call to +ip6_tnl_link_config(). After that, register_netdevice() +sets dev->iflink = -1. So we loose the iflink configuration +for ipv6 tunnels. Fix this by using ip6_tnl_dev_init() as the +ndo_init function. Then ip6_tnl_dev_init() is called after +dev->iflink is set to -1 from register_netdevice(). + +Signed-off-by: Steffen Klassert +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_tunnel.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -272,9 +272,6 @@ static int ip6_tnl_create2(struct net_de + int err; + + t = netdev_priv(dev); +- err = ip6_tnl_dev_init(dev); +- if (err < 0) +- goto out; + + err = register_netdevice(dev); + if (err < 0) +@@ -1462,6 +1459,7 @@ ip6_tnl_change_mtu(struct net_device *de + + + static const struct net_device_ops ip6_tnl_netdev_ops = { ++ .ndo_init = ip6_tnl_dev_init, + .ndo_uninit = ip6_tnl_dev_uninit, + .ndo_start_xmit = ip6_tnl_xmit, + .ndo_do_ioctl = ip6_tnl_ioctl, +@@ -1546,16 +1544,10 @@ static int __net_init ip6_fb_tnl_dev_ini + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); +- int err = ip6_tnl_dev_init_gen(dev); +- +- if (err) +- return err; + + t->parms.proto = IPPROTO_IPV6; + dev_hold(dev); + +- ip6_tnl_link_config(t); +- + rcu_assign_pointer(ip6n->tnls_wc[0], t); + return 0; + } diff --git a/queue-3.17/ipv6-fix-ipv6_pktinfo-with-v4-mapped.patch b/queue-3.17/ipv6-fix-ipv6_pktinfo-with-v4-mapped.patch new file mode 100644 index 00000000000..62db1ea8364 --- /dev/null +++ b/queue-3.17/ipv6-fix-ipv6_pktinfo-with-v4-mapped.patch @@ -0,0 +1,32 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Eric Dumazet +Date: Mon, 10 Nov 2014 17:54:25 -0800 +Subject: ipv6: fix IPV6_PKTINFO with v4 mapped + +From: Eric Dumazet + +[ Upstream commit 5337b5b75cd9bd3624a6820e3c2a084d2480061c ] + +Use IS_ENABLED(CONFIG_IPV6), to enable this code if IPv6 is +a module. + +Signed-off-by: Eric Dumazet +Fixes: c8e6ad0829a7 ("ipv6: honor IPV6_PKTINFO with v4 mapped addresses on sendmsg") +Acked-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/ip_sockglue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv4/ip_sockglue.c ++++ b/net/ipv4/ip_sockglue.c +@@ -195,7 +195,7 @@ int ip_cmsg_send(struct net *net, struct + for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (!CMSG_OK(msg, cmsg)) + return -EINVAL; +-#if defined(CONFIG_IPV6) ++#if IS_ENABLED(CONFIG_IPV6) + if (allow_ipv6 && + cmsg->cmsg_level == SOL_IPV6 && + cmsg->cmsg_type == IPV6_PKTINFO) { diff --git a/queue-3.17/net-mv643xx_eth-reclaim-tx-skbs-only-when-released-by-the-hw.patch b/queue-3.17/net-mv643xx_eth-reclaim-tx-skbs-only-when-released-by-the-hw.patch new file mode 100644 index 00000000000..3763f81b942 --- /dev/null +++ b/queue-3.17/net-mv643xx_eth-reclaim-tx-skbs-only-when-released-by-the-hw.patch @@ -0,0 +1,73 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Karl Beldan +Date: Wed, 5 Nov 2014 15:32:59 +0100 +Subject: net: mv643xx_eth: reclaim TX skbs only when released by the HW + +From: Karl Beldan + +[ Upstream commit 2c2a9cbd64387d6b70ac5db013e9bfe9412c7354 ] + +ATM, txq_reclaim will dequeue and free an skb for each tx desc released +by the hw that has TX_LAST_DESC set. However, in case of TSO, each +hw desc embedding the last part of a segment has TX_LAST_DESC set, +losing the one-to-one 'last skb frag'/'TX_LAST_DESC set' correspondance, +which causes data corruption. + +Fix this by checking TX_ENABLE_INTERRUPT instead of TX_LAST_DESC, and +warn when trying to dequeue from an empty txq (which can be symptomatic +of releasing skbs prematurely). + +Fixes: 3ae8f4e0b98 ('net: mv643xx_eth: Implement software TSO') +Reported-by: Slawomir Gajzner +Reported-by: Julien D'Ascenzio +Signed-off-by: Karl Beldan +Cc: Ian Campbell +Cc: Eric Dumazet +Cc: Ezequiel Garcia +Cc: Sebastian Hesselbarth +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/marvell/mv643xx_eth.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/net/ethernet/marvell/mv643xx_eth.c ++++ b/drivers/net/ethernet/marvell/mv643xx_eth.c +@@ -1047,7 +1047,6 @@ static int txq_reclaim(struct tx_queue * + int tx_index; + struct tx_desc *desc; + u32 cmd_sts; +- struct sk_buff *skb; + + tx_index = txq->tx_used_desc; + desc = &txq->tx_desc_area[tx_index]; +@@ -1066,19 +1065,22 @@ static int txq_reclaim(struct tx_queue * + reclaimed++; + txq->tx_desc_count--; + +- skb = NULL; +- if (cmd_sts & TX_LAST_DESC) +- skb = __skb_dequeue(&txq->tx_skb); ++ if (!IS_TSO_HEADER(txq, desc->buf_ptr)) ++ dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr, ++ desc->byte_cnt, DMA_TO_DEVICE); ++ ++ if (cmd_sts & TX_ENABLE_INTERRUPT) { ++ struct sk_buff *skb = __skb_dequeue(&txq->tx_skb); ++ ++ if (!WARN_ON(!skb)) ++ dev_kfree_skb(skb); ++ } + + if (cmd_sts & ERROR_SUMMARY) { + netdev_info(mp->dev, "tx error\n"); + mp->dev->stats.tx_errors++; + } + +- if (!IS_TSO_HEADER(txq, desc->buf_ptr)) +- dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr, +- desc->byte_cnt, DMA_TO_DEVICE); +- dev_kfree_skb(skb); + } + + __netif_tx_unlock_bh(nq); diff --git a/queue-3.17/net-ppp-don-t-call-bpf_prog_create-in-ppp_lock.patch b/queue-3.17/net-ppp-don-t-call-bpf_prog_create-in-ppp_lock.patch new file mode 100644 index 00000000000..59846c1c218 --- /dev/null +++ b/queue-3.17/net-ppp-don-t-call-bpf_prog_create-in-ppp_lock.patch @@ -0,0 +1,94 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Takashi Iwai +Date: Mon, 10 Nov 2014 11:50:21 +0100 +Subject: net: ppp: Don't call bpf_prog_create() in ppp_lock + +From: Takashi Iwai + +[ Upstream commit 5748eb8f8e989a9da1ac7c96dc73d68cbdedf7df ] + +In ppp_ioctl(), bpf_prog_create() is called inside ppp_lock, which +eventually calls vmalloc() and hits BUG_ON() in vmalloc.c. This patch +works around the problem by moving the allocation outside the lock. + +The bug was revealed by the recent change in net/core/filter.c, as it +allocates via vmalloc() instead of kmalloc() now. + +Reported-and-tested-by: Stefan Seyfried +Signed-off-by: Takashi Iwai +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ppp/ppp_generic.c | 40 ++++++++++++++++++++-------------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -755,23 +755,23 @@ static long ppp_ioctl(struct file *file, + + err = get_filter(argp, &code); + if (err >= 0) { ++ struct bpf_prog *pass_filter = NULL; + struct sock_fprog_kern fprog = { + .len = err, + .filter = code, + }; + +- ppp_lock(ppp); +- if (ppp->pass_filter) { +- bpf_prog_destroy(ppp->pass_filter); +- ppp->pass_filter = NULL; ++ err = 0; ++ if (fprog.filter) ++ err = bpf_prog_create(&pass_filter, &fprog); ++ if (!err) { ++ ppp_lock(ppp); ++ if (ppp->pass_filter) ++ bpf_prog_destroy(ppp->pass_filter); ++ ppp->pass_filter = pass_filter; ++ ppp_unlock(ppp); + } +- if (fprog.filter != NULL) +- err = bpf_prog_create(&ppp->pass_filter, +- &fprog); +- else +- err = 0; + kfree(code); +- ppp_unlock(ppp); + } + break; + } +@@ -781,23 +781,23 @@ static long ppp_ioctl(struct file *file, + + err = get_filter(argp, &code); + if (err >= 0) { ++ struct bpf_prog *active_filter = NULL; + struct sock_fprog_kern fprog = { + .len = err, + .filter = code, + }; + +- ppp_lock(ppp); +- if (ppp->active_filter) { +- bpf_prog_destroy(ppp->active_filter); +- ppp->active_filter = NULL; ++ err = 0; ++ if (fprog.filter) ++ err = bpf_prog_create(&active_filter, &fprog); ++ if (!err) { ++ ppp_lock(ppp); ++ if (ppp->active_filter) ++ bpf_prog_destroy(ppp->active_filter); ++ ppp->active_filter = active_filter; ++ ppp_unlock(ppp); + } +- if (fprog.filter != NULL) +- err = bpf_prog_create(&ppp->active_filter, +- &fprog); +- else +- err = 0; + kfree(code); +- ppp_unlock(ppp); + } + break; + } diff --git a/queue-3.17/net-ptp-fix-time-stamp-matching-logic-for-vlan-packets.patch b/queue-3.17/net-ptp-fix-time-stamp-matching-logic-for-vlan-packets.patch new file mode 100644 index 00000000000..027ff86d71e --- /dev/null +++ b/queue-3.17/net-ptp-fix-time-stamp-matching-logic-for-vlan-packets.patch @@ -0,0 +1,58 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Richard Cochran +Date: Wed, 12 Nov 2014 11:33:52 +0100 +Subject: net: ptp: fix time stamp matching logic for VLAN packets. + +From: Richard Cochran + +[ Upstream commit cca04b2854ecfb7cd1b8ee84ab38bc99af59f526 ] + +Commit ae5c6c6d "ptp: Classify ptp over ip over vlan packets" changed the +code in two drivers that matches time stamps with PTP frames, with the goal +of allowing VLAN tagged PTP packets to receive hardware time stamps. + +However, that commit failed to account for the VLAN header when parsing +IPv4 packets. This patch fixes those two drivers to correctly match VLAN +tagged IPv4/UDP PTP messages with their time stamps. + +This patch should also be applied to v3.17. + +Signed-off-by: Richard Cochran +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/ti/cpts.c | 2 +- + drivers/net/phy/dp83640.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/ti/cpts.c ++++ b/drivers/net/ethernet/ti/cpts.c +@@ -264,7 +264,7 @@ static int cpts_match(struct sk_buff *sk + + switch (ptp_class & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: +- offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; ++ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; + break; + case PTP_CLASS_IPV6: + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; +--- a/drivers/net/phy/dp83640.c ++++ b/drivers/net/phy/dp83640.c +@@ -784,7 +784,7 @@ static int match(struct sk_buff *skb, un + + switch (type & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: +- offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; ++ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; + break; + case PTP_CLASS_IPV6: + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; +@@ -927,7 +927,7 @@ static int is_sync(struct sk_buff *skb, + + switch (type & PTP_CLASS_PMASK) { + case PTP_CLASS_IPV4: +- offset += ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; ++ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; + break; + case PTP_CLASS_IPV6: + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; diff --git a/queue-3.17/net-sctp-fix-memory-leak-in-auth-key-management.patch b/queue-3.17/net-sctp-fix-memory-leak-in-auth-key-management.patch new file mode 100644 index 00000000000..64b80fa3e0b --- /dev/null +++ b/queue-3.17/net-sctp-fix-memory-leak-in-auth-key-management.patch @@ -0,0 +1,57 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Daniel Borkmann +Date: Mon, 10 Nov 2014 18:00:09 +0100 +Subject: net: sctp: fix memory leak in auth key management + +From: Daniel Borkmann + +[ Upstream commit 4184b2a79a7612a9272ce20d639934584a1f3786 ] + +A very minimal and simple user space application allocating an SCTP +socket, setting SCTP_AUTH_KEY setsockopt(2) on it and then closing +the socket again will leak the memory containing the authentication +key from user space: + +unreferenced object 0xffff8800837047c0 (size 16): + comm "a.out", pid 2789, jiffies 4296954322 (age 192.258s) + hex dump (first 16 bytes): + 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................ + backtrace: + [] kmemleak_alloc+0x4e/0xb0 + [] __kmalloc+0xe8/0x270 + [] sctp_auth_create_key+0x23/0x50 [sctp] + [] sctp_auth_set_key+0xa1/0x140 [sctp] + [] sctp_setsockopt+0xd03/0x1180 [sctp] + [] sock_common_setsockopt+0x14/0x20 + [] SyS_setsockopt+0x71/0xd0 + [] system_call_fastpath+0x12/0x17 + [] 0xffffffffffffffff + +This is bad because of two things, we can bring down a machine from +user space when auth_enable=1, but also we would leave security sensitive +keying material in memory without clearing it after use. The issue is +that sctp_auth_create_key() already sets the refcount to 1, but after +allocation sctp_auth_set_key() does an additional refcount on it, and +thus leaving it around when we free the socket. + +Fixes: 65b07e5d0d0 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") +Signed-off-by: Daniel Borkmann +Cc: Vlad Yasevich +Acked-by: Neil Horman +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/auth.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/net/sctp/auth.c ++++ b/net/sctp/auth.c +@@ -862,8 +862,6 @@ int sctp_auth_set_key(struct sctp_endpoi + list_add(&cur_key->key_list, sh_keys); + + cur_key->key = key; +- sctp_auth_key_hold(key); +- + return 0; + nomem: + if (!replace) diff --git a/queue-3.17/net-sctp-fix-null-pointer-dereference-in-af-from_addr_param-on-malformed-packet.patch b/queue-3.17/net-sctp-fix-null-pointer-dereference-in-af-from_addr_param-on-malformed-packet.patch new file mode 100644 index 00000000000..01d36cf0414 --- /dev/null +++ b/queue-3.17/net-sctp-fix-null-pointer-dereference-in-af-from_addr_param-on-malformed-packet.patch @@ -0,0 +1,77 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Daniel Borkmann +Date: Mon, 10 Nov 2014 17:54:26 +0100 +Subject: net: sctp: fix NULL pointer dereference in af->from_addr_param on malformed packet + +From: Daniel Borkmann + +[ Upstream commit e40607cbe270a9e8360907cb1e62ddf0736e4864 ] + +An SCTP server doing ASCONF will panic on malformed INIT ping-of-death +in the form of: + + ------------ INIT[PARAM: SET_PRIMARY_IP] ------------> + +While the INIT chunk parameter verification dissects through many things +in order to detect malformed input, it misses to actually check parameters +inside of parameters. E.g. RFC5061, section 4.2.4 proposes a 'set primary +IP address' parameter in ASCONF, which has as a subparameter an address +parameter. + +So an attacker may send a parameter type other than SCTP_PARAM_IPV4_ADDRESS +or SCTP_PARAM_IPV6_ADDRESS, param_type2af() will subsequently return 0 +and thus sctp_get_af_specific() returns NULL, too, which we then happily +dereference unconditionally through af->from_addr_param(). + +The trace for the log: + +BUG: unable to handle kernel NULL pointer dereference at 0000000000000078 +IP: [] sctp_process_init+0x492/0x990 [sctp] +PGD 0 +Oops: 0000 [#1] SMP +[...] +Pid: 0, comm: swapper Not tainted 2.6.32-504.el6.x86_64 #1 Bochs Bochs +RIP: 0010:[] [] sctp_process_init+0x492/0x990 [sctp] +[...] +Call Trace: + + [] ? sctp_bind_addr_copy+0x5d/0xe0 [sctp] + [] sctp_sf_do_5_1B_init+0x21b/0x340 [sctp] + [] sctp_do_sm+0x71/0x1210 [sctp] + [] ? sctp_endpoint_lookup_assoc+0xc9/0xf0 [sctp] + [] sctp_endpoint_bh_rcv+0x116/0x230 [sctp] + [] sctp_inq_push+0x56/0x80 [sctp] + [] sctp_rcv+0x982/0xa10 [sctp] + [] ? ipt_local_in_hook+0x23/0x28 [iptable_filter] + [] ? nf_iterate+0x69/0xb0 + [] ? ip_local_deliver_finish+0x0/0x2d0 + [] ? nf_hook_slow+0x76/0x120 + [] ? ip_local_deliver_finish+0x0/0x2d0 +[...] + +A minimal way to address this is to check for NULL as we do on all +other such occasions where we know sctp_get_af_specific() could +possibly return with NULL. + +Fixes: d6de3097592b ("[SCTP]: Add the handling of "Set Primary IP Address" parameter to INIT") +Signed-off-by: Daniel Borkmann +Cc: Vlad Yasevich +Acked-by: Neil Horman +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/sm_make_chunk.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -2609,6 +2609,9 @@ do_addr_param: + addr_param = param.v + sizeof(sctp_addip_param_t); + + af = sctp_get_af_specific(param_type2af(param.p->type)); ++ if (af == NULL) ++ break; ++ + af->from_addr_param(&addr, addr_param, + htons(asoc->peer.port), 0); + diff --git a/queue-3.17/netlink-properly-unbind-in-error-conditions.patch b/queue-3.17/netlink-properly-unbind-in-error-conditions.patch new file mode 100644 index 00000000000..70d0b3d6704 --- /dev/null +++ b/queue-3.17/netlink-properly-unbind-in-error-conditions.patch @@ -0,0 +1,54 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Hiroaki SHIMODA +Date: Thu, 13 Nov 2014 04:24:10 +0900 +Subject: netlink: Properly unbind in error conditions. + +From: Hiroaki SHIMODA + +[ Upstream commit 6251edd932ce3faadbfe27b0a0fe79780e0972e9 ] + +Even if netlink_kernel_cfg::unbind is implemented the unbind() method is +not called, because cfg->unbind is omitted in __netlink_kernel_create(). +And fix wrong argument of test_bit() and off by one problem. + +At this point, no unbind() method is implemented, so there is no real +issue. + +Fixes: 4f520900522f ("netlink: have netlink per-protocol bind function return an error code.") +Signed-off-by: Hiroaki SHIMODA +Cc: Richard Guy Briggs +Acked-by: Richard Guy Briggs +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/netlink/af_netlink.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -1440,7 +1440,7 @@ static void netlink_unbind(int group, lo + return; + + for (undo = 0; undo < group; undo++) +- if (test_bit(group, &groups)) ++ if (test_bit(undo, &groups)) + nlk->netlink_unbind(undo); + } + +@@ -1492,7 +1492,7 @@ static int netlink_bind(struct socket *s + netlink_insert(sk, net, nladdr->nl_pid) : + netlink_autobind(sock); + if (err) { +- netlink_unbind(nlk->ngroups - 1, groups, nlk); ++ netlink_unbind(nlk->ngroups, groups, nlk); + return err; + } + } +@@ -2509,6 +2509,7 @@ __netlink_kernel_create(struct net *net, + nl_table[unit].module = module; + if (cfg) { + nl_table[unit].bind = cfg->bind; ++ nl_table[unit].unbind = cfg->unbind; + nl_table[unit].flags = cfg->flags; + if (cfg->compare) + nl_table[unit].compare = cfg->compare; diff --git a/queue-3.17/series b/queue-3.17/series index a12bfb65197..961fb90bfd7 100644 --- a/queue-3.17/series +++ b/queue-3.17/series @@ -1 +1,25 @@ x86-build-add-arch-x86-purgatory-make-generated-files-to-gitignore.patch +inet-frags-fix-a-race-between-inet_evict_bucket-and-inet_frag_kill.patch +inet-frags-remove-the-warn_on-from-inet_evict_bucket.patch +ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch +vti6-use-vti6_dev_init-as-the-ndo_init-function.patch +sit-use-ipip6_tunnel_init-as-the-ndo_init-function.patch +gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch +net-mv643xx_eth-reclaim-tx-skbs-only-when-released-by-the-hw.patch +udptunnel-add-skb_gso_udp_tunnel-during-gro_complete.patch +vxlan-do-not-reuse-sockets-for-a-different-address-family.patch +net-ppp-don-t-call-bpf_prog_create-in-ppp_lock.patch +net-sctp-fix-null-pointer-dereference-in-af-from_addr_param-on-malformed-packet.patch +net-sctp-fix-memory-leak-in-auth-key-management.patch +ipv6-fix-ipv6_pktinfo-with-v4-mapped.patch +net-ptp-fix-time-stamp-matching-logic-for-vlan-packets.patch +netlink-properly-unbind-in-error-conditions.patch +smsc911x-power-up-phydev-before-doing-a-software-reset.patch +sunvdc-add-cdrom-and-v1.1-protocol-support.patch +sunvdc-compute-vdisk-geometry-from-capacity.patch +sunvdc-limit-each-sg-segment-to-a-page.patch +vio-fix-reuse-of-vio_dring-slot.patch +sunvdc-don-t-call-vd_op_get_vtoc.patch +sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch +sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch +sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch diff --git a/queue-3.17/sit-use-ipip6_tunnel_init-as-the-ndo_init-function.patch b/queue-3.17/sit-use-ipip6_tunnel_init-as-the-ndo_init-function.patch new file mode 100644 index 00000000000..75f45d694e7 --- /dev/null +++ b/queue-3.17/sit-use-ipip6_tunnel_init-as-the-ndo_init-function.patch @@ -0,0 +1,75 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Steffen Klassert +Date: Mon, 3 Nov 2014 09:19:29 +0100 +Subject: sit: Use ipip6_tunnel_init as the ndo_init function. + +From: Steffen Klassert + +[ Upstream commit ebe084aafb7e93adf210e80043c9f69adf56820d ] + +ipip6_tunnel_init() sets the dev->iflink via a call to +ipip6_tunnel_bind_dev(). After that, register_netdevice() +sets dev->iflink = -1. So we loose the iflink configuration +for ipv6 tunnels. Fix this by using ipip6_tunnel_init() as the +ndo_init function. Then ipip6_tunnel_init() is called after +dev->iflink is set to -1 from register_netdevice(). + +Signed-off-by: Steffen Klassert +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/sit.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +--- a/net/ipv6/sit.c ++++ b/net/ipv6/sit.c +@@ -195,10 +195,8 @@ static int ipip6_tunnel_create(struct ne + struct sit_net *sitn = net_generic(net, sit_net_id); + int err; + +- err = ipip6_tunnel_init(dev); +- if (err < 0) +- goto out; +- ipip6_tunnel_clone_6rd(dev, sitn); ++ memcpy(dev->dev_addr, &t->parms.iph.saddr, 4); ++ memcpy(dev->broadcast, &t->parms.iph.daddr, 4); + + if ((__force u16)t->parms.i_flags & SIT_ISATAP) + dev->priv_flags |= IFF_ISATAP; +@@ -207,7 +205,8 @@ static int ipip6_tunnel_create(struct ne + if (err < 0) + goto out; + +- strcpy(t->parms.name, dev->name); ++ ipip6_tunnel_clone_6rd(dev, sitn); ++ + dev->rtnl_link_ops = &sit_link_ops; + + dev_hold(dev); +@@ -1314,6 +1313,7 @@ static int ipip6_tunnel_change_mtu(struc + } + + static const struct net_device_ops ipip6_netdev_ops = { ++ .ndo_init = ipip6_tunnel_init, + .ndo_uninit = ipip6_tunnel_uninit, + .ndo_start_xmit = sit_tunnel_xmit, + .ndo_do_ioctl = ipip6_tunnel_ioctl, +@@ -1359,9 +1359,7 @@ static int ipip6_tunnel_init(struct net_ + + tunnel->dev = dev; + tunnel->net = dev_net(dev); +- +- memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); +- memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); ++ strcpy(tunnel->parms.name, dev->name); + + ipip6_tunnel_bind_dev(dev); + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); +@@ -1386,7 +1384,6 @@ static int __net_init ipip6_fb_tunnel_in + + tunnel->dev = dev; + tunnel->net = dev_net(dev); +- strcpy(tunnel->parms.name, dev->name); + + iph->version = 4; + iph->protocol = IPPROTO_IPV6; diff --git a/queue-3.17/smsc911x-power-up-phydev-before-doing-a-software-reset.patch b/queue-3.17/smsc911x-power-up-phydev-before-doing-a-software-reset.patch new file mode 100644 index 00000000000..b4618153ffc --- /dev/null +++ b/queue-3.17/smsc911x-power-up-phydev-before-doing-a-software-reset.patch @@ -0,0 +1,94 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Enric Balletbo i Serra +Date: Thu, 13 Nov 2014 09:14:34 +0100 +Subject: smsc911x: power-up phydev before doing a software reset. + +From: Enric Balletbo i Serra + +[ Upstream commit ccf899a27c08038db91765ff12bb0380dcd85887 ] + +With commit be9dad1f9f26604fb ("net: phy: suspend phydev when going +to HALTED"), the PHY device will be put in a low-power mode using +BMCR_PDOWN if the the interface is set down. The smsc911x driver does +a software_reset opening the device driver (ndo_open). In such case, +the PHY must be powered-up before access to any register and before +calling the software_reset function. Otherwise, as the PHY is powered +down the software reset fails and the interface can not be enabled +again. + +This patch fixes this scenario that is easy to reproduce setting down +the network interface and setting up again. + + $ ifconfig eth0 down + $ ifconfig eth0 up + ifconfig: SIOCSIFFLAGS: Input/output error + +Signed-off-by: Enric Balletbo i Serra +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/smsc/smsc911x.c | 46 +++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +--- a/drivers/net/ethernet/smsc/smsc911x.c ++++ b/drivers/net/ethernet/smsc/smsc911x.c +@@ -1342,6 +1342,42 @@ static void smsc911x_rx_multicast_update + spin_unlock(&pdata->mac_lock); + } + ++static int smsc911x_phy_general_power_up(struct smsc911x_data *pdata) ++{ ++ int rc = 0; ++ ++ if (!pdata->phy_dev) ++ return rc; ++ ++ /* If the internal PHY is in General Power-Down mode, all, except the ++ * management interface, is powered-down and stays in that condition as ++ * long as Phy register bit 0.11 is HIGH. ++ * ++ * In that case, clear the bit 0.11, so the PHY powers up and we can ++ * access to the phy registers. ++ */ ++ rc = phy_read(pdata->phy_dev, MII_BMCR); ++ if (rc < 0) { ++ SMSC_WARN(pdata, drv, "Failed reading PHY control reg"); ++ return rc; ++ } ++ ++ /* If the PHY general power-down bit is not set is not necessary to ++ * disable the general power down-mode. ++ */ ++ if (rc & BMCR_PDOWN) { ++ rc = phy_write(pdata->phy_dev, MII_BMCR, rc & ~BMCR_PDOWN); ++ if (rc < 0) { ++ SMSC_WARN(pdata, drv, "Failed writing PHY control reg"); ++ return rc; ++ } ++ ++ usleep_range(1000, 1500); ++ } ++ ++ return 0; ++} ++ + static int smsc911x_phy_disable_energy_detect(struct smsc911x_data *pdata) + { + int rc = 0; +@@ -1415,6 +1451,16 @@ static int smsc911x_soft_reset(struct sm + int ret; + + /* ++ * Make sure to power-up the PHY chip before doing a reset, otherwise ++ * the reset fails. ++ */ ++ ret = smsc911x_phy_general_power_up(pdata); ++ if (ret) { ++ SMSC_WARN(pdata, drv, "Failed to power-up the PHY chip"); ++ return ret; ++ } ++ ++ /* + * LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that + * are initialized in a Energy Detect Power-Down mode that prevents + * the MAC chip to be software reseted. So we have to wakeup the PHY diff --git a/queue-3.17/sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch b/queue-3.17/sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch new file mode 100644 index 00000000000..f2b61f4141c --- /dev/null +++ b/queue-3.17/sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch @@ -0,0 +1,100 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: Andreas Larsson +Date: Wed, 5 Nov 2014 15:52:08 +0100 +Subject: sparc32: Implement xchg and atomic_xchg using ATOMIC_HASH locks + +From: Andreas Larsson + +[ Upstream commit 1a17fdc4f4ed06b63fac1937470378a5441a663a ] + +Atomicity between xchg and cmpxchg cannot be guaranteed when xchg is +implemented with a swap and cmpxchg is implemented with locks. +Without this, e.g. mcs_spin_lock and mcs_spin_unlock are broken. + +Signed-off-by: Andreas Larsson +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/include/asm/atomic_32.h | 2 +- + arch/sparc/include/asm/cmpxchg_32.h | 12 ++---------- + arch/sparc/lib/atomic32.c | 27 +++++++++++++++++++++++++++ + 3 files changed, 30 insertions(+), 11 deletions(-) + +--- a/arch/sparc/include/asm/atomic_32.h ++++ b/arch/sparc/include/asm/atomic_32.h +@@ -22,7 +22,7 @@ + + int __atomic_add_return(int, atomic_t *); + int atomic_cmpxchg(atomic_t *, int, int); +-#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) ++int atomic_xchg(atomic_t *, int); + int __atomic_add_unless(atomic_t *, int, int); + void atomic_set(atomic_t *, int); + +--- a/arch/sparc/include/asm/cmpxchg_32.h ++++ b/arch/sparc/include/asm/cmpxchg_32.h +@@ -11,22 +11,14 @@ + #ifndef __ARCH_SPARC_CMPXCHG__ + #define __ARCH_SPARC_CMPXCHG__ + +-static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) +-{ +- __asm__ __volatile__("swap [%2], %0" +- : "=&r" (val) +- : "0" (val), "r" (m) +- : "memory"); +- return val; +-} +- ++unsigned long __xchg_u32(volatile u32 *m, u32 new); + void __xchg_called_with_bad_pointer(void); + + static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) + { + switch (size) { + case 4: +- return xchg_u32(ptr, x); ++ return __xchg_u32(ptr, x); + } + __xchg_called_with_bad_pointer(); + return x; +--- a/arch/sparc/lib/atomic32.c ++++ b/arch/sparc/lib/atomic32.c +@@ -40,6 +40,19 @@ int __atomic_add_return(int i, atomic_t + } + EXPORT_SYMBOL(__atomic_add_return); + ++int atomic_xchg(atomic_t *v, int new) ++{ ++ int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(ATOMIC_HASH(v), flags); ++ ret = v->counter; ++ v->counter = new; ++ spin_unlock_irqrestore(ATOMIC_HASH(v), flags); ++ return ret; ++} ++EXPORT_SYMBOL(atomic_xchg); ++ + int atomic_cmpxchg(atomic_t *v, int old, int new) + { + int ret; +@@ -132,3 +145,17 @@ unsigned long __cmpxchg_u32(volatile u32 + return (unsigned long)prev; + } + EXPORT_SYMBOL(__cmpxchg_u32); ++ ++unsigned long __xchg_u32(volatile u32 *ptr, u32 new) ++{ ++ unsigned long flags; ++ u32 prev; ++ ++ spin_lock_irqsave(ATOMIC_HASH(ptr), flags); ++ prev = *ptr; ++ *ptr = new; ++ spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags); ++ ++ return (unsigned long)prev; ++} ++EXPORT_SYMBOL(__xchg_u32); diff --git a/queue-3.17/sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch b/queue-3.17/sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch new file mode 100644 index 00000000000..258d50ac8f3 --- /dev/null +++ b/queue-3.17/sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch @@ -0,0 +1,80 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: "David S. Miller" +Date: Fri, 7 Nov 2014 09:50:48 -0800 +Subject: sparc64: Do irq_{enter,exit}() around generic_smp_call_function*(). + +From: "David S. Miller" + +[ Upstream commit ab5c780913bca0a5763ca05dd5c2cb5cb08ccb26 ] + +Otherwise rcu_irq_{enter,exit}() do not happen and we get dumps like: + +==================== +[ 188.275021] =============================== +[ 188.309351] [ INFO: suspicious RCU usage. ] +[ 188.343737] 3.18.0-rc3-00068-g20f3963-dirty #54 Not tainted +[ 188.394786] ------------------------------- +[ 188.429170] include/linux/rcupdate.h:883 rcu_read_lock() used +illegally while idle! +[ 188.505235] +other info that might help us debug this: + +[ 188.554230] +RCU used illegally from idle CPU! +rcu_scheduler_active = 1, debug_locks = 0 +[ 188.637587] RCU used illegally from extended quiescent state! +[ 188.690684] 3 locks held by swapper/7/0: +[ 188.721932] #0: (&x->wait#11){......}, at: [<0000000000495de8>] complete+0x8/0x60 +[ 188.797994] #1: (&p->pi_lock){-.-.-.}, at: [<000000000048510c>] try_to_wake_up+0xc/0x400 +[ 188.881343] #2: (rcu_read_lock){......}, at: [<000000000048a910>] select_task_rq_fair+0x90/0xb40 +[ 188.973043]stack backtrace: +[ 188.993879] CPU: 7 PID: 0 Comm: swapper/7 Not tainted 3.18.0-rc3-00068-g20f3963-dirty #54 +[ 189.076187] Call Trace: +[ 189.089719] [0000000000499360] lockdep_rcu_suspicious+0xe0/0x100 +[ 189.147035] [000000000048a99c] select_task_rq_fair+0x11c/0xb40 +[ 189.202253] [00000000004852d8] try_to_wake_up+0x1d8/0x400 +[ 189.252258] [000000000048554c] default_wake_function+0xc/0x20 +[ 189.306435] [0000000000495554] __wake_up_common+0x34/0x80 +[ 189.356448] [00000000004955b4] __wake_up_locked+0x14/0x40 +[ 189.406456] [0000000000495e08] complete+0x28/0x60 +[ 189.448142] [0000000000636e28] blk_end_sync_rq+0x8/0x20 +[ 189.496057] [0000000000639898] __blk_mq_end_request+0x18/0x60 +[ 189.550249] [00000000006ee014] scsi_end_request+0x94/0x180 +[ 189.601286] [00000000006ee334] scsi_io_completion+0x1d4/0x600 +[ 189.655463] [00000000006e51c4] scsi_finish_command+0xc4/0xe0 +[ 189.708598] [00000000006ed958] scsi_softirq_done+0x118/0x140 +[ 189.761735] [00000000006398ec] __blk_mq_complete_request_remote+0xc/0x20 +[ 189.827383] [00000000004c75d0] generic_smp_call_function_single_interrupt+0x150/0x1c0 +[ 189.906581] [000000000043e514] smp_call_function_single_client+0x14/0x40 +==================== + +Based almost entirely upon a patch by Paul E. McKenney. + +Reported-by: Meelis Roos +Tested-by: Meelis Roos +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/kernel/smp_64.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/sparc/kernel/smp_64.c ++++ b/arch/sparc/kernel/smp_64.c +@@ -816,13 +816,17 @@ void arch_send_call_function_single_ipi( + void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs) + { + clear_softint(1 << irq); ++ irq_enter(); + generic_smp_call_function_interrupt(); ++ irq_exit(); + } + + void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs) + { + clear_softint(1 << irq); ++ irq_enter(); + generic_smp_call_function_single_interrupt(); ++ irq_exit(); + } + + static void tsb_sync(void *info) diff --git a/queue-3.17/sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch b/queue-3.17/sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch new file mode 100644 index 00000000000..df107a24552 --- /dev/null +++ b/queue-3.17/sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch @@ -0,0 +1,99 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: "David S. Miller" +Date: Sat, 1 Nov 2014 00:33:58 -0400 +Subject: sparc64: Fix crashes in schizo_pcierr_intr_other(). + +From: "David S. Miller" + +[ Upstream commit 7da89a2a3776442a57e918ca0b8678d1b16a7072 ] + +Meelis Roos reports crashes during bootup on a V480 that look like +this: + +==================== +[ 61.300577] PCI: Scanning PBM /pci@9,600000 +[ 61.304867] schizo f009b070: PCI host bridge to bus 0003:00 +[ 61.310385] pci_bus 0003:00: root bus resource [io 0x7ffe9000000-0x7ffe9ffffff] (bus address [0x0000-0xffffff]) +[ 61.320515] pci_bus 0003:00: root bus resource [mem 0x7fb00000000-0x7fbffffffff] (bus address [0x00000000-0xffffffff]) +[ 61.331173] pci_bus 0003:00: root bus resource [bus 00] +[ 61.385344] Unable to handle kernel NULL pointer dereference +[ 61.390970] tsk->{mm,active_mm}->context = 0000000000000000 +[ 61.396515] tsk->{mm,active_mm}->pgd = fff000b000002000 +[ 61.401716] \|/ ____ \|/ +[ 61.401716] "@'/ .. \`@" +[ 61.401716] /_| \__/ |_\ +[ 61.401716] \__U_/ +[ 61.416362] swapper/0(0): Oops [#1] +[ 61.419837] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.18.0-rc1-00422-g2cc9188-dirty #24 +[ 61.427975] task: fff000b0fd8e9c40 ti: fff000b0fd928000 task.ti: fff000b0fd928000 +[ 61.435426] TSTATE: 0000004480e01602 TPC: 00000000004455e4 TNPC: 00000000004455e8 Y: 00000000 Not tainted +[ 61.445230] TPC: +[ 61.449897] g0: 0000000000000000 g1: 0000000000000000 g2: 0000000000a10f78 g3: 000000000000000a +[ 61.458563] g4: fff000b0fd8e9c40 g5: fff000b0fdd82000 g6: fff000b0fd928000 g7: 000000000000000a +[ 61.467229] o0: 000000000000003d o1: 0000000000000000 o2: 0000000000000006 o3: fff000b0ffa5fc7e +[ 61.475894] o4: 0000000000060000 o5: c000000000000000 sp: fff000b0ffa5f3c1 ret_pc: 00000000004455cc +[ 61.484909] RPC: +[ 61.489500] l0: fff000b0fd8e9c40 l1: 0000000000a20800 l2: 0000000000000000 l3: 000000000119a430 +[ 61.498164] l4: 0000000001742400 l5: 00000000011cfbe0 l6: 00000000011319c0 l7: fff000b0fd8ea348 +[ 61.506830] i0: 0000000000000000 i1: fff000b0fdb34000 i2: 0000000320000000 i3: 0000000000000000 +[ 61.515497] i4: 00060002010b003f i5: 0000040004e02000 i6: fff000b0ffa5f481 i7: 00000000004a9920 +[ 61.524175] I7: +[ 61.529099] Call Trace: +[ 61.531531] [00000000004a9920] handle_irq_event_percpu+0x40/0x140 +[ 61.537681] [00000000004a9a58] handle_irq_event+0x38/0x80 +[ 61.543145] [00000000004ac77c] handle_fasteoi_irq+0xbc/0x200 +[ 61.548860] [00000000004a9084] generic_handle_irq+0x24/0x40 +[ 61.554500] [000000000042be0c] handler_irq+0xac/0x100 +==================== + +The problem is that pbm->pci_bus->self is NULL. + +This code is trying to go through the standard PCI config space +interfaces to read the PCI controller's PCI_STATUS register. + +This doesn't work, because we more often than not do not enumerate +the PCI controller as a bonafide PCI device during the OF device +node scan. Therefore bus->self remains NULL. + +Existing common code for PSYCHO and PSYCHO-like PCI controllers +handles this properly, by doing the config space access directly. + +Do the same here, pbm->pci_ops->{read,write}(). + +Reported-by: Meelis Roos +Tested-by: Meelis Roos +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/kernel/pci_schizo.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/sparc/kernel/pci_schizo.c ++++ b/arch/sparc/kernel/pci_schizo.c +@@ -581,7 +581,7 @@ static irqreturn_t schizo_pcierr_intr_ot + { + unsigned long csr_reg, csr, csr_error_bits; + irqreturn_t ret = IRQ_NONE; +- u16 stat; ++ u32 stat; + + csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL; + csr = upa_readq(csr_reg); +@@ -617,7 +617,7 @@ static irqreturn_t schizo_pcierr_intr_ot + pbm->name); + ret = IRQ_HANDLED; + } +- pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat); ++ pbm->pci_ops->read(pbm->pci_bus, 0, PCI_STATUS, 2, &stat); + if (stat & (PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | +@@ -625,7 +625,7 @@ static irqreturn_t schizo_pcierr_intr_ot + PCI_STATUS_SIG_SYSTEM_ERROR)) { + printk("%s: PCI bus error, PCI_STATUS[%04x]\n", + pbm->name, stat); +- pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff); ++ pbm->pci_ops->write(pbm->pci_bus, 0, PCI_STATUS, 2, 0xffff); + ret = IRQ_HANDLED; + } + return ret; diff --git a/queue-3.17/sunvdc-add-cdrom-and-v1.1-protocol-support.patch b/queue-3.17/sunvdc-add-cdrom-and-v1.1-protocol-support.patch new file mode 100644 index 00000000000..7bdb0e5c822 --- /dev/null +++ b/queue-3.17/sunvdc-add-cdrom-and-v1.1-protocol-support.patch @@ -0,0 +1,246 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: Allen Pais +Date: Fri, 19 Sep 2014 09:42:14 -0400 +Subject: sunvdc: add cdrom and v1.1 protocol support + +From: Allen Pais + +[ Upstream commit 9bce21828d54a95143f1b74619705c2dd8e88b92 ] + +Interpret the media type from v1.1 protocol to support CDROM/DVD. + +For v1.0 protocol, a disk's size continues to be calculated from the +geometry returned by the vdisk server. The geometry returned by the server +can be less than the actual number of sectors available in the backing +image/device due to the rounding in the division used to compute the +geometry in the vdisk server. + +In v1.1 protocol a disk's actual size in sectors is returned during the +handshake. Use this size when v1.1 protocol is negotiated. Since this size +will always be larger than the former geometry computed size, disks created +under v1.0 will be forwards compatible to v1.1, but not vice versa. + +Signed-off-by: Dwight Engen +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/include/asm/vio.h | 12 +++- + drivers/block/sunvdc.c | 109 ++++++++++++++++++++++++++++++++++++------- + 2 files changed, 101 insertions(+), 20 deletions(-) + +--- a/arch/sparc/include/asm/vio.h ++++ b/arch/sparc/include/asm/vio.h +@@ -118,12 +118,18 @@ struct vio_disk_attr_info { + u8 vdisk_type; + #define VD_DISK_TYPE_SLICE 0x01 /* Slice in block device */ + #define VD_DISK_TYPE_DISK 0x02 /* Entire block device */ +- u16 resv1; ++ u8 vdisk_mtype; /* v1.1 */ ++#define VD_MEDIA_TYPE_FIXED 0x01 /* Fixed device */ ++#define VD_MEDIA_TYPE_CD 0x02 /* CD Device */ ++#define VD_MEDIA_TYPE_DVD 0x03 /* DVD Device */ ++ u8 resv1; + u32 vdisk_block_size; + u64 operations; +- u64 vdisk_size; ++ u64 vdisk_size; /* v1.1 */ + u64 max_xfer_size; +- u64 resv2[2]; ++ u32 phys_block_size; /* v1.2 */ ++ u32 resv2; ++ u64 resv3[1]; + }; + + struct vio_disk_desc { +--- a/drivers/block/sunvdc.c ++++ b/drivers/block/sunvdc.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -22,8 +23,8 @@ + + #define DRV_MODULE_NAME "sunvdc" + #define PFX DRV_MODULE_NAME ": " +-#define DRV_MODULE_VERSION "1.0" +-#define DRV_MODULE_RELDATE "June 25, 2007" ++#define DRV_MODULE_VERSION "1.1" ++#define DRV_MODULE_RELDATE "February 13, 2013" + + static char version[] = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; +@@ -65,6 +66,7 @@ struct vdc_port { + u64 operations; + u32 vdisk_size; + u8 vdisk_type; ++ u8 vdisk_mtype; + + char disk_name[32]; + +@@ -79,9 +81,16 @@ static inline struct vdc_port *to_vdc_po + + /* Ordered from largest major to lowest */ + static struct vio_version vdc_versions[] = { ++ { .major = 1, .minor = 1 }, + { .major = 1, .minor = 0 }, + }; + ++static inline int vdc_version_supported(struct vdc_port *port, ++ u16 major, u16 minor) ++{ ++ return port->vio.ver.major == major && port->vio.ver.minor >= minor; ++} ++ + #define VDCBLK_NAME "vdisk" + static int vdc_major; + #define PARTITION_SHIFT 3 +@@ -103,9 +112,41 @@ static int vdc_getgeo(struct block_devic + return 0; + } + ++/* Add ioctl/CDROM_GET_CAPABILITY to support cdrom_id in udev ++ * when vdisk_mtype is VD_MEDIA_TYPE_CD or VD_MEDIA_TYPE_DVD. ++ * Needed to be able to install inside an ldom from an iso image. ++ */ ++static int vdc_ioctl(struct block_device *bdev, fmode_t mode, ++ unsigned command, unsigned long argument) ++{ ++ int i; ++ struct gendisk *disk; ++ ++ switch (command) { ++ case CDROMMULTISESSION: ++ pr_debug(PFX "Multisession CDs not supported\n"); ++ for (i = 0; i < sizeof(struct cdrom_multisession); i++) ++ if (put_user(0, (char __user *)(argument + i))) ++ return -EFAULT; ++ return 0; ++ ++ case CDROM_GET_CAPABILITY: ++ disk = bdev->bd_disk; ++ ++ if (bdev->bd_disk && (disk->flags & GENHD_FL_CD)) ++ return 0; ++ return -EINVAL; ++ ++ default: ++ pr_debug(PFX "ioctl %08x not supported\n", command); ++ return -EINVAL; ++ } ++} ++ + static const struct block_device_operations vdc_fops = { + .owner = THIS_MODULE, + .getgeo = vdc_getgeo, ++ .ioctl = vdc_ioctl, + }; + + static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for) +@@ -165,9 +206,9 @@ static int vdc_handle_attr(struct vio_dr + struct vio_disk_attr_info *pkt = arg; + + viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] " +- "xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n", ++ "mtype[0x%x] xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n", + pkt->tag.stype, pkt->operations, +- pkt->vdisk_size, pkt->vdisk_type, ++ pkt->vdisk_size, pkt->vdisk_type, pkt->vdisk_mtype, + pkt->xfer_mode, pkt->vdisk_block_size, + pkt->max_xfer_size); + +@@ -192,8 +233,11 @@ static int vdc_handle_attr(struct vio_dr + } + + port->operations = pkt->operations; +- port->vdisk_size = pkt->vdisk_size; + port->vdisk_type = pkt->vdisk_type; ++ if (vdc_version_supported(port, 1, 1)) { ++ port->vdisk_size = pkt->vdisk_size; ++ port->vdisk_mtype = pkt->vdisk_mtype; ++ } + if (pkt->max_xfer_size < port->max_xfer_size) + port->max_xfer_size = pkt->max_xfer_size; + port->vdisk_block_size = pkt->vdisk_block_size; +@@ -663,18 +707,25 @@ static int probe_disk(struct vdc_port *p + return err; + } + +- err = generic_request(port, VD_OP_GET_DISKGEOM, +- &port->geom, sizeof(port->geom)); +- if (err < 0) { +- printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " +- "error %d\n", err); +- return err; ++ if (vdc_version_supported(port, 1, 1)) { ++ /* vdisk_size should be set during the handshake, if it wasn't ++ * then the underlying disk is reserved by another system ++ */ ++ if (port->vdisk_size == -1) ++ return -ENODEV; ++ } else { ++ err = generic_request(port, VD_OP_GET_DISKGEOM, ++ &port->geom, sizeof(port->geom)); ++ if (err < 0) { ++ printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " ++ "error %d\n", err); ++ return err; ++ } ++ port->vdisk_size = ((u64)port->geom.num_cyl * ++ (u64)port->geom.num_hd * ++ (u64)port->geom.num_sec); + } + +- port->vdisk_size = ((u64)port->geom.num_cyl * +- (u64)port->geom.num_hd * +- (u64)port->geom.num_sec); +- + q = blk_init_queue(do_vdc_request, &port->vio.lock); + if (!q) { + printk(KERN_ERR PFX "%s: Could not allocate queue.\n", +@@ -704,9 +755,32 @@ static int probe_disk(struct vdc_port *p + + set_capacity(g, port->vdisk_size); + +- printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n", ++ if (vdc_version_supported(port, 1, 1)) { ++ switch (port->vdisk_mtype) { ++ case VD_MEDIA_TYPE_CD: ++ pr_info(PFX "Virtual CDROM %s\n", port->disk_name); ++ g->flags |= GENHD_FL_CD; ++ g->flags |= GENHD_FL_REMOVABLE; ++ set_disk_ro(g, 1); ++ break; ++ ++ case VD_MEDIA_TYPE_DVD: ++ pr_info(PFX "Virtual DVD %s\n", port->disk_name); ++ g->flags |= GENHD_FL_CD; ++ g->flags |= GENHD_FL_REMOVABLE; ++ set_disk_ro(g, 1); ++ break; ++ ++ case VD_MEDIA_TYPE_FIXED: ++ pr_info(PFX "Virtual Hard disk %s\n", port->disk_name); ++ break; ++ } ++ } ++ ++ pr_info(PFX "%s: %u sectors (%u MB) protocol %d.%d\n", + g->disk_name, +- port->vdisk_size, (port->vdisk_size >> (20 - 9))); ++ port->vdisk_size, (port->vdisk_size >> (20 - 9)), ++ port->vio.ver.major, port->vio.ver.minor); + + add_disk(g); + +@@ -765,6 +839,7 @@ static int vdc_port_probe(struct vio_dev + else + snprintf(port->disk_name, sizeof(port->disk_name), + VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26)); ++ port->vdisk_size = -1; + + err = vio_driver_init(&port->vio, vdev, VDEV_DISK, + vdc_versions, ARRAY_SIZE(vdc_versions), diff --git a/queue-3.17/sunvdc-compute-vdisk-geometry-from-capacity.patch b/queue-3.17/sunvdc-compute-vdisk-geometry-from-capacity.patch new file mode 100644 index 00000000000..dce87062677 --- /dev/null +++ b/queue-3.17/sunvdc-compute-vdisk-geometry-from-capacity.patch @@ -0,0 +1,76 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: Allen Pais +Date: Fri, 19 Sep 2014 09:42:26 -0400 +Subject: sunvdc: compute vdisk geometry from capacity + +From: Allen Pais + +[ Upstream commit de5b73f08468b4fc5e2f6d1505f650262622f78b ] + +The LDom diskserver doesn't return reliable geometry data. In addition, +the types for all fields in the vio_disk_geom are u16, which were being +truncated in the cast into the u8's of the Linux struct hd_geometry. + +Modify vdc_getgeo() to compute the geometry from the disk's capacity in a +manner consistent with xen-blkfront::blkif_getgeo(). + +Signed-off-by: Dwight Engen +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/sunvdc.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +--- a/drivers/block/sunvdc.c ++++ b/drivers/block/sunvdc.c +@@ -70,7 +70,6 @@ struct vdc_port { + + char disk_name[32]; + +- struct vio_disk_geom geom; + struct vio_disk_vtoc label; + }; + +@@ -103,11 +102,15 @@ static inline u32 vdc_tx_dring_avail(str + static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo) + { + struct gendisk *disk = bdev->bd_disk; +- struct vdc_port *port = disk->private_data; ++ sector_t nsect = get_capacity(disk); ++ sector_t cylinders = nsect; + +- geo->heads = (u8) port->geom.num_hd; +- geo->sectors = (u8) port->geom.num_sec; +- geo->cylinders = port->geom.num_cyl; ++ geo->heads = 0xff; ++ geo->sectors = 0x3f; ++ sector_div(cylinders, geo->heads * geo->sectors); ++ geo->cylinders = cylinders; ++ if ((sector_t)(geo->cylinders + 1) * geo->heads * geo->sectors < nsect) ++ geo->cylinders = 0xffff; + + return 0; + } +@@ -714,16 +717,18 @@ static int probe_disk(struct vdc_port *p + if (port->vdisk_size == -1) + return -ENODEV; + } else { ++ struct vio_disk_geom geom; ++ + err = generic_request(port, VD_OP_GET_DISKGEOM, +- &port->geom, sizeof(port->geom)); ++ &geom, sizeof(geom)); + if (err < 0) { + printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " + "error %d\n", err); + return err; + } +- port->vdisk_size = ((u64)port->geom.num_cyl * +- (u64)port->geom.num_hd * +- (u64)port->geom.num_sec); ++ port->vdisk_size = ((u64)geom.num_cyl * ++ (u64)geom.num_hd * ++ (u64)geom.num_sec); + } + + q = blk_init_queue(do_vdc_request, &port->vio.lock); diff --git a/queue-3.17/sunvdc-don-t-call-vd_op_get_vtoc.patch b/queue-3.17/sunvdc-don-t-call-vd_op_get_vtoc.patch new file mode 100644 index 00000000000..96e75fc217d --- /dev/null +++ b/queue-3.17/sunvdc-don-t-call-vd_op_get_vtoc.patch @@ -0,0 +1,48 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: Dwight Engen +Date: Thu, 30 Oct 2014 15:55:35 -0400 +Subject: sunvdc: don't call VD_OP_GET_VTOC + +From: Dwight Engen + +[ Upstream commit 85b0c6e62c48bb9179fd5b3e954f362fb346cbd5 ] + +The VD_OP_GET_VTOC operation will succeed only if the vdisk backend has a +VTOC label, otherwise it will fail. In particular, it will return error +48 (ENOTSUP) if the disk has an EFI label. VTOC disk labels are already +handled by directly reading the disk in block/partitions/sun.c (enabled by +CONFIG_SUN_PARTITION which defaults to y on SPARC). Since port->label is +unused in the driver, remove the call and the field. + +Signed-off-by: Dwight Engen +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/sunvdc.c | 9 --------- + 1 file changed, 9 deletions(-) + +--- a/drivers/block/sunvdc.c ++++ b/drivers/block/sunvdc.c +@@ -69,8 +69,6 @@ struct vdc_port { + u8 vdisk_mtype; + + char disk_name[32]; +- +- struct vio_disk_vtoc label; + }; + + static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) +@@ -710,13 +708,6 @@ static int probe_disk(struct vdc_port *p + if (comp.err) + return comp.err; + +- err = generic_request(port, VD_OP_GET_VTOC, +- &port->label, sizeof(port->label)); +- if (err < 0) { +- printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err); +- return err; +- } +- + if (vdc_version_supported(port, 1, 1)) { + /* vdisk_size should be set during the handshake, if it wasn't + * then the underlying disk is reserved by another system diff --git a/queue-3.17/sunvdc-limit-each-sg-segment-to-a-page.patch b/queue-3.17/sunvdc-limit-each-sg-segment-to-a-page.patch new file mode 100644 index 00000000000..c31e4c310c1 --- /dev/null +++ b/queue-3.17/sunvdc-limit-each-sg-segment-to-a-page.patch @@ -0,0 +1,40 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: Dwight Engen +Date: Fri, 19 Sep 2014 09:42:53 -0400 +Subject: sunvdc: limit each sg segment to a page + +From: Dwight Engen + +[ Upstream commit 5eed69ffd248c9f68f56c710caf07db134aef28b ] + +ldc_map_sg() could fail its check that the number of pages referred to +by the sg scatterlist was <= the number of cookies. + +This fixes the issue by doing a similar thing to the xen-blkfront driver, +ensuring that the scatterlist will only ever contain a segment count <= +port->ring_cookies, and each segment will be page aligned, and <= page +size. This ensures that the scatterlist is always mappable. + +Orabug: 19347817 +OraBZ: 15945 + +Signed-off-by: Dwight Engen +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/sunvdc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/block/sunvdc.c ++++ b/drivers/block/sunvdc.c +@@ -747,6 +747,10 @@ static int probe_disk(struct vdc_port *p + + port->disk = g; + ++ /* Each segment in a request is up to an aligned page in size. */ ++ blk_queue_segment_boundary(q, PAGE_SIZE - 1); ++ blk_queue_max_segment_size(q, PAGE_SIZE); ++ + blk_queue_max_segments(q, port->ring_cookies); + blk_queue_max_hw_sectors(q, port->max_xfer_size); + g->major = vdc_major; diff --git a/queue-3.17/udptunnel-add-skb_gso_udp_tunnel-during-gro_complete.patch b/queue-3.17/udptunnel-add-skb_gso_udp_tunnel-during-gro_complete.patch new file mode 100644 index 00000000000..f61c7600523 --- /dev/null +++ b/queue-3.17/udptunnel-add-skb_gso_udp_tunnel-during-gro_complete.patch @@ -0,0 +1,53 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Jesse Gross +Date: Mon, 10 Nov 2014 11:45:13 -0800 +Subject: udptunnel: Add SKB_GSO_UDP_TUNNEL during gro_complete. + +From: Jesse Gross + +[ Upstream commit cfdf1e1ba5bf55e095cf4bcaa9585c4759f239e8 ] + +When doing GRO processing for UDP tunnels, we never add +SKB_GSO_UDP_TUNNEL to gso_type - only the type of the inner protocol +is added (such as SKB_GSO_TCPV4). The result is that if the packet is +later resegmented we will do GSO but not treat it as a tunnel. This +results in UDP fragmentation of the outer header instead of (i.e.) TCP +segmentation of the inner header as was originally on the wire. + +Signed-off-by: Jesse Gross +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/vxlan.c | 2 ++ + include/net/udp_tunnel.h | 9 +++++++++ + 2 files changed, 11 insertions(+) + +--- a/drivers/net/vxlan.c ++++ b/drivers/net/vxlan.c +@@ -620,6 +620,8 @@ static int vxlan_gro_complete(struct sk_ + int vxlan_len = sizeof(struct vxlanhdr) + sizeof(struct ethhdr); + int err = -ENOSYS; + ++ udp_tunnel_gro_complete(skb, nhoff); ++ + eh = (struct ethhdr *)(skb->data + nhoff + sizeof(struct vxlanhdr)); + type = eh->h_proto; + +--- a/include/net/udp_tunnel.h ++++ b/include/net/udp_tunnel.h +@@ -26,6 +26,15 @@ struct udp_port_cfg { + use_udp6_rx_checksums:1; + }; + ++static inline void udp_tunnel_gro_complete(struct sk_buff *skb, int nhoff) ++{ ++ struct udphdr *uh; ++ ++ uh = (struct udphdr *)(skb->data + nhoff - sizeof(struct udphdr)); ++ skb_shinfo(skb)->gso_type |= uh->check ? ++ SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; ++} ++ + int udp_sock_create(struct net *net, struct udp_port_cfg *cfg, + struct socket **sockp); + diff --git a/queue-3.17/vio-fix-reuse-of-vio_dring-slot.patch b/queue-3.17/vio-fix-reuse-of-vio_dring-slot.patch new file mode 100644 index 00000000000..780c697f340 --- /dev/null +++ b/queue-3.17/vio-fix-reuse-of-vio_dring-slot.patch @@ -0,0 +1,145 @@ +From foo@baz Tue Nov 18 09:08:30 PST 2014 +From: Dwight Engen +Date: Fri, 19 Sep 2014 09:43:02 -0400 +Subject: vio: fix reuse of vio_dring slot + +From: Dwight Engen + +[ Upstream commit d0aedcd4f14a22e23b313f42b7e6e6ebfc0fbc31 ] + +vio_dring_avail() will allow use of every dring entry, but when the last +entry is allocated then dr->prod == dr->cons which is indistinguishable from +the ring empty condition. This causes the next allocation to reuse an entry. +When this happens in sunvdc, the server side vds driver begins nack'ing the +messages and ends up resetting the ldc channel. This problem does not effect +sunvnet since it checks for < 2. + +The fix here is to just never allocate the very last dring slot so that full +and empty are not the same condition. The request start path was changed to +check for the ring being full a bit earlier, and to stop the blk_queue if +there is no space left. The blk_queue will be restarted once the ring is +only half full again. The number of ring entries was increased to 512 which +matches the sunvnet and Solaris vdc drivers, and greatly reduces the +frequency of hitting the ring full condition and the associated blk_queue +stop/starting. The checks in sunvent were adjusted to account for +vio_dring_avail() returning 1 less. + +Orabug: 19441666 +OraBZ: 14983 + +Signed-off-by: Dwight Engen +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + arch/sparc/include/asm/vio.h | 2 - + drivers/block/sunvdc.c | 39 +++++++++++++++++++++---------------- + drivers/net/ethernet/sun/sunvnet.c | 4 +-- + 3 files changed, 26 insertions(+), 19 deletions(-) + +--- a/arch/sparc/include/asm/vio.h ++++ b/arch/sparc/include/asm/vio.h +@@ -265,7 +265,7 @@ static inline u32 vio_dring_avail(struct + unsigned int ring_size) + { + return (dr->pending - +- ((dr->prod - dr->cons) & (ring_size - 1))); ++ ((dr->prod - dr->cons) & (ring_size - 1)) - 1); + } + + #define VIO_MAX_TYPE_LEN 32 +--- a/drivers/block/sunvdc.c ++++ b/drivers/block/sunvdc.c +@@ -33,7 +33,7 @@ MODULE_DESCRIPTION("Sun LDOM virtual dis + MODULE_LICENSE("GPL"); + MODULE_VERSION(DRV_MODULE_VERSION); + +-#define VDC_TX_RING_SIZE 256 ++#define VDC_TX_RING_SIZE 512 + + #define WAITING_FOR_LINK_UP 0x01 + #define WAITING_FOR_TX_SPACE 0x02 +@@ -283,7 +283,9 @@ static void vdc_end_one(struct vdc_port + + __blk_end_request(req, (desc->status ? -EIO : 0), desc->size); + +- if (blk_queue_stopped(port->disk->queue)) ++ /* restart blk queue when ring is half emptied */ ++ if (blk_queue_stopped(port->disk->queue) && ++ vdc_tx_dring_avail(dr) * 100 / VDC_TX_RING_SIZE >= 50) + blk_start_queue(port->disk->queue); + } + +@@ -435,12 +437,6 @@ static int __send_request(struct request + for (i = 0; i < nsg; i++) + len += sg[i].length; + +- if (unlikely(vdc_tx_dring_avail(dr) < 1)) { +- blk_stop_queue(port->disk->queue); +- err = -ENOMEM; +- goto out; +- } +- + desc = vio_dring_cur(dr); + + err = ldc_map_sg(port->vio.lp, sg, nsg, +@@ -480,21 +476,32 @@ static int __send_request(struct request + port->req_id++; + dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1); + } +-out: + + return err; + } + +-static void do_vdc_request(struct request_queue *q) ++static void do_vdc_request(struct request_queue *rq) + { +- while (1) { +- struct request *req = blk_fetch_request(q); ++ struct request *req; + +- if (!req) ++ while ((req = blk_peek_request(rq)) != NULL) { ++ struct vdc_port *port; ++ struct vio_dring_state *dr; ++ ++ port = req->rq_disk->private_data; ++ dr = &port->vio.drings[VIO_DRIVER_TX_RING]; ++ if (unlikely(vdc_tx_dring_avail(dr) < 1)) ++ goto wait; ++ ++ blk_start_request(req); ++ ++ if (__send_request(req) < 0) { ++ blk_requeue_request(rq, req); ++wait: ++ /* Avoid pointless unplugs. */ ++ blk_stop_queue(rq); + break; +- +- if (__send_request(req) < 0) +- __blk_end_request_all(req, -EIO); ++ } + } + } + +--- a/drivers/net/ethernet/sun/sunvnet.c ++++ b/drivers/net/ethernet/sun/sunvnet.c +@@ -693,7 +693,7 @@ static int vnet_start_xmit(struct sk_buf + spin_lock_irqsave(&port->vio.lock, flags); + + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; +- if (unlikely(vnet_tx_dring_avail(dr) < 2)) { ++ if (unlikely(vnet_tx_dring_avail(dr) < 1)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + +@@ -749,7 +749,7 @@ static int vnet_start_xmit(struct sk_buf + dev->stats.tx_bytes += skb->len; + + dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); +- if (unlikely(vnet_tx_dring_avail(dr) < 2)) { ++ if (unlikely(vnet_tx_dring_avail(dr) < 1)) { + netif_stop_queue(dev); + if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr)) + netif_wake_queue(dev); diff --git a/queue-3.17/vti6-use-vti6_dev_init-as-the-ndo_init-function.patch b/queue-3.17/vti6-use-vti6_dev_init-as-the-ndo_init-function.patch new file mode 100644 index 00000000000..71203d7c961 --- /dev/null +++ b/queue-3.17/vti6-use-vti6_dev_init-as-the-ndo_init-function.patch @@ -0,0 +1,61 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Steffen Klassert +Date: Mon, 3 Nov 2014 09:19:28 +0100 +Subject: vti6: Use vti6_dev_init as the ndo_init function. + +From: Steffen Klassert + +[ Upstream commit 16a0231bf7dc3fb37e9b1f1cb1a277dc220b5c5e ] + +vti6_dev_init() sets the dev->iflink via a call to +vti6_link_config(). After that, register_netdevice() +sets dev->iflink = -1. So we loose the iflink configuration +for vti6 tunnels. Fix this by using vti6_dev_init() as the +ndo_init function. Then vti6_dev_init() is called after +dev->iflink is set to -1 from register_netdevice(). + +Signed-off-by: Steffen Klassert +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_vti.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +--- a/net/ipv6/ip6_vti.c ++++ b/net/ipv6/ip6_vti.c +@@ -172,10 +172,6 @@ static int vti6_tnl_create2(struct net_d + struct vti6_net *ip6n = net_generic(net, vti6_net_id); + int err; + +- err = vti6_dev_init(dev); +- if (err < 0) +- goto out; +- + err = register_netdevice(dev); + if (err < 0) + goto out; +@@ -783,6 +779,7 @@ static int vti6_change_mtu(struct net_de + } + + static const struct net_device_ops vti6_netdev_ops = { ++ .ndo_init = vti6_dev_init, + .ndo_uninit = vti6_dev_uninit, + .ndo_start_xmit = vti6_tnl_xmit, + .ndo_do_ioctl = vti6_ioctl, +@@ -852,16 +849,10 @@ static int __net_init vti6_fb_tnl_dev_in + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = dev_net(dev); + struct vti6_net *ip6n = net_generic(net, vti6_net_id); +- int err = vti6_dev_init_gen(dev); +- +- if (err) +- return err; + + t->parms.proto = IPPROTO_IPV6; + dev_hold(dev); + +- vti6_link_config(t); +- + rcu_assign_pointer(ip6n->tnls_wc[0], t); + return 0; + } diff --git a/queue-3.17/vxlan-do-not-reuse-sockets-for-a-different-address-family.patch b/queue-3.17/vxlan-do-not-reuse-sockets-for-a-different-address-family.patch new file mode 100644 index 00000000000..96f156820f5 --- /dev/null +++ b/queue-3.17/vxlan-do-not-reuse-sockets-for-a-different-address-family.patch @@ -0,0 +1,142 @@ +From foo@baz Tue Nov 18 09:07:25 PST 2014 +From: Marcelo Leitner +Date: Thu, 13 Nov 2014 14:43:08 -0200 +Subject: vxlan: Do not reuse sockets for a different address family + +From: Marcelo Leitner + +[ Upstream commit 19ca9fc1445b76b60d34148f7ff837b055f5dcf3 ] + +Currently, we only match against local port number in order to reuse +socket. But if this new vxlan wants an IPv6 socket and a IPv4 one bound +to that port, vxlan will reuse an IPv4 socket as IPv6 and a panic will +follow. The following steps reproduce it: + + # ip link add vxlan6 type vxlan id 42 group 229.10.10.10 \ + srcport 5000 6000 dev eth0 + # ip link add vxlan7 type vxlan id 43 group ff0e::110 \ + srcport 5000 6000 dev eth0 + # ip link set vxlan6 up + # ip link set vxlan7 up + + +[ 4.187481] BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 +... +[ 4.188076] Call Trace: +[ 4.188085] [] ? ipv6_sock_mc_join+0x3a/0x630 +[ 4.188098] [] vxlan_igmp_join+0x66/0xd0 [vxlan] +[ 4.188113] [] process_one_work+0x220/0x710 +[ 4.188125] [] ? process_one_work+0x1b4/0x710 +[ 4.188138] [] worker_thread+0x11b/0x3a0 +[ 4.188149] [] ? process_one_work+0x710/0x710 + +So address family must also match in order to reuse a socket. + +Reported-by: Jean-Tsung Hsiao +Signed-off-by: Marcelo Ricardo Leitner +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/vxlan.c | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +--- a/drivers/net/vxlan.c ++++ b/drivers/net/vxlan.c +@@ -274,13 +274,15 @@ static inline struct vxlan_rdst *first_r + return list_first_entry(&fdb->remotes, struct vxlan_rdst, list); + } + +-/* Find VXLAN socket based on network namespace and UDP port */ +-static struct vxlan_sock *vxlan_find_sock(struct net *net, __be16 port) ++/* Find VXLAN socket based on network namespace, address family and UDP port */ ++static struct vxlan_sock *vxlan_find_sock(struct net *net, ++ sa_family_t family, __be16 port) + { + struct vxlan_sock *vs; + + hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) { +- if (inet_sk(vs->sock->sk)->inet_sport == port) ++ if (inet_sk(vs->sock->sk)->inet_sport == port && ++ inet_sk(vs->sock->sk)->sk.sk_family == family) + return vs; + } + return NULL; +@@ -299,11 +301,12 @@ static struct vxlan_dev *vxlan_vs_find_v + } + + /* Look up VNI in a per net namespace table */ +-static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, __be16 port) ++static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, ++ sa_family_t family, __be16 port) + { + struct vxlan_sock *vs; + +- vs = vxlan_find_sock(net, port); ++ vs = vxlan_find_sock(net, family, port); + if (!vs) + return NULL; + +@@ -1822,7 +1825,8 @@ static void vxlan_xmit_one(struct sk_buf + struct vxlan_dev *dst_vxlan; + + ip_rt_put(rt); +- dst_vxlan = vxlan_find_vni(vxlan->net, vni, dst_port); ++ dst_vxlan = vxlan_find_vni(vxlan->net, vni, ++ dst->sa.sa_family, dst_port); + if (!dst_vxlan) + goto tx_error; + vxlan_encap_bypass(skb, vxlan, dst_vxlan); +@@ -1876,7 +1880,8 @@ static void vxlan_xmit_one(struct sk_buf + struct vxlan_dev *dst_vxlan; + + dst_release(ndst); +- dst_vxlan = vxlan_find_vni(vxlan->net, vni, dst_port); ++ dst_vxlan = vxlan_find_vni(vxlan->net, vni, ++ dst->sa.sa_family, dst_port); + if (!dst_vxlan) + goto tx_error; + vxlan_encap_bypass(skb, vxlan, dst_vxlan); +@@ -2036,13 +2041,15 @@ static int vxlan_init(struct net_device + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); + struct vxlan_sock *vs; ++ bool ipv6 = vxlan->flags & VXLAN_F_IPV6; + + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!dev->tstats) + return -ENOMEM; + + spin_lock(&vn->sock_lock); +- vs = vxlan_find_sock(vxlan->net, vxlan->dst_port); ++ vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET, ++ vxlan->dst_port); + if (vs) { + /* If we have a socket with same port already, reuse it */ + atomic_inc(&vs->refcnt); +@@ -2441,6 +2448,7 @@ struct vxlan_sock *vxlan_sock_add(struct + { + struct vxlan_net *vn = net_generic(net, vxlan_net_id); + struct vxlan_sock *vs; ++ bool ipv6 = flags & VXLAN_F_IPV6; + + vs = vxlan_socket_create(net, port, rcv, data, flags); + if (!IS_ERR(vs)) +@@ -2450,7 +2458,7 @@ struct vxlan_sock *vxlan_sock_add(struct + return vs; + + spin_lock(&vn->sock_lock); +- vs = vxlan_find_sock(net, port); ++ vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port); + if (vs) { + if (vs->rcv == rcv) + atomic_inc(&vs->refcnt); +@@ -2609,7 +2617,8 @@ static int vxlan_newlink(struct net *net + nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) + vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; + +- if (vxlan_find_vni(net, vni, vxlan->dst_port)) { ++ if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET, ++ vxlan->dst_port)) { + pr_info("duplicate VNI %u\n", vni); + return -EEXIST; + }