* Re: [PATCH 1/7] netpoll: use GFP_ATOMIC in slave_enable_netpoll() and __netpoll_setup()
From: Eric Dumazet @ 2012-08-03 9:17 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, David S. Miller, Jay Vosburgh, Andy Gospodarek,
Eric Dumazet, Cong Wang, Joe Perches, Neil Horman, linux-kernel
In-Reply-To: <1343403484-29347-2-git-send-email-amwang@redhat.com>
On Fri, 2012-07-27 at 23:37 +0800, Cong Wang wrote:
> slave_enable_netpoll() and __netpoll_setup() may be called
> with read_lock() held, so should use GFP_ATOMIC to allocate
> memory.
>
> Cc: "David S. Miller" <davem@davemloft.net>
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> Signed-off-by: Cong Wang <amwang@redhat.com>
> ---
> drivers/net/bonding/bond_main.c | 2 +-
> net/core/netpoll.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 6fae5f3..ab773d4 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1235,7 +1235,7 @@ static inline int slave_enable_netpoll(struct slave *slave)
> struct netpoll *np;
> int err = 0;
>
> - np = kzalloc(sizeof(*np), GFP_KERNEL);
> + np = kzalloc(sizeof(*np), GFP_ATOMIC);
> err = -ENOMEM;
> if (!np)
> goto out;
> diff --git a/net/core/netpoll.c b/net/core/netpoll.c
> index b4c90e4..c78a966 100644
> --- a/net/core/netpoll.c
> +++ b/net/core/netpoll.c
> @@ -734,7 +734,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
> }
>
> if (!ndev->npinfo) {
> - npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
> + npinfo = kmalloc(sizeof(*npinfo), GFP_ATOMIC);
> if (!npinfo) {
> err = -ENOMEM;
> goto out;
Yes this works, but maybe you instead could pass/add a gfp_t flags
argument to __netpoll_setup() ?
Management tasks should allow GFP_KERNEL allocations to have less
failure risks.
Its sad bonding uses the rwlock here instead of a mutex
^ permalink raw reply
* Re: [PATCH] ipv4: remove parentheses in return statement
From: Eric Dumazet @ 2012-08-03 9:19 UTC (permalink / raw)
To: Jean Sacren; +Cc: netdev
In-Reply-To: <1343979790-17408-1-git-send-email-sakiwit@gmail.com>
On Fri, 2012-08-03 at 01:43 -0600, Jean Sacren wrote:
> @@ -106,8 +106,8 @@ static inline unsigned int inet_addr_hash(struct net *net, __be32 addr)
> {
> u32 val = (__force u32) addr ^ hash_ptr(net, 8);
>
> - return ((val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
> - (IN4_ADDR_HSIZE - 1));
> + return (val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
> + (IN4_ADDR_HSIZE - 1);
> }
BTW This should use a faster implementation, I'll send a patch when
net-next is opened.
^ permalink raw reply
* Re: [PATCH] ipv4: remove parentheses in return statement
From: David Miller @ 2012-08-03 9:22 UTC (permalink / raw)
To: eric.dumazet; +Cc: sakiwit, netdev
In-Reply-To: <1343985584.9299.873.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Fri, 03 Aug 2012 11:19:44 +0200
> On Fri, 2012-08-03 at 01:43 -0600, Jean Sacren wrote:
>
>> @@ -106,8 +106,8 @@ static inline unsigned int inet_addr_hash(struct net *net, __be32 addr)
>> {
>> u32 val = (__force u32) addr ^ hash_ptr(net, 8);
>>
>> - return ((val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
>> - (IN4_ADDR_HSIZE - 1));
>> + return (val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
>> + (IN4_ADDR_HSIZE - 1);
>> }
>
> BTW This should use a faster implementation, I'll send a patch when
> net-next is opened.
There seems to be a few spots where we want the pointer "as a 32-bit
integer" for hashing. We were discussing arp_hashfn() and ndisc_hashfn()
the other day.
It should basically do something like:
(u32) ((u64)ptr >> 32 | ((u32) ptr))
on 64-bit and simply (u32)(ptr) on 32-bit.
^ permalink raw reply
* [PATCH v2] ipv4/ipv6: multicast api unappropriate errno fix.
From: Li Wei @ 2012-08-03 9:29 UTC (permalink / raw)
To: davem; +Cc: Li Wei, netdev, dlstevens
In-Reply-To: <1343977605-14446-1-git-send-email-lw@cn.fujitsu.com>
commit 917f2f105([IPV4]: multicast API "join" issues) corrected
some errno values but also caused unappropriate errno returned.
With an unjoined group address, return -EADDRNOTAVAIL would be
much better than -EINVAL.
Also correct the errno when to join an source group which we have
already joined to -EADDRINUSE.
Signed-off-by: Li Wei <lw@cn.fujitsu.com>
--
V2: return -EADDRINUSE when join an already joined source group.
---
net/ipv4/igmp.c | 8 +++-----
net/ipv6/mcast.c | 12 ++++++------
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 6699f23..c45c092 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1933,10 +1933,8 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
(pmc->multi.imr_ifindex == imr.imr_ifindex))
break;
}
- if (!pmc) { /* must have a prior join */
- err = -EINVAL;
- goto done;
- }
+ if (!pmc) /* must have a prior join */
+ goto done; /* err = -EADDRNOTAVAIL */
/* if a source filter was set, must be the same mode as before */
if (pmc->sflist) {
if (pmc->sfmode != omode) {
@@ -2076,7 +2074,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
break;
}
if (!pmc) { /* must have a prior join */
- err = -EINVAL;
+ err = -EADDRNOTAVAIL;
goto done;
}
if (msf->imsf_numsrc) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 92f8e48..dcd12c0 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -347,10 +347,8 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
if (ipv6_addr_equal(&pmc->addr, group))
break;
}
- if (!pmc) { /* must have a prior join */
- err = -EINVAL;
- goto done;
- }
+ if (!pmc) /* must have a prior join */
+ goto done; /* err = -EADDRNOTAVAIL */
/* if a source filter was set, must be the same mode as before */
if (pmc->sflist) {
if (pmc->sfmode != omode) {
@@ -428,8 +426,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
if (rv == 0)
break;
}
- if (rv == 0) /* address already there is an error */
+ if (rv == 0) { /* address already there is an error */
+ err = -EADDRINUSE;
goto done;
+ }
for (j=psl->sl_count-1; j>=i; j--)
psl->sl_addr[j+1] = psl->sl_addr[j];
psl->sl_addr[i] = *source;
@@ -488,7 +488,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
break;
}
if (!pmc) { /* must have a prior join */
- err = -EINVAL;
+ err = -EADDRNOTAVAIL;
goto done;
}
if (gsf->gf_numsrc) {
--
1.7.10.1
^ permalink raw reply related
* Re: [PATCH] ipv4/ipv6: multicast api unappropriate errno fix.
From: Li Wei @ 2012-08-03 9:31 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <1343977605-14446-1-git-send-email-lw@cn.fujitsu.com>
Hi David,
I have sent a v2 of this patch, please consider to apply that one.
thanks
^ permalink raw reply
* Re: [PATCH 1/7] netpoll: use GFP_ATOMIC in slave_enable_netpoll() and __netpoll_setup()
From: Cong Wang @ 2012-08-03 9:34 UTC (permalink / raw)
To: Eric Dumazet
Cc: netdev, David S. Miller, Jay Vosburgh, Andy Gospodarek,
Eric Dumazet, Cong Wang, Joe Perches, Neil Horman, linux-kernel
In-Reply-To: <1343985428.9299.868.camel@edumazet-glaptop>
On Fri, 2012-08-03 at 11:17 +0200, Eric Dumazet wrote:
> On Fri, 2012-07-27 at 23:37 +0800, Cong Wang wrote:
> > slave_enable_netpoll() and __netpoll_setup() may be called
> > with read_lock() held, so should use GFP_ATOMIC to allocate
> > memory.
> >
> > Cc: "David S. Miller" <davem@davemloft.net>
> > Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> > Signed-off-by: Cong Wang <amwang@redhat.com>
> > ---
> > drivers/net/bonding/bond_main.c | 2 +-
> > net/core/netpoll.c | 2 +-
> > 2 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> > index 6fae5f3..ab773d4 100644
> > --- a/drivers/net/bonding/bond_main.c
> > +++ b/drivers/net/bonding/bond_main.c
> > @@ -1235,7 +1235,7 @@ static inline int slave_enable_netpoll(struct slave *slave)
> > struct netpoll *np;
> > int err = 0;
> >
> > - np = kzalloc(sizeof(*np), GFP_KERNEL);
> > + np = kzalloc(sizeof(*np), GFP_ATOMIC);
> > err = -ENOMEM;
> > if (!np)
> > goto out;
> > diff --git a/net/core/netpoll.c b/net/core/netpoll.c
> > index b4c90e4..c78a966 100644
> > --- a/net/core/netpoll.c
> > +++ b/net/core/netpoll.c
> > @@ -734,7 +734,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
> > }
> >
> > if (!ndev->npinfo) {
> > - npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
> > + npinfo = kmalloc(sizeof(*npinfo), GFP_ATOMIC);
> > if (!npinfo) {
> > err = -ENOMEM;
> > goto out;
>
> Yes this works, but maybe you instead could pass/add a gfp_t flags
> argument to __netpoll_setup() ?
>
> Management tasks should allow GFP_KERNEL allocations to have less
> failure risks.
>
> Its sad bonding uses the rwlock here instead of a mutex
>
Yup, that is a good idea. I will update this patch.
Thanks!
^ permalink raw reply
* Re: [PATCH] ipv4: remove parentheses in return statement
From: Eric Dumazet @ 2012-08-03 9:53 UTC (permalink / raw)
To: David Miller; +Cc: sakiwit, netdev
In-Reply-To: <20120803.022240.1997423719431165575.davem@davemloft.net>
On Fri, 2012-08-03 at 02:22 -0700, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Fri, 03 Aug 2012 11:19:44 +0200
>
> > On Fri, 2012-08-03 at 01:43 -0600, Jean Sacren wrote:
> >
> >> @@ -106,8 +106,8 @@ static inline unsigned int inet_addr_hash(struct net *net, __be32 addr)
> >> {
> >> u32 val = (__force u32) addr ^ hash_ptr(net, 8);
> >>
> >> - return ((val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
> >> - (IN4_ADDR_HSIZE - 1));
> >> + return (val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
> >> + (IN4_ADDR_HSIZE - 1);
> >> }
> >
> > BTW This should use a faster implementation, I'll send a patch when
> > net-next is opened.
>
> There seems to be a few spots where we want the pointer "as a 32-bit
> integer" for hashing. We were discussing arp_hashfn() and ndisc_hashfn()
> the other day.
>
> It should basically do something like:
>
> (u32) ((u64)ptr >> 32 | ((u32) ptr))
>
> on 64-bit and simply (u32)(ptr) on 32-bit.
We already have such thing in fact : net_hash_mix() which returns 0 if
NS are not configured.
(hash_ptr(net,8) is really overkill on 64bit arches)
High order bits on "struct net *" have absolutely no entropy, unless you
have a monster machine (more than 256 GB of ram)
This is the patch I prepared :
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 44bf82e..b9753ab 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -94,25 +94,22 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
[IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
};
-/* inet_addr_hash's shifting is dependent upon this IN4_ADDR_HSIZE
- * value. So if you change this define, make appropriate changes to
- * inet_addr_hash as well.
- */
-#define IN4_ADDR_HSIZE 256
+#define IN4_ADDR_HSIZE_SHIFT 8
+#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT)
+
static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
static DEFINE_SPINLOCK(inet_addr_hash_lock);
-static inline unsigned int inet_addr_hash(struct net *net, __be32 addr)
+static u32 inet_addr_hash(struct net *net, __be32 addr)
{
- u32 val = (__force u32) addr ^ hash_ptr(net, 8);
+ u32 val = (__force u32) addr ^ net_hash_mix(net);
- return ((val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
- (IN4_ADDR_HSIZE - 1));
+ return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
}
static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
{
- unsigned int hash = inet_addr_hash(net, ifa->ifa_local);
+ u32 hash = inet_addr_hash(net, ifa->ifa_local);
spin_lock(&inet_addr_hash_lock);
hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
@@ -136,18 +133,18 @@ static void inet_hash_remove(struct in_ifaddr *ifa)
*/
struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
{
- unsigned int hash = inet_addr_hash(net, addr);
+ u32 hash = inet_addr_hash(net, addr);
struct net_device *result = NULL;
struct in_ifaddr *ifa;
struct hlist_node *node;
rcu_read_lock();
hlist_for_each_entry_rcu(ifa, node, &inet_addr_lst[hash], hash) {
- struct net_device *dev = ifa->ifa_dev->dev;
-
- if (!net_eq(dev_net(dev), net))
- continue;
if (ifa->ifa_local == addr) {
+ struct net_device *dev = ifa->ifa_dev->dev;
+
+ if (!net_eq(dev_net(dev), net)
+ continue;
result = dev;
break;
}
^ permalink raw reply related
* Re: [PATCH 1/7] netpoll: use GFP_ATOMIC in slave_enable_netpoll() and __netpoll_setup()
From: Eric Dumazet @ 2012-08-03 10:10 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, David S. Miller, Jay Vosburgh, Andy Gospodarek,
Eric Dumazet, Cong Wang, Joe Perches, Neil Horman, linux-kernel
In-Reply-To: <1343986487.20871.2.camel@cr0>
On Fri, 2012-08-03 at 17:34 +0800, Cong Wang wrote:
> On Fri, 2012-08-03 at 11:17 +0200, Eric Dumazet wrote:
> > On Fri, 2012-07-27 at 23:37 +0800, Cong Wang wrote:
> > > slave_enable_netpoll() and __netpoll_setup() may be called
> > > with read_lock() held, so should use GFP_ATOMIC to allocate
> > > memory.
> > >
> > > Cc: "David S. Miller" <davem@davemloft.net>
> > > Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> > > Signed-off-by: Cong Wang <amwang@redhat.com>
> > > ---
> > > drivers/net/bonding/bond_main.c | 2 +-
> > > net/core/netpoll.c | 2 +-
> > > 2 files changed, 2 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> > > index 6fae5f3..ab773d4 100644
> > > --- a/drivers/net/bonding/bond_main.c
> > > +++ b/drivers/net/bonding/bond_main.c
> > > @@ -1235,7 +1235,7 @@ static inline int slave_enable_netpoll(struct slave *slave)
> > > struct netpoll *np;
> > > int err = 0;
> > >
> > > - np = kzalloc(sizeof(*np), GFP_KERNEL);
> > > + np = kzalloc(sizeof(*np), GFP_ATOMIC);
> > > err = -ENOMEM;
> > > if (!np)
> > > goto out;
> > > diff --git a/net/core/netpoll.c b/net/core/netpoll.c
> > > index b4c90e4..c78a966 100644
> > > --- a/net/core/netpoll.c
> > > +++ b/net/core/netpoll.c
> > > @@ -734,7 +734,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
> > > }
> > >
> > > if (!ndev->npinfo) {
> > > - npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
> > > + npinfo = kmalloc(sizeof(*npinfo), GFP_ATOMIC);
> > > if (!npinfo) {
> > > err = -ENOMEM;
> > > goto out;
> >
> > Yes this works, but maybe you instead could pass/add a gfp_t flags
> > argument to __netpoll_setup() ?
> >
> > Management tasks should allow GFP_KERNEL allocations to have less
> > failure risks.
> >
> > Its sad bonding uses the rwlock here instead of a mutex
> >
>
> Yup, that is a good idea. I will update this patch.
>
> Thanks!
>
I did this , just take it ;)
drivers/net/bonding/bond_main.c | 6 +++---
drivers/net/team/team.c | 14 +++++++-------
include/linux/netdevice.h | 2 +-
include/linux/netpoll.h | 2 +-
net/8021q/vlan_dev.c | 6 +++---
net/bridge/br_device.c | 10 +++++-----
net/bridge/br_if.c | 2 +-
net/bridge/br_private.h | 4 ++--
net/core/netpoll.c | 8 ++++----
9 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6fae5f3..ccff590 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1235,12 +1235,12 @@ static inline int slave_enable_netpoll(struct slave *slave)
struct netpoll *np;
int err = 0;
- np = kzalloc(sizeof(*np), GFP_KERNEL);
+ np = kzalloc(sizeof(*np), GFP_ATOMIC);
err = -ENOMEM;
if (!np)
goto out;
- err = __netpoll_setup(np, slave->dev);
+ err = __netpoll_setup(np, slave->dev, GFP_ATOMIC);
if (err) {
kfree(np);
goto out;
@@ -1292,7 +1292,7 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
read_unlock(&bond->lock);
}
-static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
+static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t flags)
{
struct bonding *bond = netdev_priv(dev);
struct slave *slave;
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 87707ab..3177d6b 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -795,16 +795,16 @@ static void team_port_leave(struct team *team, struct team_port *port)
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port, gfp_t flags)
{
struct netpoll *np;
int err;
- np = kzalloc(sizeof(*np), GFP_KERNEL);
+ np = kzalloc(sizeof(*np), flags);
if (!np)
return -ENOMEM;
- err = __netpoll_setup(np, port->dev);
+ err = __netpoll_setup(np, port->dev, flags);
if (err) {
kfree(np);
return err;
@@ -833,7 +833,7 @@ static struct netpoll_info *team_netpoll_info(struct team *team)
}
#else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port, gfp_t flags)
{
return 0;
}
@@ -913,7 +913,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
}
if (team_netpoll_info(team)) {
- err = team_port_enable_netpoll(team, port);
+ err = team_port_enable_netpoll(team, port, GFP_KERNEL);
if (err) {
netdev_err(dev, "Failed to enable netpoll on device %s\n",
portname);
@@ -1443,7 +1443,7 @@ static void team_netpoll_cleanup(struct net_device *dev)
}
static int team_netpoll_setup(struct net_device *dev,
- struct netpoll_info *npifo)
+ struct netpoll_info *npifo, gfp_t flags)
{
struct team *team = netdev_priv(dev);
struct team_port *port;
@@ -1451,7 +1451,7 @@ static int team_netpoll_setup(struct net_device *dev,
mutex_lock(&team->lock);
list_for_each_entry(port, &team->port_list, list) {
- err = team_port_enable_netpoll(team, port);
+ err = team_port_enable_netpoll(team, port, flags);
if (err) {
__team_netpoll_cleanup(team);
break;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a9db4f3..2ad76e3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -953,7 +953,7 @@ struct net_device_ops {
#ifdef CONFIG_NET_POLL_CONTROLLER
void (*ndo_poll_controller)(struct net_device *dev);
int (*ndo_netpoll_setup)(struct net_device *dev,
- struct netpoll_info *info);
+ struct netpoll_info *info, gfp_t flags);
void (*ndo_netpoll_cleanup)(struct net_device *dev);
#endif
int (*ndo_set_vf_mac)(struct net_device *dev,
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 28f5389..d67d4be3 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -43,7 +43,7 @@ struct netpoll_info {
void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
void netpoll_print_options(struct netpoll *np);
int netpoll_parse_options(struct netpoll *np, char *opt);
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev);
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t flags);
int netpoll_setup(struct netpoll *np);
int netpoll_trap(void);
void netpoll_set_trap(int trap);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 73a2a83..4ca0b39 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -669,19 +669,19 @@ static void vlan_dev_poll_controller(struct net_device *dev)
return;
}
-static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)
+static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo, gfp_t flags)
{
struct vlan_dev_priv *info = vlan_dev_priv(dev);
struct net_device *real_dev = info->real_dev;
struct netpoll *netpoll;
int err = 0;
- netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
+ netpoll = kzalloc(sizeof(*netpoll), flags);
err = -ENOMEM;
if (!netpoll)
goto out;
- err = __netpoll_setup(netpoll, real_dev);
+ err = __netpoll_setup(netpoll, real_dev, flags);
if (err) {
kfree(netpoll);
goto out;
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 3334845..efcd36c 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -213,7 +213,7 @@ static void br_netpoll_cleanup(struct net_device *dev)
}
}
-static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
+static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t flags)
{
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p, *n;
@@ -223,7 +223,7 @@ static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
if (!p->dev)
continue;
- err = br_netpoll_enable(p);
+ err = br_netpoll_enable(p, flags);
if (err)
goto fail;
}
@@ -236,17 +236,17 @@ fail:
goto out;
}
-int br_netpoll_enable(struct net_bridge_port *p)
+int br_netpoll_enable(struct net_bridge_port *p, gfp_t flags)
{
struct netpoll *np;
int err = 0;
- np = kzalloc(sizeof(*p->np), GFP_KERNEL);
+ np = kzalloc(sizeof(*p->np), flags);
err = -ENOMEM;
if (!np)
goto out;
- err = __netpoll_setup(np, p->dev);
+ err = __netpoll_setup(np, p->dev, flags);
if (err) {
kfree(np);
goto out;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index e1144e1..171fd6b 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -361,7 +361,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
if (err)
goto err2;
- if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
+ if (br_netpoll_info(br) && ((err = br_netpoll_enable(p, GFP_KERNEL))))
goto err3;
err = netdev_set_master(dev, br->dev);
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index a768b24..bfdb5ab 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -316,7 +316,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
netpoll_send_skb(np, skb);
}
-extern int br_netpoll_enable(struct net_bridge_port *p);
+extern int br_netpoll_enable(struct net_bridge_port *p, gfp_t flags);
extern void br_netpoll_disable(struct net_bridge_port *p);
#else
static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
@@ -329,7 +329,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
{
}
-static inline int br_netpoll_enable(struct net_bridge_port *p)
+static inline int br_netpoll_enable(struct net_bridge_port *p, gfp_t flags)
{
return 0;
}
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index b4c90e4..37cc854 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -715,7 +715,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
}
EXPORT_SYMBOL(netpoll_parse_options);
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
{
struct netpoll_info *npinfo;
const struct net_device_ops *ops;
@@ -734,7 +734,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
}
if (!ndev->npinfo) {
- npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
+ npinfo = kmalloc(sizeof(*npinfo), gfp);
if (!npinfo) {
err = -ENOMEM;
goto out;
@@ -752,7 +752,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
ops = np->dev->netdev_ops;
if (ops->ndo_netpoll_setup) {
- err = ops->ndo_netpoll_setup(ndev, npinfo);
+ err = ops->ndo_netpoll_setup(ndev, npinfo, gfp);
if (err)
goto free_npinfo;
}
@@ -857,7 +857,7 @@ int netpoll_setup(struct netpoll *np)
refill_skbs();
rtnl_lock();
- err = __netpoll_setup(np, ndev);
+ err = __netpoll_setup(np, ndev, GFP_KERNEL);
rtnl_unlock();
if (err)
^ permalink raw reply related
* [PATCH V1 3/3] net/mlx4_core: Remove port type restrictions
From: Yevgeny Petrilin @ 2012-08-03 10:38 UTC (permalink / raw)
To: davem; +Cc: netdev, Yevgeny Petrilin
In-Reply-To: <1343990318-10744-1-git-send-email-yevgenyp@mellanox.co.il>
Port1=Eth, Port2=IB restriction is no longer required.
Having RoCE, there will always rdma port initialized over ConnectX
physical port, no matter whether the link layer is IB or Ethernet.
So we always have dual port IB device.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/net/ethernet/mellanox/mlx4/main.c | 3 ---
drivers/net/ethernet/mellanox/mlx4/sense.c | 14 --------------
2 files changed, 0 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 48d0e90..827b72d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -157,9 +157,6 @@ int mlx4_check_port_params(struct mlx4_dev *dev,
"on this HCA, aborting.\n");
return -EINVAL;
}
- if (port_type[i] == MLX4_PORT_TYPE_ETH &&
- port_type[i + 1] == MLX4_PORT_TYPE_IB)
- return -EINVAL;
}
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/sense.c b/drivers/net/ethernet/mellanox/mlx4/sense.c
index 8024982..34ee09b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/sense.c
+++ b/drivers/net/ethernet/mellanox/mlx4/sense.c
@@ -81,20 +81,6 @@ void mlx4_do_sense_ports(struct mlx4_dev *dev,
}
/*
- * Adjust port configuration:
- * If port 1 sensed nothing and port 2 is IB, set both as IB
- * If port 2 sensed nothing and port 1 is Eth, set both as Eth
- */
- if (stype[0] == MLX4_PORT_TYPE_ETH) {
- for (i = 1; i < dev->caps.num_ports; i++)
- stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_ETH;
- }
- if (stype[dev->caps.num_ports - 1] == MLX4_PORT_TYPE_IB) {
- for (i = 0; i < dev->caps.num_ports - 1; i++)
- stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_IB;
- }
-
- /*
* If sensed nothing, remain in current configuration.
*/
for (i = 0; i < dev->caps.num_ports; i++)
--
1.7.7
^ permalink raw reply related
* [PATCH V1 1/3] net/mlx4_en: loopbacked packets are dropped when SMAC=DMAC
From: Yevgeny Petrilin @ 2012-08-03 10:38 UTC (permalink / raw)
To: davem; +Cc: netdev, Amir Vadai
In-Reply-To: <1343990318-10744-1-git-send-email-yevgenyp@mellanox.co.il>
From: Amir Vadai <amirv@mellanox.com>
Should NOT check SMAC=DMAC when:
1. loopback is turned on
2. validate_loopback is true.
Fixed it accordingly.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index f32e703..5aba5ec 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -614,8 +614,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
/* If source MAC is equal to our own MAC and not performing
* the selftest or flb disabled - drop the packet */
if (s_mac == priv->mac &&
- (!(dev->features & NETIF_F_LOOPBACK) ||
- !priv->validate_loopback))
+ !((dev->features & NETIF_F_LOOPBACK) ||
+ priv->validate_loopback))
goto next;
/*
--
1.7.7
^ permalink raw reply related
* [PATCH V1 2/3] net/mlx4_en: Fixing TX queue stop/wake flow
From: Yevgeny Petrilin @ 2012-08-03 10:38 UTC (permalink / raw)
To: davem; +Cc: netdev, Yevgeny Petrilin
In-Reply-To: <1343990318-10744-1-git-send-email-yevgenyp@mellanox.co.il>
Removing the ring->blocked flag, it is redundant and leads to a race:
We close the TX queue and then set the "blocked" flag.
Between those 2 operations the completion function can check the "blocked"
flag, sees that it is 0, and wouldn't open the TX queue.
Using netif_tx_queue_stopped to check the state of the queue to avoid this race.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/net/ethernet/mellanox/mlx4/en_tx.c | 17 +++++++----------
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 -
2 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 019d856..10bba09 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -164,7 +164,6 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
ring->cons = 0xffffffff;
ring->last_nr_txbb = 1;
ring->poll_cnt = 0;
- ring->blocked = 0;
memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info));
memset(ring->buf, 0, ring->buf_size);
@@ -365,14 +364,13 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
ring->cons += txbbs_skipped;
netdev_tx_completed_queue(ring->tx_queue, packets, bytes);
- /* Wakeup Tx queue if this ring stopped it */
- if (unlikely(ring->blocked)) {
- if ((u32) (ring->prod - ring->cons) <=
- ring->size - HEADROOM - MAX_DESC_TXBBS) {
- ring->blocked = 0;
- netif_tx_wake_queue(ring->tx_queue);
- priv->port_stats.wake_queue++;
- }
+ /*
+ * Wakeup Tx queue if this stopped, and at least 1 packet
+ * was completed
+ */
+ if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) {
+ netif_tx_wake_queue(ring->tx_queue);
+ priv->port_stats.wake_queue++;
}
}
@@ -592,7 +590,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
ring->size - HEADROOM - MAX_DESC_TXBBS)) {
/* every full Tx ring stops queue */
netif_tx_stop_queue(ring->tx_queue);
- ring->blocked = 1;
priv->port_stats.queue_stopped++;
return NETDEV_TX_BUSY;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 5f1ab10..9d27e42 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -248,7 +248,6 @@ struct mlx4_en_tx_ring {
u32 doorbell_qpn;
void *buf;
u16 poll_cnt;
- int blocked;
struct mlx4_en_tx_info *tx_info;
u8 *bounce_buf;
u32 last_nr_txbb;
--
1.7.7
^ permalink raw reply related
* [PATCH V1 0/4] net/mlx4: Fixes to mlx4 driver
From: Yevgeny Petrilin @ 2012-08-03 10:38 UTC (permalink / raw)
To: davem; +Cc: netdev, Yevgeny Petrilin
Hello Dave,
This is a patchset of 3 fixes and additional change that removes
a port Link layer type restriction that is no longer relevant.
Thanks,
Yevgeny
---
Diff from V0:
-Removed the NETIF_F_GRO patch
Yevgeny Petrilin (2):
net/mlx4_en: Fixing TX queue stop/wake flow
net/mlx4_core: Remove port type restrictions
Amir Vadai (1):
net/mlx4_en: loopbacked packets are dropped when SMAC=DMAC
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 4 ++--
drivers/net/ethernet/mellanox/mlx4/en_tx.c | 17 +++++++----------
drivers/net/ethernet/mellanox/mlx4/main.c | 3 ---
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 -
drivers/net/ethernet/mellanox/mlx4/sense.c | 14 --------------
5 files changed, 9 insertions(+), 30 deletions(-)
^ permalink raw reply
* Re: [PATCH V1 0/4] net/mlx4: Fixes to mlx4 driver
From: David Miller @ 2012-08-03 10:56 UTC (permalink / raw)
To: yevgenyp; +Cc: netdev
In-Reply-To: <1343990318-10744-1-git-send-email-yevgenyp@mellanox.co.il>
"0/4" eh?
^ permalink raw reply
* [PATCH net] net_sched: gact: Fix potential panic in tcf_gact().
From: Hiroaki SHIMODA @ 2012-08-03 10:57 UTC (permalink / raw)
To: davem; +Cc: netdev
gact_rand array is accessed by gact->tcfg_ptype whose value
is assumed to less than MAX_RAND, but any range checks are
not performed.
So add a check in tcf_gact_init(). And in tcf_gact(), we can
reduce a branch.
Signed-off-by: Hiroaki SHIMODA <shimoda.hiroaki@gmail.com>
---
net/sched/act_gact.c | 14 +++++++++++---
1 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index f10fb82..05d60859 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -67,6 +67,9 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
struct tcf_common *pc;
int ret = 0;
int err;
+#ifdef CONFIG_GACT_PROB
+ struct tc_gact_p *p_parm = NULL;
+#endif
if (nla == NULL)
return -EINVAL;
@@ -82,6 +85,12 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
#ifndef CONFIG_GACT_PROB
if (tb[TCA_GACT_PROB] != NULL)
return -EOPNOTSUPP;
+#else
+ if (tb[TCA_GACT_PROB]) {
+ p_parm = nla_data(tb[TCA_GACT_PROB]);
+ if (p_parm->ptype >= MAX_RAND)
+ return -EINVAL;
+ }
#endif
pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info);
@@ -103,8 +112,7 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
spin_lock_bh(&gact->tcf_lock);
gact->tcf_action = parm->action;
#ifdef CONFIG_GACT_PROB
- if (tb[TCA_GACT_PROB] != NULL) {
- struct tc_gact_p *p_parm = nla_data(tb[TCA_GACT_PROB]);
+ if (p_parm) {
gact->tcfg_paction = p_parm->paction;
gact->tcfg_pval = p_parm->pval;
gact->tcfg_ptype = p_parm->ptype;
@@ -133,7 +141,7 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a,
spin_lock(&gact->tcf_lock);
#ifdef CONFIG_GACT_PROB
- if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL)
+ if (gact->tcfg_ptype)
action = gact_rand[gact->tcfg_ptype](gact);
else
action = gact->tcf_action;
--
1.7.8.6
^ permalink raw reply related
* Re: [PATCH v2] ipv4/ipv6: multicast api unappropriate errno fix.
From: David Stevens @ 2012-08-03 12:09 UTC (permalink / raw)
To: Li Wei; +Cc: davem, Li Wei, netdev, netdev-owner
In-Reply-To: <501B99E1.9090803@cn.fujitsu.com>
netdev-owner@vger.kernel.org wrote on 08/03/2012 05:29:05 AM:
> @@ -1933,10 +1933,8 @@ int ip_mc_source(int add, int omode, struct
> sock *sk, struct
> (pmc->multi.imr_ifindex == imr.imr_ifindex))
> break;
> }
> - if (!pmc) { /* must have a prior join */
> - err = -EINVAL;
> - goto done;
> - }
> + if (!pmc) /* must have a prior join */
> + goto done; /* err = -EADDRNOTAVAIL */
RFC3678, section 4.1.3:
"When the option itself is not legal on the group (i.e., when
trying a
Source-Specific option on a group after doing IP_ADD_MEMBERSHIP, or
when trying an Any-Source option without doing IP_ADD_MEMBERSHIP) the
error generated is EINVAL."
> }
> - if (rv == 0) /* address already there is an error */
> + if (rv == 0) { /* address already there is an error */
> + err = -EADDRINUSE;
> goto done;
> + }
EADDRINUSE is not one of the API's listed error codes. Section 4.1.3
of RFC3678 specifies:
"When the option would be legal on the group, but an address is
invalid (e.g., when trying to block a source that is already blocked
by the socket, or when trying to drop an unjoined group) the error
generated is EADDRNOTAVAIL."
At least some of this patch directly differs with RFC3678.
+-DLS
^ permalink raw reply
* [PATCH] emulex: benet: Add a missing CR in the end of message
From: Masanari Iida @ 2012-08-03 12:36 UTC (permalink / raw)
To: linux-kernel, netdev, sathya.perla, subbu.seetharaman,
ajit.khaparde
Cc: Masanari Iida
Missing a CR in printk causes 2 messages printed in one line.
Signed-off-by: Masanari Iida <standby24x7@gmail.com>
---
drivers/net/ethernet/emulex/benet/be_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 896f283..82031d3 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1916,7 +1916,7 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
if (adapter->num_rx_qs != MAX_RX_QS)
dev_info(&adapter->pdev->dev,
- "Created only %d receive queues", adapter->num_rx_qs);
+ "Created only %d receive queues\n", adapter->num_rx_qs);
return 0;
}
--
1.7.12.rc1
^ permalink raw reply related
* Re: Premature timeout for MLDv1 Host compatibility mode?
From: David Stevens @ 2012-08-03 13:00 UTC (permalink / raw)
To: Dragos Ilie; +Cc: netdev, netdev-owner
In-Reply-To: <CAOLNa-e0DB7Vhvv8tcSdW_JSWavpmyNt0vFYHLymh_zDaqUiMw@mail.gmail.com>
Dragos Ilie <dragos.ilie@gmail.com> wrote on 08/03/2012 04:54:09 AM:
> a) Section 5.1.9 states that the QQIC field is meant for other
> multicast routers that are not the current querier. I "grep-ed" after
> mld2q_qqic in the entire kernel source tree and it is not being used
> at all. I take this as a sign that the field is not to be interpreted
> by listeners. Of course, that does not mean we cannot use it, but see
> b) below
The kernel doesn't use it because it doesn't use the QI in the
timer to switch back to MLDv2 -- the problem you're trying to address.
If you think that's a bug (and I agree it is), the QQIC is how we
determine the QI. Missing functionality isn't evidence we shouldn't
use the QQIC. :-)
> b) Section 8.3.1 says that "if an MLDv1 router is present on the link,
> the Querier MUST use the lowest version of MLD present on the
> network". Also, "if an MLDv1 router is present on the link, the system
> administrator must explicitly configure all MLDv2 routers to act in
> MLDv1 mode". It seems to me that these statements together preclude a
> scenario with MLDv1 and MLDv2 routers mixed together on the same link,
> unless all routers speak MLDv1.
MLDv2 requires MLDv1 compatibility mode so there's no such thing
as an MLDv2 implementation that doesn't support MLDv1. The mechanism
for falling back to MLDv1 is required for exactly the case when there
is a mix of versions on the link; if that could never happen, none
of this code would be necessary or required by RFC.
> The current implementation for MLDv1 compatibility mode works very
> badly. The listeners fail most of the time to join the groups on the
> MLDv1 server.
I'm not sure what you mean here. Certainly you can, as suggested
above, force all hosts on the subnet to use MLDv1 using the
"force_mld_version" sysctl and an MLDv1 querier will also do that.
They'll switch back to MLDv2 too soon, if the v1 queries happen
infrequently which you can trivially work around by querying more
often.
>I suggest that my patch sent earlier this week is
> pushed upstream, unless there are concerns that it will make things
> worse than they are today. This will improve the behavior of MLDv2
> listeners with MLDv1 routers and keep us compliant with the RFC. What
> do you think?
I think it should be correct, and a fixed QI isn't. If we're going to
do a hack, I think a v2-based QI is better than a fixed value.
However, I was thinking we could directly
measure the v1 QI based on received v1 queries. The main problem with
that is you don't know if you lost one or not, but we could work
around that by using the min of a saved QI and the measured interval
since the last query from the same source. The measured QI with losses
is always a multiple of the actual QI.
So, when we get a v1 query, save a timestamp of it and use the timestamp,
if set, to compute the interval since the last query. If the interval
is less than our current QI, it's the new QI. For the switchback time,
we use QI if set and 125 if not, where not being set would indicate
we haven't gotten more than 2 v1 queries.
Finally, periodically (e.g., based on query counts, or multiple
larger QIs) reset in case an admin has increased the QI without a
reboot.
The QI value only matters if it's the same querier, so also
with the timestamp save the source querier IP address and reset
if you get a general query from a different querier.
+-DLS
^ permalink raw reply
* Re: [PATCH] mlx4_en: add UFO support
From: Thadeu Lima de Souza Cascardo @ 2012-08-03 13:34 UTC (permalink / raw)
To: Yevgeny Petrilin; +Cc: David S. Miller, netdev@vger.kernel.org, Or Gerlitz
In-Reply-To: <953B660C027164448AE903364AC447D2871F0CCC@MTLDAG01.mtl.com>
On Fri, Aug 03, 2012 at 08:29:26AM +0000, Yevgeny Petrilin wrote:
> >
> > Mellanox Ethernet adapters support Large Segmentation Offload for UDP
> > packets. The only change needed is using the proper header size when the
> > packet is UDP instead of TCP.
> >
> > This significantly increases performance for large UDP packets on platforms
> > which have an expensive dma_map call, like pseries.
> >
> > On a simple test with 64000 payload size, throughput has increased from
> > about 6Gbps to 9.5Gbps, while CPU use dropped from about 600% to about
> > 80% or less, on a 8-core Power7 machine.
> >
> Hi Thadeu,
> Can you please send the info regarding the adapter you are testing with? What test are you running?
> I just tried this patch with netperf on my x86_64, and it doesn't work. Packets are not fragmented properly (fragment offsets are not calculated).
> It is true that the TX side doesn't work as hard (OS doesn't need to do the fragmentation), but traffic is not sent properly on the wire.
>
> I'll do further investigation and get back with more details.
>
> Yevgeny
>
Hi, Yevgeny.
At first, I only added the UFO feature. When testing that, I got lots of
errors on the receiving end, like:
UDP: short packet: From 10.0.0.2:0 0/1480 to 10.0.0.3:0
After finding out what the driver was writing to the LSO descriptor, it
was obvious why this happened. The driver was using as the header size
the TCP header size, which would use a value from the UDP packet
payload.
After the other change, however, everything should work fine. I ran a
uperf test with 64000-sized payload packets and everything seemed to
work fine.
The card I have in here is:
0001:01:00.0 Ethernet controller: Mellanox Technologies MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] (rev b0)
Subsystem: Mellanox Technologies Device 0016
Flags: bus master, fast devsel, latency 0, IRQ 17
Memory at 3da0fbe00000 (64-bit, non-prefetchable) [size=1M]
Memory at 3da0fc000000 (64-bit, prefetchable) [size=32M]
Expansion ROM at 3da0fbf00000 [disabled] [size=1M]
Capabilities: [40] Power Management version 3
Capabilities: [48] Vital Product Data
Capabilities: [9c] MSI-X: Enable+ Count=128 Masked-
Capabilities: [60] Express Endpoint, MSI 00
Capabilities: [100] Alternative Routing-ID Interpretation (ARI)
Capabilities: [148] Device Serial Number 00-02-c9-03-00-4b-97-c4
Kernel driver in use: mlx4_core
Kernel modules: mlx4_core
I will try some other tests in here and report my results.
Regards.
Cascardo.
^ permalink raw reply
* Re: [PATCH] mlx4_en: add UFO support
From: Thadeu Lima de Souza Cascardo @ 2012-08-03 13:54 UTC (permalink / raw)
To: Yevgeny Petrilin; +Cc: David S. Miller, netdev@vger.kernel.org, Or Gerlitz
In-Reply-To: <953B660C027164448AE903364AC447D2871F0CCC@MTLDAG01.mtl.com>
On Fri, Aug 03, 2012 at 08:29:26AM +0000, Yevgeny Petrilin wrote:
> >
> > Mellanox Ethernet adapters support Large Segmentation Offload for UDP
> > packets. The only change needed is using the proper header size when the
> > packet is UDP instead of TCP.
> >
> > This significantly increases performance for large UDP packets on platforms
> > which have an expensive dma_map call, like pseries.
> >
> > On a simple test with 64000 payload size, throughput has increased from
> > about 6Gbps to 9.5Gbps, while CPU use dropped from about 600% to about
> > 80% or less, on a 8-core Power7 machine.
> >
> Hi Thadeu,
> Can you please send the info regarding the adapter you are testing with? What test are you running?
> I just tried this patch with netperf on my x86_64, and it doesn't work. Packets are not fragmented properly (fragment offsets are not calculated).
> It is true that the TX side doesn't work as hard (OS doesn't need to do the fragmentation), but traffic is not sent properly on the wire.
>
> I'll do further investigation and get back with more details.
>
> Yevgeny
>
Hi, Yevgeny.
You are right. After generating a dump on the receiving end, and sending
a single large packet, I did notice that fragment offsets were all 0,
more fragments flag is not set and id is incremented.
Does the hardware really support UFO as documented? Should we just write
the IP header to the descriptor? I will try this and report my results.
Meanwhile, can you find out what is needed to get this working?
Thanks a lot.
Cascardo.
^ permalink raw reply
* [RFC v2 0/7] generic hashtable implementation
From: Sasha Levin @ 2012-08-03 14:23 UTC (permalink / raw)
To: torvalds
Cc: tj, akpm, linux-kernel, linux-mm, paul.gortmaker, davem, rostedt,
mingo, ebiederm, aarcange, ericvh, netdev, Sasha Levin
There are quite a few places in the kernel which implement a hashtable
in a very similar way. Instead of having implementations of a hashtable
all over the kernel, we can re-use the code.
This patch series introduces a very simple hashtable implementation, and
modifies three (random) modules to use it. I've limited it to 3 only
so that it would be easy to review and modify, and to show that even
at this number we already eliminate a big amount of duplicated code.
If this basic hashtable looks ok, future code will include:
- RCU support
- Self locking (list_bl?)
- Converting more code to use the hashtable
Changes in V2:
- Address review comments by Tejun Heo, Josh Triplett and Eric Beiderman (Thanks all!).
- Rebase on top of latest master.
- Convert more places to use the hashtable. Hopefully it will trigger more reviews by
touching more subsystems.
Sasha Levin (7):
hashtable: introduce a small and naive hashtable
user_ns: use new hashtable implementation
mm,ksm: use new hashtable implementation
workqueue: use new hashtable implementation
mm/huge_memory: use new hashtable implementation
tracepoint: use new hashtable implementation
net,9p: use new hashtable implementation
include/linux/hashtable.h | 75 ++++++++++++++++++++++++++++++++++++
kernel/tracepoint.c | 26 ++++--------
kernel/user.c | 53 +++++++++-----------------
kernel/workqueue.c | 93 +++++++--------------------------------------
mm/huge_memory.c | 56 +++++----------------------
mm/ksm.c | 29 ++++----------
net/9p/error.c | 17 ++++----
7 files changed, 144 insertions(+), 205 deletions(-)
create mode 100644 include/linux/hashtable.h
--
1.7.8.6
--
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
* [RFC v2 1/7] hashtable: introduce a small and naive hashtable
From: Sasha Levin @ 2012-08-03 14:23 UTC (permalink / raw)
To: torvalds
Cc: tj, akpm, linux-kernel, linux-mm, paul.gortmaker, davem, rostedt,
mingo, ebiederm, aarcange, ericvh, netdev, Sasha Levin
In-Reply-To: <1344003788-1417-1-git-send-email-levinsasha928@gmail.com>
This hashtable implementation is using hlist buckets to provide a simple
hashtable to prevent it from getting reimplemented all over the kernel.
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
include/linux/hashtable.h | 75 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 75 insertions(+), 0 deletions(-)
create mode 100644 include/linux/hashtable.h
diff --git a/include/linux/hashtable.h b/include/linux/hashtable.h
new file mode 100644
index 0000000..b004cf7
--- /dev/null
+++ b/include/linux/hashtable.h
@@ -0,0 +1,75 @@
+#ifndef _LINUX_HASHTABLE_H
+#define _LINUX_HASHTABLE_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/hash.h>
+
+struct hash_table {
+ size_t bits;
+ struct hlist_head buckets[];
+};
+
+#define DEFINE_STATIC_HASHTABLE(n, b) \
+ static struct hash_table n = { .bits = (b), \
+ .buckets = { [0 ... ((1 << (b)) - 1)] = HLIST_HEAD_INIT } }
+
+#define DEFINE_HASHTABLE(n, b) \
+ union { \
+ struct hash_table n; \
+ struct { \
+ size_t bits; \
+ struct hlist_head buckets[1 << (b)]; \
+ } __##n ; \
+ };
+
+#define HASH_BITS(name) ((name)->bits)
+#define HASH_SIZE(name) (1 << (HASH_BITS(name)))
+
+__attribute__ ((unused))
+static void hash_init(struct hash_table *ht, size_t bits)
+{
+ size_t i;
+
+ ht->bits = bits;
+ for (i = 0; i < (1 << bits); i++)
+ INIT_HLIST_HEAD(&ht->buckets[i]);
+}
+
+static void hash_add(struct hash_table *ht, struct hlist_node *node, long key)
+{
+ hlist_add_head(node,
+ &ht->buckets[hash_long((unsigned long)key, HASH_BITS(ht))]);
+}
+
+
+#define hash_get(name, key, type, member, cmp_fn) \
+({ \
+ struct hlist_node *__node; \
+ typeof(key) __key = key; \
+ type *__obj = NULL; \
+ hlist_for_each_entry(__obj, __node, &(name)->buckets[ \
+ hash_long((unsigned long) __key, \
+ HASH_BITS(name))], member) \
+ if (cmp_fn(__obj, __key)) \
+ break; \
+ __obj; \
+})
+
+__attribute__ ((unused))
+static void hash_del(struct hlist_node *node)
+{
+ hlist_del_init(node);
+}
+
+#define hash_for_each(bkt, node, name, obj, member) \
+ for (bkt = 0; bkt < HASH_SIZE(name); bkt++) \
+ hlist_for_each_entry(obj, node, &(name)->buckets[i], member)
+
+#define hash_for_each_possible(name, node, obj, member, key) \
+ hlist_for_each_entry(obj, node, \
+ &(name)->buckets[hash_long((unsigned long) key, \
+ HASH_BITS(name))], member)
+
+#endif
--
1.7.8.6
--
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 related
* [RFC v2 2/7] user_ns: use new hashtable implementation
From: Sasha Levin @ 2012-08-03 14:23 UTC (permalink / raw)
To: torvalds
Cc: tj, akpm, linux-kernel, linux-mm, paul.gortmaker, davem, rostedt,
mingo, ebiederm, aarcange, ericvh, netdev, Sasha Levin
In-Reply-To: <1344003788-1417-1-git-send-email-levinsasha928@gmail.com>
Switch user_ns to use the new hashtable implementation. This reduces the amount of
generic unrelated code in user_ns.
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
kernel/user.c | 53 ++++++++++++++++++-----------------------------------
1 files changed, 18 insertions(+), 35 deletions(-)
diff --git a/kernel/user.c b/kernel/user.c
index b815fef..555c71a 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/export.h>
#include <linux/user_namespace.h>
+#include <linux/hashtable.h>
/*
* userns count is 1 for root user, 1 for init_uts_ns,
@@ -50,15 +51,14 @@ EXPORT_SYMBOL_GPL(init_user_ns);
* UID task count cache, to get fast user lookup in "alloc_uid"
* when changing user ID's (ie setuid() and friends).
*/
-
-#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7)
-#define UIDHASH_SZ (1 << UIDHASH_BITS)
-#define UIDHASH_MASK (UIDHASH_SZ - 1)
-#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
-#define uidhashentry(uid) (uidhash_table + __uidhashfn((__kuid_val(uid))))
+#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7)
+#define UIDHASH_CMP(obj, key) ((obj)->uid == (key))
+#define uidhash_entry(key) (hash_get(&uidhash_table, key, \
+ struct user_struct, uidhash_node, \
+ UIDHASH_CMP))
static struct kmem_cache *uid_cachep;
-struct hlist_head uidhash_table[UIDHASH_SZ];
+DEFINE_STATIC_HASHTABLE(uidhash_table, UIDHASH_BITS);
/*
* The uidhash_lock is mostly taken from process context, but it is
@@ -84,29 +84,14 @@ struct user_struct root_user = {
/*
* These routines must be called with the uidhash spinlock held!
*/
-static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
+static void uid_hash_insert(struct user_struct *up)
{
- hlist_add_head(&up->uidhash_node, hashent);
+ hash_add(&uidhash_table, &up->uidhash_node, up->uid);
}
static void uid_hash_remove(struct user_struct *up)
{
- hlist_del_init(&up->uidhash_node);
-}
-
-static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
-{
- struct user_struct *user;
- struct hlist_node *h;
-
- hlist_for_each_entry(user, h, hashent, uidhash_node) {
- if (uid_eq(user->uid, uid)) {
- atomic_inc(&user->__count);
- return user;
- }
- }
-
- return NULL;
+ hash_del(&up->uidhash_node);
}
/* IRQs are disabled and uidhash_lock is held upon function entry.
@@ -135,7 +120,9 @@ struct user_struct *find_user(kuid_t uid)
unsigned long flags;
spin_lock_irqsave(&uidhash_lock, flags);
- ret = uid_hash_find(uid, uidhashentry(uid));
+ ret = uidhash_entry(uid);
+ if (ret)
+ atomic_inc(&ret->__count);
spin_unlock_irqrestore(&uidhash_lock, flags);
return ret;
}
@@ -156,11 +143,10 @@ void free_uid(struct user_struct *up)
struct user_struct *alloc_uid(kuid_t uid)
{
- struct hlist_head *hashent = uidhashentry(uid);
struct user_struct *up, *new;
spin_lock_irq(&uidhash_lock);
- up = uid_hash_find(uid, hashent);
+ up = uidhash_entry(uid);
spin_unlock_irq(&uidhash_lock);
if (!up) {
@@ -176,13 +162,13 @@ struct user_struct *alloc_uid(kuid_t uid)
* on adding the same user already..
*/
spin_lock_irq(&uidhash_lock);
- up = uid_hash_find(uid, hashent);
+ up = uidhash_entry(uid);
if (up) {
key_put(new->uid_keyring);
key_put(new->session_keyring);
kmem_cache_free(uid_cachep, new);
} else {
- uid_hash_insert(new, hashent);
+ uid_hash_insert(new);
up = new;
}
spin_unlock_irq(&uidhash_lock);
@@ -196,17 +182,14 @@ out_unlock:
static int __init uid_cache_init(void)
{
- int n;
-
uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
- for(n = 0; n < UIDHASH_SZ; ++n)
- INIT_HLIST_HEAD(uidhash_table + n);
+ hash_init(&uidhash_table, UIDHASH_BITS);
/* Insert the root user immediately (init already runs as root) */
spin_lock_irq(&uidhash_lock);
- uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
+ uid_hash_insert(&root_user);
spin_unlock_irq(&uidhash_lock);
return 0;
--
1.7.8.6
--
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 related
* [RFC v2 3/7] mm,ksm: use new hashtable implementation
From: Sasha Levin @ 2012-08-03 14:23 UTC (permalink / raw)
To: torvalds
Cc: tj, akpm, linux-kernel, linux-mm, paul.gortmaker, davem, rostedt,
mingo, ebiederm, aarcange, ericvh, netdev, Sasha Levin
In-Reply-To: <1344003788-1417-1-git-send-email-levinsasha928@gmail.com>
Switch ksm to use the new hashtable implementation. This reduces the amount of
generic unrelated code in the ksm module.
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
mm/ksm.c | 29 +++++++++--------------------
1 files changed, 9 insertions(+), 20 deletions(-)
diff --git a/mm/ksm.c b/mm/ksm.c
index 47c8853..72d062a 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -33,7 +33,7 @@
#include <linux/mmu_notifier.h>
#include <linux/swap.h>
#include <linux/ksm.h>
-#include <linux/hash.h>
+#include <linux/hashtable.h>
#include <linux/freezer.h>
#include <linux/oom.h>
@@ -157,8 +157,8 @@ static struct rb_root root_stable_tree = RB_ROOT;
static struct rb_root root_unstable_tree = RB_ROOT;
#define MM_SLOTS_HASH_SHIFT 10
-#define MM_SLOTS_HASH_HEADS (1 << MM_SLOTS_HASH_SHIFT)
-static struct hlist_head mm_slots_hash[MM_SLOTS_HASH_HEADS];
+#define mm_hash_cmp(slot, key) ((slot)->mm == (key))
+DEFINE_STATIC_HASHTABLE(mm_slots_hash, MM_SLOTS_HASH_SHIFT);
static struct mm_slot ksm_mm_head = {
.mm_list = LIST_HEAD_INIT(ksm_mm_head.mm_list),
@@ -275,26 +275,15 @@ static inline void free_mm_slot(struct mm_slot *mm_slot)
static struct mm_slot *get_mm_slot(struct mm_struct *mm)
{
- struct mm_slot *mm_slot;
- struct hlist_head *bucket;
- struct hlist_node *node;
-
- bucket = &mm_slots_hash[hash_ptr(mm, MM_SLOTS_HASH_SHIFT)];
- hlist_for_each_entry(mm_slot, node, bucket, link) {
- if (mm == mm_slot->mm)
- return mm_slot;
- }
- return NULL;
+ return hash_get(&mm_slots_hash, mm, struct mm_slot,
+ link, mm_hash_cmp);
}
static void insert_to_mm_slots_hash(struct mm_struct *mm,
struct mm_slot *mm_slot)
{
- struct hlist_head *bucket;
-
- bucket = &mm_slots_hash[hash_ptr(mm, MM_SLOTS_HASH_SHIFT)];
mm_slot->mm = mm;
- hlist_add_head(&mm_slot->link, bucket);
+ hash_add(&mm_slots_hash, &mm_slot->link, (long)mm);
}
static inline int in_stable_tree(struct rmap_item *rmap_item)
@@ -647,7 +636,7 @@ static int unmerge_and_remove_all_rmap_items(void)
ksm_scan.mm_slot = list_entry(mm_slot->mm_list.next,
struct mm_slot, mm_list);
if (ksm_test_exit(mm)) {
- hlist_del(&mm_slot->link);
+ hash_del(&mm_slot->link);
list_del(&mm_slot->mm_list);
spin_unlock(&ksm_mmlist_lock);
@@ -1385,7 +1374,7 @@ next_mm:
* or when all VM_MERGEABLE areas have been unmapped (and
* mmap_sem then protects against race with MADV_MERGEABLE).
*/
- hlist_del(&slot->link);
+ hash_del(&slot->link);
list_del(&slot->mm_list);
spin_unlock(&ksm_mmlist_lock);
@@ -1548,7 +1537,7 @@ void __ksm_exit(struct mm_struct *mm)
mm_slot = get_mm_slot(mm);
if (mm_slot && ksm_scan.mm_slot != mm_slot) {
if (!mm_slot->rmap_list) {
- hlist_del(&mm_slot->link);
+ hash_del(&mm_slot->link);
list_del(&mm_slot->mm_list);
easy_to_free = 1;
} else {
--
1.7.8.6
--
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 related
* [RFC v2 4/7] workqueue: use new hashtable implementation
From: Sasha Levin @ 2012-08-03 14:23 UTC (permalink / raw)
To: torvalds
Cc: tj, akpm, linux-kernel, linux-mm, paul.gortmaker, davem, rostedt,
mingo, ebiederm, aarcange, ericvh, netdev, Sasha Levin
In-Reply-To: <1344003788-1417-1-git-send-email-levinsasha928@gmail.com>
Switch workqueues to use the new hashtable implementation. This reduces the amount of
generic unrelated code in the workqueues.
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
kernel/workqueue.c | 93 ++++++++--------------------------------------------
1 files changed, 14 insertions(+), 79 deletions(-)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 692d976..480975d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -41,6 +41,7 @@
#include <linux/debug_locks.h>
#include <linux/lockdep.h>
#include <linux/idr.h>
+#include <linux/hashtable.h>
#include "workqueue_sched.h"
@@ -82,8 +83,6 @@ enum {
NR_WORKER_POOLS = 2, /* # worker pools per gcwq */
BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */
- BUSY_WORKER_HASH_SIZE = 1 << BUSY_WORKER_HASH_ORDER,
- BUSY_WORKER_HASH_MASK = BUSY_WORKER_HASH_SIZE - 1,
MAX_IDLE_WORKERS_RATIO = 4, /* 1/4 of busy can be idle */
IDLE_WORKER_TIMEOUT = 300 * HZ, /* keep idle ones for 5 mins */
@@ -102,6 +101,8 @@ enum {
HIGHPRI_NICE_LEVEL = -20,
};
+#define worker_hash_cmp(obj, key) ((obj)->current_work == (key))
+
/*
* Structure fields follow one of the following exclusion rules.
*
@@ -180,7 +181,7 @@ struct global_cwq {
unsigned int flags; /* L: GCWQ_* flags */
/* workers are chained either in busy_hash or pool idle_list */
- struct hlist_head busy_hash[BUSY_WORKER_HASH_SIZE];
+ DEFINE_HASHTABLE(busy_hash, BUSY_WORKER_HASH_ORDER);
/* L: hash of busy workers */
struct worker_pool pools[2]; /* normal and highpri pools */
@@ -287,10 +288,6 @@ EXPORT_SYMBOL_GPL(system_nrt_freezable_wq);
for ((pool) = &(gcwq)->pools[0]; \
(pool) < &(gcwq)->pools[NR_WORKER_POOLS]; (pool)++)
-#define for_each_busy_worker(worker, i, pos, gcwq) \
- for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++) \
- hlist_for_each_entry(worker, pos, &gcwq->busy_hash[i], hentry)
-
static inline int __next_gcwq_cpu(int cpu, const struct cpumask *mask,
unsigned int sw)
{
@@ -822,70 +819,11 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
}
/**
- * busy_worker_head - return the busy hash head for a work
- * @gcwq: gcwq of interest
- * @work: work to be hashed
- *
- * Return hash head of @gcwq for @work.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock).
- *
- * RETURNS:
- * Pointer to the hash head.
- */
-static struct hlist_head *busy_worker_head(struct global_cwq *gcwq,
- struct work_struct *work)
-{
- const int base_shift = ilog2(sizeof(struct work_struct));
- unsigned long v = (unsigned long)work;
-
- /* simple shift and fold hash, do we need something better? */
- v >>= base_shift;
- v += v >> BUSY_WORKER_HASH_ORDER;
- v &= BUSY_WORKER_HASH_MASK;
-
- return &gcwq->busy_hash[v];
-}
-
-/**
- * __find_worker_executing_work - find worker which is executing a work
- * @gcwq: gcwq of interest
- * @bwh: hash head as returned by busy_worker_head()
- * @work: work to find worker for
- *
- * Find a worker which is executing @work on @gcwq. @bwh should be
- * the hash head obtained by calling busy_worker_head() with the same
- * work.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock).
- *
- * RETURNS:
- * Pointer to worker which is executing @work if found, NULL
- * otherwise.
- */
-static struct worker *__find_worker_executing_work(struct global_cwq *gcwq,
- struct hlist_head *bwh,
- struct work_struct *work)
-{
- struct worker *worker;
- struct hlist_node *tmp;
-
- hlist_for_each_entry(worker, tmp, bwh, hentry)
- if (worker->current_work == work)
- return worker;
- return NULL;
-}
-
-/**
* find_worker_executing_work - find worker which is executing a work
* @gcwq: gcwq of interest
* @work: work to find worker for
*
- * Find a worker which is executing @work on @gcwq. This function is
- * identical to __find_worker_executing_work() except that this
- * function calculates @bwh itself.
+ * Find a worker which is executing @work on @gcwq.
*
* CONTEXT:
* spin_lock_irq(gcwq->lock).
@@ -897,8 +835,8 @@ static struct worker *__find_worker_executing_work(struct global_cwq *gcwq,
static struct worker *find_worker_executing_work(struct global_cwq *gcwq,
struct work_struct *work)
{
- return __find_worker_executing_work(gcwq, busy_worker_head(gcwq, work),
- work);
+ return hash_get(&gcwq->busy_hash, work, struct worker,
+ hentry, worker_hash_cmp);
}
/**
@@ -959,7 +897,7 @@ static bool is_chained_work(struct workqueue_struct *wq)
int i;
spin_lock_irqsave(&gcwq->lock, flags);
- for_each_busy_worker(worker, i, pos, gcwq) {
+ hash_for_each(i, pos, &gcwq->busy_hash, worker, hentry) {
if (worker->task != current)
continue;
spin_unlock_irqrestore(&gcwq->lock, flags);
@@ -1432,7 +1370,7 @@ retry:
wake_up_all(&gcwq->rebind_hold);
/* rebind busy workers */
- for_each_busy_worker(worker, i, pos, gcwq) {
+ hash_for_each(i, pos, &gcwq->busy_hash, worker, hentry) {
struct work_struct *rebind_work = &worker->rebind_work;
/* morph UNBOUND to REBIND */
@@ -1932,7 +1870,6 @@ __acquires(&gcwq->lock)
struct cpu_workqueue_struct *cwq = get_work_cwq(work);
struct worker_pool *pool = worker->pool;
struct global_cwq *gcwq = pool->gcwq;
- struct hlist_head *bwh = busy_worker_head(gcwq, work);
bool cpu_intensive = cwq->wq->flags & WQ_CPU_INTENSIVE;
work_func_t f = work->func;
int work_color;
@@ -1964,7 +1901,7 @@ __acquires(&gcwq->lock)
* already processing the work. If so, defer the work to the
* currently executing one.
*/
- collision = __find_worker_executing_work(gcwq, bwh, work);
+ collision = find_worker_executing_work(gcwq, work);
if (unlikely(collision)) {
move_linked_works(work, &collision->scheduled, NULL);
return;
@@ -1972,7 +1909,7 @@ __acquires(&gcwq->lock)
/* claim and process */
debug_work_deactivate(work);
- hlist_add_head(&worker->hentry, bwh);
+ hash_add(&gcwq->busy_hash, &worker->hentry, (long)work);
worker->current_work = work;
worker->current_cwq = cwq;
work_color = get_work_color(work);
@@ -2027,7 +1964,7 @@ __acquires(&gcwq->lock)
worker_clr_flags(worker, WORKER_CPU_INTENSIVE);
/* we're done with it, release */
- hlist_del_init(&worker->hentry);
+ hash_del(&worker->hentry);
worker->current_work = NULL;
worker->current_cwq = NULL;
cwq_dec_nr_in_flight(cwq, work_color, false);
@@ -3405,7 +3342,7 @@ static void gcwq_unbind_fn(struct work_struct *work)
list_for_each_entry(worker, &pool->idle_list, entry)
worker->flags |= WORKER_UNBOUND;
- for_each_busy_worker(worker, i, pos, gcwq)
+ hash_for_each(i, pos, &gcwq->busy_hash, worker, hentry)
worker->flags |= WORKER_UNBOUND;
gcwq->flags |= GCWQ_DISASSOCIATED;
@@ -3690,7 +3627,6 @@ out_unlock:
static int __init init_workqueues(void)
{
unsigned int cpu;
- int i;
cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP);
cpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN);
@@ -3704,8 +3640,7 @@ static int __init init_workqueues(void)
gcwq->cpu = cpu;
gcwq->flags |= GCWQ_DISASSOCIATED;
- for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++)
- INIT_HLIST_HEAD(&gcwq->busy_hash[i]);
+ hash_init(&gcwq->busy_hash, BUSY_WORKER_HASH_ORDER);
for_each_worker_pool(pool, gcwq) {
pool->gcwq = gcwq;
--
1.7.8.6
--
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 related
* [RFC v2 5/7] mm/huge_memory: use new hashtable implementation
From: Sasha Levin @ 2012-08-03 14:23 UTC (permalink / raw)
To: torvalds
Cc: tj, akpm, linux-kernel, linux-mm, paul.gortmaker, davem, rostedt,
mingo, ebiederm, aarcange, ericvh, netdev, Sasha Levin
In-Reply-To: <1344003788-1417-1-git-send-email-levinsasha928@gmail.com>
Switch hugemem to use the new hashtable implementation. This reduces the amount of
generic unrelated code in the hugemem.
This also removes the dymanic allocation of the hash table. The size of the table is
constant so there's no point in paying the price of an extra dereference when accessing
it.
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
mm/huge_memory.c | 56 ++++++++++-------------------------------------------
1 files changed, 11 insertions(+), 45 deletions(-)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 57c4b93..7b2cad5 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -17,6 +17,7 @@
#include <linux/khugepaged.h>
#include <linux/freezer.h>
#include <linux/mman.h>
+#include <linux/hashtable.h>
#include <asm/tlb.h>
#include <asm/pgalloc.h>
#include "internal.h"
@@ -57,12 +58,13 @@ static DECLARE_WAIT_QUEUE_HEAD(khugepaged_wait);
static unsigned int khugepaged_max_ptes_none __read_mostly = HPAGE_PMD_NR-1;
static int khugepaged(void *none);
-static int mm_slots_hash_init(void);
static int khugepaged_slab_init(void);
static void khugepaged_slab_free(void);
-#define MM_SLOTS_HASH_HEADS 1024
-static struct hlist_head *mm_slots_hash __read_mostly;
+#define MM_SLOTS_HASH_BITS 10
+#define MM_SLOTS_HASH_CMP(mm_slot, obj) ((mm_slot)->mm == (obj))
+DEFINE_STATIC_HASHTABLE(mm_slots_hash, MM_SLOTS_HASH_BITS);
+
static struct kmem_cache *mm_slot_cache __read_mostly;
/**
@@ -140,7 +142,7 @@ static int start_khugepaged(void)
int err = 0;
if (khugepaged_enabled()) {
int wakeup;
- if (unlikely(!mm_slot_cache || !mm_slots_hash)) {
+ if (unlikely(!mm_slot_cache)) {
err = -ENOMEM;
goto out;
}
@@ -554,12 +556,6 @@ static int __init hugepage_init(void)
if (err)
goto out;
- err = mm_slots_hash_init();
- if (err) {
- khugepaged_slab_free();
- goto out;
- }
-
/*
* By default disable transparent hugepages on smaller systems,
* where the extra memory used could hurt more than TLB overhead
@@ -1562,47 +1558,17 @@ static inline void free_mm_slot(struct mm_slot *mm_slot)
kmem_cache_free(mm_slot_cache, mm_slot);
}
-static int __init mm_slots_hash_init(void)
-{
- mm_slots_hash = kzalloc(MM_SLOTS_HASH_HEADS * sizeof(struct hlist_head),
- GFP_KERNEL);
- if (!mm_slots_hash)
- return -ENOMEM;
- return 0;
-}
-
-#if 0
-static void __init mm_slots_hash_free(void)
-{
- kfree(mm_slots_hash);
- mm_slots_hash = NULL;
-}
-#endif
-
static struct mm_slot *get_mm_slot(struct mm_struct *mm)
{
- struct mm_slot *mm_slot;
- struct hlist_head *bucket;
- struct hlist_node *node;
-
- bucket = &mm_slots_hash[((unsigned long)mm / sizeof(struct mm_struct))
- % MM_SLOTS_HASH_HEADS];
- hlist_for_each_entry(mm_slot, node, bucket, hash) {
- if (mm == mm_slot->mm)
- return mm_slot;
- }
- return NULL;
+ return hash_get(&mm_slots_hash, mm, struct mm_slot,
+ hash, MM_SLOTS_HASH_CMP);
}
static void insert_to_mm_slots_hash(struct mm_struct *mm,
struct mm_slot *mm_slot)
{
- struct hlist_head *bucket;
-
- bucket = &mm_slots_hash[((unsigned long)mm / sizeof(struct mm_struct))
- % MM_SLOTS_HASH_HEADS];
mm_slot->mm = mm;
- hlist_add_head(&mm_slot->hash, bucket);
+ hash_add(&mm_slots_hash, &mm_slot->hash, (long)mm);
}
static inline int khugepaged_test_exit(struct mm_struct *mm)
@@ -1675,7 +1641,7 @@ void __khugepaged_exit(struct mm_struct *mm)
spin_lock(&khugepaged_mm_lock);
mm_slot = get_mm_slot(mm);
if (mm_slot && khugepaged_scan.mm_slot != mm_slot) {
- hlist_del(&mm_slot->hash);
+ hash_del(&mm_slot->hash);
list_del(&mm_slot->mm_node);
free = 1;
}
@@ -2089,7 +2055,7 @@ static void collect_mm_slot(struct mm_slot *mm_slot)
if (khugepaged_test_exit(mm)) {
/* free mm_slot */
- hlist_del(&mm_slot->hash);
+ hash_del(&mm_slot->hash);
list_del(&mm_slot->mm_node);
/*
--
1.7.8.6
--
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 related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox