Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] xfrm:Use rcu_dereference_bh to deference pointer protected by rcu_read_lock_bh
From: Fan Du @ 2012-08-17  6:36 UTC (permalink / raw)
  To: David Miller; +Cc: fengguang.wu, netdev
In-Reply-To: <20120816.232414.545877018277576779.davem@davemloft.net>



On 2012年08月17日 14:24, David Miller wrote:
>
> I already applied your patch, as I told you here:
>
> http://marc.info/?l=linux-netdev&m=134517122805719&w=2
>
> This means you are submitting a patch which doesn't not even apply
> to the net-next tree.
>
> Instead of continuing to dig yourself deeper and deeper, take a
> break, take a deep breath, and work slowly and carefully.
>

OK, thanks for your kind guidance :)

-- 

Love each day!
--fan

^ permalink raw reply

* Re: [PATCH] xfrm:Use rcu_dereference_bh to deference pointer protected by rcu_read_lock_bh
From: David Miller @ 2012-08-17  6:24 UTC (permalink / raw)
  To: fan.du; +Cc: fengguang.wu, netdev
In-Reply-To: <1345184349-5849-1-git-send-email-fan.du@windriver.com>


I already applied your patch, as I told you here:

http://marc.info/?l=linux-netdev&m=134517122805719&w=2

This means you are submitting a patch which doesn't not even apply
to the net-next tree.

Instead of continuing to dig yourself deeper and deeper, take a
break, take a deep breath, and work slowly and carefully.

^ permalink raw reply

* [PATCH] xfrm:Use rcu_dereference_bh to deference pointer protected by rcu_read_lock_bh
From: Fan Du @ 2012-08-17  6:19 UTC (permalink / raw)
  To: davem; +Cc: fengguang.wu, netdev

418a99ac6ad487dc9c42e6b0e85f941af56330f2 "Replace rwlock on xfrm_policy_afinfo with rcu"
triggers below warnings, which is caused by abusing rcu_dereference_bh with rcu_read_lock.

RCU rules must be honored:
 - rcu_dereference_bh paired with rcu_read_lock_bh/rcu_read_unlock_bh
 - rcu_dereference  paired with rcu_read_lock/rcu_read_unlock

[    0.921216]
[    0.921645] ===============================
[    0.922766] [ INFO: suspicious RCU usage. ]
[    0.923887] 3.5.0-01540-g1669891 #64 Not tainted
[    0.925123] -------------------------------
[    0.932860] /c/kernel-tests/src/tip/net/xfrm/xfrm_policy.c:2504 suspicious rcu_dereference_check() usage!
[    0.935361]
[    0.935361] other info that might help us debug this:
[    0.935361]
[    0.937472]
[    0.937472] rcu_scheduler_active = 1, debug_locks = 0
[    0.939182] 2 locks held by swapper/1:
[    0.940171]  #0:  (net_mutex){+.+.+.}, at: [<ffffffff814e1ad0>] register_pernet_subsys+0x21/0x57
[    0.942705]  #1:  (rcu_read_lock_bh){......}, at: [<ffffffff822c7329>] xfrm_net_init+0x1e4/0x437
[    0.951507]
[    0.951507] stack backtrace:
[    0.952660] Pid: 1, comm: swapper Not tainted 3.5.0-01540-g1669891 #64
[    0.954364] Call Trace:
[    0.955074]  [<ffffffff8108b375>] lockdep_rcu_suspicious+0x174/0x187
[    0.956736]  [<ffffffff822c7453>] xfrm_net_init+0x30e/0x437
[    0.958205]  [<ffffffff822c7329>] ? xfrm_net_init+0x1e4/0x437
[    0.959712]  [<ffffffff814e134a>] ops_init+0x1bb/0x1ff
[    0.961067]  [<ffffffff810861f9>] ? trace_hardirqs_on+0x1b/0x24
[    0.962644]  [<ffffffff814e17cd>] register_pernet_operations.isra.5+0x9d/0xfe
[    0.971376]  [<ffffffff814e1adf>] register_pernet_subsys+0x30/0x57
[    0.972992]  [<ffffffff822c7130>] xfrm_init+0x17/0x2c
[    0.974316]  [<ffffffff822c2f8c>] ip_rt_init+0x82/0xe7
[    0.975668]  [<ffffffff822c31dc>] ip_init+0x10/0x25
[    0.976952]  [<ffffffff822c3f77>] inet_init+0x235/0x360
[    0.978352]  [<ffffffff822c3d42>] ? devinet_init+0xf2/0xf2
[    0.979808]  [<ffffffff82283252>] do_one_initcall+0xb4/0x203
[    0.981313]  [<ffffffff8228354a>] kernel_init+0x1a9/0x29a
[    0.982732]  [<ffffffff822826d9>] ? loglevel+0x46/0x46
[    0.990889]  [<ffffffff816d3d84>] kernel_thread_helper+0x4/0x10
[    0.992472]  [<ffffffff816d262c>] ? retint_restore_args+0x13/0x13
[    0.994076]  [<ffffffff822833a1>] ? do_one_initcall+0x203/0x203
[    0.995636]  [<ffffffff816d3d80>] ? gs_change+0x13/0x13
[    0.997197] TCP established hash table entries: 8192 (order: 5, 131072 bytes)
[    1.000074] TCP bind hash table entries: 8192 (order: 7, 655360 bytes)

Reported-by: Wu Fengguang <fengguang.wu@intel.com>
Tested-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Fan Du <fan.du@windriver.com>
---
 net/xfrm/xfrm_policy.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 5ad4d2c..6405764 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2501,11 +2501,11 @@ static void __net_init xfrm_dst_ops_init(struct net *net)
 	struct xfrm_policy_afinfo *afinfo;
 
 	rcu_read_lock_bh();
-	afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
+	afinfo = rcu_dereference_bh(xfrm_policy_afinfo[AF_INET]);
 	if (afinfo)
 		net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
 #if IS_ENABLED(CONFIG_IPV6)
-	afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]);
+	afinfo = rcu_dereference_bh(xfrm_policy_afinfo[AF_INET6]);
 	if (afinfo)
 		net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
 #endif
-- 
1.7.1

^ permalink raw reply related

* [PATCH 3/3] netfilter: replace list_for_each_continue_rcu with new interface
From: Michael Wang @ 2012-08-17  4:33 UTC (permalink / raw)
  To: LKML, netdev@vger.kernel.org, netfilter, coreteam,
	netfilter-devel
  Cc: David Miller, kaber, pablo, paulmck@linux.vnet.ibm.com
In-Reply-To: <502CB939.3050008@linux.vnet.ibm.com>

From: Michael Wang <wangyun@linux.vnet.ibm.com>

This patch replaces list_for_each_continue_rcu() with
list_for_each_entry_continue_rcu() to allow removing
list_for_each_continue_rcu().

Signed-off-by: Michael Wang <wangyun@linux.vnet.ibm.com>
---
 net/netfilter/core.c |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index e19f365..50225bd 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -131,14 +131,14 @@ unsigned int nf_iterate(struct list_head *head,
 			int hook_thresh)
 {
 	unsigned int verdict;
+	struct nf_hook_ops *elem = list_entry_rcu(*i,
+						struct nf_hook_ops, list);

 	/*
 	 * The caller must not block between calls to this
 	 * function because of risk of continuing from deleted element.
 	 */
-	list_for_each_continue_rcu(*i, head) {
-		struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
-
+	list_for_each_entry_continue_rcu(elem, head, list) {
 		if (hook_thresh > elem->priority)
 			continue;

@@ -155,11 +155,14 @@ repeat:
 				continue;
 			}
 #endif
-			if (verdict != NF_REPEAT)
+			if (verdict != NF_REPEAT) {
+				*i = &elem->list;
 				return verdict;
+			}
 			goto repeat;
 		}
 	}
+	*i = &elem->list;
 	return NF_ACCEPT;
 }

-- 
1.7.4.1

^ permalink raw reply related

* [PATCH 0/3] raid, kmemleak, netfilter: replace list_for_each_continue_rcu with new interface
From: Michael Wang @ 2012-08-17  4:33 UTC (permalink / raw)
  To: LKML, linux-raid, linux-mm, netdev@vger.kernel.org, netfilter,
	coreteam, netfilter-devel
  Cc: neilb, catalin.marinas, David Miller, kaber, pablo,
	paulmck@linux.vnet.ibm.com
In-Reply-To: <502CB91E.4050304@linux.vnet.ibm.com>

From: Michael Wang <wangyun@linux.vnet.ibm.com>

This patch set will replace the list_for_each_continue_rcu with the new
interface list_for_each_entry_continue_rcu, so we could remove the old
one later.

Changed:
	raid:		in "next_active_rdev"
	kmemleak:	in "kmemleak_seq_next"
	netfilter:	in "nf_iterate"	

Tested:
	raid:
		mdadm command with an internal bitmap.
	kmemleak:
		enable kmemleak and check the info it captured.
	netfilter:
		add rule to iptables and check result by ping.
		nfqnl_test which is a test utility of libnetfilter_queue.

	All testing are using printk to make sure the code we want test
	was invoked.

Signed-off-by: Michael Wang <wangyun@linux.vnet.ibm.com>
---
 drivers/md/bitmap.c  |    9 +++------
 mm/kmemleak.c        |    6 ++----
 net/netfilter/core.c |   11 +++++++----
 3 files changed, 12 insertions(+), 14 deletions(-)


--
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

* Re: suspicious RCU usage in xfrm_net_init()
From: David Miller @ 2012-08-17  2:41 UTC (permalink / raw)
  To: paul.gortmaker; +Cc: fan.du, fengguang.wu, Priyanka.Jain, netdev, linux-kernel
In-Reply-To: <CAP=VYLqHW+NOS-gPgUkUpZh-Vim2jkmMT7NK+7uRbg730d=xHw@mail.gmail.com>

From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Thu, 16 Aug 2012 21:34:25 -0400

> Also, a patch should describe the problem it solves (i.e. the symptom
> the end user sees), and how the problem originated, and why the fix
> in the patch is the _right_ fix.  The worst description a commit log
> can have is one that just describes the C change in words, since
> most people can read C on their own.

I've frankly given up on Fan Du submitting sophisticated patches
that are easy to review and are properly documented.

Just getting simple things like a WORKING EMAIL ADDRESS was beyond a
struggle.

So when I get a patch that applies, from a properly working email
address, it's an accomplishment.

^ permalink raw reply

* Re: suspicious RCU usage in xfrm_net_init()
From: David Miller @ 2012-08-17  2:39 UTC (permalink / raw)
  To: fan.du; +Cc: fengguang.wu, Priyanka.Jain, netdev, linux-kernel
In-Reply-To: <502D9938.2010908@windriver.com>

From: Fan Du <fan.du@windriver.com>
Date: Fri, 17 Aug 2012 09:07:04 +0800

> Could you please pick up this patch?

Done, but could you please put proper prefixes in your commit
message subject lines?  I had to prepend "xfrm: " this time.

^ permalink raw reply

* Re: suspicious RCU usage in xfrm_net_init()
From: Fan Du @ 2012-08-17  2:03 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: David Miller, Fengguang Wu, Priyanka Jain, netdev, LKML
In-Reply-To: <CAP=VYLqHW+NOS-gPgUkUpZh-Vim2jkmMT7NK+7uRbg730d=xHw@mail.gmail.com>



On 2012年08月17日 09:34, Paul Gortmaker wrote:
> On Thu, Aug 16, 2012 at 9:07 PM, Fan Du<fan.du@windriver.com>  wrote:
>>
>>
>> On 2012年08月16日 23:19, Fengguang Wu wrote:
>>>
>>> Hi Fan,
>>>
>>> On Thu, Aug 16, 2012 at 05:36:35PM +0800, Fan Du wrote:
>>>>
>>>>
>>>> Hi, Fengguang
>>>>
>>>> Could you please try the below patch, see if spewing still there?
>>>> thanks
>>>
>>>
>>> Yes, it worked, thank you very much!
>>>
>>
>> Hi, Dave
>>
>> Could you please pick up this patch?
>
> Please do not make extra work for maintainers by sending attachments,
> or requests for status/merge etc.  Your 1st patch had to be manually
> set to an RFC, and now you add another patch less than 24h later.
>
> Please see:
>
>    http://patchwork.ozlabs.org/patch/177934/
>    http://patchwork.ozlabs.org/patch/178132/
>
> Also, a patch should describe the problem it solves (i.e. the symptom
> the end user sees), and how the problem originated, and why the fix
> in the patch is the _right_ fix.  The worst description a commit log
> can have is one that just describes the C change in words, since
> most people can read C on their own.
>
> Here you add "_bh" in the code and then repeat exactly that in
> the commit log.  Your commit log does not tell me when it broke,
> or why it broke, or who had their use case broken.  Can you see
> why this is not acceptable?
>
> Please take the time to look at the traffic in netdev, and read
> the feedback given by maintainers on other patches, so that the
> common errors are understood by you, and not repeated.  It
> will be time well spent!
>

Rick Jones has already well informed me the etiquettes off the list,
which I just broken.

Anyway, thanks for your time writing those suggestions.

> Thanks,
> Paul.
> ---
>
>> thanks
>>
>>
>>
>>
>>> btw, your email client wraps long lines..
>>>
>> Oh, I will definitely fix this.
>> thanks feng guang for the testing :)
>>
>>
>>
>>> Thanks,
>>> Fengguang
>>>
>>>>    From a3f86ecc3ee16ff81d49416bbf791780422988b3 Mon Sep 17 00:00:00 2001
>>>> From: Fan Du<fan.du@windriver.com>
>>>> Date: Thu, 16 Aug 2012 17:31:25 +0800
>>>> Subject: [PATCH] Use rcu_dereference_bh to deference pointer
>>>> protected by rcu_read_lock_bh
>>>>
>>>> Signed-off-by: Fan Du<fan.du@windriver.com>
>>>> ---
>>>>    net/xfrm/xfrm_policy.c |    2 +-
>>>>    1 files changed, 1 insertions(+), 1 deletions(-)
>>>>
>>>> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
>>>> index 5ad4d2c..75a9d6a 100644
>>>> --- a/net/xfrm/xfrm_policy.c
>>>> +++ b/net/xfrm/xfrm_policy.c
>>>> @@ -2501,7 +2501,7 @@ static void __net_init
>>>> xfrm_dst_ops_init(struct net *net)
>>>>          struct xfrm_policy_afinfo *afinfo;
>>>>
>>>>          rcu_read_lock_bh();
>>>> -       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
>>>> +       afinfo = rcu_dereference_bh(xfrm_policy_afinfo[AF_INET]);
>>>>          if (afinfo)
>>>>                  net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
>>>>    #if IS_ENABLED(CONFIG_IPV6)
>>>> --
>>>> 1.7.1
>>>>
>>>>
>>>>
>>>>
>>>> On 2012年08月16日 15:37, Fengguang Wu wrote:
>>>>>
>>>>> Hi Priyanka,
>>>>>
>>>>> The below warning shows up, probably related to this commit:
>>>>>
>>>>> 418a99ac6ad487dc9c42e6b0e85f941af56330f2 Replace rwlock on
>>>>> xfrm_policy_afinfo with rcu
>>>>>
>>>>> [    0.921216]
>>>>> [    0.921645] ===============================
>>>>> [    0.922766] [ INFO: suspicious RCU usage. ]
>>>>> [    0.923887] 3.5.0-01540-g1669891 #64 Not tainted
>>>>> [    0.925123] -------------------------------
>>>>> [    0.932860] /c/kernel-tests/src/tip/net/xfrm/xfrm_policy.c:2504
>>>>> suspicious rcu_dereference_check() usage!
>>>>> [    0.935361]
>>>>> [    0.935361] other info that might help us debug this:
>>>>> [    0.935361]
>>>>> [    0.937472]
>>>>> [    0.937472] rcu_scheduler_active = 1, debug_locks = 0
>>>>> [    0.939182] 2 locks held by swapper/1:
>>>>> [    0.940171]  #0:  (net_mutex){+.+.+.}, at: [<ffffffff814e1ad0>]
>>>>> register_pernet_subsys+0x21/0x57
>>>>> [    0.942705]  #1:  (rcu_read_lock_bh){......}, at:
>>>>> [<ffffffff822c7329>] xfrm_net_init+0x1e4/0x437
>>>>> [    0.951507]
>>>>> [    0.951507] stack backtrace:
>>>>> [    0.952660] Pid: 1, comm: swapper Not tainted 3.5.0-01540-g1669891
>>>>> #64
>>>>> [    0.954364] Call Trace:
>>>>> [    0.955074]  [<ffffffff8108b375>] lockdep_rcu_suspicious+0x174/0x187
>>>>> [    0.956736]  [<ffffffff822c7453>] xfrm_net_init+0x30e/0x437
>>>>> [    0.958205]  [<ffffffff822c7329>] ? xfrm_net_init+0x1e4/0x437
>>>>> [    0.959712]  [<ffffffff814e134a>] ops_init+0x1bb/0x1ff
>>>>> [    0.961067]  [<ffffffff810861f9>] ? trace_hardirqs_on+0x1b/0x24
>>>>> [    0.962644]  [<ffffffff814e17cd>]
>>>>> register_pernet_operations.isra.5+0x9d/0xfe
>>>>> [    0.971376]  [<ffffffff814e1adf>] register_pernet_subsys+0x30/0x57
>>>>> [    0.972992]  [<ffffffff822c7130>] xfrm_init+0x17/0x2c
>>>>> [    0.974316]  [<ffffffff822c2f8c>] ip_rt_init+0x82/0xe7
>>>>> [    0.975668]  [<ffffffff822c31dc>] ip_init+0x10/0x25
>>>>> [    0.976952]  [<ffffffff822c3f77>] inet_init+0x235/0x360
>>>>> [    0.978352]  [<ffffffff822c3d42>] ? devinet_init+0xf2/0xf2
>>>>> [    0.979808]  [<ffffffff82283252>] do_one_initcall+0xb4/0x203
>>>>> [    0.981313]  [<ffffffff8228354a>] kernel_init+0x1a9/0x29a
>>>>> [    0.982732]  [<ffffffff822826d9>] ? loglevel+0x46/0x46
>>>>> [    0.990889]  [<ffffffff816d3d84>] kernel_thread_helper+0x4/0x10
>>>>> [    0.992472]  [<ffffffff816d262c>] ? retint_restore_args+0x13/0x13
>>>>> [    0.994076]  [<ffffffff822833a1>] ? do_one_initcall+0x203/0x203
>>>>> [    0.995636]  [<ffffffff816d3d80>] ? gs_change+0x13/0x13
>>>>> [    0.997197] TCP established hash table entries: 8192 (order: 5,
>>>>> 131072 bytes)
>>>>> [    1.000074] TCP bind hash table entries: 8192 (order: 7, 655360
>>>>> bytes)
>>>>>
>>>>> Thanks,
>>>>> Fengguang
>>>>
>>>>
>>>> --
>>>>
>>>> Love each day!
>>>> --fan
>>>
>>>
>>
>> --
>>
>> Love each day!
>> --fan
>

-- 

Love each day!
--fan

^ permalink raw reply

* RE: [PATCH] net: add new QCA alx ethernet driver
From: Ren, Cloud @ 2012-08-17  1:49 UTC (permalink / raw)
  To: Joe Perches
  Cc: davem@davemloft.net, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, qca-linux-team, nic-devel,
	Huang, Xiong, Rodriguez, Luis
In-Reply-To: <1345122983.26882.9.camel@joe2Laptop>

From: Joe Perches [mailto:joe@perches.com]
Sent: Thursday, August 16, 2012 9:16 PM
>Hi Cloud.  Please convert this to
>
>		netdev_printk(level, hw->adpt->netdev, "%pV", &vaf);
>
>I will submit a patch soon to make the __netdev_printk variant static.

Ok, thanks.


^ permalink raw reply

* Re: suspicious RCU usage in xfrm_net_init()
From: Paul Gortmaker @ 2012-08-17  1:34 UTC (permalink / raw)
  To: Fan Du; +Cc: David Miller, Fengguang Wu, Priyanka Jain, netdev, LKML
In-Reply-To: <502D9938.2010908@windriver.com>

On Thu, Aug 16, 2012 at 9:07 PM, Fan Du <fan.du@windriver.com> wrote:
>
>
> On 2012年08月16日 23:19, Fengguang Wu wrote:
>>
>> Hi Fan,
>>
>> On Thu, Aug 16, 2012 at 05:36:35PM +0800, Fan Du wrote:
>>>
>>>
>>> Hi, Fengguang
>>>
>>> Could you please try the below patch, see if spewing still there?
>>> thanks
>>
>>
>> Yes, it worked, thank you very much!
>>
>
> Hi, Dave
>
> Could you please pick up this patch?

Please do not make extra work for maintainers by sending attachments,
or requests for status/merge etc.  Your 1st patch had to be manually
set to an RFC, and now you add another patch less than 24h later.

Please see:

  http://patchwork.ozlabs.org/patch/177934/
  http://patchwork.ozlabs.org/patch/178132/

Also, a patch should describe the problem it solves (i.e. the symptom
the end user sees), and how the problem originated, and why the fix
in the patch is the _right_ fix.  The worst description a commit log
can have is one that just describes the C change in words, since
most people can read C on their own.

Here you add "_bh" in the code and then repeat exactly that in
the commit log.  Your commit log does not tell me when it broke,
or why it broke, or who had their use case broken.  Can you see
why this is not acceptable?

Please take the time to look at the traffic in netdev, and read
the feedback given by maintainers on other patches, so that the
common errors are understood by you, and not repeated.  It
will be time well spent!

Thanks,
Paul.
---

> thanks
>
>
>
>
>> btw, your email client wraps long lines..
>>
> Oh, I will definitely fix this.
> thanks feng guang for the testing :)
>
>
>
>> Thanks,
>> Fengguang
>>
>>>  From a3f86ecc3ee16ff81d49416bbf791780422988b3 Mon Sep 17 00:00:00 2001
>>> From: Fan Du<fan.du@windriver.com>
>>> Date: Thu, 16 Aug 2012 17:31:25 +0800
>>> Subject: [PATCH] Use rcu_dereference_bh to deference pointer
>>> protected by rcu_read_lock_bh
>>>
>>> Signed-off-by: Fan Du<fan.du@windriver.com>
>>> ---
>>>   net/xfrm/xfrm_policy.c |    2 +-
>>>   1 files changed, 1 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
>>> index 5ad4d2c..75a9d6a 100644
>>> --- a/net/xfrm/xfrm_policy.c
>>> +++ b/net/xfrm/xfrm_policy.c
>>> @@ -2501,7 +2501,7 @@ static void __net_init
>>> xfrm_dst_ops_init(struct net *net)
>>>         struct xfrm_policy_afinfo *afinfo;
>>>
>>>         rcu_read_lock_bh();
>>> -       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
>>> +       afinfo = rcu_dereference_bh(xfrm_policy_afinfo[AF_INET]);
>>>         if (afinfo)
>>>                 net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
>>>   #if IS_ENABLED(CONFIG_IPV6)
>>> --
>>> 1.7.1
>>>
>>>
>>>
>>>
>>> On 2012年08月16日 15:37, Fengguang Wu wrote:
>>>>
>>>> Hi Priyanka,
>>>>
>>>> The below warning shows up, probably related to this commit:
>>>>
>>>> 418a99ac6ad487dc9c42e6b0e85f941af56330f2 Replace rwlock on
>>>> xfrm_policy_afinfo with rcu
>>>>
>>>> [    0.921216]
>>>> [    0.921645] ===============================
>>>> [    0.922766] [ INFO: suspicious RCU usage. ]
>>>> [    0.923887] 3.5.0-01540-g1669891 #64 Not tainted
>>>> [    0.925123] -------------------------------
>>>> [    0.932860] /c/kernel-tests/src/tip/net/xfrm/xfrm_policy.c:2504
>>>> suspicious rcu_dereference_check() usage!
>>>> [    0.935361]
>>>> [    0.935361] other info that might help us debug this:
>>>> [    0.935361]
>>>> [    0.937472]
>>>> [    0.937472] rcu_scheduler_active = 1, debug_locks = 0
>>>> [    0.939182] 2 locks held by swapper/1:
>>>> [    0.940171]  #0:  (net_mutex){+.+.+.}, at: [<ffffffff814e1ad0>]
>>>> register_pernet_subsys+0x21/0x57
>>>> [    0.942705]  #1:  (rcu_read_lock_bh){......}, at:
>>>> [<ffffffff822c7329>] xfrm_net_init+0x1e4/0x437
>>>> [    0.951507]
>>>> [    0.951507] stack backtrace:
>>>> [    0.952660] Pid: 1, comm: swapper Not tainted 3.5.0-01540-g1669891
>>>> #64
>>>> [    0.954364] Call Trace:
>>>> [    0.955074]  [<ffffffff8108b375>] lockdep_rcu_suspicious+0x174/0x187
>>>> [    0.956736]  [<ffffffff822c7453>] xfrm_net_init+0x30e/0x437
>>>> [    0.958205]  [<ffffffff822c7329>] ? xfrm_net_init+0x1e4/0x437
>>>> [    0.959712]  [<ffffffff814e134a>] ops_init+0x1bb/0x1ff
>>>> [    0.961067]  [<ffffffff810861f9>] ? trace_hardirqs_on+0x1b/0x24
>>>> [    0.962644]  [<ffffffff814e17cd>]
>>>> register_pernet_operations.isra.5+0x9d/0xfe
>>>> [    0.971376]  [<ffffffff814e1adf>] register_pernet_subsys+0x30/0x57
>>>> [    0.972992]  [<ffffffff822c7130>] xfrm_init+0x17/0x2c
>>>> [    0.974316]  [<ffffffff822c2f8c>] ip_rt_init+0x82/0xe7
>>>> [    0.975668]  [<ffffffff822c31dc>] ip_init+0x10/0x25
>>>> [    0.976952]  [<ffffffff822c3f77>] inet_init+0x235/0x360
>>>> [    0.978352]  [<ffffffff822c3d42>] ? devinet_init+0xf2/0xf2
>>>> [    0.979808]  [<ffffffff82283252>] do_one_initcall+0xb4/0x203
>>>> [    0.981313]  [<ffffffff8228354a>] kernel_init+0x1a9/0x29a
>>>> [    0.982732]  [<ffffffff822826d9>] ? loglevel+0x46/0x46
>>>> [    0.990889]  [<ffffffff816d3d84>] kernel_thread_helper+0x4/0x10
>>>> [    0.992472]  [<ffffffff816d262c>] ? retint_restore_args+0x13/0x13
>>>> [    0.994076]  [<ffffffff822833a1>] ? do_one_initcall+0x203/0x203
>>>> [    0.995636]  [<ffffffff816d3d80>] ? gs_change+0x13/0x13
>>>> [    0.997197] TCP established hash table entries: 8192 (order: 5,
>>>> 131072 bytes)
>>>> [    1.000074] TCP bind hash table entries: 8192 (order: 7, 655360
>>>> bytes)
>>>>
>>>> Thanks,
>>>> Fengguang
>>>
>>>
>>> --
>>>
>>> Love each day!
>>> --fan
>>
>>
>
> --
>
> Love each day!
> --fan

^ permalink raw reply

* Re: suspicious RCU usage in xfrm_net_init()
From: Fan Du @ 2012-08-17  1:07 UTC (permalink / raw)
  To: David Miller; +Cc: Fengguang Wu, Priyanka Jain, netdev, LKML
In-Reply-To: <20120816151949.GA18681@localhost>

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



On 2012年08月16日 23:19, Fengguang Wu wrote:
> Hi Fan,
>
> On Thu, Aug 16, 2012 at 05:36:35PM +0800, Fan Du wrote:
>>
>> Hi, Fengguang
>>
>> Could you please try the below patch, see if spewing still there?
>> thanks
>
> Yes, it worked, thank you very much!
>

Hi, Dave

Could you please pick up this patch?
thanks



> btw, your email client wraps long lines..
>
Oh, I will definitely fix this.
thanks feng guang for the testing :)


> Thanks,
> Fengguang
>
>>  From a3f86ecc3ee16ff81d49416bbf791780422988b3 Mon Sep 17 00:00:00 2001
>> From: Fan Du<fan.du@windriver.com>
>> Date: Thu, 16 Aug 2012 17:31:25 +0800
>> Subject: [PATCH] Use rcu_dereference_bh to deference pointer
>> protected by rcu_read_lock_bh
>>
>> Signed-off-by: Fan Du<fan.du@windriver.com>
>> ---
>>   net/xfrm/xfrm_policy.c |    2 +-
>>   1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
>> index 5ad4d2c..75a9d6a 100644
>> --- a/net/xfrm/xfrm_policy.c
>> +++ b/net/xfrm/xfrm_policy.c
>> @@ -2501,7 +2501,7 @@ static void __net_init
>> xfrm_dst_ops_init(struct net *net)
>>   	struct xfrm_policy_afinfo *afinfo;
>>
>>   	rcu_read_lock_bh();
>> -	afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
>> +	afinfo = rcu_dereference_bh(xfrm_policy_afinfo[AF_INET]);
>>   	if (afinfo)
>>   		net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
>>   #if IS_ENABLED(CONFIG_IPV6)
>> --
>> 1.7.1
>>
>>
>>
>>
>> On 2012年08月16日 15:37, Fengguang Wu wrote:
>>> Hi Priyanka,
>>>
>>> The below warning shows up, probably related to this commit:
>>>
>>> 418a99ac6ad487dc9c42e6b0e85f941af56330f2 Replace rwlock on xfrm_policy_afinfo with rcu
>>>
>>> [    0.921216]
>>> [    0.921645] ===============================
>>> [    0.922766] [ INFO: suspicious RCU usage. ]
>>> [    0.923887] 3.5.0-01540-g1669891 #64 Not tainted
>>> [    0.925123] -------------------------------
>>> [    0.932860] /c/kernel-tests/src/tip/net/xfrm/xfrm_policy.c:2504 suspicious rcu_dereference_check() usage!
>>> [    0.935361]
>>> [    0.935361] other info that might help us debug this:
>>> [    0.935361]
>>> [    0.937472]
>>> [    0.937472] rcu_scheduler_active = 1, debug_locks = 0
>>> [    0.939182] 2 locks held by swapper/1:
>>> [    0.940171]  #0:  (net_mutex){+.+.+.}, at: [<ffffffff814e1ad0>] register_pernet_subsys+0x21/0x57
>>> [    0.942705]  #1:  (rcu_read_lock_bh){......}, at: [<ffffffff822c7329>] xfrm_net_init+0x1e4/0x437
>>> [    0.951507]
>>> [    0.951507] stack backtrace:
>>> [    0.952660] Pid: 1, comm: swapper Not tainted 3.5.0-01540-g1669891 #64
>>> [    0.954364] Call Trace:
>>> [    0.955074]  [<ffffffff8108b375>] lockdep_rcu_suspicious+0x174/0x187
>>> [    0.956736]  [<ffffffff822c7453>] xfrm_net_init+0x30e/0x437
>>> [    0.958205]  [<ffffffff822c7329>] ? xfrm_net_init+0x1e4/0x437
>>> [    0.959712]  [<ffffffff814e134a>] ops_init+0x1bb/0x1ff
>>> [    0.961067]  [<ffffffff810861f9>] ? trace_hardirqs_on+0x1b/0x24
>>> [    0.962644]  [<ffffffff814e17cd>] register_pernet_operations.isra.5+0x9d/0xfe
>>> [    0.971376]  [<ffffffff814e1adf>] register_pernet_subsys+0x30/0x57
>>> [    0.972992]  [<ffffffff822c7130>] xfrm_init+0x17/0x2c
>>> [    0.974316]  [<ffffffff822c2f8c>] ip_rt_init+0x82/0xe7
>>> [    0.975668]  [<ffffffff822c31dc>] ip_init+0x10/0x25
>>> [    0.976952]  [<ffffffff822c3f77>] inet_init+0x235/0x360
>>> [    0.978352]  [<ffffffff822c3d42>] ? devinet_init+0xf2/0xf2
>>> [    0.979808]  [<ffffffff82283252>] do_one_initcall+0xb4/0x203
>>> [    0.981313]  [<ffffffff8228354a>] kernel_init+0x1a9/0x29a
>>> [    0.982732]  [<ffffffff822826d9>] ? loglevel+0x46/0x46
>>> [    0.990889]  [<ffffffff816d3d84>] kernel_thread_helper+0x4/0x10
>>> [    0.992472]  [<ffffffff816d262c>] ? retint_restore_args+0x13/0x13
>>> [    0.994076]  [<ffffffff822833a1>] ? do_one_initcall+0x203/0x203
>>> [    0.995636]  [<ffffffff816d3d80>] ? gs_change+0x13/0x13
>>> [    0.997197] TCP established hash table entries: 8192 (order: 5, 131072 bytes)
>>> [    1.000074] TCP bind hash table entries: 8192 (order: 7, 655360 bytes)
>>>
>>> Thanks,
>>> Fengguang
>>
>> --
>>
>> Love each day!
>> --fan
>

-- 

Love each day!
--fan

[-- Attachment #2: 0001-Use-rcu_dereference_bh-to-deference-pointer-protecte.patch --]
[-- Type: text/x-diff, Size: 1072 bytes --]

>From f3b4d84f7ca2ed235c8c8ae5186f45e20b9b80db Mon Sep 17 00:00:00 2001
From: Fan Du <fan.du@windriver.com>
Date: Thu, 16 Aug 2012 17:51:25 +0800
Subject: [PATCH] Use rcu_dereference_bh to deference pointer protected by rcu_read_lock_bh

Signed-off-by: Fan Du <fan.du@windriver.com>
---
 net/xfrm/xfrm_policy.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 5ad4d2c..6405764 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2501,11 +2501,11 @@ static void __net_init xfrm_dst_ops_init(struct net *net)
 	struct xfrm_policy_afinfo *afinfo;
 
 	rcu_read_lock_bh();
-	afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
+	afinfo = rcu_dereference_bh(xfrm_policy_afinfo[AF_INET]);
 	if (afinfo)
 		net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
 #if IS_ENABLED(CONFIG_IPV6)
-	afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]);
+	afinfo = rcu_dereference_bh(xfrm_policy_afinfo[AF_INET6]);
 	if (afinfo)
 		net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
 #endif
-- 
1.7.1


^ permalink raw reply related

* Re: [PATCH v0 5/5] cgroup: Assign subsystem IDs during compile time
From: Tejun Heo @ 2012-08-16 23:20 UTC (permalink / raw)
  To: Daniel Wagner
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, cgroups-u79uwXL29TY76Z2rM5mHXA,
	Daniel Wagner, David S. Miller, Andrew Morton, Eric Dumazet,
	Gao feng, Glauber Costa, Jamal Hadi Salim, John Fastabend,
	Kamezawa Hiroyuki, Li Zefan, Neil Horman
In-Reply-To: <1345126336-20755-6-git-send-email-wagi-kQCPcA+X3s7YtjvyW6yDsg@public.gmane.org>

On Thu, Aug 16, 2012 at 04:12:16PM +0200, Daniel Wagner wrote:
> From: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
> 
> We are able to safe some space when we assign the subsystem
> IDs at compile time. Instead of allocating per cgroup
> cgroup->subsys[CGROUP_SUBSYS_COUNT] where CGROUP_SUBSYS_COUNT is
> always 64, we allocate 12 + 1 at max (at this point there are 12
> subsystem).

So, IIUC, this is effectively removing the capability to implement
modularized controller which isn't known at kernel compile time.  Am I
right?

I don't think that's a bad idea but if we're doing that, can't we make
things even simpler?  Do we need to distinguish in-kernel and module
at all?

Li, what do you think about this?

Thanks.

-- 
tejun

^ permalink raw reply

* Re: [patch] ipv6: move dereference after check in fl_free()
From: Eric W. Biederman @ 2012-08-16 23:11 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: David S. Miller, Alexey Kuznetsov, James Morris,
	Hideaki YOSHIFUJI, Patrick McHardy, netdev, kernel-janitors
In-Reply-To: <20120816131502.GB23188@elgon.mountain>

Dan Carpenter <dan.carpenter@oracle.com> writes:

> There is a dereference before checking for NULL bug here.  Generally
> free() functions should accept NULL pointers.  For example, fl_create()
> can pass a NULL pointer to fl_free() on the error path.

Thanks.

Applied to user-namespace.git

Eric

>
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
> ---
> Only needed on linux-next.
>
> diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
> index c836a6a..90bbefb 100644
> --- a/net/ipv6/ip6_flowlabel.c
> +++ b/net/ipv6/ip6_flowlabel.c
> @@ -91,12 +91,9 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
>  
>  static void fl_free(struct ip6_flowlabel *fl)
>  {
> -	switch (fl->share) {
> -	case IPV6_FL_S_PROCESS:
> -		put_pid(fl->owner.pid);
> -		break;
> -	}
>  	if (fl) {
> +		if (fl->share == IPV6_FL_S_PROCESS)
> +			put_pid(fl->owner.pid);
>  		release_net(fl->fl_net);
>  		kfree(fl->opt);
>  	}

^ permalink raw reply

* [net-next 9/9] ixgbe: Rewrite code related to configuring IFCS bit in Tx descriptor
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This change updates the code related to configuring the transmit frame
checksum.  Specifically I have updated the code so that we can only skip
inserting the checksum in the case that we are not performing some other
offload that will modify the frame data.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe.h      |  1 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 16 ++++++++++------
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index fd2bc69..bffcf1f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -107,6 +107,7 @@
 #define IXGBE_TX_FLAGS_FSO		(u32)(1 << 6)
 #define IXGBE_TX_FLAGS_TXSW		(u32)(1 << 7)
 #define IXGBE_TX_FLAGS_TSTAMP		(u32)(1 << 8)
+#define IXGBE_TX_FLAGS_NO_IFCS		(u32)(1 << 9)
 #define IXGBE_TX_FLAGS_VLAN_MASK	0xffff0000
 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK	0xe0000000
 #define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT  29
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index aa37b84..fa0d6e1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -5903,9 +5903,12 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
 	u32 type_tucmd = 0;
 
 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
-		if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
-		    !(first->tx_flags & IXGBE_TX_FLAGS_TXSW))
-			return;
+		if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN)) {
+			if (unlikely(skb->no_fcs))
+				first->tx_flags |= IXGBE_TX_FLAGS_NO_IFCS;
+			if (!(first->tx_flags & IXGBE_TX_FLAGS_TXSW))
+				return;
+		}
 	} else {
 		u8 l4_hdr = 0;
 		switch (first->protocol) {
@@ -5967,7 +5970,6 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
 {
 	/* set type for advanced descriptor with frame checksum insertion */
 	__le32 cmd_type = cpu_to_le32(IXGBE_ADVTXD_DTYP_DATA |
-				      IXGBE_ADVTXD_DCMD_IFCS |
 				      IXGBE_ADVTXD_DCMD_DEXT);
 
 	/* set HW vlan bit if vlan is present */
@@ -5987,6 +5989,10 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
 #endif
 		cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_TSE);
 
+	/* insert frame checksum */
+	if (!(tx_flags & IXGBE_TX_FLAGS_NO_IFCS))
+		cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_IFCS);
+
 	return cmd_type;
 }
 
@@ -6092,8 +6098,6 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
 		if (likely(!data_len))
 			break;
 
