--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:28:45 2007
+Date: Wed, 06 Jun 2007 22:28:53 -0700 (PDT)
+Message-Id: <20070606.222853.10297477.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: Fix AF_UNIX OOPS
+
+This combines two upstream commits to fix an OOPS with
+AF_UNIX and SELINUX.
+
+basically, sk->sk_socket can become null because we access
+a peer socket without any locking, so it can be shut down and
+released in another thread.
+
+Commit: d410b81b4eef2e4409f9c38ef201253fbbcc7d94
+[AF_UNIX]: Make socket locking much less confusing.
+
+The unix_state_*() locking macros imply that there is some
+rwlock kind of thing going on, but the implementation is
+actually a spinlock which makes the code more confusing than
+it needs to be.
+
+So use plain unix_state_lock and unix_state_unlock.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Commit: 19fec3e807a487415e77113cb9dbdaa2da739836
+[AF_UNIX]: Fix datagram connect race causing an OOPS.
+
+Based upon an excellent bug report and initial patch by
+Frederik Deweerdt.
+
+The UNIX datagram connect code blindly dereferences other->sk_socket
+via the call down to the security_unix_may_send() function.
+
+Without locking 'other' that pointer can go NULL via unix_release_sock()
+which does sock_orphan() which also marks the socket SOCK_DEAD.
+
+So we have to lock both 'sk' and 'other' yet avoid all kinds of
+potential deadlocks (connect to self is OK for datagram sockets and it
+is possible for two datagram sockets to perform a simultaneous connect
+to each other). So what we do is have a "double lock" function similar
+to how we handle this situation in other areas of the kernel. We take
+the lock of the socket pointer with the smallest address first in
+order to avoid ABBA style deadlocks.
+
+Once we have them both locked, we check to see if SOCK_DEAD is set
+for 'other' and if so, drop everything and retry the lookup.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ include/net/af_unix.h | 8 +--
+ net/unix/af_unix.c | 127 +++++++++++++++++++++++++++++++-------------------
+ 2 files changed, 83 insertions(+), 52 deletions(-)
+
+--- linux-2.6.20.12.orig/include/net/af_unix.h
++++ linux-2.6.20.12/include/net/af_unix.h
+@@ -62,13 +62,11 @@ struct unix_skb_parms {
+ #define UNIXCREDS(skb) (&UNIXCB((skb)).creds)
+ #define UNIXSID(skb) (&UNIXCB((skb)).secid)
+
+-#define unix_state_rlock(s) spin_lock(&unix_sk(s)->lock)
+-#define unix_state_runlock(s) spin_unlock(&unix_sk(s)->lock)
+-#define unix_state_wlock(s) spin_lock(&unix_sk(s)->lock)
+-#define unix_state_wlock_nested(s) \
++#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
++#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
++#define unix_state_lock_nested(s) \
+ spin_lock_nested(&unix_sk(s)->lock, \
+ SINGLE_DEPTH_NESTING)
+-#define unix_state_wunlock(s) spin_unlock(&unix_sk(s)->lock)
+
+ #ifdef __KERNEL__
+ /* The AF_UNIX socket */
+--- linux-2.6.20.12.orig/net/unix/af_unix.c
++++ linux-2.6.20.12/net/unix/af_unix.c
+@@ -175,11 +175,11 @@ static struct sock *unix_peer_get(struct
+ {
+ struct sock *peer;
+
+- unix_state_rlock(s);
++ unix_state_lock(s);
+ peer = unix_peer(s);
+ if (peer)
+ sock_hold(peer);
+- unix_state_runlock(s);
++ unix_state_unlock(s);
+ return peer;
+ }
+
+@@ -370,7 +370,7 @@ static int unix_release_sock (struct soc
+ unix_remove_socket(sk);
+
+ /* Clear state */
+- unix_state_wlock(sk);
++ unix_state_lock(sk);
+ sock_orphan(sk);
+ sk->sk_shutdown = SHUTDOWN_MASK;
+ dentry = u->dentry;
+@@ -379,7 +379,7 @@ static int unix_release_sock (struct soc
+ u->mnt = NULL;
+ state = sk->sk_state;
+ sk->sk_state = TCP_CLOSE;
+- unix_state_wunlock(sk);
++ unix_state_unlock(sk);
+
+ wake_up_interruptible_all(&u->peer_wait);
+
+@@ -387,12 +387,12 @@ static int unix_release_sock (struct soc
+
+ if (skpair!=NULL) {
+ if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
+- unix_state_wlock(skpair);
++ unix_state_lock(skpair);
+ /* No more writes */
+ skpair->sk_shutdown = SHUTDOWN_MASK;
+ if (!skb_queue_empty(&sk->sk_receive_queue) || embrion)
+ skpair->sk_err = ECONNRESET;
+- unix_state_wunlock(skpair);
++ unix_state_unlock(skpair);
+ skpair->sk_state_change(skpair);
+ read_lock(&skpair->sk_callback_lock);
+ sk_wake_async(skpair,1,POLL_HUP);
+@@ -449,7 +449,7 @@ static int unix_listen(struct socket *so
+ err = -EINVAL;
+ if (!u->addr)
+ goto out; /* No listens on an unbound socket */
+- unix_state_wlock(sk);
++ unix_state_lock(sk);
+ if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN)
+ goto out_unlock;
+ if (backlog > sk->sk_max_ack_backlog)
+@@ -463,7 +463,7 @@ static int unix_listen(struct socket *so
+ err = 0;
+
+ out_unlock:
+- unix_state_wunlock(sk);
++ unix_state_unlock(sk);
+ out:
+ return err;
+ }
+@@ -859,6 +859,31 @@ out_mknod_parent:
+ goto out_up;
+ }
+
++static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)
++{
++ if (unlikely(sk1 == sk2) || !sk2) {
++ unix_state_lock(sk1);
++ return;
++ }
++ if (sk1 < sk2) {
++ unix_state_lock(sk1);
++ unix_state_lock_nested(sk2);
++ } else {
++ unix_state_lock(sk2);
++ unix_state_lock_nested(sk1);
++ }
++}
++
++static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2)
++{
++ if (unlikely(sk1 == sk2) || !sk2) {
++ unix_state_unlock(sk1);
++ return;
++ }
++ unix_state_unlock(sk1);
++ unix_state_unlock(sk2);
++}
++
+ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
+ int alen, int flags)
+ {
+@@ -878,11 +903,19 @@ static int unix_dgram_connect(struct soc
+ !unix_sk(sk)->addr && (err = unix_autobind(sock)) != 0)
+ goto out;
+
++restart:
+ other=unix_find_other(sunaddr, alen, sock->type, hash, &err);
+ if (!other)
+ goto out;
+
+- unix_state_wlock(sk);
++ unix_state_double_lock(sk, other);
++
++ /* Apparently VFS overslept socket death. Retry. */
++ if (sock_flag(other, SOCK_DEAD)) {
++ unix_state_double_unlock(sk, other);
++ sock_put(other);
++ goto restart;
++ }
+
+ err = -EPERM;
+ if (!unix_may_send(sk, other))
+@@ -897,7 +930,7 @@ static int unix_dgram_connect(struct soc
+ * 1003.1g breaking connected state with AF_UNSPEC
+ */
+ other = NULL;
+- unix_state_wlock(sk);
++ unix_state_double_lock(sk, other);
+ }
+
+ /*
+@@ -906,19 +939,19 @@ static int unix_dgram_connect(struct soc
+ if (unix_peer(sk)) {
+ struct sock *old_peer = unix_peer(sk);
+ unix_peer(sk)=other;
+- unix_state_wunlock(sk);
++ unix_state_double_unlock(sk, other);
+
+ if (other != old_peer)
+ unix_dgram_disconnected(sk, old_peer);
+ sock_put(old_peer);
+ } else {
+ unix_peer(sk)=other;
+- unix_state_wunlock(sk);
++ unix_state_double_unlock(sk, other);
+ }
+ return 0;
+
+ out_unlock:
+- unix_state_wunlock(sk);
++ unix_state_double_unlock(sk, other);
+ sock_put(other);
+ out:
+ return err;
+@@ -937,7 +970,7 @@ static long unix_wait_for_peer(struct so
+ (skb_queue_len(&other->sk_receive_queue) >
+ other->sk_max_ack_backlog);
+
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+
+ if (sched)
+ timeo = schedule_timeout(timeo);
+@@ -995,11 +1028,11 @@ restart:
+ goto out;
+
+ /* Latch state of peer */
+- unix_state_rlock(other);
++ unix_state_lock(other);
+
+ /* Apparently VFS overslept socket death. Retry. */
+ if (sock_flag(other, SOCK_DEAD)) {
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+ sock_put(other);
+ goto restart;
+ }
+@@ -1049,18 +1082,18 @@ restart:
+ goto out_unlock;
+ }
+
+- unix_state_wlock_nested(sk);
++ unix_state_lock_nested(sk);
+
+ if (sk->sk_state != st) {
+- unix_state_wunlock(sk);
+- unix_state_runlock(other);
++ unix_state_unlock(sk);
++ unix_state_unlock(other);
+ sock_put(other);
+ goto restart;
+ }
+
+ err = security_unix_stream_connect(sock, other->sk_socket, newsk);
+ if (err) {
+- unix_state_wunlock(sk);
++ unix_state_unlock(sk);
+ goto out_unlock;
+ }
+
+@@ -1097,7 +1130,7 @@ restart:
+ smp_mb__after_atomic_inc(); /* sock_hold() does an atomic_inc() */
+ unix_peer(sk) = newsk;
+
+- unix_state_wunlock(sk);
++ unix_state_unlock(sk);
+
+ /* take ten and and send info to listening sock */
+ spin_lock(&other->sk_receive_queue.lock);
+@@ -1106,14 +1139,14 @@ restart:
+ * is installed to listening socket. */
+ atomic_inc(&newu->inflight);
+ spin_unlock(&other->sk_receive_queue.lock);
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+ other->sk_data_ready(other, 0);
+ sock_put(other);
+ return 0;
+
+ out_unlock:
+ if (other)
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+
+ out:
+ if (skb)
+@@ -1179,10 +1212,10 @@ static int unix_accept(struct socket *so
+ wake_up_interruptible(&unix_sk(sk)->peer_wait);
+
+ /* attach accepted sock to socket */
+- unix_state_wlock(tsk);
++ unix_state_lock(tsk);
+ newsock->state = SS_CONNECTED;
+ sock_graft(tsk, newsock);
+- unix_state_wunlock(tsk);
++ unix_state_unlock(tsk);
+ return 0;
+
+ out:
+@@ -1209,7 +1242,7 @@ static int unix_getname(struct socket *s
+ }
+
+ u = unix_sk(sk);
+- unix_state_rlock(sk);
++ unix_state_lock(sk);
+ if (!u->addr) {
+ sunaddr->sun_family = AF_UNIX;
+ sunaddr->sun_path[0] = 0;
+@@ -1220,7 +1253,7 @@ static int unix_getname(struct socket *s
+ *uaddr_len = addr->len;
+ memcpy(sunaddr, addr->name, *uaddr_len);
+ }
+- unix_state_runlock(sk);
++ unix_state_unlock(sk);
+ sock_put(sk);
+ out:
+ return err;
+@@ -1338,7 +1371,7 @@ restart:
+ goto out_free;
+ }
+
+- unix_state_rlock(other);
++ unix_state_lock(other);
+ err = -EPERM;
+ if (!unix_may_send(sk, other))
+ goto out_unlock;
+@@ -1348,20 +1381,20 @@ restart:
+ * Check with 1003.1g - what should
+ * datagram error
+ */
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+ sock_put(other);
+
+ err = 0;
+- unix_state_wlock(sk);
++ unix_state_lock(sk);
+ if (unix_peer(sk) == other) {
+ unix_peer(sk)=NULL;
+- unix_state_wunlock(sk);
++ unix_state_unlock(sk);
+
+ unix_dgram_disconnected(sk, other);
+ sock_put(other);
+ err = -ECONNREFUSED;
+ } else {
+- unix_state_wunlock(sk);
++ unix_state_unlock(sk);
+ }
+
+ other = NULL;
+@@ -1398,14 +1431,14 @@ restart:
+ }
+
+ skb_queue_tail(&other->sk_receive_queue, skb);
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+ other->sk_data_ready(other, len);
+ sock_put(other);
+ scm_destroy(siocb->scm);
+ return len;
+
+ out_unlock:
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+ out_free:
+ kfree_skb(skb);
+ out:
+@@ -1495,14 +1528,14 @@ static int unix_stream_sendmsg(struct ki
+ goto out_err;
+ }
+
+- unix_state_rlock(other);
++ unix_state_lock(other);
+
+ if (sock_flag(other, SOCK_DEAD) ||
+ (other->sk_shutdown & RCV_SHUTDOWN))
+ goto pipe_err_free;
+
+ skb_queue_tail(&other->sk_receive_queue, skb);
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+ other->sk_data_ready(other, size);
+ sent+=size;
+ }
+@@ -1513,7 +1546,7 @@ static int unix_stream_sendmsg(struct ki
+ return sent;
+
+ pipe_err_free:
+- unix_state_runlock(other);
++ unix_state_unlock(other);
+ kfree_skb(skb);
+ pipe_err:
+ if (sent==0 && !(msg->msg_flags&MSG_NOSIGNAL))
+@@ -1642,7 +1675,7 @@ static long unix_stream_data_wait(struct
+ {
+ DEFINE_WAIT(wait);
+
+- unix_state_rlock(sk);
++ unix_state_lock(sk);
+
+ for (;;) {
+ prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+@@ -1655,14 +1688,14 @@ static long unix_stream_data_wait(struct
+ break;
+
+ set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+- unix_state_runlock(sk);
++ unix_state_unlock(sk);
+ timeo = schedule_timeout(timeo);
+- unix_state_rlock(sk);
++ unix_state_lock(sk);
+ clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ }
+
+ finish_wait(sk->sk_sleep, &wait);
+- unix_state_runlock(sk);
++ unix_state_unlock(sk);
+ return timeo;
+ }
+
+@@ -1817,12 +1850,12 @@ static int unix_shutdown(struct socket *
+ mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN);
+
+ if (mode) {
+- unix_state_wlock(sk);
++ unix_state_lock(sk);
+ sk->sk_shutdown |= mode;
+ other=unix_peer(sk);
+ if (other)
+ sock_hold(other);
+- unix_state_wunlock(sk);
++ unix_state_unlock(sk);
+ sk->sk_state_change(sk);
+
+ if (other &&
+@@ -1834,9 +1867,9 @@ static int unix_shutdown(struct socket *
+ peer_mode |= SEND_SHUTDOWN;
+ if (mode&SEND_SHUTDOWN)
+ peer_mode |= RCV_SHUTDOWN;
+- unix_state_wlock(other);
++ unix_state_lock(other);
+ other->sk_shutdown |= peer_mode;
+- unix_state_wunlock(other);
++ unix_state_unlock(other);
+ other->sk_state_change(other);
+ read_lock(&other->sk_callback_lock);
+ if (peer_mode == SHUTDOWN_MASK)
+@@ -1974,7 +2007,7 @@ static int unix_seq_show(struct seq_file
+ else {
+ struct sock *s = v;
+ struct unix_sock *u = unix_sk(s);
+- unix_state_rlock(s);
++ unix_state_lock(s);
+
+ seq_printf(seq, "%p: %08X %08X %08X %04X %02X %5lu",
+ s,
+@@ -2002,7 +2035,7 @@ static int unix_seq_show(struct seq_file
+ for ( ; i < len; i++)
+ seq_putc(seq, u->addr->name->sun_path[i]);
+ }
+- unix_state_runlock(s);
++ unix_state_unlock(s);
+ seq_putc(seq, '\n');
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:38:00 2007
+Date: Wed, 06 Jun 2007 22:38:11 -0700 (PDT)
+Message-Id: <20070606.223811.34759359.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: ICMP: Fix icmp_errors_use_inbound_ifaddr sysctl
+
+Currently when icmp_errors_use_inbound_ifaddr is set and an ICMP error is
+sent after the packet passed through ip_output(), an address from the
+outgoing interface is chosen as ICMP source address since skb->dev doesn't
+point to the incoming interface anymore.
+
+Fix this by doing an interface lookup on rt->dst.iif and using that device.
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv4/icmp.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/icmp.c
++++ linux-2.6.20.12/net/ipv4/icmp.c
+@@ -513,9 +513,15 @@ void icmp_send(struct sk_buff *skb_in, i
+
+ saddr = iph->daddr;
+ if (!(rt->rt_flags & RTCF_LOCAL)) {
+- if (sysctl_icmp_errors_use_inbound_ifaddr)
+- saddr = inet_select_addr(skb_in->dev, 0, RT_SCOPE_LINK);
+- else
++ struct net_device *dev = NULL;
++
++ if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr)
++ dev = dev_get_by_index(rt->fl.iif);
++
++ if (dev) {
++ saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK);
++ dev_put(dev);
++ } else
+ saddr = 0;
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:41:41 2007
+Date: Wed, 06 Jun 2007 22:41:52 -0700 (PDT)
+Message-Id: <20070606.224152.68156938.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: IPSEC: Fix panic when using inter address familiy IPsec on loopback.
+
+From: Kazunori MIYAZAWA <kazunori@miyazawa.org>
+
+Signed-off-by: Kazunori MIYAZAWA <kazunori@miyazawa.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv4/xfrm4_input.c | 6 ++----
+ net/ipv4/xfrm4_mode_tunnel.c | 2 ++
+ net/ipv6/xfrm6_input.c | 6 ++----
+ net/ipv6/xfrm6_mode_tunnel.c | 1 +
+ 4 files changed, 7 insertions(+), 8 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/xfrm4_input.c
++++ linux-2.6.20.12/net/ipv4/xfrm4_input.c
+@@ -136,10 +136,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb,
+ nf_reset(skb);
+
+ if (decaps) {
+- if (!(skb->dev->flags&IFF_LOOPBACK)) {
+- dst_release(skb->dst);
+- skb->dst = NULL;
+- }
++ dst_release(skb->dst);
++ skb->dst = NULL;
+ netif_rx(skb);
+ return 0;
+ } else {
+--- linux-2.6.20.12.orig/net/ipv4/xfrm4_mode_tunnel.c
++++ linux-2.6.20.12/net/ipv4/xfrm4_mode_tunnel.c
+@@ -66,6 +66,8 @@ static int xfrm4_tunnel_output(struct xf
+ top_iph->daddr = x->id.daddr.a4;
+ top_iph->protocol = IPPROTO_IPIP;
+
++ skb->protocol = htons(ETH_P_IP);
++
+ memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+ return 0;
+ }
+--- linux-2.6.20.12.orig/net/ipv6/xfrm6_input.c
++++ linux-2.6.20.12/net/ipv6/xfrm6_input.c
+@@ -103,10 +103,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, _
+ nf_reset(skb);
+
+ if (decaps) {
+- if (!(skb->dev->flags&IFF_LOOPBACK)) {
+- dst_release(skb->dst);
+- skb->dst = NULL;
+- }
++ dst_release(skb->dst);
++ skb->dst = NULL;
+ netif_rx(skb);
+ return -1;
+ } else {
+--- linux-2.6.20.12.orig/net/ipv6/xfrm6_mode_tunnel.c
++++ linux-2.6.20.12/net/ipv6/xfrm6_mode_tunnel.c
+@@ -65,6 +65,7 @@ static int xfrm6_tunnel_output(struct xf
+ top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
+ ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
+ ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
++ skb->protocol = htons(ETH_P_IPV6);
+ return 0;
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:47:58 2007
+Date: Wed, 06 Jun 2007 22:48:09 -0700 (PDT)
+Message-Id: <20070606.224809.35355405.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: IPV4: Correct rp_filter help text.
+
+From: Dave Jones <davej@redhat.com>
+
+As mentioned in http://bugzilla.kernel.org/show_bug.cgi?id=5015
+The helptext implies that this is on by default.
+This may be true on some distros (Fedora/RHEL have it enabled
+in /etc/sysctl.conf), but the kernel defaults to it off.
+
+Signed-off-by: Dave Jones <davej@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv4/Kconfig | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/Kconfig
++++ linux-2.6.20.12/net/ipv4/Kconfig
+@@ -43,11 +43,11 @@ config IP_ADVANCED_ROUTER
+ asymmetric routing (packets from you to a host take a different path
+ than packets from that host to you) or if you operate a non-routing
+ host which has several IP addresses on different interfaces. To turn
+- rp_filter off use:
++ rp_filter on use:
+
+- echo 0 > /proc/sys/net/ipv4/conf/<device>/rp_filter
++ echo 1 > /proc/sys/net/ipv4/conf/<device>/rp_filter
+ or
+- echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
++ echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
+
+ If unsure, say N here.
+
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:42:46 2007
+Date: Wed, 06 Jun 2007 22:42:58 -0700 (PDT)
+Message-Id: <20070606.224258.27782785.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: IPV6 ROUTE: No longer handle ::/0 specially.
+
+From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+
+We do not need to handle ::/0 routes specially any longer.
+This should fix BUG #8349.
+
+Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+Acked-by: Yuji Sekiya <sekiya@wide.ad.jp>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv6/ip6_fib.c | 8 --------
+ 1 file changed, 8 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv6/ip6_fib.c
++++ linux-2.6.20.12/net/ipv6/ip6_fib.c
+@@ -620,14 +620,6 @@ static int fib6_add_rt2node(struct fib6_
+
+ ins = &fn->leaf;
+
+- if (fn->fn_flags&RTN_TL_ROOT &&
+- fn->leaf == &ip6_null_entry &&
+- !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ){
+- fn->leaf = rt;
+- rt->u.next = NULL;
+- goto out;
+- }
+-
+ for (iter = fn->leaf; iter; iter=iter->u.next) {
+ /*
+ * Search for duplicates
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:44:02 2007
+Date: Wed, 06 Jun 2007 22:44:14 -0700 (PDT)
+Message-Id: <20070606.224414.77057904.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: Fix BMSR_100{HALF,FULL}2 defines in linux/mii.h
+
+Noticed by Matvejchikov Ilya.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ include/linux/mii.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- linux-2.6.20.12.orig/include/linux/mii.h
++++ linux-2.6.20.12/include/linux/mii.h
+@@ -56,8 +56,8 @@
+ #define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
+ #define BMSR_RESV 0x00c0 /* Unused... */
+ #define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
+-#define BMSR_100FULL2 0x0200 /* Can do 100BASE-T2 HDX */
+-#define BMSR_100HALF2 0x0400 /* Can do 100BASE-T2 FDX */
++#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
++#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
+ #define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
+ #define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
+ #define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:46:56 2007
+Date: Wed, 06 Jun 2007 22:47:07 -0700 (PDT)
+Message-Id: <20070606.224707.26532542.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: Fix race condition about network device name allocation.
+
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+Kenji Kaneshige found this race between device removal and
+registration. On unregister it is possible for the old device to
+exist, because sysfs file is still open. A new device with 'eth%d'
+will select the same name, but sysfs kobject register will fial.
+
+The following changes the shutdown order slightly. It hold a removes
+the sysfs entries earlier (on unregister_netdevice), but holds a
+kobject reference. Then when todo runs the actual last put free
+happens.
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/core/dev.c | 10 ++++++----
+ net/core/net-sysfs.c | 8 +++++++-
+ 2 files changed, 13 insertions(+), 5 deletions(-)
+
+--- linux-2.6.20.12.orig/net/core/dev.c
++++ linux-2.6.20.12/net/core/dev.c
+@@ -3138,7 +3138,6 @@ void netdev_run_todo(void)
+ continue;
+ }
+
+- netdev_unregister_sysfs(dev);
+ dev->reg_state = NETREG_UNREGISTERED;
+
+ netdev_wait_allrefs(dev);
+@@ -3149,11 +3148,11 @@ void netdev_run_todo(void)
+ BUG_TRAP(!dev->ip6_ptr);
+ BUG_TRAP(!dev->dn_ptr);
+
+- /* It must be the very last action,
+- * after this 'dev' may point to freed up memory.
+- */
+ if (dev->destructor)
+ dev->destructor(dev);
++
++ /* Free network device */
++ kobject_put(&dev->dev.kobj);
+ }
+
+ out:
+@@ -3310,6 +3309,9 @@ int unregister_netdevice(struct net_devi
+ /* Notifier chain MUST detach us from master device. */
+ BUG_TRAP(!dev->master);
+
++ /* Remove entries from sysfs */
++ netdev_unregister_sysfs(dev);
++
+ /* Finish processing unregister after unlock */
+ net_set_todo(dev);
+
+--- linux-2.6.20.12.orig/net/core/net-sysfs.c
++++ linux-2.6.20.12/net/core/net-sysfs.c
+@@ -440,9 +440,15 @@ static struct class net_class = {
+ #endif
+ };
+
++/* Delete sysfs entries but hold kobject reference until after all
++ * netdev references are gone.
++ */
+ void netdev_unregister_sysfs(struct net_device * net)
+ {
+- class_device_del(&(net->class_dev));
++ struct device *dev = &(net->dev);
++
++ kobject_get(&dev->kobj);
++ device_del(dev);
+ }
+
+ /* Create sysfs entries for network device. */
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:40:19 2007
+Date: Wed, 06 Jun 2007 22:40:27 -0700 (PDT)
+Message-Id: <20070606.224027.02298887.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: parse ip:port strings correctly in in4_pton
+
+From: Jerome Borsboom <j.borsboom@erasmusmc.nl>
+
+in4_pton converts a textual representation of an ip4 address
+into an integer representation. However, when the textual representation
+is of in the form ip:port, e.g. 192.168.1.1:5060, and 'delim' is set to
+-1, the function bails out with an error when reading the colon.
+
+It makes sense to allow the colon as a delimiting character without
+explicitly having to set it through the 'delim' variable as there can be
+no ambiguity in the point where the ip address is completely parsed. This
+function is indeed called from nf_conntrack_sip.c in this way to parse
+textual ip:port combinations which fails due to the reason stated above.
+
+Signed-off-by: Jerome Borsboom <j.borsboom@erasmusmc.nl>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/core/utils.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/net/core/utils.c
++++ linux-2.6.20.12/net/core/utils.c
+@@ -137,16 +137,16 @@ int in4_pton(const char *src, int srclen
+ while(1) {
+ int c;
+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
+- if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) {
++ if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
+ goto out;
+ }
+- if (c & (IN6PTON_DOT | IN6PTON_DELIM)) {
++ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (w == 0)
+ goto out;
+ *d++ = w & 0xff;
+ w = 0;
+ i++;
+- if (c & IN6PTON_DELIM) {
++ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+ if (i != 4)
+ goto out;
+ break;
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:50:52 2007
+Date: Wed, 06 Jun 2007 22:51:03 -0700 (PDT)
+Message-Id: <20070606.225103.52166535.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: "wrong timeout value" in sk_wait_data() v2
+
+From: Vasily Averin <vvs@sw.ru>
+
+sys_setsockopt() do not check properly timeout values for
+SO_RCVTIMEO/SO_SNDTIMEO, for example it's possible to set negative timeout
+values. POSIX do not defines behaviour for sys_setsockopt in case negative
+timeouts, but requires that setsockopt() shall fail with -EDOM if the send and
+receive timeout values are too big to fit into the timeout fields in the socket
+structure.
+In current implementation negative timeout can lead to error messages like
+"schedule_timeout: wrong timeout value".
+
+Proposed patch:
+- checks tv_usec and returns -EDOM if it is wrong
+- do not allows to set negative timeout values (sets 0 instead) and outputs
+ratelimited information message about such attempts.
+
+Signed-off-By: Vasily Averin <vvs@sw.ru>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/core/sock.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- linux-2.6.20.12.orig/net/core/sock.c
++++ linux-2.6.20.12/net/core/sock.c
+@@ -204,7 +204,19 @@ static int sock_set_timeout(long *timeo_
+ return -EINVAL;
+ if (copy_from_user(&tv, optval, sizeof(tv)))
+ return -EFAULT;
++ if (tv.tv_usec < 0 || tv.tv_usec >= USEC_PER_SEC)
++ return -EDOM;
+
++ if (tv.tv_sec < 0) {
++ static int warned = 0;
++ *timeo_p = 0;
++ if (warned < 10 && net_ratelimit())
++ warned++;
++ printk(KERN_INFO "sock_set_timeout: `%s' (pid %d) "
++ "tries to set negative timeout\n",
++ current->comm, current->pid);
++ return 0;
++ }
+ *timeo_p = MAX_SCHEDULE_TIMEOUT;
+ if (tv.tv_sec == 0 && tv.tv_usec == 0)
+ return 0;
v4l-dvb-budget-ci-fix-tuning-for-tdm-1316.patch
kbuild-fixdep-segfault-on-pathological-string-o-death.patch
ntfs_init_locked_inode-fix-array-indexing.patch
+icmp-fix-icmp_errors_use_inbound_ifaddr-sysctl.patch
+net-parse-ip-port-strings-correctly-in-in4_pton.patch
+ipsec-fix-panic-when-using-inter-address-familiy-ipsec-on-loopback.patch
+net-fix-bmsr_100-half-full-2-defines-in-linux-mii.h.patch
+ipv4-correct-rp_filter-help-text.patch
+sparc-linux-always-started-with-9600-8n1.patch
+net-wrong-timeout-value-in-sk_wait_data-v2.patch
+sparc64-fix-two-bugs-wrt.-kernel-4mb-tsb.patch
+sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch
+sparc64-fix-_page_exec_4u-check-in-sun4u-i-tlb-miss-handler.patch
+tcp-use-default-32768-61000-outgoing-port-range-in-all-cases.patch
+net-fix-race-condition-about-network-device-name-allocation.patch
+fix-af_unix-oops.patch
+ipv6-route-no-longer-handle-0-specially.patch
+sparc64-don-t-be-picky-about-virtual-dma-values-on-sun4v.patch
netfilter-ip-nf-_conntrack_sctp-fix-remotely-triggerable-null-ptr-dereference.patch
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:49:03 2007
+Date: Wed, 06 Jun 2007 22:49:14 -0700 (PDT)
+Message-Id: <20070606.224914.26966192.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC: Linux always started with 9600 8N1
+
+From: Jan Engelhardt <jengelh@gmx.de>
+
+The Linux kernel ignored the PROM's serial settings (115200,n,8,1 in
+my case). This was because mode_prop remained "ttyX-mode" (expected:
+"ttya-mode") due to the constness of string literals when used with
+"char *". Since there is no "ttyX-mode" property in the PROM, Linux
+always used the default 9600.
+
+[ Investigation of the suncore.s assembler reveals that gcc optimizied
+ away the stores, yet did not emit a warning, which is a pretty
+ anti-social thing to do and is the only reason this bug lived for
+ so long -DaveM ]
+
+Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ drivers/serial/suncore.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/drivers/serial/suncore.c
++++ linux-2.6.20.12/drivers/serial/suncore.c
+@@ -30,9 +30,9 @@ void
+ sunserial_console_termios(struct console *con)
+ {
+ char mode[16], buf[16], *s;
+- char *mode_prop = "ttyX-mode";
+- char *cd_prop = "ttyX-ignore-cd";
+- char *dtr_prop = "ttyX-rts-dtr-off";
++ char mode_prop[] = "ttyX-mode";
++ char cd_prop[] = "ttyX-ignore-cd";
++ char dtr_prop[] = "ttyX-rts-dtr-off";
+ char *ssp_console_modes_prop = "ssp-console-modes";
+ int baud, bits, stop, cflag;
+ char parity;
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:54:25 2007
+Date: Wed, 06 Jun 2007 22:54:33 -0700 (PDT)
+Message-Id: <20070606.225433.58454202.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Add hypervisor API negotiation and fix console bugs.
+
+Hypervisor interfaces need to be negotiated in order to use
+some API calls reliably. So add a small set of interfaces
+to request API versions and query current settings.
+
+This allows us to fix some bugs in the hypervisor console:
+
+1) If we can negotiate API group CORE of at least major 1
+ minor 1 we can use con_read and con_write which can improve
+ console performance quite a bit.
+
+2) When we do a console write request, we should hold the
+ spinlock around the whole request, not a byte at a time.
+ What would happen is that it's easy for output from
+ different cpus to get mixed with each other.
+
+3) Use consistent udelay() based polling, udelay(1) each
+ loop with a limit of 1000 polls to handle stuck hypervisor
+ console.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/Makefile | 2
+ arch/sparc64/kernel/entry.S | 94 +++++++++++++
+ arch/sparc64/kernel/hvapi.c | 189 ++++++++++++++++++++++++++
+ arch/sparc64/kernel/setup.c | 3
+ drivers/serial/sunhv.c | 276 ++++++++++++++++++++++++++++-----------
+ include/asm-sparc64/hypervisor.h | 83 +++++++++++
+ 6 files changed, 574 insertions(+), 73 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/Makefile
++++ linux-2.6.20.12/arch/sparc64/kernel/Makefile
+@@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom
+ irq.o ptrace.o time.o sys_sparc.o signal.o \
+ unaligned.o central.o pci.o starfire.o semaphore.o \
+ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
+- visemul.o prom.o of_device.o
++ visemul.o prom.o of_device.o hvapi.o
+
+ obj-$(CONFIG_STACKTRACE) += stacktrace.o
+ obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/entry.S
++++ linux-2.6.20.12/arch/sparc64/kernel/entry.S
+@@ -1843,3 +1843,97 @@ sun4v_cpu_state:
+ mov %o1, %o0
+ 1: retl
+ nop
++
++ /* %o0: API group number
++ * %o1: pointer to unsigned long major number storage
++ * %o2: pointer to unsigned long minor number storage
++ *
++ * returns %o0: status
++ */
++ .globl sun4v_get_version
++sun4v_get_version:
++ mov HV_CORE_GET_VER, %o5
++ mov %o1, %o3
++ mov %o2, %o4
++ ta HV_CORE_TRAP
++ stx %o1, [%o3]
++ retl
++ stx %o2, [%o4]
++
++ /* %o0: API group number
++ * %o1: desired major number
++ * %o2: desired minor number
++ * %o3: pointer to unsigned long actual minor number storage
++ *
++ * returns %o0: status
++ */
++ .globl sun4v_set_version
++sun4v_set_version:
++ mov HV_CORE_SET_VER, %o5
++ mov %o3, %o4
++ ta HV_CORE_TRAP
++ retl
++ stx %o1, [%o4]
++
++ /* %o0: pointer to unsigned long status
++ *
++ * returns %o0: signed character
++ */
++ .globl sun4v_con_getchar
++sun4v_con_getchar:
++ mov %o0, %o4
++ mov HV_FAST_CONS_GETCHAR, %o5
++ clr %o0
++ clr %o1
++ ta HV_FAST_TRAP
++ stx %o0, [%o4]
++ retl
++ sra %o1, 0, %o0
++
++ /* %o0: signed long character
++ *
++ * returns %o0: status
++ */
++ .globl sun4v_con_putchar
++sun4v_con_putchar:
++ mov HV_FAST_CONS_PUTCHAR, %o5
++ ta HV_FAST_TRAP
++ retl
++ sra %o0, 0, %o0
++
++ /* %o0: buffer real address
++ * %o1: buffer size
++ * %o2: pointer to unsigned long bytes_read
++ *
++ * returns %o0: status
++ */
++ .globl sun4v_con_read
++sun4v_con_read:
++ mov %o2, %o4
++ mov HV_FAST_CONS_READ, %o5
++ ta HV_FAST_TRAP
++ brnz %o0, 1f
++ cmp %o1, -1 /* break */
++ be,a,pn %icc, 1f
++ mov %o1, %o0
++ cmp %o1, -2 /* hup */
++ be,a,pn %icc, 1f
++ mov %o1, %o0
++ stx %o1, [%o4]
++1: retl
++ nop
++
++ /* %o0: buffer real address
++ * %o1: buffer size
++ * %o2: pointer to unsigned long bytes_written
++ *
++ * returns %o0: status
++ */
++ .globl sun4v_con_write
++sun4v_con_write:
++ mov %o2, %o4
++ mov HV_FAST_CONS_WRITE, %o5
++ ta HV_FAST_TRAP
++ stx %o1, [%o4]
++ retl
++ nop
+--- /dev/null
++++ linux-2.6.20.12/arch/sparc64/kernel/hvapi.c
+@@ -0,0 +1,189 @@
++/* hvapi.c: Hypervisor API management.
++ *
++ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++
++#include <asm/hypervisor.h>
++#include <asm/oplib.h>
++
++/* If the hypervisor indicates that the API setting
++ * calls are unsupported, by returning HV_EBADTRAP or
++ * HV_ENOTSUPPORTED, we assume that API groups with the
++ * PRE_API flag set are major 1 minor 0.
++ */
++struct api_info {
++ unsigned long group;
++ unsigned long major;
++ unsigned long minor;
++ unsigned int refcnt;
++ unsigned int flags;
++#define FLAG_PRE_API 0x00000001
++};
++
++static struct api_info api_table[] = {
++ { .group = HV_GRP_SUN4V, .flags = FLAG_PRE_API },
++ { .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
++ { .group = HV_GRP_INTR, },
++ { .group = HV_GRP_SOFT_STATE, },
++ { .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
++ { .group = HV_GRP_LDOM, },
++ { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
++ { .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
++ { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
++ { .group = HV_GRP_FIRE_PERF, },
++ { .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
++};
++
++static DEFINE_SPINLOCK(hvapi_lock);
++
++static struct api_info *__get_info(unsigned long group)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(api_table); i++) {
++ if (api_table[i].group == group)
++ return &api_table[i];
++ }
++ return NULL;
++}
++
++static void __get_ref(struct api_info *p)
++{
++ p->refcnt++;
++}
++
++static void __put_ref(struct api_info *p)
++{
++ if (--p->refcnt == 0) {
++ unsigned long ignore;
++
++ sun4v_set_version(p->group, 0, 0, &ignore);
++ p->major = p->minor = 0;
++ }
++}
++
++/* Register a hypervisor API specification. It indicates the
++ * API group and desired major+minor.
++ *
++ * If an existing API registration exists '0' (success) will
++ * be returned if it is compatible with the one being registered.
++ * Otherwise a negative error code will be returned.
++ *
++ * Otherwise an attempt will be made to negotiate the requested
++ * API group/major/minor with the hypervisor, and errors returned
++ * if that does not succeed.
++ */
++int sun4v_hvapi_register(unsigned long group, unsigned long major,
++ unsigned long *minor)
++{
++ struct api_info *p;
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&hvapi_lock, flags);
++ p = __get_info(group);
++ ret = -EINVAL;
++ if (p) {
++ if (p->refcnt) {
++ ret = -EINVAL;
++ if (p->major == major) {
++ *minor = p->minor;
++ ret = 0;
++ }
++ } else {
++ unsigned long actual_minor;
++ unsigned long hv_ret;
++
++ hv_ret = sun4v_set_version(group, major, *minor,
++ &actual_minor);
++ ret = -EINVAL;
++ if (hv_ret == HV_EOK) {
++ *minor = actual_minor;
++ p->major = major;
++ p->minor = actual_minor;
++ ret = 0;
++ } else if (hv_ret == HV_EBADTRAP ||
++ HV_ENOTSUPPORTED) {
++ if (p->flags & FLAG_PRE_API) {
++ if (major == 1) {
++ p->major = 1;
++ p->minor = 0;
++ *minor = 0;
++ ret = 0;
++ }
++ }
++ }
++ }
++
++ if (ret == 0)
++ __get_ref(p);
++ }
++ spin_unlock_irqrestore(&hvapi_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(sun4v_hvapi_register);
++
++void sun4v_hvapi_unregister(unsigned long group)
++{
++ struct api_info *p;
++ unsigned long flags;
++
++ spin_lock_irqsave(&hvapi_lock, flags);
++ p = __get_info(group);
++ if (p)
++ __put_ref(p);
++ spin_unlock_irqrestore(&hvapi_lock, flags);
++}
++EXPORT_SYMBOL(sun4v_hvapi_unregister);
++
++int sun4v_hvapi_get(unsigned long group,
++ unsigned long *major,
++ unsigned long *minor)
++{
++ struct api_info *p;
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&hvapi_lock, flags);
++ ret = -EINVAL;
++ p = __get_info(group);
++ if (p && p->refcnt) {
++ *major = p->major;
++ *minor = p->minor;
++ ret = 0;
++ }
++ spin_unlock_irqrestore(&hvapi_lock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(sun4v_hvapi_get);
++
++void __init sun4v_hvapi_init(void)
++{
++ unsigned long group, major, minor;
++
++ group = HV_GRP_SUN4V;
++ major = 1;
++ minor = 0;
++ if (sun4v_hvapi_register(group, major, &minor))
++ goto bad;
++
++ group = HV_GRP_CORE;
++ major = 1;
++ minor = 1;
++ if (sun4v_hvapi_register(group, major, &minor))
++ goto bad;
++
++ return;
++
++bad:
++ prom_printf("HVAPI: Cannot register API group "
++ "%lx with major(%u) minor(%u)\n",
++ group, major, minor);
++ prom_halt();
++}
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/setup.c
++++ linux-2.6.20.12/arch/sparc64/kernel/setup.c
+@@ -269,6 +269,7 @@ void __init per_cpu_patch(void)
+
+ void __init sun4v_patch(void)
+ {
++ extern void sun4v_hvapi_init(void);
+ struct sun4v_1insn_patch_entry *p1;
+ struct sun4v_2insn_patch_entry *p2;
+
+@@ -300,6 +301,8 @@ void __init sun4v_patch(void)
+
+ p2++;
+ }
++
++ sun4v_hvapi_init();
+ }
+
+ #ifdef CONFIG_SMP
+--- linux-2.6.20.12.orig/drivers/serial/sunhv.c
++++ linux-2.6.20.12/drivers/serial/sunhv.c
+@@ -1,6 +1,6 @@
+ /* sunhv.c: Serial driver for SUN4V hypervisor console.
+ *
+- * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
++ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
+ */
+
+ #include <linux/module.h>
+@@ -35,57 +35,51 @@
+ #define CON_BREAK ((long)-1)
+ #define CON_HUP ((long)-2)
+
+-static inline long hypervisor_con_getchar(long *status)
+-{
+- register unsigned long func asm("%o5");
+- register unsigned long arg0 asm("%o0");
+- register unsigned long arg1 asm("%o1");
+-
+- func = HV_FAST_CONS_GETCHAR;
+- arg0 = 0;
+- arg1 = 0;
+- __asm__ __volatile__("ta %6"
+- : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
+- : "0" (func), "1" (arg0), "2" (arg1),
+- "i" (HV_FAST_TRAP));
++#define IGNORE_BREAK 0x1
++#define IGNORE_ALL 0x2
+
+- *status = arg0;
++static char *con_write_page;
++static char *con_read_page;
+
+- return (long) arg1;
+-}
++static int hung_up = 0;
+
+-static inline long hypervisor_con_putchar(long ch)
++static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
+ {
+- register unsigned long func asm("%o5");
+- register unsigned long arg0 asm("%o0");
++ while (!uart_circ_empty(xmit)) {
++ long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
+
+- func = HV_FAST_CONS_PUTCHAR;
+- arg0 = ch;
+- __asm__ __volatile__("ta %4"
+- : "=&r" (func), "=&r" (arg0)
+- : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
++ if (status != HV_EOK)
++ break;
+
+- return (long) arg0;
++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++ port->icount.tx++;
++ }
+ }
+
+-#define IGNORE_BREAK 0x1
+-#define IGNORE_ALL 0x2
++static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
++{
++ while (!uart_circ_empty(xmit)) {
++ unsigned long ra = __pa(xmit->buf + xmit->tail);
++ unsigned long len, status, sent;
+
+-static int hung_up = 0;
++ len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
++ UART_XMIT_SIZE);
++ status = sun4v_con_write(ra, len, &sent);
++ if (status != HV_EOK)
++ break;
++ xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
++ port->icount.tx += sent;
++ }
++}
+
+-static struct tty_struct *receive_chars(struct uart_port *port)
++static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
+ {
+- struct tty_struct *tty = NULL;
+ int saw_console_brk = 0;
+ int limit = 10000;
+
+- if (port->info != NULL) /* Unopened serial console */
+- tty = port->info->tty;
+-
+ while (limit-- > 0) {
+ long status;
+- long c = hypervisor_con_getchar(&status);
+- unsigned char flag;
++ long c = sun4v_con_getchar(&status);
+
+ if (status == HV_EWOULDBLOCK)
+ break;
+@@ -110,27 +104,90 @@ static struct tty_struct *receive_chars(
+ continue;
+ }
+
+- flag = TTY_NORMAL;
+ port->icount.rx++;
+- if (c == CON_BREAK) {
+- port->icount.brk++;
+- if (uart_handle_break(port))
+- continue;
+- flag = TTY_BREAK;
+- }
+
+ if (uart_handle_sysrq_char(port, c))
+ continue;
+
+- if ((port->ignore_status_mask & IGNORE_ALL) ||
+- ((port->ignore_status_mask & IGNORE_BREAK) &&
+- (c == CON_BREAK)))
++ tty_insert_flip_char(tty, c, TTY_NORMAL);
++ }
++
++ return saw_console_brk;
++}
++
++static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
++{
++ int saw_console_brk = 0;
++ int limit = 10000;
++
++ while (limit-- > 0) {
++ unsigned long ra = __pa(con_read_page);
++ unsigned long bytes_read, i;
++ long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
++
++ if (stat != HV_EOK) {
++ bytes_read = 0;
++
++ if (stat == CON_BREAK) {
++ if (uart_handle_break(port))
++ continue;
++ saw_console_brk = 1;
++ *con_read_page = 0;
++ bytes_read = 1;
++ } else if (stat == CON_HUP) {
++ hung_up = 1;
++ uart_handle_dcd_change(port, 0);
++ continue;
++ } else {
++ /* HV_EWOULDBLOCK, etc. */
++ break;
++ }
++ }
++
++ if (hung_up) {
++ hung_up = 0;
++ uart_handle_dcd_change(port, 1);
++ }
++
++ for (i = 0; i < bytes_read; i++)
++ uart_handle_sysrq_char(port, con_read_page[i]);
++
++ if (tty == NULL)
+ continue;
+
+- tty_insert_flip_char(tty, c, flag);
++ port->icount.rx += bytes_read;
++
++ tty_insert_flip_string(tty, con_read_page, bytes_read);
+ }
+
+- if (saw_console_brk)
++ return saw_console_brk;
++}
++
++struct sunhv_ops {
++ void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
++ int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
++};
++
++static struct sunhv_ops bychar_ops = {
++ .transmit_chars = transmit_chars_putchar,
++ .receive_chars = receive_chars_getchar,
++};
++
++static struct sunhv_ops bywrite_ops = {
++ .transmit_chars = transmit_chars_write,
++ .receive_chars = receive_chars_read,
++};
++
++static struct sunhv_ops *sunhv_ops = &bychar_ops;
++
++static struct tty_struct *receive_chars(struct uart_port *port)
++{
++ struct tty_struct *tty = NULL;
++
++ if (port->info != NULL) /* Unopened serial console */
++ tty = port->info->tty;
++
++ if (sunhv_ops->receive_chars(port, tty))
+ sun_do_break();
+
+ return tty;
+@@ -147,15 +204,7 @@ static void transmit_chars(struct uart_p
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ return;
+
+- while (!uart_circ_empty(xmit)) {
+- long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
+-
+- if (status != HV_EOK)
+- break;
+-
+- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+- port->icount.tx++;
+- }
++ sunhv_ops->transmit_chars(port, xmit);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+@@ -212,7 +261,7 @@ static void sunhv_start_tx(struct uart_p
+ struct circ_buf *xmit = &port->info->xmit;
+
+ while (!uart_circ_empty(xmit)) {
+- long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
++ long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
+
+ if (status != HV_EOK)
+ break;
+@@ -231,9 +280,10 @@ static void sunhv_send_xchar(struct uart
+ spin_lock_irqsave(&port->lock, flags);
+
+ while (limit-- > 0) {
+- long status = hypervisor_con_putchar(ch);
++ long status = sun4v_con_putchar(ch);
+ if (status == HV_EOK)
+ break;
++ udelay(1);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+@@ -254,15 +304,15 @@ static void sunhv_break_ctl(struct uart_
+ {
+ if (break_state) {
+ unsigned long flags;
+- int limit = 1000000;
++ int limit = 10000;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while (limit-- > 0) {
+- long status = hypervisor_con_putchar(CON_BREAK);
++ long status = sun4v_con_putchar(CON_BREAK);
+ if (status == HV_EOK)
+ break;
+- udelay(2);
++ udelay(1);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+@@ -359,38 +409,99 @@ static struct uart_driver sunhv_reg = {
+
+ static struct uart_port *sunhv_port;
+
+-static inline void sunhv_console_putchar(struct uart_port *port, char c)
++/* Copy 's' into the con_write_page, decoding "\n" into
++ * "\r\n" along the way. We have to return two lengths
++ * because the caller needs to know how much to advance
++ * 's' and also how many bytes to output via con_write_page.
++ */
++static int fill_con_write_page(const char *s, unsigned int n,
++ unsigned long *page_bytes)
+ {
++ const char *orig_s = s;
++ char *p = con_write_page;
++ int left = PAGE_SIZE;
++
++ while (n--) {
++ if (*s == '\n') {
++ if (left < 2)
++ break;
++ *p++ = '\r';
++ left--;
++ } else if (left < 1)
++ break;
++ *p++ = *s++;
++ left--;
++ }
++ *page_bytes = p - con_write_page;
++ return s - orig_s;
++}
++
++static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
++{
++ struct uart_port *port = sunhv_port;
+ unsigned long flags;
+- int limit = 1000000;
+
+ spin_lock_irqsave(&port->lock, flags);
++ while (n > 0) {
++ unsigned long ra = __pa(con_write_page);
++ unsigned long page_bytes;
++ unsigned int cpy = fill_con_write_page(s, n,
++ &page_bytes);
++
++ n -= cpy;
++ s += cpy;
++ while (page_bytes > 0) {
++ unsigned long written;
++ int limit = 1000000;
++
++ while (limit--) {
++ unsigned long stat;
++
++ stat = sun4v_con_write(ra, page_bytes,
++ &written);
++ if (stat == HV_EOK)
++ break;
++ udelay(1);
++ }
++ if (limit <= 0)
++ break;
++ page_bytes -= written;
++ ra += written;
++ }
++ }
++ spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static inline void sunhv_console_putchar(struct uart_port *port, char c)
++{
++ int limit = 1000000;
+
+ while (limit-- > 0) {
+- long status = hypervisor_con_putchar(c);
++ long status = sun4v_con_putchar(c);
+ if (status == HV_EOK)
+ break;
+- udelay(2);
++ udelay(1);
+ }
+-
+- spin_unlock_irqrestore(&port->lock, flags);
+ }
+
+-static void sunhv_console_write(struct console *con, const char *s, unsigned n)
++static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
+ {
+ struct uart_port *port = sunhv_port;
++ unsigned long flags;
+ int i;
+
++ spin_lock_irqsave(&port->lock, flags);
+ for (i = 0; i < n; i++) {
+ if (*s == '\n')
+ sunhv_console_putchar(port, '\r');
+ sunhv_console_putchar(port, *s++);
+ }
++ spin_unlock_irqrestore(&port->lock, flags);
+ }
+
+ static struct console sunhv_console = {
+ .name = "ttyHV",
+- .write = sunhv_console_write,
++ .write = sunhv_console_write_bychar,
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+@@ -410,6 +521,7 @@ static inline struct console *SUNHV_CONS
+ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
+ {
+ struct uart_port *port;
++ unsigned long minor;
+ int err;
+
+ if (op->irqs[0] == 0xffffffff)
+@@ -419,6 +531,22 @@ static int __devinit hv_probe(struct of_
+ if (unlikely(!port))
+ return -ENOMEM;
+
++ minor = 1;
++ if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
++ minor >= 1) {
++ err = -ENOMEM;
++ con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!con_write_page)
++ goto out_free_port;
++
++ con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
++ if (!con_read_page)
++ goto out_free_con_write_page;
++
++ sunhv_console.write = sunhv_console_write_paged;
++ sunhv_ops = &bywrite_ops;
++ }
++
+ sunhv_port = port;
+
+ port->line = 0;
+@@ -437,7 +565,7 @@ static int __devinit hv_probe(struct of_
+
+ err = uart_register_driver(&sunhv_reg);
+ if (err)
+- goto out_free_port;
++ goto out_free_con_read_page;
+
+ sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
+ sunserial_current_minor += 1;
+@@ -463,6 +591,12 @@ out_unregister_driver:
+ sunserial_current_minor -= 1;
+ uart_unregister_driver(&sunhv_reg);
+
++out_free_con_read_page:
++ kfree(con_read_page);
++
++out_free_con_write_page:
++ kfree(con_write_page);
++
+ out_free_port:
+ kfree(port);
+ sunhv_port = NULL;
+--- linux-2.6.20.12.orig/include/asm-sparc64/hypervisor.h
++++ linux-2.6.20.12/include/asm-sparc64/hypervisor.h
+@@ -940,6 +940,54 @@ struct hv_fault_status {
+ */
+ #define HV_FAST_CONS_PUTCHAR 0x61
+
++/* con_read()
++ * TRAP: HV_FAST_TRAP
++ * FUNCTION: HV_FAST_CONS_READ
++ * ARG0: buffer real address
++ * ARG1: buffer size in bytes
++ * RET0: status
++ * RET1: bytes read or BREAK or HUP
++ * ERRORS: EWOULDBLOCK No character available.
++ *
++ * Reads characters into a buffer from the console device. If no
++ * character is available then an EWOULDBLOCK error is returned.
++ * If a character is available, then the returned status is EOK
++ * and the number of bytes read into the given buffer is provided
++ * in RET1.
++ *
++ * A virtual BREAK is represented by the 64-bit RET1 value -1.
++ *
++ * A virtual HUP signal is represented by the 64-bit RET1 value -2.
++ *
++ * If BREAK or HUP are indicated, no bytes were read into buffer.
++ */
++#define HV_FAST_CONS_READ 0x62
++
++/* con_write()
++ * TRAP: HV_FAST_TRAP
++ * FUNCTION: HV_FAST_CONS_WRITE
++ * ARG0: buffer real address
++ * ARG1: buffer size in bytes
++ * RET0: status
++ * RET1: bytes written
++ * ERRORS: EWOULDBLOCK Output buffer currently full, would block
++ *
++ * Send a characters in buffer to the console device. Breaks must be
++ * sent using con_putchar().
++ */
++#define HV_FAST_CONS_WRITE 0x63
++
++#ifndef __ASSEMBLY__
++extern long sun4v_con_getchar(long *status);
++extern long sun4v_con_putchar(long c);
++extern long sun4v_con_read(unsigned long buffer,
++ unsigned long size,
++ unsigned long *bytes_read);
++extern unsigned long sun4v_con_write(unsigned long buffer,
++ unsigned long size,
++ unsigned long *bytes_written);
++#endif
++
+ /* Trap trace services.
+ *
+ * The hypervisor provides a trap tracing capability for privileged
+@@ -2121,8 +2169,41 @@ struct hv_mmu_statistics {
+ #define HV_FAST_MMUSTAT_INFO 0x103
+
+ /* Function numbers for HV_CORE_TRAP. */
+-#define HV_CORE_VER 0x00
++#define HV_CORE_SET_VER 0x00
+ #define HV_CORE_PUTCHAR 0x01
+ #define HV_CORE_EXIT 0x02
++#define HV_CORE_GET_VER 0x03
++
++/* Hypervisor API groups for use with HV_CORE_SET_VER and
++ * HV_CORE_GET_VER.
++ */
++#define HV_GRP_SUN4V 0x0000
++#define HV_GRP_CORE 0x0001
++#define HV_GRP_INTR 0x0002
++#define HV_GRP_SOFT_STATE 0x0003
++#define HV_GRP_PCI 0x0100
++#define HV_GRP_LDOM 0x0101
++#define HV_GRP_SVC_CHAN 0x0102
++#define HV_GRP_NCS 0x0103
++#define HV_GRP_NIAG_PERF 0x0200
++#define HV_GRP_FIRE_PERF 0x0201
++#define HV_GRP_DIAG 0x0300
++
++#ifndef __ASSEMBLY__
++extern unsigned long sun4v_get_version(unsigned long group,
++ unsigned long *major,
++ unsigned long *minor);
++extern unsigned long sun4v_set_version(unsigned long group,
++ unsigned long major,
++ unsigned long minor,
++ unsigned long *actual_minor);
++
++extern int sun4v_hvapi_register(unsigned long group, unsigned long major,
++ unsigned long *minor);
++extern void sun4v_hvapi_unregister(unsigned long group);
++extern int sun4v_hvapi_get(unsigned long group,
++ unsigned long *major,
++ unsigned long *minor);
++#endif
+
+ #endif /* !(_SPARC64_HYPERVISOR_H) */
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:59:13 2007
+Date: Wed, 06 Jun 2007 22:59:24 -0700 (PDT)
+Message-Id: <20070606.225924.88342677.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Don't be picky about virtual-dma values on sun4v.
+
+Handle arbitrary base and length values as long as they
+are multiples of IO_PAGE_SIZE.
+
+Bug found by Arun Kumar Rao.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/pci_sun4v.c | 36 ++++++++++--------------------------
+ 1 file changed, 10 insertions(+), 26 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/pci_sun4v.c
++++ linux-2.6.20.12/arch/sparc64/kernel/pci_sun4v.c
+@@ -10,6 +10,7 @@
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+ #include <linux/percpu.h>
++#include <linux/log2.h>
+
+ #include <asm/pbm.h>
+ #include <asm/iommu.h>
+@@ -994,9 +995,8 @@ static void pci_sun4v_iommu_init(struct
+ {
+ struct pci_iommu *iommu = pbm->iommu;
+ struct property *prop;
+- unsigned long num_tsb_entries, sz;
++ unsigned long num_tsb_entries, sz, tsbsize;
+ u32 vdma[2], dma_mask, dma_offset;
+- int tsbsize;
+
+ prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
+ if (prop) {
+@@ -1010,31 +1010,15 @@ static void pci_sun4v_iommu_init(struct
+ vdma[1] = 0x80000000;
+ }
+
+- dma_mask = vdma[0];
+- switch (vdma[1]) {
+- case 0x20000000:
+- dma_mask |= 0x1fffffff;
+- tsbsize = 64;
+- break;
+-
+- case 0x40000000:
+- dma_mask |= 0x3fffffff;
+- tsbsize = 128;
+- break;
+-
+- case 0x80000000:
+- dma_mask |= 0x7fffffff;
+- tsbsize = 256;
+- break;
+-
+- default:
+- prom_printf("PCI-SUN4V: strange virtual-dma size.\n");
+- prom_halt();
++ if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
++ prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
++ vdma[0], vdma[1]);
++ prom_halt();
+ };
+
+- tsbsize *= (8 * 1024);
+-
+- num_tsb_entries = tsbsize / sizeof(iopte_t);
++ dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
++ num_tsb_entries = vdma[1] / IO_PAGE_SIZE;
++ tsbsize = num_tsb_entries * sizeof(iopte_t);
+
+ dma_offset = vdma[0];
+
+@@ -1045,7 +1029,7 @@ static void pci_sun4v_iommu_init(struct
+ iommu->dma_addr_mask = dma_mask;
+
+ /* Allocate and initialize the free area map. */
+- sz = num_tsb_entries / 8;
++ sz = (num_tsb_entries + 7) / 8;
+ sz = (sz + 7UL) & ~7UL;
+ iommu->arena.map = kzalloc(sz, GFP_KERNEL);
+ if (!iommu->arena.map) {
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:56:08 2007
+Date: Wed, 06 Jun 2007 22:56:19 -0700 (PDT)
+Message-Id: <20070606.225619.91314293.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Fix _PAGE_EXEC_4U check in sun4u I-TLB miss handler.
+
+It was using an immediate _PAGE_EXEC_4U value in an 'and'
+instruction to perform the test. This doesn't work because
+the immediate field is signed 13-bit, this the mask being
+tested against the PTE was 0x1000 sign-extended to 32-bits
+instead of just plain 0x1000.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/itlb_miss.S | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/itlb_miss.S
++++ linux-2.6.20.12/arch/sparc64/kernel/itlb_miss.S
+@@ -11,12 +11,12 @@
+ /* ITLB ** ICACHE line 2: TSB compare and TLB load */
+ bne,pn %xcc, tsb_miss_itlb ! Miss
+ mov FAULT_CODE_ITLB, %g3
+- andcc %g5, _PAGE_EXEC_4U, %g0 ! Executable?
++ sethi %hi(_PAGE_EXEC_4U), %g4
++ andcc %g5, %g4, %g0 ! Executable?
+ be,pn %xcc, tsb_do_fault
+ nop ! Delay slot, fill me
+ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB
+ retry ! Trap done
+- nop
+
+ /* ITLB ** ICACHE line 3: */
+ nop
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 22:52:23 2007
+Date: Wed, 06 Jun 2007 22:52:35 -0700 (PDT)
+Message-Id: <20070606.225235.53338976.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Fix two bugs wrt. kernel 4MB TSB.
+
+1) The TSB lookup was not using the correct hash mask.
+
+2) It was not aligned on a boundary equal to it's size,
+ which is required by the sun4v Hypervisor.
+
+wasn't having it's return value checked, and that bug will be fixed up
+as well in a subsequent changeset.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/head.S | 31 ++++++++++++++++++++++++++-----
+ arch/sparc64/mm/init.c | 7 +++++--
+ include/asm-sparc64/tsb.h | 2 +-
+ 3 files changed, 32 insertions(+), 8 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/head.S
++++ linux-2.6.20.12/arch/sparc64/kernel/head.S
+@@ -653,33 +653,54 @@ setup_tba:
+ restore
+ sparc64_boot_end:
+
+-#include "ktlb.S"
+-#include "tsb.S"
+ #include "etrap.S"
+ #include "rtrap.S"
+ #include "winfixup.S"
+ #include "entry.S"
+ #include "sun4v_tlb_miss.S"
+ #include "sun4v_ivec.S"
++#include "ktlb.S"
++#include "tsb.S"
+
+ /*
+ * The following skip makes sure the trap table in ttable.S is aligned
+ * on a 32K boundary as required by the v9 specs for TBA register.
+ *
+ * We align to a 32K boundary, then we have the 32K kernel TSB,
+- * then the 32K aligned trap table.
++ * the 64K kernel 4MB TSB, and then the 32K aligned trap table.
+ */
+ 1:
+ .skip 0x4000 + _start - 1b
+
++! 0x0000000000408000
++
+ .globl swapper_tsb
+ swapper_tsb:
+ .skip (32 * 1024)
+
+-! 0x0000000000408000
+-
++ .globl swapper_4m_tsb
++swapper_4m_tsb:
++ .skip (64 * 1024)
++
++! 0x0000000000420000
++
++ /* Some care needs to be exercised if you try to move the
++ * location of the trap table relative to other things. For
++ * one thing there are br* instructions in some of the
++ * trap table entires which branch back to code in ktlb.S
++ * Those instructions can only handle a signed 16-bit
++ * displacement.
++ *
++ * There is a binutils bug (bugzilla #4558) which causes
++ * the relocation overflow checks for such instructions to
++ * not be done correctly. So bintuils will not notice the
++ * error and will instead write junk into the relocation and
++ * you'll have an unbootable kernel.
++ */
+ #include "ttable.S"
+
++! 0x0000000000428000
++
+ #include "systbls.S"
+
+ .data
+--- linux-2.6.20.12.orig/arch/sparc64/mm/init.c
++++ linux-2.6.20.12/arch/sparc64/mm/init.c
+@@ -60,8 +60,11 @@ unsigned long kern_linear_pte_xor[2] __r
+ unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+
+ #ifndef CONFIG_DEBUG_PAGEALLOC
+-/* A special kernel TSB for 4MB and 256MB linear mappings. */
+-struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
++/* A special kernel TSB for 4MB and 256MB linear mappings.
++ * Space is allocated for this right after the trap table
++ * in arch/sparc64/kernel/head.S
++ */
++extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
+ #endif
+
+ #define MAX_BANKS 32
+--- linux-2.6.20.12.orig/include/asm-sparc64/tsb.h
++++ linux-2.6.20.12/include/asm-sparc64/tsb.h
+@@ -271,7 +271,7 @@ extern struct tsb_phys_patch_entry __tsb
+ #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
+ sethi %hi(swapper_4m_tsb), REG1; \
+ or REG1, %lo(swapper_4m_tsb), REG1; \
+- and TAG, (KERNEL_TSB_NENTRIES - 1), REG2; \
++ and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
+ sllx REG2, 4, REG2; \
+ add REG1, REG2, REG2; \
+ KTSB_LOAD_QUAD(REG2, REG3); \
--- /dev/null
+From stable-bounces@linux.kernel.org Wed Jun 6 23:01:11 2007
+Date: Wed, 06 Jun 2007 23:01:05 -0700 (PDT)
+Message-Id: <20070606.230105.57444963.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: TCP: Use default 32768-61000 outgoing port range in all cases.
+
+From: Mark Glines <mark@glines.org>
+
+This diff changes the default port range used for outgoing connections,
+from "use 32768-61000 in most cases, but use N-4999 on small boxes
+(where N is a multiple of 1024, depending on just *how* small the box
+is)" to just "use 32768-61000 in all cases".
+
+I don't believe there are any drawbacks to this change, and it keeps
+outgoing connection ports farther away from the mess of
+IANA-registered ports.
+
+Signed-off-by: Mark Glines <mark@glines.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+ net/ipv4/inet_connection_sock.c | 4 +---
+ net/ipv4/tcp.c | 3 ---
+ 2 files changed, 1 insertion(+), 6 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/inet_connection_sock.c
++++ linux-2.6.20.12/net/ipv4/inet_connection_sock.c
+@@ -31,10 +31,8 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
+
+ /*
+ * This array holds the first and last local port number.
+- * For high-usage systems, use sysctl to change this to
+- * 32768-61000
+ */
+-int sysctl_local_port_range[2] = { 1024, 4999 };
++int sysctl_local_port_range[2] = { 32768, 61000 };
+
+ int inet_csk_bind_conflict(const struct sock *sk,
+ const struct inet_bind_bucket *tb)
+--- linux-2.6.20.12.orig/net/ipv4/tcp.c
++++ linux-2.6.20.12/net/ipv4/tcp.c
+@@ -2445,13 +2445,10 @@ void __init tcp_init(void)
+ order++)
+ ;
+ if (order >= 4) {
+- sysctl_local_port_range[0] = 32768;
+- sysctl_local_port_range[1] = 61000;
+ tcp_death_row.sysctl_max_tw_buckets = 180000;
+ sysctl_tcp_max_orphans = 4096 << (order - 4);
+ sysctl_max_syn_backlog = 1024;
+ } else if (order < 3) {
+- sysctl_local_port_range[0] = 1024 * (3 - order);
+ tcp_death_row.sysctl_max_tw_buckets >>= (3 - order);
+ sysctl_tcp_max_orphans >>= (3 - order);
+ sysctl_max_syn_backlog = 128;