From: Greg Kroah-Hartman Date: Tue, 18 Nov 2014 17:12:05 +0000 (-0800) Subject: 3.10-stable patches X-Git-Tag: v3.10.61~50 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0774b41107df696233531beddb5cf612756c9b5f;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.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 series 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 vio-fix-reuse-of-vio_dring-slot.patch --- diff --git a/queue-3.10/gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch b/queue-3.10/gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch new file mode 100644 index 00000000000..082ac5dadfe --- /dev/null +++ b/queue-3.10/gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.patch @@ -0,0 +1,55 @@ +From foo@baz Tue Nov 18 09:07:46 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 | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/net/ipv6/ip6_gre.c ++++ b/net/ipv6/ip6_gre.c +@@ -962,8 +962,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) +@@ -1267,6 +1265,8 @@ static int ip6gre_tunnel_init(struct net + if (!dev->tstats) + return -ENOMEM; + ++ dev->iflink = tunnel->parms.link; ++ + return 0; + } + +@@ -1282,7 +1282,6 @@ static void ip6gre_fb_tunnel_init(struct + dev_hold(dev); + } + +- + static struct inet6_protocol ip6gre_protocol __read_mostly = { + .handler = ip6gre_rcv, + .err_handler = ip6gre_err, +@@ -1458,6 +1457,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.10/ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch b/queue-3.10/ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch new file mode 100644 index 00000000000..9649d8d9cf5 --- /dev/null +++ b/queue-3.10/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:46 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 +@@ -265,9 +265,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) +@@ -1433,6 +1430,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, +@@ -1514,16 +1512,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.10/net-sctp-fix-memory-leak-in-auth-key-management.patch b/queue-3.10/net-sctp-fix-memory-leak-in-auth-key-management.patch new file mode 100644 index 00000000000..e027fbb512d --- /dev/null +++ b/queue-3.10/net-sctp-fix-memory-leak-in-auth-key-management.patch @@ -0,0 +1,57 @@ +From foo@baz Tue Nov 18 09:07:46 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 +@@ -874,8 +874,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.10/net-sctp-fix-null-pointer-dereference-in-af-from_addr_param-on-malformed-packet.patch b/queue-3.10/net-sctp-fix-null-pointer-dereference-in-af-from_addr_param-on-malformed-packet.patch new file mode 100644 index 00000000000..2cb6c9ded2c --- /dev/null +++ b/queue-3.10/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:46 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 +@@ -2596,6 +2596,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.10/series b/queue-3.10/series new file mode 100644 index 00000000000..03a724589d1 --- /dev/null +++ b/queue-3.10/series @@ -0,0 +1,12 @@ +ip6_tunnel-use-ip6_tnl_dev_init-as-the-ndo_init-function.patch +gre6-move-the-setting-of-dev-iflink-into-the-ndo_init-functions.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 +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.10/sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch b/queue-3.10/sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch new file mode 100644 index 00000000000..bc661f6147e --- /dev/null +++ b/queue-3.10/sparc32-implement-xchg-and-atomic_xchg-using-atomic_hash-locks.patch @@ -0,0 +1,100 @@ +From foo@baz Tue Nov 18 09:08:47 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 +@@ -21,7 +21,7 @@ + + extern int __atomic_add_return(int, atomic_t *); + extern int atomic_cmpxchg(atomic_t *, int, int); +-#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) ++extern int atomic_xchg(atomic_t *, int); + extern int __atomic_add_unless(atomic_t *, int, int); + extern 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; +-} +- ++extern unsigned long __xchg_u32(volatile u32 *m, u32 new); + extern 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.10/sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch b/queue-3.10/sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch new file mode 100644 index 00000000000..46013d2c9ff --- /dev/null +++ b/queue-3.10/sparc64-do-irq_-enter-exit-around-generic_smp_call_function.patch @@ -0,0 +1,80 @@ +From foo@baz Tue Nov 18 09:08:47 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 +@@ -821,13 +821,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.10/sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch b/queue-3.10/sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch new file mode 100644 index 00000000000..82e09cf6366 --- /dev/null +++ b/queue-3.10/sparc64-fix-crashes-in-schizo_pcierr_intr_other.patch @@ -0,0 +1,99 @@ +From foo@baz Tue Nov 18 09:08:47 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.10/sunvdc-add-cdrom-and-v1.1-protocol-support.patch b/queue-3.10/sunvdc-add-cdrom-and-v1.1-protocol-support.patch new file mode 100644 index 00000000000..49d22b93457 --- /dev/null +++ b/queue-3.10/sunvdc-add-cdrom-and-v1.1-protocol-support.patch @@ -0,0 +1,246 @@ +From foo@baz Tue Nov 18 09:08:46 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.10/sunvdc-compute-vdisk-geometry-from-capacity.patch b/queue-3.10/sunvdc-compute-vdisk-geometry-from-capacity.patch new file mode 100644 index 00000000000..a84dd379e61 --- /dev/null +++ b/queue-3.10/sunvdc-compute-vdisk-geometry-from-capacity.patch @@ -0,0 +1,76 @@ +From foo@baz Tue Nov 18 09:08:47 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.10/sunvdc-don-t-call-vd_op_get_vtoc.patch b/queue-3.10/sunvdc-don-t-call-vd_op_get_vtoc.patch new file mode 100644 index 00000000000..81ed98b2e6e --- /dev/null +++ b/queue-3.10/sunvdc-don-t-call-vd_op_get_vtoc.patch @@ -0,0 +1,48 @@ +From foo@baz Tue Nov 18 09:08:47 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.10/sunvdc-limit-each-sg-segment-to-a-page.patch b/queue-3.10/sunvdc-limit-each-sg-segment-to-a-page.patch new file mode 100644 index 00000000000..e1861edd4c1 --- /dev/null +++ b/queue-3.10/sunvdc-limit-each-sg-segment-to-a-page.patch @@ -0,0 +1,40 @@ +From foo@baz Tue Nov 18 09:08:47 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.10/vio-fix-reuse-of-vio_dring-slot.patch b/queue-3.10/vio-fix-reuse-of-vio_dring-slot.patch new file mode 100644 index 00000000000..e2c48c2d632 --- /dev/null +++ b/queue-3.10/vio-fix-reuse-of-vio_dring-slot.patch @@ -0,0 +1,145 @@ +From foo@baz Tue Nov 18 09:08:47 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 +@@ -656,7 +656,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); + +@@ -704,7 +704,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);