-		if (unlikely(skb->no_fcs))
-			cmd_type &= ~(cpu_to_le32(IXGBE_ADVTXD_DCMD_IFCS));
 		tx_desc->read.cmd_type_len = cmd_type | cpu_to_le32(size);
 
 		i++;
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 8/9] ixgbe: Roll RSC code into non-EOP code
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This change moves the RSC code into the non-EOP descriptor handling
function. The main motivation behind this change is to help reduce the
overhead in the non-RSC case. Previously the non-RSC path code would
always be checking for append count even if RSC had been disabled. Now
this code is completely skipped in a single conditional check instead of
having to make two separate checks.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 51 ++++++++++-----------------
 1 file changed, 19 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 9e72ae6..aa37b84 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1320,29 +1320,6 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
 		return max_len;
 }
 
-static void ixgbe_get_rsc_cnt(struct ixgbe_ring *rx_ring,
-			      union ixgbe_adv_rx_desc *rx_desc,
-			      struct sk_buff *skb)
-{
-	__le32 rsc_enabled;
-	u32 rsc_cnt;
-
-	if (!ring_is_rsc_enabled(rx_ring))
-		return;
-
-	rsc_enabled = rx_desc->wb.lower.lo_dword.data &
-		      cpu_to_le32(IXGBE_RXDADV_RSCCNT_MASK);
-
-	/* If this is an RSC frame rsc_cnt should be non-zero */
-	if (!rsc_enabled)
-		return;
-
-	rsc_cnt = le32_to_cpu(rsc_enabled);
-	rsc_cnt >>= IXGBE_RXDADV_RSCCNT_SHIFT;
-
-	IXGBE_CB(skb)->append_cnt += rsc_cnt - 1;
-}
-
 static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
 				   struct sk_buff *skb)
 {
@@ -1440,16 +1417,28 @@ static bool ixgbe_is_non_eop(struct ixgbe_ring *rx_ring,
 
 	prefetch(IXGBE_RX_DESC(rx_ring, ntc));
 
-	if (likely(ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP)))
-		return false;
+	/* update RSC append count if present */
+	if (ring_is_rsc_enabled(rx_ring)) {
+		__le32 rsc_enabled = rx_desc->wb.lower.lo_dword.data &
+				     cpu_to_le32(IXGBE_RXDADV_RSCCNT_MASK);
+
+		if (unlikely(rsc_enabled)) {
+			u32 rsc_cnt = le32_to_cpu(rsc_enabled);
+
+			rsc_cnt >>= IXGBE_RXDADV_RSCCNT_SHIFT;
+			IXGBE_CB(skb)->append_cnt += rsc_cnt - 1;
 
-	/* append_cnt indicates packet is RSC, if so fetch nextp */
-	if (IXGBE_CB(skb)->append_cnt) {
-		ntc = le32_to_cpu(rx_desc->wb.upper.status_error);
-		ntc &= IXGBE_RXDADV_NEXTP_MASK;
-		ntc >>= IXGBE_RXDADV_NEXTP_SHIFT;
+			/* update ntc based on RSC value */
+			ntc = le32_to_cpu(rx_desc->wb.upper.status_error);
+			ntc &= IXGBE_RXDADV_NEXTP_MASK;
+			ntc >>= IXGBE_RXDADV_NEXTP_SHIFT;
+		}
 	}
 
+	/* if we are the last buffer then there is nothing else to do */
+	if (likely(ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP)))
+		return false;
+
 	/* place skb in next buffer to be received */
 	rx_ring->rx_buffer_info[ntc].skb = skb;
 	rx_ring->rx_stats.non_eop_descs++;
@@ -1829,8 +1818,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 		if (!skb)
 			break;
 
-		ixgbe_get_rsc_cnt(rx_ring, rx_desc, skb);
-
 		cleaned_count++;
 
 		/* place incomplete frames back on ring for completion */
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 7/9] ixgbe: Make allocating skb and placing data in it a separate function
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This patch creates a function named ixgbe_fetch_rx_buffer. The sole
purpose of this function is to retrieve a single buffer off of the ring and
to place it in an skb.

The advantage to doing this is that it helps improve the readability since
I can decrease the indentation and for the code in this section.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 166 ++++++++++++++------------
 1 file changed, 89 insertions(+), 77 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index d11fac5..9e72ae6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1693,6 +1693,89 @@ static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
 	return true;
 }
 
+static struct sk_buff *ixgbe_fetch_rx_buffer(struct ixgbe_ring *rx_ring,
+					     union ixgbe_adv_rx_desc *rx_desc)
+{
+	struct ixgbe_rx_buffer *rx_buffer;
+	struct sk_buff *skb;
+	struct page *page;
+
+	rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
+	page = rx_buffer->page;
+	prefetchw(page);
+
+	skb = rx_buffer->skb;
+
+	if (likely(!skb)) {
+		void *page_addr = page_address(page) +
+				  rx_buffer->page_offset;
+
+		/* prefetch first cache line of first page */
+		prefetch(page_addr);
+#if L1_CACHE_BYTES < 128
+		prefetch(page_addr + L1_CACHE_BYTES);
+#endif
+
+		/* allocate a skb to store the frags */
+		skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
+						IXGBE_RX_HDR_SIZE);
+		if (unlikely(!skb)) {
+			rx_ring->rx_stats.alloc_rx_buff_failed++;
+			return NULL;
+		}
+
+		/*
+		 * we will be copying header into skb->data in
+		 * pskb_may_pull so it is in our interest to prefetch
+		 * it now to avoid a possible cache miss
+		 */
+		prefetchw(skb->data);
+
+		/*
+		 * Delay unmapping of the first packet. It carries the
+		 * header information, HW may still access the header
+		 * after the writeback.  Only unmap it when EOP is
+		 * reached
+		 */
+		if (likely(ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP)))
+			goto dma_sync;
+
+		IXGBE_CB(skb)->dma = rx_buffer->dma;
+	} else {
+		if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP))
+			ixgbe_dma_sync_frag(rx_ring, skb);
+
+dma_sync:
+		/* we are reusing so sync this buffer for CPU use */
+		dma_sync_single_range_for_cpu(rx_ring->dev,
+					      rx_buffer->dma,
+					      rx_buffer->page_offset,
+					      ixgbe_rx_bufsz(rx_ring),
+					      DMA_FROM_DEVICE);
+	}
+
+	/* pull page into skb */
+	if (ixgbe_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
+		/* hand second half of page back to the ring */
+		ixgbe_reuse_rx_page(rx_ring, rx_buffer);
+	} else if (IXGBE_CB(skb)->dma == rx_buffer->dma) {
+		/* the page has been released from the ring */
+		IXGBE_CB(skb)->page_released = true;
+	} else {
+		/* we are not reusing the buffer so unmap it */
+		dma_unmap_page(rx_ring->dev, rx_buffer->dma,
+			       ixgbe_rx_pg_size(rx_ring),
+			       DMA_FROM_DEVICE);
+	}
+
+	/* clear contents of buffer_info */
+	rx_buffer->skb = NULL;
+	rx_buffer->dma = 0;
+	rx_buffer->page = NULL;
+
+	return skb;
+}
+
 /**
  * ixgbe_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf
  * @q_vector: structure containing interrupt and ring information
@@ -1718,11 +1801,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 	u16 cleaned_count = ixgbe_desc_unused(rx_ring);
 
 	do {
-		struct ixgbe_rx_buffer *rx_buffer;
 		union ixgbe_adv_rx_desc *rx_desc;
 		struct sk_buff *skb;
-		struct page *page;
-		u16 ntc;
 
 		/* return some buffers to hardware, one at a time is too slow */
 		if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) {
@@ -1730,9 +1810,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 			cleaned_count = 0;
 		}
 
-		ntc = rx_ring->next_to_clean;
-		rx_desc = IXGBE_RX_DESC(rx_ring, ntc);
-		rx_buffer = &rx_ring->rx_buffer_info[ntc];
+		rx_desc = IXGBE_RX_DESC(rx_ring, rx_ring->next_to_clean);
 
 		if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_DD))
 			break;
@@ -1744,78 +1822,12 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 		 */
 		rmb();
 
-		page = rx_buffer->page;
-		prefetchw(page);
-
-		skb = rx_buffer->skb;
-
-		if (likely(!skb)) {
-			void *page_addr = page_address(page) +
-					  rx_buffer->page_offset;
-
-			/* prefetch first cache line of first page */
-			prefetch(page_addr);
-#if L1_CACHE_BYTES < 128
-			prefetch(page_addr + L1_CACHE_BYTES);
-#endif
-
-			/* allocate a skb to store the frags */
-			skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-							IXGBE_RX_HDR_SIZE);
-			if (unlikely(!skb)) {
-				rx_ring->rx_stats.alloc_rx_buff_failed++;
-				break;
-			}
-
-			/*
-			 * we will be copying header into skb->data in
-			 * pskb_may_pull so it is in our interest to prefetch
-			 * it now to avoid a possible cache miss
-			 */
-			prefetchw(skb->data);
-
-			/*
-			 * Delay unmapping of the first packet. It carries the
-			 * header information, HW may still access the header
-			 * after the writeback.  Only unmap it when EOP is
-			 * reached
-			 */
-			if (likely(ixgbe_test_staterr(rx_desc,
-						      IXGBE_RXD_STAT_EOP)))
-				goto dma_sync;
+		/* retrieve a buffer from the ring */
+		skb = ixgbe_fetch_rx_buffer(rx_ring, rx_desc);
 
