Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v4 12/12] tree-wide: convert open calls to remove spaces to skip_spaces() lib function
From: Theodore Tso @ 2009-11-08 18:47 UTC (permalink / raw)
  To: André Goddard Rosa
  Cc: Pavel Roskin, Stefan Haberland, Jan Kara, linux-cachefs,
	Mike Snitzer, Neil Brown, Frederic Weisbecker, Jens Axboe,
	Heiko Carstens, James E . J . Bottomley, ibm-acpi-devel, dm-devel,
	Julia Lawall, H . Peter Anvin, Daire Byrne, Alasdair G Kergon,
	Greg Banks, Stefan Weinhuber, Eric Sandeen, Adam Belay,
	Helge Deller, x86, James Morris, Takashi Iwai, Ingo Molnar,
	Alan Cox
In-Reply-To: <7d5883637aa976b54e944998f635d47a41618a75.1257602781.git.andre.goddard@gmail.com>

On Sat, Nov 07, 2009 at 01:16:20PM -0200, André Goddard Rosa wrote:
> Makes use of skip_spaces() defined in lib/string.c for removing leading
> spaces from strings all over the tree.
> 
> Also, while at it, if we see (*str && isspace(*str)), we can be sure to
> remove the first condition (*str) as the second one (isspace(*str)) also
> evaluates to 0 whenever *str == 0, making it redundant. In other words,
> "a char equals zero is never a space".

There are a number of places that have the pattern of skipping
whitespace, calling simpler_strtoul(), and then skipping whitespace
afterwards.  And thinkpad_acpi.c and fs/ext4/super.c both have an
indentical function, parse_strotul(), which basically does this plus
doing actual error checking (a number of callers of simple_strtoul
aren't checking to see if the user passed in a valid number or not,
boo.)

I would suggest that we should lift parse_strtoul() into lib/, both to
save a bit of code, as well as encouraging people to do proper input
validation, while we are doing this tree-wide cleanup.

						- Ted

^ permalink raw reply

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Paul E. McKenney @ 2009-11-08 19:36 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Michael S. Tsirkin, Gregory Haskins, Eric Dumazet, netdev,
	virtualization, kvm, linux-kernel, mingo, linux-mm, akpm, hpa,
	s.hetze
In-Reply-To: <200911081439.59770.rusty@rustcorp.com.au>

On Sun, Nov 08, 2009 at 02:39:59PM +1030, Rusty Russell wrote:
> On Sat, 7 Nov 2009 03:00:07 am Paul E. McKenney wrote:
> > On Fri, Nov 06, 2009 at 03:31:20PM +1030, Rusty Russell wrote:
> > > But it's still nasty to use half an API.  If it were a few places I would
> > > have open-coded it with a comment, or wrapped it.  As it is, I don't think
> > > that would be a win.
> > 
> > So would it help to have a rcu_read_lock_workqueue() and
> > rcu_read_unlock_workqueue() that checked nesting and whether they were
> > actually running in the context of a workqueue item?  Or did you have
> > something else in mind?  Or am I misjudging the level of sarcasm in
> > your reply?  ;-)
> 
> You read correctly.  If we get a second user, creating an API makes sense.

Makes sense to me as well.  Which does provide some time to come up with
a primitive designed to answer the question "Am I currently executing in
the context of a workqueue item?".  ;-)

							Thanx, Paul

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* [PATCH 0/8 net-next-2.6] udp: optimisations
From: Eric Dumazet @ 2009-11-08 20:16 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

This patch series address UDP scalability problems, we failed to solve in 2007
(commit 6aaf47fa48d3c44 INET : IPV4 UDP lookups converted to a 2 pass algo)
we had to revert a bit later.

One of the problem of UDP is its use of a single hash table, with
a key based on local port value only. When many IP addresses are used,
it is possible to have a chain with very large number N of sockets,
lookup time being N/2 in average.

Size of hash table has no effect on this, since all sockets are
chained in one particular slot.

It seems Lucian Adrian Grijincu & Octavian Purdila from IXIACOM have 
real workloads hitting hard this problem and posted a preliminary
patch/RFC, using a second hash, but based on (local address).

I took part of Lucian ideas and my previous patches, and cooked
a clean upgrade path.

With following patches, we might handle 1.000.000+ udp sockets
in linux without major slowdown, and no penalty for common cases.

Thanks

[PATCH 1/8] udp: add a counter into udp_hslot

Adds a counter in udp_hslot to keep an accurate count
of sockets present in chain.

This will permit to upcoming UDP lookup algo to chose
the shortest chain when secondary hash is added.

[PATCH 2/8] udp: split sk_hash into two u16 hashes

nion sk_hash with two u16 hashes for udp (no extra memory taken)

One 16 bits hash on (local port) value (the previous udp 'hash')

One 16 bits hash on (local address, local port) values, initialized
but not yet used. This second hash is using jenkin hash for better
distribution.

Because the 'port' is xored later, a partial hash is performed
on local address + net_hash_mix(net)

[PATCH 3/8] udp: secondary hash on (local port, local address)

Extends udp_table to contain a secondary hash table.

socket anchor for this second hash is free, because UDP
doesnt use skc_bind_node : We define an union to hold
both skc_bind_node & a new hlist_nulls_node udp_portaddr_node

udp_lib_get_port() inserts sockets into second hash chain
(additional cost of one atomic op)

udp_lib_unhash() deletes socket from second hash chain
(additional cost of one atomic op)

Note : No special lockdep annotation is needed, because
lock for the secondary hash chain is always get after
lock for primary hash chain.

[PATCH 4/8] ipv4: udp: optimize unicast RX path

We first locate the (local port) hash chain head
If few sockets are in this chain, we proceed with previous lookup algo.

If too many sockets are listed, we take a look at the secondary
(port, address) hash chain.

We choose the shortest chain and proceed with a RCU lookup on the elected chain.

But, if we chose (port, address) chain, and fail to find a socket on given address,
 we must try another lookup on (port, INADDR_ANY) chain to find sockets not bound
to a particular IP.

-> No extra cost for typical setups, where the first lookup will probabbly
be performed.

RCU lookups everywhere, we dont acquire spinlock.

[PATCH 5/8] ipv6: udp: optimize unicast RX path

Same algo than patch 4, but for ipv6


[PATCH 6/8] ipv4: udp: Optimise multicast reception

UDP multicast rx path is a bit complex and can hold a spinlock
for a long time.

Using a small (32 or 64 entries) stack of socket pointers can help
to perform expensive operations (skb_clone(), udp_queue_rcv_skb())
outside of the lock, in most cases.

It's also a base for a future RCU conversion of multicast recption.


[PATCH 7/8] ipv6: udp: Optimise multicast reception

Same optimisation, but for ipv6

[PATCH 8/8] udp: multicast RX should increment SNMP/sk_drops counter in allocation failures

When skb_clone() fails, we should increment sk_drops and SNMP counters.
This fix is not urgent and better done after previous patches.

-------------------------------------------------------------------------------------

Furthers patches could be :

udp: bind() optimisations
udp: multicast uses of secondary hash 
udp: multicast path uses RCU  

^ permalink raw reply

* [PATCH 1/8] udp: add a counter into udp_hslot
From: Eric Dumazet @ 2009-11-08 20:17 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

Adds a counter in udp_hslot to keep an accurate count
of sockets present in chain.

This will permit to upcoming UDP lookup algo to chose
the shortest chain when secondary hash is added.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 include/net/udp.h |    8 ++++++++
 net/ipv4/udp.c    |    3 +++
 2 files changed, 11 insertions(+)

diff --git a/include/net/udp.h b/include/net/udp.h
index 22aa2e7..9167281 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -50,8 +50,16 @@ struct udp_skb_cb {
 };
 #define UDP_SKB_CB(__skb)	((struct udp_skb_cb *)((__skb)->cb))
 
+/**
+ *	struct udp_hslot - UDP hash slot
+ *
+ *	@head:	head of list of sockets
+ *	@count:	number of sockets in 'head' list
+ *	@lock:	spinlock protecting changes to head/count
+ */
 struct udp_hslot {
 	struct hlist_nulls_head	head;
+	int			count;
 	spinlock_t		lock;
 } __attribute__((aligned(2 * sizeof(long))));
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d5e75e9..ffc8376 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -218,6 +218,7 @@ found:
 	sk->sk_hash = snum;
 	if (sk_unhashed(sk)) {
 		sk_nulls_add_node_rcu(sk, &hslot->head);
+		hslot->count++;
 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	}
 	error = 0;
@@ -1053,6 +1054,7 @@ void udp_lib_unhash(struct sock *sk)
 
 		spin_lock_bh(&hslot->lock);
 		if (sk_nulls_del_node_init_rcu(sk)) {
+			hslot->count--;
 			inet_sk(sk)->inet_num = 0;
 			sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
 		}
@@ -1862,6 +1864,7 @@ void __init udp_table_init(struct udp_table *table, const char *name)
 	}
 	for (i = 0; i <= table->mask; i++) {
 		INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
+		table->hash[i].count = 0;
 		spin_lock_init(&table->hash[i].lock);
 	}
 }

^ permalink raw reply related

* [PATCH 2/8] udp: split sk_hash into two u16 hashes
From: Eric Dumazet @ 2009-11-08 20:17 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

Union sk_hash with two u16 hashes for udp (no extra memory taken)

One 16 bits hash on (local port) value (the previous udp 'hash')

One 16 bits hash on (local address, local port) values, initialized
but not yet used. This second hash is using jenkin hash for better
distribution.

Because the 'port' is xored later, a partial hash is performed
on local address + net_hash_mix(net)

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 include/linux/udp.h |    2 ++
 include/net/sock.h  |    6 +++++-
 net/ipv4/udp.c      |   25 +++++++++++++++++++------
 net/ipv6/udp.c      |   27 +++++++++++++++++++++++++--
 4 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/include/linux/udp.h b/include/linux/udp.h
index 832361e..5b4b527 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -55,6 +55,8 @@ static inline int udp_hashfn(struct net *net, unsigned num, unsigned mask)
 struct udp_sock {
 	/* inet_sock has to be the first member */
 	struct inet_sock inet;
+#define udp_port_hash		inet.sk.__sk_common.skc_u16hashes[0]
+#define udp_portaddr_hash	inet.sk.__sk_common.skc_u16hashes[1]
 	int		 pending;	/* Any pending frames ? */
 	unsigned int	 corkflag;	/* Cork is required */
   	__u16		 encap_type;	/* Is this an Encapsulation socket? */
diff --git a/include/net/sock.h b/include/net/sock.h
index 55de3bd..827366b 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -109,6 +109,7 @@ struct net;
  *	@skc_refcnt: reference count
  *	@skc_tx_queue_mapping: tx queue number for this connection
  *	@skc_hash: hash value used with various protocol lookup tables
+ *	@skc_u16hashes: two u16 hash values used by UDP lookup tables
  *	@skc_family: network address family
  *	@skc_state: Connection state
  *	@skc_reuse: %SO_REUSEADDR setting
@@ -131,7 +132,10 @@ struct sock_common {
 	atomic_t		skc_refcnt;
 	int			skc_tx_queue_mapping;
 
-	unsigned int		skc_hash;
+	union  {
+		unsigned int	skc_hash;
+		__u16		skc_u16hashes[2];
+	};
 	unsigned short		skc_family;
 	volatile unsigned char	skc_state;
 	unsigned char		skc_reuse;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ffc8376..af72de1 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -138,13 +138,14 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
 	sk_nulls_for_each(sk2, node, &hslot->head)
 		if (net_eq(sock_net(sk2), net)			&&
 		    sk2 != sk					&&
-		    (bitmap || sk2->sk_hash == num)		&&
+		    (bitmap || udp_sk(sk2)->udp_port_hash == num) &&
 		    (!sk2->sk_reuse || !sk->sk_reuse)		&&
 		    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
 			|| sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
 		    (*saddr_comp)(sk, sk2)) {
 			if (bitmap)
-				__set_bit(sk2->sk_hash >> log, bitmap);
+				__set_bit(udp_sk(sk2)->udp_port_hash >> log,
+					  bitmap);
 			else
 				return 1;
 		}
@@ -215,7 +216,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
 	}
 found:
 	inet_sk(sk)->inet_num = snum;
-	sk->sk_hash = snum;
+	udp_sk(sk)->udp_port_hash = snum;
+	udp_sk(sk)->udp_portaddr_hash ^= snum;
 	if (sk_unhashed(sk)) {
 		sk_nulls_add_node_rcu(sk, &hslot->head);
 		hslot->count++;
@@ -238,8 +240,19 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 		   inet1->inet_rcv_saddr == inet2->inet_rcv_saddr));
 }
 
+static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr,
+				       unsigned int port)
+{
+	return jhash_1word(saddr, net_hash_mix(net)) ^ port;
+}
+
 int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
+	/* precompute partial secondary hash */
+	udp_sk(sk)->udp_portaddr_hash =
+		udp4_portaddr_hash(sock_net(sk),
+				   inet_sk(sk)->inet_rcv_saddr,
+				   0);
 	return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal);
 }
 
@@ -249,7 +262,7 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
 {
 	int score = -1;
 
-	if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
+	if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
 			!ipv6_only_sock(sk)) {
 		struct inet_sock *inet = inet_sk(sk);
 
@@ -360,7 +373,7 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk,
 		struct inet_sock *inet = inet_sk(s);
 
 		if (!net_eq(sock_net(s), net)				||
-		    s->sk_hash != hnum					||
+		    udp_sk(s)->udp_port_hash != hnum			||
 		    (inet->inet_daddr && inet->inet_daddr != rmt_addr)	||
 		    (inet->inet_dport != rmt_port && inet->inet_dport)	||
 		    (inet->inet_rcv_saddr	&&
@@ -1050,7 +1063,7 @@ void udp_lib_unhash(struct sock *sk)
 	if (sk_hashed(sk)) {
 		struct udp_table *udptable = sk->sk_prot->h.udp_table;
 		struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk),
-						     sk->sk_hash);
+						       udp_sk(sk)->udp_port_hash);
 
 		spin_lock_bh(&hslot->lock);
 		if (sk_nulls_del_node_init_rcu(sk)) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 5bc7cdb..1e5fadd 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -81,8 +81,30 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 	return 0;
 }
 
+static unsigned int udp6_portaddr_hash(struct net *net,
+				       const struct in6_addr *addr6,
+				       unsigned int port)
+{
+	unsigned int hash, mix = net_hash_mix(net);
+
+	if (ipv6_addr_any(addr6))
+		hash = jhash_1word(0, mix);
+	else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED)
+		hash = jhash_1word(addr6->s6_addr32[3], mix);
+	else
+		hash = jhash2(addr6->s6_addr32, 4, mix);
+
+	return hash ^ port;
+}
+
+
 int udp_v6_get_port(struct sock *sk, unsigned short snum)
 {
+	/* precompute partial secondary hash */
+	udp_sk(sk)->udp_portaddr_hash =
+		udp6_portaddr_hash(sock_net(sk),
+				   &inet6_sk(sk)->rcv_saddr,
+				   0);
 	return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal);
 }
 
@@ -94,7 +116,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
 {
 	int score = -1;
 
-	if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
+	if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
 			sk->sk_family == PF_INET6) {
 		struct ipv6_pinfo *np = inet6_sk(sk);
 		struct inet_sock *inet = inet_sk(sk);
@@ -415,7 +437,8 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk,
 		if (!net_eq(sock_net(s), net))
 			continue;
 
-		if (s->sk_hash == num && s->sk_family == PF_INET6) {
+		if (udp_sk(s)->udp_port_hash == num &&
+		    s->sk_family == PF_INET6) {
 			struct ipv6_pinfo *np = inet6_sk(s);
 			if (inet->inet_dport) {
 				if (inet->inet_dport != rmt_port)

^ permalink raw reply related

* [PATCH 3/8] udp: secondary hash on (local port, local address)
From: Eric Dumazet @ 2009-11-08 20:17 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

Extends udp_table to contain a secondary hash table.

socket anchor for this second hash is free, because UDP
doesnt use skc_bind_node : We define an union to hold
both skc_bind_node & a new hlist_nulls_node udp_portaddr_node

udp_lib_get_port() inserts sockets into second hash chain
(additional cost of one atomic op)

udp_lib_unhash() deletes socket from second hash chain
(additional cost of one atomic op)

Note : No spinlock lockdep annotation is needed, because
lock for the secondary hash chain is always get after
lock for primary hash chain.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 include/linux/udp.h |    1 +
 include/net/sock.h  |    8 ++++++--
 include/net/udp.h   |   22 ++++++++++++++++++++--
 net/ipv4/udp.c      |   31 ++++++++++++++++++++++++++-----
 4 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/include/linux/udp.h b/include/linux/udp.h
index 5b4b527..59f0ddf 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -57,6 +57,7 @@ struct udp_sock {
 	struct inet_sock inet;
 #define udp_port_hash		inet.sk.__sk_common.skc_u16hashes[0]
 #define udp_portaddr_hash	inet.sk.__sk_common.skc_u16hashes[1]
+#define udp_portaddr_node	inet.sk.__sk_common.skc_portaddr_node
 	int		 pending;	/* Any pending frames ? */
 	unsigned int	 corkflag;	/* Cork is required */
   	__u16		 encap_type;	/* Is this an Encapsulation socket? */
diff --git a/include/net/sock.h b/include/net/sock.h
index 827366b..3f1a480 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -105,7 +105,7 @@ struct net;
 /**
  *	struct sock_common - minimal network layer representation of sockets
  *	@skc_node: main hash linkage for various protocol lookup tables
- *	@skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol
+ *	@skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol
  *	@skc_refcnt: reference count
  *	@skc_tx_queue_mapping: tx queue number for this connection
  *	@skc_hash: hash value used with various protocol lookup tables
@@ -115,6 +115,7 @@ struct net;
  *	@skc_reuse: %SO_REUSEADDR setting
  *	@skc_bound_dev_if: bound device index if != 0
  *	@skc_bind_node: bind hash linkage for various protocol lookup tables
+ *	@skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol
  *	@skc_prot: protocol handlers inside a network family
  *	@skc_net: reference to the network namespace of this socket
  *
@@ -140,7 +141,10 @@ struct sock_common {
 	volatile unsigned char	skc_state;
 	unsigned char		skc_reuse;
 	int			skc_bound_dev_if;
-	struct hlist_node	skc_bind_node;
+	union {
+		struct hlist_node	skc_bind_node;
+		struct hlist_nulls_node skc_portaddr_node;
+	};
 	struct proto		*skc_prot;
 #ifdef CONFIG_NET_NS
 	struct net	 	*skc_net;
diff --git a/include/net/udp.h b/include/net/udp.h
index 9167281..af41850 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -63,10 +63,19 @@ struct udp_hslot {
 	spinlock_t		lock;
 } __attribute__((aligned(2 * sizeof(long))));
 
+/**
+ *	struct udp_table - UDP table
+ *
+ *	@hash:	hash table, sockets are hashed on (local port)
+ *	@hash2:	hash table, sockets are hashed on (local port, local address)
+ *	@mask:	number of slots in hash tables, minus 1
+ *	@log:	log2(number of slots in hash table)
+ */
 struct udp_table {
 	struct udp_hslot	*hash;
-	unsigned int mask;
-	unsigned int log;
+	struct udp_hslot	*hash2;
+	unsigned int		mask;
+	unsigned int		log;
 };
 extern struct udp_table udp_table;
 extern void udp_table_init(struct udp_table *, const char *);
@@ -75,6 +84,15 @@ static inline struct udp_hslot *udp_hashslot(struct udp_table *table,
 {
 	return &table->hash[udp_hashfn(net, num, table->mask)];
 }
+/*
+ * For secondary hash, net_hash_mix() is performed before calling
+ * udp_hashslot2(), this explains difference with udp_hashslot()
+ */
+static inline struct udp_hslot *udp_hashslot2(struct udp_table *table,
+					      unsigned int hash)
+{
+	return &table->hash2[hash & table->mask];
+}
 
 /* Note: this must match 'valbool' in sock_setsockopt */
 #define UDP_CSUM_NOXMIT		1
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index af72de1..5f04216 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -163,7 +163,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
 		       int (*saddr_comp)(const struct sock *sk1,
 					 const struct sock *sk2))
 {
-	struct udp_hslot *hslot;
+	struct udp_hslot *hslot, *hslot2;
 	struct udp_table *udptable = sk->sk_prot->h.udp_table;
 	int    error = 1;
 	struct net *net = sock_net(sk);
@@ -222,6 +222,13 @@ found:
 		sk_nulls_add_node_rcu(sk, &hslot->head);
 		hslot->count++;
 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+
+		hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
+		spin_lock(&hslot2->lock);
+		hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node,
+					 &hslot2->head);
+		hslot2->count++;
+		spin_unlock(&hslot2->lock);
 	}
 	error = 0;
 fail_unlock:
@@ -1062,14 +1069,22 @@ void udp_lib_unhash(struct sock *sk)
 {
 	if (sk_hashed(sk)) {
 		struct udp_table *udptable = sk->sk_prot->h.udp_table;
-		struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk),
-						       udp_sk(sk)->udp_port_hash);
+		struct udp_hslot *hslot, *hslot2;
+
+		hslot  = udp_hashslot(udptable, sock_net(sk),
+				      udp_sk(sk)->udp_port_hash);
+		hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
 
 		spin_lock_bh(&hslot->lock);
 		if (sk_nulls_del_node_init_rcu(sk)) {
 			hslot->count--;
 			inet_sk(sk)->inet_num = 0;
 			sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+
+			spin_lock(&hslot2->lock);
+			hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node);
+			hslot2->count--;
+			spin_unlock(&hslot2->lock);
 		}
 		spin_unlock_bh(&hslot->lock);
 	}
@@ -1857,7 +1872,7 @@ void __init udp_table_init(struct udp_table *table, const char *name)
 
 	if (!CONFIG_BASE_SMALL)
 		table->hash = alloc_large_system_hash(name,
-			sizeof(struct udp_hslot),
+			2 * sizeof(struct udp_hslot),
 			uhash_entries,
 			21, /* one slot per 2 MB */
 			0,
@@ -1869,17 +1884,23 @@ void __init udp_table_init(struct udp_table *table, const char *name)
 	 */
 	if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) {
 		table->hash = kmalloc(UDP_HTABLE_SIZE_MIN *
-				      sizeof(struct udp_hslot), GFP_KERNEL);
+				      2 * sizeof(struct udp_hslot), GFP_KERNEL);
 		if (!table->hash)
 			panic(name);
 		table->log = ilog2(UDP_HTABLE_SIZE_MIN);
 		table->mask = UDP_HTABLE_SIZE_MIN - 1;
 	}
+	table->hash2 = table->hash + (table->mask + 1);
 	for (i = 0; i <= table->mask; i++) {
 		INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
 		table->hash[i].count = 0;
 		spin_lock_init(&table->hash[i].lock);
 	}
+	for (i = 0; i <= table->mask; i++) {
+		INIT_HLIST_NULLS_HEAD(&table->hash2[i].head, i);
+		table->hash2[i].count = 0;
+		spin_lock_init(&table->hash2[i].lock);
+	}
 }
 
 void __init udp_init(void)

^ permalink raw reply related

* [PATCH 4/8] ipv4: udp: optimize unicast RX path
From: Eric Dumazet @ 2009-11-08 20:18 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

We first locate the (local port) hash chain head
If few sockets are in this chain, we proceed with previous lookup algo.

If too many sockets are listed, we take a look at the secondary
(port, address) hash chain we added in previous patch.

We choose the shortest chain and proceed with a RCU lookup on the elected chain.

But, if we chose (port, address) chain, and fail to find a socket on given address,
 we must try another lookup on (port, INADDR_ANY) chain to find socket not bound
to a particular IP.

-> No extra cost for typical setups, where the first lookup will probabbly
be performed.

RCU lookups everywhere, we dont acquire spinlock.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv4/udp.c |  115 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 112 insertions(+), 3 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 5f04216..dd7f3d2 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -298,6 +298,91 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
 	return score;
 }
 
+/*
+ * In this second variant, we check (daddr, dport) matches (inet_rcv_sadd, inet_num)
+ */
+#define SCORE2_MAX (1 + 2 + 2 + 2)
+static inline int compute_score2(struct sock *sk, struct net *net,
+				 __be32 saddr, __be16 sport,
+				 __be32 daddr, unsigned int hnum, int dif)
+{
+	int score = -1;
+
+	if (net_eq(sock_net(sk), net) && !ipv6_only_sock(sk)) {
+		struct inet_sock *inet = inet_sk(sk);
+
+		if (inet->inet_rcv_saddr != daddr)
+			return -1;
+		if (inet->inet_num != hnum)
+			return -1;
+
+		score = (sk->sk_family == PF_INET ? 1 : 0);
+		if (inet->inet_daddr) {
+			if (inet->inet_daddr != saddr)
+				return -1;
+			score += 2;
+		}
+		if (inet->inet_dport) {
+			if (inet->inet_dport != sport)
+				return -1;
+			score += 2;
+		}
+		if (sk->sk_bound_dev_if) {
+			if (sk->sk_bound_dev_if != dif)
+				return -1;
+			score += 2;
+		}
+	}
+	return score;
+}
+
+#define udp_portaddr_for_each_entry_rcu(__sk, node, list) \
+	hlist_nulls_for_each_entry_rcu(__sk, node, list, __sk_common.skc_portaddr_node)
+
+/* called with read_rcu_lock() */
+static struct sock *udp4_lib_lookup2(struct net *net,
+		__be32 saddr, __be16 sport,
+		__be32 daddr, unsigned int hnum, int dif,
+		struct udp_hslot *hslot2, unsigned int slot2)
+{
+	struct sock *sk, *result;
+	struct hlist_nulls_node *node;
+	int score, badness;
+
+begin:
+	result = NULL;
+	badness = -1;
+	udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) {
+		score = compute_score2(sk, net, saddr, sport,
+				      daddr, hnum, dif);
+		if (score > badness) {
+			result = sk;
+			badness = score;
+			if (score == SCORE2_MAX)
+				goto exact_match;
+		}
+	}
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != slot2)
+		goto begin;
+
+	if (result) {
+exact_match:
+		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
+			result = NULL;
+		else if (unlikely(compute_score2(result, net, saddr, sport,
+				  daddr, hnum, dif) < badness)) {
+			sock_put(result);
+			goto begin;
+		}
+	}
+	return result;
+}
+
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
  */
@@ -308,11 +393,35 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 	struct sock *sk, *result;
 	struct hlist_nulls_node *node;
 	unsigned short hnum = ntohs(dport);
-	unsigned int hash = udp_hashfn(net, hnum, udptable->mask);
-	struct udp_hslot *hslot = &udptable->hash[hash];
+	unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
+	struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
 	int score, badness;
 
 	rcu_read_lock();
+	if (hslot->count > 10) {
+		hash2 = udp4_portaddr_hash(net, daddr, hnum);
+		slot2 = hash2 & udptable->mask;
+		hslot2 = &udptable->hash2[slot2];
+		if (hslot->count < hslot2->count)
+			goto begin;
+
+		result = udp4_lib_lookup2(net, saddr, sport,
+					  daddr, hnum, dif,
+					  hslot2, slot2);
+		if (!result) {
+			hash2 = udp4_portaddr_hash(net, INADDR_ANY, hnum);
+			slot2 = hash2 & udptable->mask;
+			hslot2 = &udptable->hash2[slot2];
+			if (hslot->count < hslot2->count)
+				goto begin;
+
+			result = udp4_lib_lookup2(net, INADDR_ANY, sport,
+						  daddr, hnum, dif,
+						  hslot2, slot2);
+		}
+		rcu_read_unlock();
+		return result;
+	}
 begin:
 	result = NULL;
 	badness = -1;
@@ -329,7 +438,7 @@ begin:
 	 * not the expected one, we must restart lookup.
 	 * We probably met an item that was moved to another chain.
 	 */
-	if (get_nulls_value(node) != hash)
+	if (get_nulls_value(node) != slot)
 		goto begin;
 
 	if (result) {

^ permalink raw reply related

* [PATCH 5/8] ipv6: udp: optimize unicast RX path
From: Eric Dumazet @ 2009-11-08 20:18 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

We first locate the (local port) hash chain head
If few sockets are in this chain, we proceed with previous lookup algo.

If too many sockets are listed, we take a look at the secondary
(port, address) hash chain.

We choose the shortest chain and proceed with a RCU lookup on the elected chain.

But, if we chose (port, address) chain, and fail to find a socket on given address,
 we must try another lookup on (port, in6addr_any) chain to find sockets not bound
to a particular IP.

-> No extra cost for typical setups, where the first lookup will probabbly
be performed.

RCU lookups everywhere, we dont acquire spinlock.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv6/udp.c |  112 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 109 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 1e5fadd..c5b0451 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -146,6 +146,88 @@ static inline int compute_score(struct sock *sk, struct net *net,
 	return score;
 }
 
+#define SCORE2_MAX (1 + 1 + 1)
+static inline int compute_score2(struct sock *sk, struct net *net,
+				const struct in6_addr *saddr, __be16 sport,
+				const struct in6_addr *daddr, unsigned short hnum,
+				int dif)
+{
+	int score = -1;
+
+	if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
+			sk->sk_family == PF_INET6) {
+		struct ipv6_pinfo *np = inet6_sk(sk);
+		struct inet_sock *inet = inet_sk(sk);
+
+		if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
+			return -1;
+		score = 0;
+		if (inet->inet_dport) {
+			if (inet->inet_dport != sport)
+				return -1;
+			score++;
+		}
+		if (!ipv6_addr_any(&np->daddr)) {
+			if (!ipv6_addr_equal(&np->daddr, saddr))
+				return -1;
+			score++;
+		}
+		if (sk->sk_bound_dev_if) {
+			if (sk->sk_bound_dev_if != dif)
+				return -1;
+			score++;
+		}
+	}
+	return score;
+}
+
+#define udp_portaddr_for_each_entry_rcu(__sk, node, list) \
+	hlist_nulls_for_each_entry_rcu(__sk, node, list, __sk_common.skc_portaddr_node)
+
+/* called with read_rcu_lock() */
+static struct sock *udp6_lib_lookup2(struct net *net,
+		const struct in6_addr *saddr, __be16 sport,
+		const struct in6_addr *daddr, unsigned int hnum, int dif,
+		struct udp_hslot *hslot2, unsigned int slot2)
+{
+	struct sock *sk, *result;
+	struct hlist_nulls_node *node;
+	int score, badness;
+
+begin:
+	result = NULL;
+	badness = -1;
+	udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) {
+		score = compute_score2(sk, net, saddr, sport,
+				      daddr, hnum, dif);
+		if (score > badness) {
+			result = sk;
+			badness = score;
+			if (score == SCORE2_MAX)
+				goto exact_match;
+		}
+	}
+	/*
+	 * if the nulls value we got at the end of this lookup is
+	 * not the expected one, we must restart lookup.
+	 * We probably met an item that was moved to another chain.
+	 */
+	if (get_nulls_value(node) != slot2)
+		goto begin;
+
+	if (result) {
+exact_match:
+		if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt)))
+			result = NULL;
+		else if (unlikely(compute_score2(result, net, saddr, sport,
+				  daddr, hnum, dif) < badness)) {
+			sock_put(result);
+			goto begin;
+		}
+	}
+	return result;
+}
+
 static struct sock *__udp6_lib_lookup(struct net *net,
 				      struct in6_addr *saddr, __be16 sport,
 				      struct in6_addr *daddr, __be16 dport,
@@ -154,11 +236,35 @@ static struct sock *__udp6_lib_lookup(struct net *net,
 	struct sock *sk, *result;
 	struct hlist_nulls_node *node;
 	unsigned short hnum = ntohs(dport);
-	unsigned int hash = udp_hashfn(net, hnum, udptable->mask);
-	struct udp_hslot *hslot = &udptable->hash[hash];
+	unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask);
+	struct udp_hslot *hslot2, *hslot = &udptable->hash[slot];
 	int score, badness;
 
 	rcu_read_lock();
+	if (hslot->count > 10) {
+		hash2 = udp6_portaddr_hash(net, daddr, hnum);
+		slot2 = hash2 & udptable->mask;
+		hslot2 = &udptable->hash2[slot2];
+		if (hslot->count < hslot2->count)
+			goto begin;
+
+		result = udp6_lib_lookup2(net, saddr, sport,
+					  daddr, hnum, dif,
+					  hslot2, slot2);
+		if (!result) {
+			hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum);
+			slot2 = hash2 & udptable->mask;
+			hslot2 = &udptable->hash2[slot2];
+			if (hslot->count < hslot2->count)
+				goto begin;
+
+			result = udp6_lib_lookup2(net, &in6addr_any, sport,
+						  daddr, hnum, dif,
+						  hslot2, slot2);
+		}
+		rcu_read_unlock();
+		return result;
+	}
 begin:
 	result = NULL;
 	badness = -1;
@@ -174,7 +280,7 @@ begin:
 	 * not the expected one, we must restart lookup.
 	 * We probably met an item that was moved to another chain.
 	 */
-	if (get_nulls_value(node) != hash)
+	if (get_nulls_value(node) != slot)
 		goto begin;
 
 	if (result) {

^ permalink raw reply related

* [PATCH 6/8] ipv4: udp: Optimise multicast reception
From: Eric Dumazet @ 2009-11-08 20:18 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

UDP multicast rx path is a bit complex and can hold a spinlock
for a long time.

Using a small (32 or 64 entries) stack of socket pointers can help
to perform expensive operations (skb_clone(), udp_queue_rcv_skb())
outside of the lock, in most cases.

It's also a base for a future RCU conversion of multicast recption.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Lucian Adrian Grijincu <lgrijincu@ixiacom.com>
---
 net/ipv4/udp.c |   76 ++++++++++++++++++++++++++++++-----------------
 1 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index dd7f3d2..9d9072c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1329,49 +1329,73 @@ drop:
 	return -1;
 }
 
+
+static void flush_stack(struct sock **stack, unsigned int count,
+			struct sk_buff *skb, unsigned int final)
+{
+	unsigned int i;
+	struct sk_buff *skb1 = NULL;
+
+	for (i = 0; i < count; i++) {
+		if (likely(skb1 == NULL))
+			skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
+
+		if (skb1 && udp_queue_rcv_skb(stack[i], skb1) <= 0)
+			skb1 = NULL;
+	}
+	if (unlikely(skb1))
+		kfree_skb(skb1);
+}
+
 /*
  *	Multicasts and broadcasts go to each listener.
  *
- *	Note: called only from the BH handler context,
- *	so we don't need to lock the hashes.
+ *	Note: called only from the BH handler context.
  */
 static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 				    struct udphdr  *uh,
 				    __be32 saddr, __be32 daddr,
 				    struct udp_table *udptable)
 {
-	struct sock *sk;
+	struct sock *sk, *stack[256 / sizeof(struct sock *)];
 	struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
 	int dif;
+	unsigned int i, count = 0;
 
 	spin_lock(&hslot->lock);
 	sk = sk_nulls_head(&hslot->head);
 	dif = skb->dev->ifindex;
 	sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
-	if (sk) {
-		struct sock *sknext = NULL;
-
-		do {
-			struct sk_buff *skb1 = skb;
-
-			sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest,
-						   daddr, uh->source, saddr,
-						   dif);
-			if (sknext)
-				skb1 = skb_clone(skb, GFP_ATOMIC);
-
-			if (skb1) {
-				int ret = udp_queue_rcv_skb(sk, skb1);
-				if (ret > 0)
-					/* we should probably re-process instead
-					 * of dropping packets here. */
-					kfree_skb(skb1);
-			}
-			sk = sknext;
-		} while (sknext);
-	} else
-		consume_skb(skb);
+	while (sk) {
+		stack[count++] = sk;
+		sk = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest,
+				       daddr, uh->source, saddr, dif);
+		if (unlikely(count == ARRAY_SIZE(stack))) {
+			if (!sk)
+				break;
+			flush_stack(stack, count, skb, ~0);
+			count = 0;
+		}
+	}
+	/*
+	 * before releasing chain lock, we must take a reference on sockets
+	 */
+	for (i = 0; i < count; i++)
+		sock_hold(stack[i]);
+
 	spin_unlock(&hslot->lock);
+
+	/*
+	 * do the slow work with no lock held
+	 */
+	if (count) {
+		flush_stack(stack, count, skb, count - 1);
+
+		for (i = 0; i < count; i++)
+			sock_put(stack[i]);
+	} else {
+		kfree_skb(skb);
+	}
 	return 0;
 }
 

^ permalink raw reply related

* [PATCH 7/8] ipv6: udp: Optimise multicast reception
From: Eric Dumazet @ 2009-11-08 20:18 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila


IPV6 UDP multicast rx path is a bit complex and can hold a spinlock
for a long time.

Using a small (32 or 64 entries) stack of socket pointers can help
to perform expensive operations (skb_clone(), udp_queue_rcv_skb())
outside of the lock, in most cases.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv6/udp.c |   71 +++++++++++++++++++++++++++++++----------------
 1 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index c5b0451..173e531 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -569,6 +569,27 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk,
 	return NULL;
 }
 
+static void flush_stack(struct sock **stack, unsigned int count,
+			struct sk_buff *skb, unsigned int final)
+{
+	unsigned int i;
+	struct sock *sk;
+	struct sk_buff *skb1;
+
+	for (i = 0; i < count; i++) {
+		skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
+
+		if (skb1) {
+			sk = stack[i];
+			bh_lock_sock(sk);
+			if (!sock_owned_by_user(sk))
+				udpv6_queue_rcv_skb(sk, skb1);
+			else
+				sk_add_backlog(sk, skb1);
+			bh_unlock_sock(sk);
+		}
+	}
+}
 /*
  * Note: called only from the BH handler context,
  * so we don't need to lock the hashes.
@@ -577,41 +598,43 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
 		struct in6_addr *saddr, struct in6_addr *daddr,
 		struct udp_table *udptable)
 {
-	struct sock *sk, *sk2;
+	struct sock *sk, *stack[256 / sizeof(struct sock *)];
 	const struct udphdr *uh = udp_hdr(skb);
 	struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
 	int dif;
+	unsigned int i, count = 0;
 
 	spin_lock(&hslot->lock);
 	sk = sk_nulls_head(&hslot->head);
 	dif = inet6_iif(skb);
 	sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
-	if (!sk) {
-		kfree_skb(skb);
-		goto out;
-	}
-
-	sk2 = sk;
-	while ((sk2 = udp_v6_mcast_next(net, sk_nulls_next(sk2), uh->dest, daddr,
-					uh->source, saddr, dif))) {
-		struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
-		if (buff) {
-			bh_lock_sock(sk2);
-			if (!sock_owned_by_user(sk2))
-				udpv6_queue_rcv_skb(sk2, buff);
-			else
-				sk_add_backlog(sk2, buff);
-			bh_unlock_sock(sk2);
+	while (sk) {
+		stack[count++] = sk;
+		sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr,
+				       uh->source, saddr, dif);
+		if (unlikely(count == ARRAY_SIZE(stack))) {
+			if (!sk)
+				break;
+			flush_stack(stack, count, skb, ~0);
+			count = 0;
 		}
 	}
-	bh_lock_sock(sk);
-	if (!sock_owned_by_user(sk))
-		udpv6_queue_rcv_skb(sk, skb);
-	else
-		sk_add_backlog(sk, skb);
-	bh_unlock_sock(sk);
-out:
+	/*
+	 * before releasing the lock, we must take reference on sockets
+	 */
+	for (i = 0; i < count; i++)
+		sock_hold(stack[i]);
+
 	spin_unlock(&hslot->lock);