-			IXGBE_CB(skb)->dma = rx_buffer->dma;
-		} else {
-			if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP))
-				ixgbe_dma_sync_frag(rx_ring, skb);
-
-dma_sync:
-			/* we are reusing so sync this buffer for CPU use */
-			dma_sync_single_range_for_cpu(rx_ring->dev,
-						      rx_buffer->dma,
-						      rx_buffer->page_offset,
-						      ixgbe_rx_bufsz(rx_ring),
-						      DMA_FROM_DEVICE);
-		}
-
-		/* pull page into skb */
-		if (ixgbe_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
-			/* hand second half of page back to the ring */
-			ixgbe_reuse_rx_page(rx_ring, rx_buffer);
-		} else if (IXGBE_CB(skb)->dma == rx_buffer->dma) {
-			/* the page has been released from the ring */
-			IXGBE_CB(skb)->page_released = true;
-		} else {
-			/* we are not reusing the buffer so unmap it */
-			dma_unmap_page(rx_ring->dev, rx_buffer->dma,
-				       ixgbe_rx_pg_size(rx_ring),
-				       DMA_FROM_DEVICE);
-		}
-
-		/* clear contents of buffer_info */
-		rx_buffer->skb = NULL;
-		rx_buffer->dma = 0;
-		rx_buffer->page = NULL;
+		/* exit if we failed to retrieve a buffer */
+		if (!skb)
+			break;
 
 		ixgbe_get_rsc_cnt(rx_ring, rx_desc, skb);
 
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 5/9] ixgbe: Make pull tail function separate from rest of cleanup_headers
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This change creates a separate function for functionality similar to
pskb_pull_tail.  The main motivation for moving it to a separate function
is so that later I can just skip this function in the case where we have
already copied the buffer into skb->head.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 94 ++++++++++++++++-----------
 1 file changed, 57 insertions(+), 37 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index b0020fc..d926973 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1458,6 +1458,61 @@ static bool ixgbe_is_non_eop(struct ixgbe_ring *rx_ring,
 }
 
 /**
+ * ixgbe_pull_tail - ixgbe specific version of skb_pull_tail
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @skb: pointer to current skb being adjusted
+ *
+ * This function is an ixgbe specific version of __pskb_pull_tail.  The
+ * main difference between this version and the original function is that
+ * this function can make several assumptions about the state of things
+ * that allow for significant optimizations versus the standard function.
+ * As a result we can do things like drop a frag and maintain an accurate
+ * truesize for the skb.
+ */
+static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
+			    struct sk_buff *skb)
+{
+	struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+	unsigned char *va;
+	unsigned int pull_len;
+
+	/*
+	 * it is valid to use page_address instead of kmap since we are
+	 * working with pages allocated out of the lomem pool per
+	 * alloc_page(GFP_ATOMIC)
+	 */
+	va = skb_frag_address(frag);
+
+	/*
+	 * we need the header to contain the greater of either ETH_HLEN or
+	 * 60 bytes if the skb->len is less than 60 for skb_pad.
+	 */
+	pull_len = skb_frag_size(frag);
+	if (pull_len > IXGBE_RX_HDR_SIZE)
+		pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
+
+	/* align pull length to size of long to optimize memcpy performance */
+	skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
+
+	/* update all of the pointers */
+	skb_frag_size_sub(frag, pull_len);
+	frag->page_offset += pull_len;
+	skb->data_len -= pull_len;
+	skb->tail += pull_len;
+
+	/*
+	 * if we sucked the frag empty then we should free it,
+	 * if there are other frags here something is screwed up in hardware
+	 */
+	if (skb_frag_size(frag) == 0) {
+		BUG_ON(skb_shinfo(skb)->nr_frags != 1);
+		skb_shinfo(skb)->nr_frags = 0;
+		__skb_frag_unref(frag);
+		skb->truesize -= ixgbe_rx_bufsz(rx_ring);
+	}
+}
+
+/**
  * ixgbe_dma_sync_frag - perform DMA sync for first frag of SKB
  * @rx_ring: rx descriptor ring packet is being transacted on
  * @skb: pointer to current skb being updated
@@ -1509,10 +1564,7 @@ static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
 				  union ixgbe_adv_rx_desc *rx_desc,
 				  struct sk_buff *skb)
 {
-	struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
 	struct net_device *netdev = rx_ring->netdev;
-	unsigned char *va;
-	unsigned int pull_len;
 
 	/* verify that the packet does not have any known errors */
 	if (unlikely(ixgbe_test_staterr(rx_desc,
@@ -1522,40 +1574,8 @@ static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
 		return true;
 	}
 
-	/*
-	 * it is valid to use page_address instead of kmap since we are
-	 * working with pages allocated out of the lomem pool per
-	 * alloc_page(GFP_ATOMIC)
-	 */
-	va = skb_frag_address(frag);
-
-	/*
-	 * we need the header to contain the greater of either ETH_HLEN or
-	 * 60 bytes if the skb->len is less than 60 for skb_pad.
-	 */
-	pull_len = skb_frag_size(frag);
-	if (pull_len > IXGBE_RX_HDR_SIZE)
-		pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
-
-	/* align pull length to size of long to optimize memcpy performance */
-	skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
-
-	/* update all of the pointers */
-	skb_frag_size_sub(frag, pull_len);
-	frag->page_offset += pull_len;
-	skb->data_len -= pull_len;
-	skb->tail += pull_len;
-
-	/*
-	 * if we sucked the frag empty then we should free it,
-	 * if there are other frags here something is screwed up in hardware
-	 */
-	if (skb_frag_size(frag) == 0) {
-		BUG_ON(skb_shinfo(skb)->nr_frags != 1);
-		skb_shinfo(skb)->nr_frags = 0;
-		__skb_frag_unref(frag);
-		skb->truesize -= ixgbe_rx_bufsz(rx_ring);
-	}
+	/* place header in linear portion of buffer */
+	ixgbe_pull_tail(rx_ring, skb);
 
 #ifdef IXGBE_FCOE
 	/* do not attempt to pad FCoE Frames as this will disrupt DDP */
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 4/9] ixgbe: Have the CPU take ownership of the buffers sooner
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This patch makes it so that we will always have ownership of the buffers by
the time we get to ixgbe_add_rx_frag. This is necessary as I am planning to
add a copy-break to ixgbe_add_rx_frag and in order for that to function
correctly we need the CPU to have ownership of the buffer.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 52 +++++++++++++++++++--------
 1 file changed, 38 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 9305e9a..b0020fc 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1458,6 +1458,36 @@ static bool ixgbe_is_non_eop(struct ixgbe_ring *rx_ring,
 }
 
 /**
+ * ixgbe_dma_sync_frag - perform DMA sync for first frag of SKB
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @skb: pointer to current skb being updated
+ *
+ * This function provides a basic DMA sync up for the first fragment of an
+ * skb.  The reason for doing this is that the first fragment cannot be
+ * unmapped until we have reached the end of packet descriptor for a buffer
+ * chain.
+ */
+static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring,
+				struct sk_buff *skb)
+{
+	/* if the page was released unmap it, else just sync our portion */
+	if (unlikely(IXGBE_CB(skb)->page_released)) {
+		dma_unmap_page(rx_ring->dev, IXGBE_CB(skb)->dma,
+			       ixgbe_rx_pg_size(rx_ring), DMA_FROM_DEVICE);
+		IXGBE_CB(skb)->page_released = false;
+	} else {
+		struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+
+		dma_sync_single_range_for_cpu(rx_ring->dev,
+					      IXGBE_CB(skb)->dma,
+					      frag->page_offset,
+					      ixgbe_rx_bufsz(rx_ring),
+					      DMA_FROM_DEVICE);
+	}
+	IXGBE_CB(skb)->dma = 0;
+}
+
+/**
  * ixgbe_cleanup_headers - Correct corrupted or empty headers
  * @rx_ring: rx descriptor ring packet is being transacted on
  * @rx_desc: pointer to the EOP Rx descriptor
@@ -1484,20 +1514,6 @@ static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
 	unsigned char *va;
 	unsigned int pull_len;
 
-	/* if the page was released unmap it, else just sync our portion */
-	if (unlikely(IXGBE_CB(skb)->page_released)) {
-		dma_unmap_page(rx_ring->dev, IXGBE_CB(skb)->dma,
-			       ixgbe_rx_pg_size(rx_ring), DMA_FROM_DEVICE);
-		IXGBE_CB(skb)->page_released = false;
-	} else {
-		dma_sync_single_range_for_cpu(rx_ring->dev,
-					      IXGBE_CB(skb)->dma,
-					      frag->page_offset,
-					      ixgbe_rx_bufsz(rx_ring),
-					      DMA_FROM_DEVICE);
-	}
-	IXGBE_CB(skb)->dma = 0;
-
 	/* verify that the packet does not have any known errors */
 	if (unlikely(ixgbe_test_staterr(rx_desc,
 					IXGBE_RXDADV_ERR_FRAME_ERR_MASK) &&
@@ -1742,8 +1758,16 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 			 * after the writeback.  Only unmap it when EOP is
 			 * reached
 			 */
+			if (likely(ixgbe_test_staterr(rx_desc,
+						      IXGBE_RXD_STAT_EOP)))
+				goto dma_sync;
+
 			IXGBE_CB(skb)->dma = rx_buffer->dma;
 		} else {
+			if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_EOP))
+				ixgbe_dma_sync_frag(rx_ring, skb);
+
+dma_sync:
 			/* we are reusing so sync this buffer for CPU use */
 			dma_sync_single_range_for_cpu(rx_ring->dev,
 						      rx_buffer->dma,
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 6/9] ixgbe: Copybreak sooner to avoid get_page/put_page and offset change overhead
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This change makes it so that if only the first 256 bytes of a buffer are
used we just copy the data out and leave the offset and page count
unchanged. There are multiple advantages to this. First it allows us to
reuse the page much more in the case of pages larger than 4K. It also
allows us to avoid some expensive atomic operations in the form of
get_page/put_page. In perf I have seen CPU utilization for put_page drop
from 3.5% to 1.8% as a result of this patch when doing small packet routing,
and packet rates increased by about 3%.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 32 ++++++++++++++-------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index d926973..d11fac5 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1487,9 +1487,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
 	 * we need the header to contain the greater of either ETH_HLEN or
 	 * 60 bytes if the skb->len is less than 60 for skb_pad.
 	 */
-	pull_len = skb_frag_size(frag);
-	if (pull_len > IXGBE_RX_HDR_SIZE)
-		pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
+	pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
 
 	/* align pull length to size of long to optimize memcpy performance */
 	skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
@@ -1499,17 +1497,6 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
 	frag->page_offset += pull_len;
 	skb->data_len -= pull_len;
 	skb->tail += pull_len;
-
-	/*
-	 * if we sucked the frag empty then we should free it,
-	 * if there are other frags here something is screwed up in hardware
-	 */
-	if (skb_frag_size(frag) == 0) {
-		BUG_ON(skb_shinfo(skb)->nr_frags != 1);
-		skb_shinfo(skb)->nr_frags = 0;
-		__skb_frag_unref(frag);
-		skb->truesize -= ixgbe_rx_bufsz(rx_ring);
-	}
 }
 
 /**
@@ -1575,7 +1562,8 @@ static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
 	}
 
 	/* place header in linear portion of buffer */
-	ixgbe_pull_tail(rx_ring, skb);
+	if (skb_is_nonlinear(skb))
+		ixgbe_pull_tail(rx_ring, skb);
 
 #ifdef IXGBE_FCOE
 	/* do not attempt to pad FCoE Frames as this will disrupt DDP */
@@ -1656,6 +1644,20 @@ static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
 				   ixgbe_rx_bufsz(rx_ring);
 #endif
 
+	if ((size <= IXGBE_RX_HDR_SIZE) && !skb_is_nonlinear(skb)) {
+		unsigned char *va = page_address(page) + rx_buffer->page_offset;
+
+		memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long)));
+
+		/* we can reuse buffer as-is, just make sure it is local */
+		if (likely(page_to_nid(page) == numa_node_id()))
+			return true;
+
+		/* this page cannot be reused so discard it */
+		put_page(page);
+		return false;
+	}
+
 	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
 			rx_buffer->page_offset, size, truesize);
 
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 3/9] ixgbe: Only use double buffering if page size is less than 8K
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This change makes it so that we do not use double buffering if the page
size is larger than 4K.  Instead we will simply walk through the page using
up to 3K per receive, and if we receive less than we only move the offset
by that amount.  We will free the page when there is no longer any space
left that we can use instead of checking the page count to see if we can
cycle back to the start.

The main motivation behind this is to avoid the unnecessary truesize cost
for using a half page when most packets are 2K or smaller. With this new
approach the largest possible truesize for a page fragment will be 3K when
PAGE_SIZE is larger than 4K.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe.h      | 24 ++++++++++++----
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 40 ++++++++++++++++++---------
 2 files changed, 45 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index b9623e9..fd2bc69 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -78,6 +78,9 @@
 
 /* Supported Rx Buffer Sizes */
 #define IXGBE_RXBUFFER_256    256  /* Used for skb receive header */
+#define IXGBE_RXBUFFER_2K    2048
+#define IXGBE_RXBUFFER_3K    3072
+#define IXGBE_RXBUFFER_4K    4096
 #define IXGBE_MAX_RXBUFFER  16384  /* largest size for a single descriptor */
 
 /*
@@ -293,16 +296,25 @@ struct ixgbe_ring_feature {
  * this is twice the size of a half page we need to double the page order
  * for FCoE enabled Rx queues.
  */
-#if defined(IXGBE_FCOE) && (PAGE_SIZE < 8192)
-static inline unsigned int ixgbe_rx_pg_order(struct ixgbe_ring *ring)
+static inline unsigned int ixgbe_rx_bufsz(struct ixgbe_ring *ring)
 {
-	return test_bit(__IXGBE_RX_FCOE, &ring->state) ? 1 : 0;
+#ifdef IXGBE_FCOE
+	if (test_bit(__IXGBE_RX_FCOE, &ring->state))
+		return (PAGE_SIZE < 8192) ? IXGBE_RXBUFFER_4K :
+					    IXGBE_RXBUFFER_3K;
+#endif
+	return IXGBE_RXBUFFER_2K;
 }
-#else
-#define ixgbe_rx_pg_order(_ring) 0
+
+static inline unsigned int ixgbe_rx_pg_order(struct ixgbe_ring *ring)
+{
+#ifdef IXGBE_FCOE
+	if (test_bit(__IXGBE_RX_FCOE, &ring->state))
+		return (PAGE_SIZE < 8192) ? 1 : 0;
 #endif
+	return 0;
+}
 #define ixgbe_rx_pg_size(_ring) (PAGE_SIZE << ixgbe_rx_pg_order(_ring))
-#define ixgbe_rx_bufsz(_ring) ((PAGE_SIZE / 2) << ixgbe_rx_pg_order(_ring))
 
 struct ixgbe_ring_container {
 	struct ixgbe_ring *ring;	/* pointer to linked list of rings */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 6a8c484..9305e9a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1612,21 +1612,45 @@ static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
 {
 	struct page *page = rx_buffer->page;
 	unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
+#if (PAGE_SIZE < 8192)
 	unsigned int truesize = ixgbe_rx_bufsz(rx_ring);
+#else
+	unsigned int truesize = ALIGN(size, L1_CACHE_BYTES);
+	unsigned int last_offset = ixgbe_rx_pg_size(rx_ring) -
+				   ixgbe_rx_bufsz(rx_ring);
+#endif
 
 	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
 			rx_buffer->page_offset, size, truesize);
 
-	/* if we are only owner of page and it is local we can reuse it */
-	if (unlikely(page_count(page) != 1) ||
-	    unlikely(page_to_nid(page) != numa_node_id()))
+	/* avoid re-using remote pages */
+	if (unlikely(page_to_nid(page) != numa_node_id()))
+		return false;
+
+#if (PAGE_SIZE < 8192)
+	/* if we are only owner of page we can reuse it */
+	if (unlikely(page_count(page) != 1))
 		return false;
 
 	/* flip page offset to other buffer */
 	rx_buffer->page_offset ^= truesize;
 
+	/*
+	 * since we are the only owner of the page and we need to
+	 * increment it, just set the value to 2 in order to avoid
+	 * an unecessary locked operation
+	 */
+	atomic_set(&page->_count, 2);
+#else
+	/* move offset up to the next cache line */
+	rx_buffer->page_offset += truesize;
+
+	if (rx_buffer->page_offset > last_offset)
+		return false;
+
 	/* bump ref count on page before it is given to the stack */
 	get_page(page);
+#endif
 
 	return true;
 }
@@ -2863,11 +2887,7 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter,
 	srrctl = IXGBE_RX_HDR_SIZE << IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT;
 
 	/* configure the packet buffer length */
-#if PAGE_SIZE > IXGBE_MAX_RXBUFFER
-	srrctl |= IXGBE_MAX_RXBUFFER >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
-#else
 	srrctl |= ixgbe_rx_bufsz(rx_ring) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
-#endif
 
 	/* configure descriptor type */
 	srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
@@ -2975,13 +2995,7 @@ static void ixgbe_configure_rscctl(struct ixgbe_adapter *adapter,
 	 * total size of max desc * buf_len is not greater
 	 * than 65536
 	 */
-#if (PAGE_SIZE <= 8192)
 	rscctrl |= IXGBE_RSCCTL_MAXDESC_16;
-#elif (PAGE_SIZE <= 16384)
-	rscctrl |= IXGBE_RSCCTL_MAXDESC_8;
-#else
-	rscctrl |= IXGBE_RSCCTL_MAXDESC_4;
-#endif
 	IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(reg_idx), rscctrl);
 }
 
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 2/9] ixgbe: combine ixgbe_add_rx_frag and ixgbe_can_reuse_page
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This patch combines ixgbe_add_rx_frag and ixgbe_can_reuse_page into a
single function. The main motivation behind this is to make better use of
the values so that we don't have to load them from memory and into
registers twice.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 73 +++++++++++++--------------
 1 file changed, 34 insertions(+), 39 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index f7351c6..6a8c484 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1560,33 +1560,17 @@ static bool ixgbe_cleanup_headers(struct ixgbe_ring *rx_ring,
 }
 
 /**
- * ixgbe_can_reuse_page - determine if we can reuse a page
- * @rx_buffer: pointer to rx_buffer containing the page we want to reuse
- *
- * Returns true if page can be reused in another Rx buffer
- **/
-static inline bool ixgbe_can_reuse_page(struct ixgbe_rx_buffer *rx_buffer)
-{
-	struct page *page = rx_buffer->page;
-
-	/* if we are only owner of page and it is local we can reuse it */
-	return likely(page_count(page) == 1) &&
-	       likely(page_to_nid(page) == numa_node_id());
-}
-
-/**
  * ixgbe_reuse_rx_page - page flip buffer and store it back on the ring
  * @rx_ring: rx descriptor ring to store buffers on
  * @old_buff: donor buffer to have page reused
  *
- * Syncronizes page for reuse by the adapter
+ * Synchronizes page for reuse by the adapter
  **/
 static void ixgbe_reuse_rx_page(struct ixgbe_ring *rx_ring,
 				struct ixgbe_rx_buffer *old_buff)
 {
 	struct ixgbe_rx_buffer *new_buff;
 	u16 nta = rx_ring->next_to_alloc;
-	u16 bufsz = ixgbe_rx_bufsz(rx_ring);
 
 	new_buff = &rx_ring->rx_buffer_info[nta];
 
@@ -1597,17 +1581,13 @@ static void ixgbe_reuse_rx_page(struct ixgbe_ring *rx_ring,
 	/* transfer page from old buffer to new buffer */
 	new_buff->page = old_buff->page;
 	new_buff->dma = old_buff->dma;
-
-	/* flip page offset to other buffer and store to new_buff */
-	new_buff->page_offset = old_buff->page_offset ^ bufsz;
+	new_buff->page_offset = old_buff->page_offset;
 
 	/* sync the buffer for use by the device */
 	dma_sync_single_range_for_device(rx_ring->dev, new_buff->dma,
-					 new_buff->page_offset, bufsz,
+					 new_buff->page_offset,
+					 ixgbe_rx_bufsz(rx_ring),
 					 DMA_FROM_DEVICE);
-
-	/* bump ref count on page before it is given to the stack */
-	get_page(new_buff->page);
 }
 
 /**
@@ -1617,20 +1597,38 @@ static void ixgbe_reuse_rx_page(struct ixgbe_ring *rx_ring,
  * @rx_desc: descriptor containing length of buffer written by hardware
  * @skb: sk_buff to place the data into
  *
- * This function is based on skb_add_rx_frag.  I would have used that
- * function however it doesn't handle the truesize case correctly since we
- * are allocating more memory than might be used for a single receive.
+ * This function will add the data contained in rx_buffer->page to the skb.
+ * This is done either through a direct copy if the data in the buffer is
+ * less than the skb header size, otherwise it will just attach the page as
+ * a frag to the skb.
+ *
+ * The function will then update the page offset if necessary and return
+ * true if the buffer can be reused by the adapter.
  **/
-static void ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
+static bool ixgbe_add_rx_frag(struct ixgbe_ring *rx_ring,
 			      struct ixgbe_rx_buffer *rx_buffer,
-			      struct sk_buff *skb, int size)
+			      union ixgbe_adv_rx_desc *rx_desc,
+			      struct sk_buff *skb)
 {
-	skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
-			   rx_buffer->page, rx_buffer->page_offset,
-			   size);
-	skb->len += size;
-	skb->data_len += size;
-	skb->truesize += ixgbe_rx_bufsz(rx_ring);
+	struct page *page = rx_buffer->page;
+	unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
+	unsigned int truesize = ixgbe_rx_bufsz(rx_ring);
+
+	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+			rx_buffer->page_offset, size, truesize);
+
+	/* if we are only owner of page and it is local we can reuse it */
+	if (unlikely(page_count(page) != 1) ||
+	    unlikely(page_to_nid(page) != numa_node_id()))
+		return false;
+
+	/* flip page offset to other buffer */
+	rx_buffer->page_offset ^= truesize;
+
+	/* bump ref count on page before it is given to the stack */
+	get_page(page);
+
+	return true;
 }
 
 /**
@@ -1731,10 +1729,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 		}
 
 		/* pull page into skb */
-		ixgbe_add_rx_frag(rx_ring, rx_buffer, skb,
-				  le16_to_cpu(rx_desc->wb.upper.length));
-
-		if (ixgbe_can_reuse_page(rx_buffer)) {
+		if (ixgbe_add_rx_frag(rx_ring, rx_buffer, rx_desc, skb)) {
 			/* hand second half of page back to the ring */
 			ixgbe_reuse_rx_page(rx_ring, rx_buffer);
 		} else if (IXGBE_CB(skb)->dma == rx_buffer->dma) {
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 1/9] ixgbe: Remove code that was initializing Rx page offset
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Peter P Waskiewicz Jr
In-Reply-To: <1345157318-23731-1-git-send-email-peter.p.waskiewicz.jr@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This change reverts an earlier patch that introduced
ixgbe_init_rx_page_offset. The idea behind the function was to provide
some variation in the starting offset for the page in order to reduce
hot-spots in the cache. However it doesn't appear to provide any
significant benefit in the testing I have done. It has however been a
source of several bugs, and it blocks us from being able to use 2K
fragments on larger page sizes. So the decision I made was to remove it.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 27 +--------------------------
 1 file changed, 1 insertion(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 4326f74..f7351c6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1167,7 +1167,7 @@ static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,
 	}
 
 	bi->dma = dma;
-	bi->page_offset ^= ixgbe_rx_bufsz(rx_ring);
+	bi->page_offset = 0;
 
 	return true;
 }
@@ -4130,27 +4130,6 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
 }
 
 /**
- * ixgbe_init_rx_page_offset - initialize page offset values for Rx buffers
- * @rx_ring: ring to setup
- *
- * On many IA platforms the L1 cache has a critical stride of 4K, this
- * results in each receive buffer starting in the same cache set.  To help
- * reduce the pressure on this cache set we can interleave the offsets so
- * that only every other buffer will be in the same cache set.
- **/
-static void ixgbe_init_rx_page_offset(struct ixgbe_ring *rx_ring)
-{
-	struct ixgbe_rx_buffer *rx_buffer = rx_ring->rx_buffer_info;
-	u16 i;
-
-	for (i = 0; i < rx_ring->count; i += 2) {
-		rx_buffer[0].page_offset = 0;
-		rx_buffer[1].page_offset = ixgbe_rx_bufsz(rx_ring);
-		rx_buffer = &rx_buffer[2];
-	}
-}
-
-/**
  * ixgbe_clean_rx_ring - Free Rx Buffers per Queue
  * @rx_ring: ring to free buffers from
  **/
@@ -4195,8 +4174,6 @@ static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring)
 	size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
 	memset(rx_ring->rx_buffer_info, 0, size);
 
-	ixgbe_init_rx_page_offset(rx_ring);
-
 	/* Zero out the descriptor ring */
 	memset(rx_ring->desc, 0, rx_ring->size);
 
@@ -4646,8 +4623,6 @@ int ixgbe_setup_rx_resources(struct ixgbe_ring *rx_ring)
 	rx_ring->next_to_clean = 0;
 	rx_ring->next_to_use = 0;
 
-	ixgbe_init_rx_page_offset(rx_ring);
-
 	return 0;
 err:
 	vfree(rx_ring->rx_buffer_info);
-- 
1.7.11.2

^ permalink raw reply related

* [net-next 0/9][pull request] Intel Wired LAN Driver Updates
From: Peter P Waskiewicz Jr @ 2012-08-16 22:48 UTC (permalink / raw)
  To: davem; +Cc: Peter P Waskiewicz Jr, netdev, gospo, sassmann

This series contains multiple updates to the ixgbe driver.

The following are changes since commit 02644a17457414f38e29f32d5c640b06d08fa092:
    sctp: fix bogus if statement in sctp_auth_recv_cid()
  
and are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/ppwaskie/net-next master

Alexander Duyck (9):
  ixgbe: Remove code that was initializing Rx page offset
  ixgbe: combine ixgbe_add_rx_frag and ixgbe_can_reuse_page
  ixgbe: Only use double buffering if page size is less than 8K
  ixgbe: Have the CPU take ownership of the buffers sooner
  ixgbe: Make pull tail function separate from rest of cleanup_headers
  ixgbe: Copybreak sooner to avoid get_page/put_page and offset change
    overhead
  ixgbe: Make allocating skb and placing data in it a separate function
  ixgbe: Roll RSC code into non-EOP code
  ixgbe: Rewrite code related to configuring IFCS bit in Tx descriptor

 drivers/net/ethernet/intel/ixgbe/ixgbe.h      |  25 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 497 ++++++++++++++------------
 2 files changed, 284 insertions(+), 238 deletions(-)

-- 
1.7.11.2

^ permalink raw reply

* Re: [PATCH v0 0/5] cgroup: Assign subsystem IDs during compile time
From: John Fastabend @ 2012-08-16 22:37 UTC (permalink / raw)
  To: Daniel Wagner
  Cc: Neil Horman, netdev-u79uwXL29TY76Z2rM5mHXA,
	cgroups-u79uwXL29TY76Z2rM5mHXA, Daniel Wagner, David S. Miller,
	Andrew Morton, Eric Dumazet, Gao feng, Glauber Costa,
	Jamal Hadi Salim, Kamezawa Hiroyuki, Li Zefan, Tejun Heo
In-Reply-To: <502D5737.1010604-kQCPcA+X3s7YtjvyW6yDsg@public.gmane.org>

On 8/16/2012 1:25 PM, Daniel Wagner wrote:
> Hi Neil,
>
> On 08/16/2012 09:05 PM, Neil Horman wrote:
>>> Daniel Wagner (5):
>>>     cgroup: Use empty task_cls_classid() when !CONFIG_NET_CLS(_MODULE)
>>>     cgroup: Move sock_update_classid() decleration to cls_cgroup.h
>>>     cgroup: Protect access to task_cls_classid() when built as module
>>>     cgroup: Protect access to task_netprioidx() when built as module
>>>     cgroup: Assign subsystem IDs during compile time
>>
>> The series seems reasonable.  I presume you've testing building and running both
>> net_prio and net_cls as modules and monolithically?
>> Neil
>
> Yep, I spend a good bit of time rebuilding and testing all patches in
> the different configuration. I hope I really got the small semantic
> differences between net_cls and net_prio regarding the loading and
> unloading correct. So please have a close look at the jump label
> patches (#3 and #4).
>
> BTW, I have a few mores on top of these patches, e.g. merging the
> builtin and module version of task_cls_classid()/task_netprioidx()
> implementation together and getting rid of the many ifdefs in the
> header. But let's first get this part reviewed.
>
> thanks,
> daniel
>

Also I have another series for netprio against net-next to clean up
some of the locking as suggested by Al Viro. I'll wait to submit those
until after this series has been reviewed/applied.

In the meantime I'll apply these to my local tree and test these.

^ permalink raw reply

* RE: [PATCH] bnx2: turn off the network statck during initialization
From: Jiang Wang @ 2012-08-16 22:34 UTC (permalink / raw)
  To: Michael Chan
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	Chaitanya Lala, Francis St. Amant
In-Reply-To: <1345156059.6916.67.camel@LTIRV-MCHAN1.corp.ad.broadcom.com>

Got it. Thank you very much.

Regards,

Jiang

-------------------------------------
Jiang Wang
Member of Technical Staff
Riverbed Technology
Tel: (408) 522-5109
Email: Jiang.Wang@riverbed.com
www.riverbed.com


-----Original Message-----
From: Michael Chan [mailto:mchan@broadcom.com] 
Sent: Thursday, August 16, 2012 3:28 PM
To: Jiang Wang
Cc: netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Chaitanya Lala; Francis St. Amant
Subject: RE: [PATCH] bnx2: turn off the network statck during initialization

On Thu, 2012-08-16 at 21:48 +0000, Jiang Wang wrote:
> ---- I see. I was confused by the name of bnx2_set_power_state()  and 
> I think the PHY is actually powered up by bnx2_reset_nic, right?

bnx2_init_phy() in bnx2_init_nic() will bring up the PHY if it is down.

> 
> 

^ 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