+
+	if (count) {
+		flush_stack(stack, count, skb, count - 1);
+
+		for (i = 0; i < count; i++)
+			sock_put(stack[i]);
+	} else {
+		kfree_skb(skb);
+	}
 	return 0;
 }
 

^ permalink raw reply related

* [PATCH 8/8] udp: multicast RX should increment SNMP/sk_drops counter in allocation failures
From: Eric Dumazet @ 2009-11-08 20:20 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Netdev List, Lucian Adrian Grijincu, Octavian Purdila

When skb_clone() fails, we should increment sk_drops and SNMP counters.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv4/udp.c |   12 +++++++++++-
 net/ipv6/udp.c |    8 +++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 9d9072c..d73e917 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1335,12 +1335,22 @@ static void flush_stack(struct sock **stack, unsigned int count,
 {
 	unsigned int i;
 	struct sk_buff *skb1 = NULL;
+	struct sock *sk;
 
 	for (i = 0; i < count; i++) {
+		sk = stack[i];
 		if (likely(skb1 == NULL))
 			skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
 
-		if (skb1 && udp_queue_rcv_skb(stack[i], skb1) <= 0)
+		if (!skb1) {
+			atomic_inc(&sk->sk_drops);
+			UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
+					 IS_UDPLITE(sk));
+			UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS,
+					 IS_UDPLITE(sk));
+		}
+
+		if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0)
 			skb1 = NULL;
 	}
 	if (unlikely(skb1))
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 173e531..84cc4a8 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -579,14 +579,20 @@ static void flush_stack(struct sock **stack, unsigned int count,
 	for (i = 0; i < count; i++) {
 		skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC);
 
+		sk = stack[i];
 		if (skb1) {
-			sk = stack[i];
 			bh_lock_sock(sk);
 			if (!sock_owned_by_user(sk))
 				udpv6_queue_rcv_skb(sk, skb1);
 			else
 				sk_add_backlog(sk, skb1);
 			bh_unlock_sock(sk);
+		} else {
+			atomic_inc(&sk->sk_drops);
+			UDP6_INC_STATS_BH(sock_net(sk),
+					UDP_MIB_RCVBUFERRORS, IS_UDPLITE(sk));
+			UDP6_INC_STATS_BH(sock_net(sk),
+					UDP_MIB_INERRORS, IS_UDPLITE(sk));
 		}
 	}
 }

^ permalink raw reply related

* Re: [PATCH v4 12/12] tree-wide: convert open calls to remove spaces to skip_spaces() lib function
From: Julia Lawall @ 2009-11-08 20:23 UTC (permalink / raw)
  To: Theodore Tso
  Cc: Pavel Roskin, Stefan Haberland, Jan Kara, linux-cachefs,
	Mike Snitzer, Neil Brown, Frederic Weisbecker, Jens Axboe,
	Heiko Carstens, James E . J . Bottomley, ibm-acpi-devel, dm-devel,
	H . Peter Anvin, Daire Byrne, Alasdair G Kergon, Greg Banks,
	Stefan Weinhuber, Eric Sandeen, Adam Belay, Helge Deller, x86,
	James Morris, Takashi Iwai, André Goddard Rosa, Alan Cox
In-Reply-To: <20091108184722.GA1647@mit.edu>

> > Also, while at it, if we see (*str && isspace(*str)), we can be sure to
> > remove the first condition (*str) as the second one (isspace(*str)) also
> > evaluates to 0 whenever *str == 0, making it redundant. In other words,
> > "a char equals zero is never a space".

I tried the following semantic patch (http://coccinelle.lip6.fr), and got 
the results below.

@@
expression str;
@@

( // ignore skip_spaces cases
 while (*str &&  isspace(*str)) { \(str++;\|++str;\) }
|
- *str && 
  isspace(*str)
)

I haven't checked the results in any way, however.

julia

diff -u -p a/drivers/leds/led-class.c b/drivers/leds/led-class.c
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -50,7 +50,7 @@ static ssize_t led_brightness_store(stru
 	unsigned long state = simple_strtoul(buf, &after, 10);
 	size_t count = after - buf;
 
-	if (*after && isspace(*after))
+	if (isspace(*after))
 		count++;
 
 	if (count == size) {
diff -u -p a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -83,7 +83,7 @@ static ssize_t led_delay_on_store(struct
 	unsigned long state = simple_strtoul(buf, &after, 10);
 	size_t count = after - buf;
 
-	if (*after && isspace(*after))
+	if (isspace(*after))
 		count++;
 
 	if (count == size) {
@@ -127,7 +127,7 @@ static ssize_t led_delay_off_store(struc
 	unsigned long state = simple_strtoul(buf, &after, 10);
 	size_t count = after - buf;
 
-	if (*after && isspace(*after))
+	if (isspace(*after))
 		count++;
 
 	if (count == size) {
diff -u -p a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -101,7 +101,7 @@ static ssize_t lcd_store_power(struct de
 	int power = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
-	if (*endp && isspace(*endp))
+	if (isspace(*endp))
 		size++;
 	if (size != count)
 		return -EINVAL;
@@ -140,7 +140,7 @@ static ssize_t lcd_store_contrast(struct
 	int contrast = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
-	if (*endp && isspace(*endp))
+	if (isspace(*endp))
 		size++;
 	if (size != count)
 		return -EINVAL;
diff -u -p a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c
--- a/drivers/video/display/display-sysfs.c
+++ b/drivers/video/display/display-sysfs.c
@@ -67,7 +67,7 @@ static ssize_t display_store_contrast(st
 	contrast = simple_strtoul(buf, &endp, 0);
 	size = endp - buf;
 
-	if (*endp && isspace(*endp))
+	if (isspace(*endp))
 		size++;
 
 	if (size != count)
diff -u -p a/drivers/video/output.c b/drivers/video/output.c
--- a/drivers/video/output.c
+++ b/drivers/video/output.c
@@ -50,7 +50,7 @@ static ssize_t video_output_store_state(
 	int request_state = simple_strtoul(buf,&endp,0);
 	size_t size = endp - buf;
 
-	if (*endp && isspace(*endp))
+	if (isspace(*endp))
 		size++;
 	if (size != count)
 		return -EINVAL;

^ permalink raw reply

* Re: [RFC, PATCH 0/7] net, compat_ioctl: move handlers to net/socket.c
From: Arnd Bergmann @ 2009-11-08 21:31 UTC (permalink / raw)
  To: David Miller; +Cc: linux-kernel, hch, netdev, David Woodhouse
In-Reply-To: <20091106.204753.223665411.davem@davemloft.net>

On Saturday 07 November 2009, David Miller wrote:
> From: Arnd Bergmann <arnd@arndb.de>
> Date: Fri,  6 Nov 2009 19:09:02 +0100
> 
> > This cleans up some of the socket ioctl handling by moving it
> > from fs/compat_ioctl.c to net/socket.c. The code is still untested,
> > so this is an RFC for now. If you're happy with it, I'll do some
> > testing to see if everything still works.
> > 
> > This series is a prerequisite for cleaning up the rest of
> > compat_ioctl.c, saving some 30kb of kernel memory in the end.
> > 
> > The first four patches are probably worthwhile independently,
> > because they fix some bugs in compat_ioctl handling.
> > There is some obvious conflict with the ATM patch I sent
> > independently today. That one should probably be worked out
> > first.
> 
> This looks great, all applied.  Please make the fixups recommended
> to you in the feedback as followon patches.

Thanks! Two patches follow.

Any opinion on how to proceed with the ATM stuff? From my
point of view, I'm fine with having moved it out of fs/compat_ioctl.c,
but it's still a bit silly to have two half-complete implementations.

> Also, I added the following cure after your patch series:
> 
> net: compat: No need to define IFHWADDRLEN and IFNAMSIZ twice.
> 
> It's defined colloqually in linux/if.h and linux/compat.h
> includes that.

ok.

	Arnd <><

^ permalink raw reply

* [PATCH 1/2] net, compat_ioctl: fix SIOCGMII ioctls
From: Arnd Bergmann @ 2009-11-08 21:34 UTC (permalink / raw)
  To: David Miller; +Cc: linux-kernel, hch, netdev
In-Reply-To: <200911082231.48060.arnd@arndb.de>

SIOCGMIIPHY and SIOCGMIIREG return data through ifreq,
so it needs to be converted on the way out as well.

SIOCGIFPFLAGS is unused, but has the same problem in theory.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 net/socket.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/net/socket.c b/net/socket.c
index 688de5d..28a0263 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2587,7 +2587,10 @@ static int dev_ifsioc(struct net *net, struct socket *sock,
 		case SIOCGIFBRDADDR:
 		case SIOCGIFDSTADDR:
 		case SIOCGIFNETMASK:
+		case SIOCGIFPFLAGS:
 		case SIOCGIFTXQLEN:
+		case SIOCGMIIPHY:
+		case SIOCGMIIREG:
 			if (copy_to_user(uifr32, &ifr, sizeof(*uifr32)))
 				return -EFAULT;
 			break;
-- 
1.6.3.3




^ permalink raw reply related

* [PATCH 2/2] net/compat_ioctl: support SIOCWANDEV
From: Arnd Bergmann @ 2009-11-08 21:39 UTC (permalink / raw)
  To: David Miller, Krzysztof Halasa, Daniel Walker; +Cc: linux-kernel, hch, netdev
In-Reply-To: <200911082231.48060.arnd@arndb.de>

This adds compat_ioctl support for SIOCWANDEV, which has
always been missing.

The definition of struct compat_ifreq was missing an
ifru_settings fields that is needed to support SIOCWANDEV,
so add that and clean up the whitespace damage in the
struct definition.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Krzysztof Halasa <khc@pm.waw.pl>
Cc: Daniel Walker <dwalker@fifo99.com>
---

Krzysztof, can you verify that this is really needed and that it
does the right thing?

Daniel, I didn't want to add another patch just for the broken
whitespace I copied, but since we needed another fix in this area...

---
 include/linux/compat.h |   41 ++++++++++++++++++++++++-----------------
 net/socket.c           |   23 +++++++++++++++++++++++
 2 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/include/linux/compat.h b/include/linux/compat.h
index 224c7a8..4dff55a 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -165,25 +165,32 @@ struct compat_ifmap {
 	unsigned char port;
 };
 
+struct compat_if_settings
+{
+	unsigned int type;	/* Type of physical device or protocol */
+	unsigned int size;	/* Size of the data allocated by the caller */
+	compat_uptr_t ifs_ifsu;	/* union of pointers */
+};
+
 struct compat_ifreq {
-        union {
-                char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
-        } ifr_ifrn;
-        union {
-                struct  sockaddr ifru_addr;
-                struct  sockaddr ifru_dstaddr;
-                struct  sockaddr ifru_broadaddr;
-                struct  sockaddr ifru_netmask;
-                struct  sockaddr ifru_hwaddr;
-                short   ifru_flags;
-                compat_int_t     ifru_ivalue;
-                compat_int_t     ifru_mtu;
-                struct  compat_ifmap ifru_map;
-                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+	union {
+		char	ifrn_name[IFNAMSIZ];    /* if name, e.g. "en0" */
+	} ifr_ifrn;
+	union {
+		struct	sockaddr ifru_addr;
+		struct	sockaddr ifru_dstaddr;
+		struct	sockaddr ifru_broadaddr;
+		struct	sockaddr ifru_netmask;
+		struct	sockaddr ifru_hwaddr;
+		short	ifru_flags;
+		compat_int_t	ifru_ivalue;
+		compat_int_t	ifru_mtu;
+		struct	compat_ifmap ifru_map;
+		char	ifru_slave[IFNAMSIZ];   /* Just fits the size */
 		char	ifru_newname[IFNAMSIZ];
-                compat_caddr_t ifru_data;
-	    /* XXXX? ifru_settings should be here */
-        } ifr_ifru;
+		compat_caddr_t	ifru_data;
+		struct	compat_if_settings ifru_settings;
+	} ifr_ifru;
 };
 
 struct compat_ifconf {
diff --git a/net/socket.c b/net/socket.c
index 28a0263..17c98a5 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2468,6 +2468,27 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
 	return dev_ioctl(net, SIOCETHTOOL, ifr);
 }
 
+static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
+{
+	void __user *uptr;
+	compat_uptr_t uptr32;
+	struct ifreq __user *uifr;
+
+	uifr = compat_alloc_user_space(sizeof (*uifr));
+	if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
+		return -EFAULT;
+
+	if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu))
+		return -EFAULT;
+
+	uptr = compat_ptr(uptr32);
+
+	if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc))
+		return -EFAULT;
+
+	return dev_ioctl(net, SIOCWANDEV, uifr);
+}
+
 static int bond_ioctl(struct net *net, unsigned int cmd,
 			 struct compat_ifreq __user *ifr32)
 {
@@ -2900,6 +2921,8 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
 		return dev_ifconf(net, argp);
 	case SIOCETHTOOL:
 		return ethtool_ioctl(net, argp);
+	case SIOCWANDEV:
+		return compat_siocwandev(net, argp);
 	case SIOCBONDENSLAVE:
 	case SIOCBONDRELEASE:
 	case SIOCBONDSETHWADDR:
-- 
1.6.3.3

^ permalink raw reply related

* tulip : kernel BUG in tulip_up/tulip_resume
From: Philippe De Muyter @ 2009-11-08 22:33 UTC (permalink / raw)
  To: grundler, kyle, netdev, linux-kernel
In-Reply-To: <20090129210701.GA8092@frolo.macqel>

Hello,

I have just installed 2.6.31 (from opensuse 11.2) one a tulip-equipped
computer and I get the following error message from the kernel :

[ 2495.526390] ------------[ cut here ]------------
[ 2495.526390] kernel BUG at /usr/src/packages/BUILD/kernel-default-2.6.31.5/linux-2.6.31/include/linux/netdevice.h:439!
[ 2495.526390] invalid opcode: 0000 [#1] SMP 
[ 2495.526390] last sysfs file: /sys/devices/pci0000:00/0000:00:07.1/host0/target0:0:0/0:0:0:0/block/sda/uevent
[ 2495.526390] Modules linked in: ohci_hcd raw1394 ohci1394 ieee1394 acpi_cpufreq speedstep_lib processor thermal_sys hwmon edd ipv6 af_packet fuse loop dm_mod rtc_cmos rtc_core rtc_lib apm pcspkr sg tulip uhci_hcd ehci_hcd reiserfs ata_piix ahci libata
[ 2495.526390] 
[ 2495.526390] Pid: 339, comm: kapmd Not tainted (2.6.31.5-0.1-default #1) 
[ 2495.526390] EIP: 0060:[<c3d6045d>] EFLAGS: 00010246 CPU: 0
[ 2495.526390] EIP is at tulip_up+0xa2d/0xa80 [tulip]
[ 2495.526390] EAX: 00000000 EBX: c1cd7000 ECX: c022af50 EDX: 0001ec00
[ 2495.526390] ESI: c1cd7340 EDI: 00000000 EBP: c20bde44 ESP: c20bddfc
[ 2495.526390]  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
[ 2495.526390] Process kapmd (pid: 339, ti=c20bc000 task=c25a32c0 task.ti=c20bc000)
[ 2495.526390] Stack:
[ 2495.526390]  0000000b c20bde44 c02acf76 2caa9a94 c2481800 c20bde38 c043ca4a c20bde27
[ 2495.526390] <0> 069ee44b c20ec120 c087c020 0001ec00 c1cd7000 c3d5c720 2caa9a94 c1cd7000
[ 2495.526390] <0> c2480000 00000000 c20bde68 c3d60555 00000080 c1cd7000 c1cd7000 2caa9a94
[ 2495.526390] Call Trace:
[ 2495.526390]  [<c3d60555>] tulip_resume+0xa5/0xd0 [tulip]
[ 2495.526390]  [<c043dd65>] pci_legacy_resume+0x35/0x60
[ 2495.526390]  [<c043df2f>] pci_pm_resume+0x7f/0xb0
[ 2495.526390]  [<c04d82f2>] pm_op+0xd2/0x180
[ 2495.526390]  [<c04d91ee>] device_resume+0x5e/0x1a0
[ 2495.526390]  [<c04d93dd>] dpm_resume+0xad/0x140
[ 2495.526390]  [<c04d948b>] dpm_resume_end+0x1b/0x40
[ 2495.526390]  [<c3db1978>] check_events+0x148/0x240 [apm]
[ 2495.526390]  [<c3db23a2>] apm_mainloop+0x82/0x130 [apm]
[ 2495.526390]  [<c3db28fe>] apm+0x10e/0x3d0 [apm]
[ 2495.526390]  [<c026bef4>] kthread+0x84/0x90
[ 2495.526390]  [<c0204db7>] kernel_thread_helper+0x7/0x10
[ 2495.526390] Code: 45 e4 e8 37 ce 6c fc 8b 4d e8 89 5c 24 10 89 7c 24 0c 89 4c 24 04 89 44 24 08 c7 04 24 4c 4e d6 c3 e8 86 f7 89 fc e9 f4 f8 ff ff <0f> 0b eb fe 0f be 96 16 09 00 00 b9 01 00 00 00 8b 45 e8 e8 fb 
[ 2495.526390] EIP: [<c3d6045d>] tulip_up+0xa2d/0xa80 [tulip] SS:ESP 0068:c20bddfc
[ 2495.534162] ---[ end trace 609ed25c95a75fa1 ]---

This comes from a BUG_ON in napi_enable in netdevice.h.

napi_enable itself is called by tulip_up as such :

#ifdef CONFIG_TULIP_NAPI
	napi_enable(&tp->napi);
#endif

At first reading, a matching napi_disable is called in tulip_down.

Does someone know what could be wrong and have a fix or should I look myself ?

Thanks in advance

Philippe

^ permalink raw reply

* Re: query: net-next section mismatch(es)
From: David Miller @ 2009-11-09  0:35 UTC (permalink / raw)
  To: william.allen.simpson; +Cc: netdev
In-Reply-To: <4AF6D1F5.80307@gmail.com>

From: William Allen Simpson <william.allen.simpson@gmail.com>
Date: Sun, 08 Nov 2009 09:13:09 -0500

> Yesterday morning (and for a month), I was getting the usual:
> 
>   WARNING: modpost: Found 1 section mismatch(es).
>   To see full details build your kernel with:
>   'make CONFIG_DEBUG_SECTION_MISMATCH=y'
> 
> This morning, it changed:
> 
>   WARNING: modpost: Found 4 section mismatch(es).
>   To see full details build your kernel with:
>   'make CONFIG_DEBUG_SECTION_MISMATCH=y'
> 
> I remember compiling it once with that option, and not finding
> anything
> wrong in my code, but I'm wondering how it took a great leap?

Well, type 'make CONFIG_DEBUG_SECTION_MISMATCH=y' as the message
says, in order to find out.

^ permalink raw reply

* Re: query: net-next section mismatch(es)
From: William Allen Simpson @ 2009-11-09  2:01 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20091108.163527.185100796.davem@davemloft.net>

David Miller wrote:
> From: William Allen Simpson <william.allen.simpson@gmail.com>
>> I remember compiling it once with that option, and not finding
>> anything
>> wrong in my code, but I'm wondering how it took a great leap?
> 
> Well, type 'make CONFIG_DEBUG_SECTION_MISMATCH=y' as the message
> says, in order to find out.
> 
Hardly worth the time, as 'make modules' doesn't compile today:

/home/administer/net-next-2.6/drivers/staging/android/logger.c: In function ‘logger_read’:
/home/administer/net-next-2.6/drivers/staging/android/logger.c:165: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
/home/administer/net-next-2.6/drivers/staging/android/logger.c:165: error: (Each undeclared identifier is reported only once
/home/administer/net-next-2.6/drivers/staging/android/logger.c:165: error: for each function it appears in.)
/home/administer/net-next-2.6/drivers/staging/android/logger.c:178: error: implicit declaration of function ‘signal_pending’
/home/administer/net-next-2.6/drivers/staging/android/logger.c:183: error: implicit declaration of function ‘schedule’
/home/administer/net-next-2.6/drivers/staging/android/logger.c: In function ‘logger_aio_write’:
/home/administer/net-next-2.6/drivers/staging/android/logger.c:325: error: dereferencing pointer to incomplete type
/home/administer/net-next-2.6/drivers/staging/android/logger.c:333: error: dereferencing pointer to incomplete type
/home/administer/net-next-2.6/drivers/staging/android/logger.c:334: error: dereferencing pointer to incomplete type
/home/administer/net-next-2.6/drivers/staging/android/logger.c:337: error: dereferencing pointer to incomplete type
/home/administer/net-next-2.6/drivers/staging/android/logger.c:360: error: dereferencing pointer to incomplete type
/home/administer/net-next-2.6/drivers/staging/android/logger.c:363: error: dereferencing pointer to incomplete type
/home/administer/net-next-2.6/drivers/staging/android/logger.c:370: error: increment of pointer to unknown structure
/home/administer/net-next-2.6/drivers/staging/android/logger.c:370: error: arithmetic on pointer to an incomplete type
/home/administer/net-next-2.6/drivers/staging/android/logger.c:377: error: ‘TASK_INTERRUPTIBLE’ undeclared (first use in this function)
make[4]: *** [drivers/staging/android/logger.o] Error 1
make[3]: *** [drivers/staging/android] Error 2
make[2]: *** [drivers/staging] Error 2
make[2]: *** Waiting for unfinished jobs....


But I did it with 'make vmlinux' anyway, still makes no sense to me:

/home/administer/net-next-2.6/arch/x86/include/asm/string_32.h:74: warning: array subscript is above array bounds
WARNING: drivers/acpi/processor.o(.text+0xa88): Section mismatch in reference from the function acpi_processor_add() to the function .cpuinit.text:acpi_processor_power_init()
The function acpi_processor_add() references
the function __cpuinit acpi_processor_power_init().
This is often because acpi_processor_add lacks a __cpuinit
annotation or the annotation of acpi_processor_power_init is wrong.

WARNING: drivers/acpi/built-in.o(.text+0x21f24): Section mismatch in reference from the function acpi_processor_add() to the function .cpuinit.text:acpi_processor_power_init()
The function acpi_processor_add() references
the function __cpuinit acpi_processor_power_init().
This is often because acpi_processor_add lacks a __cpuinit
annotation or the annotation of acpi_processor_power_init is wrong.

/home/administer/net-next-2.6/include/linux/mca-legacy.h:12:2: warning: #warning "MCA legacy - please move your driver to the new sysfs api"
WARNING: drivers/net/phy/built-in.o(.devexit.text+0x13): Section mismatch in reference from the function mdio_gpio_bus_destroy() to the function .devinit.text:mdio_gpio_bus_deinit()
The function __devexit mdio_gpio_bus_destroy() references
a function __devinit mdio_gpio_bus_deinit().
This is often seen when error handling in the exit function
uses functionality in the init path.
The fix is often to remove the __devinit annotation of
mdio_gpio_bus_deinit() so it may be used outside an init section.

WARNING: drivers/net/built-in.o(.devexit.text+0x13): Section mismatch in reference from the function mdio_gpio_bus_destroy() to the function .devinit.text:mdio_gpio_bus_deinit()
The function __devexit mdio_gpio_bus_destroy() references
a function __devinit mdio_gpio_bus_deinit().
This is often seen when error handling in the exit function
uses functionality in the init path.
The fix is often to remove the __devinit annotation of
mdio_gpio_bus_deinit() so it may be used outside an init section.

/home/administer/net-next-2.6/arch/x86/include/asm/string_32.h:74: warning: array subscript is above array bounds
WARNING: drivers/built-in.o(.text+0x48274): Section mismatch in reference from the function acpi_processor_add() to the function .cpuinit.text:acpi_processor_power_init()
The function acpi_processor_add() references
the function __cpuinit acpi_processor_power_init().
This is often because acpi_processor_add lacks a __cpuinit
annotation or the annotation of acpi_processor_power_init is wrong.

WARNING: drivers/built-in.o(.devexit.text+0x38c): Section mismatch in reference from the function mdio_gpio_bus_destroy() to the function .devinit.text:mdio_gpio_bus_deinit()
The function __devexit mdio_gpio_bus_destroy() references
a function __devinit mdio_gpio_bus_deinit().
This is often seen when error handling in the exit function
uses functionality in the init path.
The fix is often to remove the __devinit annotation of
mdio_gpio_bus_deinit() so it may be used outside an init section.

WARNING: vmlinux.o(.text+0x27c824): Section mismatch in reference from the function acpi_processor_add() to the function .cpuinit.text:acpi_processor_power_init()
The function acpi_processor_add() references
the function __cpuinit acpi_processor_power_init().
This is often because acpi_processor_add lacks a __cpuinit
annotation or the annotation of acpi_processor_power_init is wrong.

WARNING: vmlinux.o(.text+0x2c8469): Section mismatch in reference from the function twl4030_sih_setup() to the function .init.text:set_irq_noprobe()
The function twl4030_sih_setup() references
the function __init set_irq_noprobe().
This is often because twl4030_sih_setup lacks a __init
annotation or the annotation of set_irq_noprobe is wrong.

WARNING: vmlinux.o(.text+0x2c8581): Section mismatch in reference from the function twl_init_irq() to the function .init.text:set_irq_noprobe()
The function twl_init_irq() references
the function __init set_irq_noprobe().
This is often because twl_init_irq lacks a __init
annotation or the annotation of set_irq_noprobe is wrong.

WARNING: vmlinux.o(.devexit.text+0x3e1): Section mismatch in reference from the function mdio_gpio_bus_destroy() to the function .devinit.text:mdio_gpio_bus_deinit()
The function __devexit mdio_gpio_bus_destroy() references
a function __devinit mdio_gpio_bus_deinit().
This is often seen when error handling in the exit function
uses functionality in the init path.
The fix is often to remove the __devinit annotation of
mdio_gpio_bus_deinit() so it may be used outside an init section.




^ permalink raw reply

* linux-next: manual merge of the net tree with the net-current tree
From: Stephen Rothwell @ 2009-11-09  2:03 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: linux-next, linux-kernel, Wolfgang Grandegger, Sebastian Haas

Hi all,

Today's linux-next merge of the net tree got a conflict in
drivers/net/can/usb/ems_usb.c between commit
2b2072e902848a63168570f500a5726744b3873a ("ems_usb: Fix byte order issues
on big endian machines") from the net-current tree and commit
7b6856a0296a8f187bb88ba31fa83a08abba7966 ("can: provide library functions
for skb allocation") from the net tree.

Just context changes.  I fixed it up (see below) and can carry the fix
for a while.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --cc drivers/net/can/usb/ems_usb.c
index abdbd9c,3685f3e..0000000
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@@ -315,11 -315,7 +315,7 @@@ static void ems_usb_rx_can_msg(struct e
  	if (skb == NULL)
  		return;
  
- 	skb->protocol = htons(ETH_P_CAN);
- 
- 	cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
- 
 -	cf->can_id = msg->msg.can_msg.id;
 +	cf->can_id = le32_to_cpu(msg->msg.can_msg.id);
  	cf->can_dlc = min_t(u8, msg->msg.can_msg.length, 8);
  
  	if (msg->type == CPC_MSG_TYPE_EXT_CAN_FRAME

^ permalink raw reply

* linux-next: net tree build failure
From: Stephen Rothwell @ 2009-11-09  2:21 UTC (permalink / raw)
  To: David S. Miller, netdev; +Cc: linux-next, linux-kernel, Arnd Bergmann

Hi all,

Today's linux-next build (x86_64 allmodconfig) failed like this:

net/appletalk/ddp.c: In function 'atalk_compat_ioctl':
net/appletalk/ddp.c:1866: error: implicit declaration of function 'compat_ptr'

Caused by commit 206602217747382488fcae68351673cc9103debc
("appletalk: handle SIOCATALKDIFADDR compat ioctl").

I applied this patch for today:

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Mon, 9 Nov 2009 13:11:26 +1100
Subject: [PATCH] net/appletalk: using compat_ptr needs inclusion of linux/compat.h

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 net/appletalk/ddp.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index b631cc7..73ca4d5 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -56,6 +56,7 @@
 #include <linux/if_arp.h>
 #include <linux/smp_lock.h>
 #include <linux/termios.h>	/* For TIOCOUTQ/INQ */
+#include <linux/compat.h>
 #include <net/datalink.h>
 #include <net/psnap.h>
 #include <net/sock.h>
-- 
1.6.5.2


-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

^ permalink raw reply related

* [PATCH] xfrm: SAD entries do not expire correctly after suspend-resume
From: Yury Polyanskiy @ 2009-11-09  2:12 UTC (permalink / raw)
  To: netdev, davem, peterz, yoshfuji, Thomas Gleixner, mingo

[-- Attachment #1: Type: text/plain, Size: 5752 bytes --]


  This fixes the following bug in the current implementation of
net/xfrm: SAD entries timeouts do not count the time spent by the machine 
in the suspended state. This leads to the connectivity problems because 
after resuming local machine thinks that the SAD entry is still valid, while 
it has already been expired on the remote server.

  The cause of this is very simple: the timeouts in the net/xfrm are bound to 
the old mod_timer() timers. This patch reassigns them to the
CLOCK_REALTIME hrtimer.

  I have been using this version of the patch for a few months on my
machines without any problems. Also run a few stress tests w/o any
issues.

  This version of the patch uses tasklet_hrtimer by Peter Zijlstra
(commit 9ba5f0).

  This patch is against 2.6.31.4. Please CC me.

Signed-off-by: Yury Polyanskiy <polyanskiy@gmail.com>
---
 include/net/xfrm.h    |    5 ++++-
 net/xfrm/xfrm_state.c |   34 +++++++++++++++++++---------------
 2 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 9e3a3f4..ef28810 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -19,6 +19,9 @@
 #include <net/route.h>
 #include <net/ipv6.h>
 #include <net/ip6_fib.h>
+
+#include <linux/interrupt.h>
+
 #ifdef CONFIG_XFRM_STATISTICS
 #include <net/snmp.h>
 #endif
@@ -199,7 +202,7 @@ struct xfrm_state
 	struct xfrm_stats	stats;
 
 	struct xfrm_lifetime_cur curlft;
-	struct timer_list	timer;
+	struct tasklet_hrtimer	mtimer;
 
 	/* Last used time */
 	unsigned long		lastused;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index f2f7c63..45fff9c 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -21,6 +21,9 @@
 #include <linux/cache.h>
 #include <linux/audit.h>
 #include <asm/uaccess.h>
+#include <linux/ktime.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
 
 #include "xfrm_hash.h"
 
@@ -352,7 +355,7 @@ static void xfrm_put_mode(struct xfrm_mode *mode)
 
 static void xfrm_state_gc_destroy(struct xfrm_state *x)
 {
-	del_timer_sync(&x->timer);
+	tasklet_hrtimer_cancel(&x->mtimer);
 	del_timer_sync(&x->rtimer);
 	kfree(x->aalg);
 	kfree(x->ealg);
@@ -398,9 +401,10 @@ static inline unsigned long make_jiffies(long secs)
 		return secs*HZ;
 }
 
-static void xfrm_timer_handler(unsigned long data)
-{
-	struct xfrm_state *x = (struct xfrm_state*)data;
+static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
+{	
+	struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer);
+	struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer);
 	struct net *net = xs_net(x);
 	unsigned long now = get_seconds();
 	long next = LONG_MAX;
@@ -451,8 +455,9 @@ static void xfrm_timer_handler(unsigned long data)
 	if (warn)
 		km_state_expired(x, 0, 0);
 resched:
-	if (next != LONG_MAX)
-		mod_timer(&x->timer, jiffies + make_jiffies(next));
+	if (next != LONG_MAX){
+		tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL);
+	}
 
 	goto out;
 
@@ -474,6 +479,7 @@ expired:
 
 out:
 	spin_unlock(&x->lock);
+	return HRTIMER_NORESTART;
 }
 
 static void xfrm_replay_timer_handler(unsigned long data);
@@ -492,7 +498,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
 		INIT_HLIST_NODE(&x->bydst);
 		INIT_HLIST_NODE(&x->bysrc);
 		INIT_HLIST_NODE(&x->byspi);
-		setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x);
+		tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, CLOCK_REALTIME, HRTIMER_MODE_ABS);
 		setup_timer(&x->rtimer, xfrm_replay_timer_handler,
 				(unsigned long)x);
 		x->curlft.add_time = get_seconds();
@@ -843,8 +849,7 @@ found:
 				hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 			}
 			x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
-			x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ;
-			add_timer(&x->timer);
+			tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL);
 			net->xfrm.state_num++;
 			xfrm_hash_grow_check(net, x->bydst.next != NULL);
 		} else {
@@ -921,7 +926,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
 		hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 	}
 
-	mod_timer(&x->timer, jiffies + HZ);
+	tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
 	if (x->replay_maxage)
 		mod_timer(&x->rtimer, jiffies + x->replay_maxage);
 
@@ -1019,8 +1024,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family
 		x->props.reqid = reqid;
 		x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
 		xfrm_state_hold(x);
-		x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ;
-		add_timer(&x->timer);
+		tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL);
 		list_add(&x->km.all, &net->xfrm.state_all);
 		hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
 		h = xfrm_src_hash(net, daddr, saddr, family);
@@ -1299,8 +1303,8 @@ out:
 			memcpy(&x1->sel, &x->sel, sizeof(x1->sel));
 		memcpy(&x1->lft, &x->lft, sizeof(x1->lft));
 		x1->km.dying = 0;
-
-		mod_timer(&x1->timer, jiffies + HZ);
+		
+		tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL);
 		if (x1->curlft.use_time)
 			xfrm_state_check_expire(x1);
 
@@ -1325,7 +1329,7 @@ int xfrm_state_check_expire(struct xfrm_state *x)
 	if (x->curlft.bytes >= x->lft.hard_byte_limit ||
 	    x->curlft.packets >= x->lft.hard_packet_limit) {
 		x->km.state = XFRM_STATE_EXPIRED;
-		mod_timer(&x->timer, jiffies);
+		tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL);
 		return -EINVAL;
 	}
 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply related

* Re: [PATCH 00/23] Removal of binary sysctl support
From: Eric W. Biederman @ 2009-11-09  3:44 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-kernel, netdev, David Miller, Stephen Rothwell
In-Reply-To: <200911081306.20201.arnd@arndb.de>

Arnd Bergmann <arnd@arndb.de> writes:

> On Sunday 08 November 2009 12:16:43 Eric W. Biederman wrote:
>> This patchset reimplements sys_sysctl as a compatibility wrapper
>> around /proc/sys.  After which it removes all of the code to all over
>> the kernel that is used today to implement the binary sysctls.
>> 
>> I am posting this patchset to give everyone a heads up what is in
>> flight.
>> 
>> I intend to carry all of these patches in my sysctl tree.
>
> Very nice patches again!
>
> Looking at what you did, I had two ideas how to move on from there,
> which may be part of your plans already:
>
> 1. Make it possible to build sysctl_binary.c as a loadable module
> so you can get a smaller kernel without losing the option to use
> binary sysctl altogether. This of course requires a small portion
> to remain in the kernel, to provide the actual syscall entry point
> and load the module on demand.

I can see how this could make sense from a distribution perspective.

> 2. On top of that, put the same code into glibc so that you don't
> even have to load the module when you're running a new glibc version.
> Since the binary sysctl ABI is stable (as in stiff and dead), there
> should be no need to synchronize any extensions to it betwen kernel
> and libc.

I don't expect we will need to move this to glibc.  There are so few
users of sys_sysctl now, that I hardly expect it to be worth it to move
this code out of the kernel.

For me the big problem with sys_sysctl is solved by this patchset.
It no longer constitutes a maintenance burden on the rest of the sysctl
code, and the other sysctl users.

Now the implementation of /proc/sys can be implemented and optimized without
dealing with any sys_sysctl baggage.

All of that said if someone is interested in tweaking sysctl_binary.c to make
it easier to deal with sys_sysctl going away I don't have any problems.

Eric

^ permalink raw reply

* Stochastic Fair Blue updated for 2.6.31
From: Juliusz Chroboczek @ 2009-11-09  4:11 UTC (permalink / raw)
  To: netdev

Just a quick note to inform people that I've updated the Stochastic Fair
Blue (SFB) qdisc for 2.6.31.

  http://www.pps.jussieu.fr/~jch/software/files/sch_sfb-20091108.tar.gz
  http://www.pps.jussieu.fr/~jch/software/files/sch_sfb-20091108.tar.gz.asc

It's described in detail on

  http://www.pps.jussieu.fr/~jch/software/sfb/

                                        Juliusz

^ permalink raw reply

* Re: linux-next: net tree build failure
From: David Miller @ 2009-11-09  4:41 UTC (permalink / raw)
  To: sfr; +Cc: netdev, linux-next, linux-kernel, arnd
In-Reply-To: <20091109132151.0e0ec7bc.sfr@canb.auug.org.au>

From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Mon, 9 Nov 2009 13:21:51 +1100

> Subject: [PATCH] net/appletalk: using compat_ptr needs inclusion of linux/compat.h
> 
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>

Applied, thanks Stephen.

^ permalink raw reply

* Re: [PATCH 0/8 net-next-2.6] udp: optimisations
From: David Miller @ 2009-11-09  4:55 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, lgrijincu, opurdila
In-Reply-To: <4AF72738.7020606@gmail.com>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Sun, 08 Nov 2009 21:16:56 +0100

> This patch series address UDP scalability problems, we failed to solve in 2007
> (commit 6aaf47fa48d3c44 INET : IPV4 UDP lookups converted to a 2 pass algo)
> we had to revert a bit later.

Looks great, all applied, thanks Eric.

I would even go so far as to say that the cutoff to the second hash
table should be even lower than 10, like maybe 4 or 5.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox