* [PATCH net-next] net: add SNMP counters tracking incoming ECN bits
From: Eric Dumazet @ 2013-08-01 15:26 UTC (permalink / raw)
To: David Miller; +Cc: netdev
From: Eric Dumazet <edumazet@google.com>
With GRO/LRO processing, there is a problem because Ip[6]InReceives SNMP
counters do not count the number of frames, but number of aggregated
segments.
Its probably too late to change this now.
This patch adds four new counters, tracking number of frames, regardless
of LRO/GRO, and on a per ECN status basis, for IPv4 and IPv6.
Ip[6]NoECTPkts : Number of packets received with NOECT
Ip[6]ECT1Pkts : Number of packets received with ECT(1)
Ip[6]ECT0Pkts : Number of packets received with ECT(0)
Ip[6]CEPkts : Number of packets received with Congestion Experimented
lph37:~# nstat | egrep "Pkts|InReceive"
IpInReceives 1634137 0.0
Ip6InReceives 3714107 0.0
Ip6InNoECTPkts 19205 0.0
Ip6InECT0Pkts 52651828 0.0
IpExtInNoECTPkts 33630 0.0
IpExtInECT0Pkts 15581379 0.0
IpExtInCEPkts 6 0.0
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
include/uapi/linux/snmp.h | 4 ++++
net/ipv4/ip_input.c | 8 ++++++++
net/ipv4/proc.c | 7 ++++++-
net/ipv6/ip6_input.c | 6 +++++-
net/ipv6/proc.c | 4 ++++
5 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h
index af0a674..60601d2 100644
--- a/include/uapi/linux/snmp.h
+++ b/include/uapi/linux/snmp.h
@@ -51,6 +51,10 @@ enum
IPSTATS_MIB_INBCASTOCTETS, /* InBcastOctets */
IPSTATS_MIB_OUTBCASTOCTETS, /* OutBcastOctets */
IPSTATS_MIB_CSUMERRORS, /* InCsumErrors */
+ IPSTATS_MIB_NOECTPKTS, /* InNoECTPkts */
+ IPSTATS_MIB_ECT1PKTS, /* InECT1Pkts */
+ IPSTATS_MIB_ECT0PKTS, /* InECT0Pkts */
+ IPSTATS_MIB_CEPKTS, /* InCEPkts */
__IPSTATS_MIB_MAX
};
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 15e3e68..054a3e9 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -141,6 +141,7 @@
#include <net/icmp.h>
#include <net/raw.h>
#include <net/checksum.h>
+#include <net/inet_ecn.h>
#include <linux/netfilter_ipv4.h>
#include <net/xfrm.h>
#include <linux/mroute.h>
@@ -410,6 +411,13 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
if (iph->ihl < 5 || iph->version != 4)
goto inhdr_error;
+ BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_1);
+ BUILD_BUG_ON(IPSTATS_MIB_ECT0PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_0);
+ BUILD_BUG_ON(IPSTATS_MIB_CEPKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_CE);
+ IP_ADD_STATS_BH(dev_net(dev),
+ IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK),
+ max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
+
if (!pskb_may_pull(skb, iph->ihl*4))
goto inhdr_error;
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 6577a11..5f5fa61 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -111,7 +111,7 @@ static const struct snmp_mib snmp4_ipstats_list[] = {
SNMP_MIB_SENTINEL
};
-/* Following RFC4293 items are displayed in /proc/net/netstat */
+/* Following items are displayed in /proc/net/netstat */
static const struct snmp_mib snmp4_ipextstats_list[] = {
SNMP_MIB_ITEM("InNoRoutes", IPSTATS_MIB_INNOROUTES),
SNMP_MIB_ITEM("InTruncatedPkts", IPSTATS_MIB_INTRUNCATEDPKTS),
@@ -125,7 +125,12 @@ static const struct snmp_mib snmp4_ipextstats_list[] = {
SNMP_MIB_ITEM("OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS),
SNMP_MIB_ITEM("InBcastOctets", IPSTATS_MIB_INBCASTOCTETS),
SNMP_MIB_ITEM("OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS),
+ /* Non RFC4293 fields */
SNMP_MIB_ITEM("InCsumErrors", IPSTATS_MIB_CSUMERRORS),
+ SNMP_MIB_ITEM("InNoECTPkts", IPSTATS_MIB_NOECTPKTS),
+ SNMP_MIB_ITEM("InECT1Pkts", IPSTATS_MIB_ECT1PKTS),
+ SNMP_MIB_ITEM("InECT0Pkts", IPSTATS_MIB_ECT0PKTS),
+ SNMP_MIB_ITEM("InCEPkts", IPSTATS_MIB_CEPKTS),
SNMP_MIB_SENTINEL
};
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 2bab2aa..302d6fb 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -44,7 +44,7 @@
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/xfrm.h>
-
+#include <net/inet_ecn.h>
int ip6_rcv_finish(struct sk_buff *skb)
@@ -109,6 +109,10 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
if (hdr->version != 6)
goto err;
+ IP6_ADD_STATS_BH(dev_net(dev), idev,
+ IPSTATS_MIB_NOECTPKTS +
+ (ipv6_get_dsfield(hdr) & INET_ECN_MASK),
+ max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
/*
* RFC4291 2.5.3
* A packet received on an interface with a destination address
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 51c3285..091d066 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -91,6 +91,10 @@ static const struct snmp_mib snmp6_ipstats_list[] = {
SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS),
SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS),
/* IPSTATS_MIB_CSUMERRORS is not relevant in IPv6 (no checksum) */
+ SNMP_MIB_ITEM("Ip6InNoECTPkts", IPSTATS_MIB_NOECTPKTS),
+ SNMP_MIB_ITEM("Ip6InECT1Pkts", IPSTATS_MIB_ECT1PKTS),
+ SNMP_MIB_ITEM("Ip6InECT0Pkts", IPSTATS_MIB_ECT0PKTS),
+ SNMP_MIB_ITEM("Ip6InCEPkts", IPSTATS_MIB_CEPKTS),
SNMP_MIB_SENTINEL
};
^ permalink raw reply related
* [PATCH] fib_rules: add route suppression based on ifgroup
From: Stefan Tomanek @ 2013-08-01 15:18 UTC (permalink / raw)
To: netdev
This change adds the ability to suppress a routing decision based upon the
interface group the selected interface belongs to.
Signed-off-by: Stefan Tomanek <stefan.tomanek@wertarbyte.de>
---
include/net/fib_rules.h | 2 ++
include/uapi/linux/fib_rules.h | 2 +-
net/core/fib_rules.c | 10 ++++++++++
net/ipv4/fib_rules.c | 23 +++++++++++++++++------
net/ipv6/fib6_rules.c | 16 +++++++++++++---
5 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 2f286dc..4d32ecc 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -19,6 +19,7 @@ struct fib_rule {
u32 flags;
u32 table;
u8 table_prefixlen_min;
+ int suppress_ifgroup;
u8 action;
u32 target;
struct fib_rule __rcu *ctarget;
@@ -84,6 +85,7 @@ struct fib_rules_ops {
[FRA_FWMASK] = { .type = NLA_U32 }, \
[FRA_TABLE] = { .type = NLA_U32 }, \
[FRA_TABLE_PREFIXLEN_MIN] = { .type = NLA_U8 }, \
+ [FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
[FRA_GOTO] = { .type = NLA_U32 }
static inline void fib_rule_get(struct fib_rule *rule)
diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index 59cd31b..63e3116 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -44,7 +44,7 @@ enum {
FRA_FWMARK, /* mark */
FRA_FLOW, /* flow/class id */
FRA_UNUSED6,
- FRA_UNUSED7,
+ FRA_SUPPRESS_IFGROUP,
FRA_TABLE_PREFIXLEN_MIN,
FRA_TABLE, /* Extended table id */
FRA_FWMASK, /* mask for netfilter mark */
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 2ef5040..5040a61 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -343,6 +343,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
if (tb[FRA_TABLE_PREFIXLEN_MIN])
rule->table_prefixlen_min = nla_get_u8(tb[FRA_TABLE_PREFIXLEN_MIN]);
+ if (tb[FRA_SUPPRESS_IFGROUP])
+ rule->suppress_ifgroup = nla_get_u32(tb[FRA_SUPPRESS_IFGROUP]);
+
if (!tb[FRA_PRIORITY] && ops->default_pref)
rule->pref = ops->default_pref(ops);
@@ -529,6 +532,7 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
+ nla_total_size(4) /* FRA_PRIORITY */
+ nla_total_size(4) /* FRA_TABLE */
+ nla_total_size(1) /* FRA_TABLE_PREFIXLEN_MIN */
+ + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */
+ nla_total_size(4) /* FRA_FWMARK */
+ nla_total_size(4); /* FRA_FWMASK */
@@ -588,6 +592,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
(rule->target &&
nla_put_u32(skb, FRA_GOTO, rule->target)))
goto nla_put_failure;
+
+ if (rule->suppress_ifgroup != -1) {
+ if (nla_put_u32(skb, FRA_SUPPRESS_IFGROUP, rule->suppress_ifgroup))
+ goto nla_put_failure;
+ }
+
if (ops->fill(rule, skb, frh) < 0)
goto nla_put_failure;
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 9f29066..234b085 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -103,16 +103,27 @@ errout:
static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
{
+ struct fib_result *result = (struct fib_result *) arg->result;
+ struct net_device *dev = result->fi->fib_dev;
+
/* do not accept result if the route does
* not meet the required prefix length
*/
- struct fib_result *result = (struct fib_result *) arg->result;
- if (result->prefixlen < rule->table_prefixlen_min) {
- if (!(arg->flags & FIB_LOOKUP_NOREF))
- fib_info_put(result->fi);
- return true;
- }
+ if (result->prefixlen < rule->table_prefixlen_min)
+ goto suppress_route;
+
+ /* do not accept result if the route uses a device
+ * belonging to a forbidden interface group (!= 0)
+ */
+ if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
+ goto suppress_route;
+
return false;
+
+suppress_route:
+ if (!(arg->flags & FIB_LOOKUP_NOREF))
+ fib_info_put(result->fi);
+ return true;
}
static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 554a4fb..84cf125 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -122,14 +122,24 @@ out:
static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
{
struct rt6_info *rt = (struct rt6_info *) arg->result;
+ struct net_device *dev = rt->rt6i_idev->dev;
/* do not accept result if the route does
* not meet the required prefix length
*/
- if (rt->rt6i_dst.plen < rule->table_prefixlen_min) {
+ if (rt->rt6i_dst.plen < rule->table_prefixlen_min)
+ goto suppress_route;
+
+ /* do not accept result if the route uses a device
+ * belonging to a forbidden interface group (!= 0)
+ */
+ if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
+ goto suppress_route;
+
+ return false;
+
+suppress_route:
ip6_rt_put(rt);
return true;
- }
- return false;
}
static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
--
1.7.10.4
^ permalink raw reply related
* [PATCH net-next v3 3/5] bonding: simplify broadcast_xmit function
From: Nikolay Aleksandrov @ 2013-08-01 14:54 UTC (permalink / raw)
To: netdev; +Cc: davem, andy, fubar
In-Reply-To: <1375368891-9979-1-git-send-email-nikolay@redhat.com>
From: Nikolay Aleksandrov <razor@BlackWall.org>
We don't need to start from the curr_active_slave as the frame will be
sent to all eligible slaves anyway, so we remove the unnecessary local
variables, checks and comments, and make it use the standard list API.
This has the nice side-effect that later when it's converted to RCU
a race condition will be avoided which could lead to double packet tx.
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
v2,v3: no changes
drivers/net/bonding/bond_main.c | 52 +++++++++++++----------------------------
1 file changed, 16 insertions(+), 36 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 9bdc701..5f9d2fa 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3910,52 +3910,32 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
return NETDEV_TX_OK;
}
-/*
- * in broadcast mode, we send everything to all usable interfaces.
- */
+/* in broadcast mode, we send everything to all usable interfaces. */
static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave, *start_at;
- struct net_device *tx_dev = NULL;
- int i;
- int res = 1;
-
- start_at = bond->curr_active_slave;
- if (!start_at)
- goto out;
+ struct slave *slave = NULL;
- bond_for_each_slave_from(bond, slave, i, start_at) {
- if (IS_UP(slave->dev) &&
- (slave->link == BOND_LINK_UP) &&
- bond_is_active_slave(slave)) {
- if (tx_dev) {
- struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
- if (!skb2) {
- pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
- bond_dev->name);
- continue;
- }
+ bond_for_each_slave(bond, slave) {
+ if (bond_is_last_slave(bond, slave))
+ break;
+ if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
- res = bond_dev_queue_xmit(bond, skb2, tx_dev);
- if (res) {
- kfree_skb(skb2);
- continue;
- }
+ if (!skb2) {
+ pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
+ bond_dev->name);
+ continue;
}
- tx_dev = slave->dev;
+ /* bond_dev_queue_xmit always returns 0 */
+ bond_dev_queue_xmit(bond, skb2, slave->dev);
}
}
-
- if (tx_dev)
- res = bond_dev_queue_xmit(bond, skb, tx_dev);
-
-out:
- if (res)
- /* no suitable interface, frame not sent */
+ if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ else
kfree_skb(skb);
- /* frame sent to all suitable interfaces */
return NETDEV_TX_OK;
}
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next v3 5/5] bonding: initial RCU conversion
From: Nikolay Aleksandrov @ 2013-08-01 14:54 UTC (permalink / raw)
To: netdev; +Cc: davem, andy, fubar
In-Reply-To: <1375368891-9979-1-git-send-email-nikolay@redhat.com>
This patch does the initial bonding conversion to RCU. After it the
following modes are protected by RCU alone: roundrobin, active-backup,
broadcast and xor. Modes ALB/TLB and 3ad still acquire bond->lock for
reading, and will be dealt with later. curr_active_slave needs to be
dereferenced via rcu in the converted modes because the only thing
protecting the slave after this patch is rcu_read_lock, so we need the
proper barrier for weakly ordered archs and to make sure we don't have
stale pointer. It's not tagged with __rcu yet because there's still work
to be done to remove the curr_slave_lock, so sparse will complain when
rcu_assign_pointer and rcu_dereference are used, but the alternative to use
rcu_dereference_protected would've created much bigger code churn which is
more difficult to test and review. That will be converted in time.
1. Active-backup mode
1.1 Perf recording while doing iperf -P 4
- old bonding: iperf spent 0.55% in bonding, system spent 0.29% CPU
in bonding
- new bonding: iperf spent 0.29% in bonding, system spent 0.15% CPU
in bonding
1.2. Bandwidth measurements
- old bonding: 16.1 gbps consistently
- new bonding: 17.5 gbps consistently
2. Round-robin mode
2.1 Perf recording while doing iperf -P 4
- old bonding: iperf spent 0.51% in bonding, system spent 0.24% CPU
in bonding
- new bonding: iperf spent 0.16% in bonding, system spent 0.11% CPU
in bonding
2.2 Bandwidth measurements
- old bonding: 8 gbps (variable due to packet reorderings)
- new bonding: 10 gbps (variable due to packet reorderings)
Of course the latency has improved in all converted modes, and moreover
while
doing enslave/release (since it doesn't affect tx anymore).
Also I've stress tested all modes doing enslave/release in a loop while
transmitting traffic.
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
v3: no change
v2: include performance notes, convert curr_active_slave use in bond_sysfs
to RCU, fix a potential latency issue in slave release because TX was
unblocked after synchronize_rcu which might take a while, introduce new
primitive bond_for_each_slave_rcu
drivers/net/bonding/bond_3ad.c | 2 ++
drivers/net/bonding/bond_alb.c | 6 ++++--
drivers/net/bonding/bond_main.c | 30 +++++++++++++++---------------
drivers/net/bonding/bond_sysfs.c | 19 +++++++------------
drivers/net/bonding/bonding.h | 4 ++++
5 files changed, 32 insertions(+), 29 deletions(-)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 7d46fa8..9010265 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2426,6 +2426,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
struct ad_info ad_info;
int res = 1;
+ read_lock(&bond->lock);
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
dev->name);
@@ -2475,6 +2476,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
}
out:
+ read_unlock(&bond->lock);
if (res) {
/* no suitable interface, frame not sent */
kfree_skb(skb);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 4d35196..3a5db7b 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1337,6 +1337,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
/* make sure that the curr_active_slave do not change during tx
*/
+ read_lock(&bond->lock);
read_lock(&bond->curr_slave_lock);
switch (ntohs(skb->protocol)) {
@@ -1441,11 +1442,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
}
read_unlock(&bond->curr_slave_lock);
-
+ read_unlock(&bond->lock);
if (res) {
/* no suitable interface, frame not sent */
kfree_skb(skb);
}
+
return NETDEV_TX_OK;
}
@@ -1663,7 +1665,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
}
swap_slave = bond->curr_active_slave;
- bond->curr_active_slave = new_slave;
+ rcu_assign_pointer(bond->curr_active_slave, new_slave);
if (!new_slave || list_empty(&bond->slave_list))
return;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 196febb..b83618c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -77,6 +77,7 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/pkt_sched.h>
+#include <linux/rculist.h>
#include "bonding.h"
#include "bond_3ad.h"
#include "bond_alb.h"
@@ -1037,7 +1038,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (new_active)
bond_set_slave_active_flags(new_active);
} else {
- bond->curr_active_slave = new_active;
+ rcu_assign_pointer(bond->curr_active_slave, new_active);
}
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
@@ -1127,7 +1128,7 @@ void bond_select_active_slave(struct bonding *bond)
*/
static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
{
- list_add_tail(&new_slave->list, &bond->slave_list);
+ list_add_tail_rcu(&new_slave->list, &bond->slave_list);
bond->slave_cnt++;
}
@@ -1143,7 +1144,7 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
*/
static void bond_detach_slave(struct bonding *bond, struct slave *slave)
{
- list_del(&slave->list);
+ list_del_rcu(&slave->list);
bond->slave_cnt--;
}
@@ -1751,7 +1752,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
* so we can change it without calling change_active_interface()
*/
if (!bond->curr_active_slave && new_slave->link == BOND_LINK_UP)
- bond->curr_active_slave = new_slave;
+ rcu_assign_pointer(bond->curr_active_slave, new_slave);
break;
} /* switch(bond_mode) */
@@ -1951,7 +1952,7 @@ static int __bond_release_one(struct net_device *bond_dev,
}
if (all) {
- bond->curr_active_slave = NULL;
+ rcu_assign_pointer(bond->curr_active_slave, NULL);
} else if (oldcurrent == slave) {
/*
* Note that we hold RTNL over this sequence, so there
@@ -1983,6 +1984,7 @@ static int __bond_release_one(struct net_device *bond_dev,
write_unlock_bh(&bond->lock);
unblock_netpoll_tx();
+ synchronize_rcu();
if (list_empty(&bond->slave_list)) {
call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
@@ -3811,7 +3813,7 @@ void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
int i = slave_id;
/* Here we start from the slave with slave_id */
- bond_for_each_slave(bond, slave) {
+ bond_for_each_slave_rcu(bond, slave) {
if (--i < 0) {
if (slave_can_tx(slave)) {
bond_dev_queue_xmit(bond, skb, slave->dev);
@@ -3822,7 +3824,7 @@ void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
/* Here we start from the first slave up to slave_id */
i = slave_id;
- bond_for_each_slave(bond, slave) {
+ bond_for_each_slave_rcu(bond, slave) {
if (--i < 0)
break;
if (slave_can_tx(slave)) {
@@ -3848,7 +3850,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
* will send all of this type of traffic.
*/
if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
- slave = bond->curr_active_slave;
+ slave = rcu_dereference(bond->curr_active_slave);
if (slave && slave_can_tx(slave))
bond_dev_queue_xmit(bond, skb, slave->dev);
else
@@ -3870,7 +3872,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave;
- slave = bond->curr_active_slave;
+ slave = rcu_dereference(bond->curr_active_slave);
if (slave)
bond_dev_queue_xmit(bond, skb, slave->dev);
else
@@ -3900,7 +3902,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave = NULL;
- bond_for_each_slave(bond, slave) {
+ bond_for_each_slave_rcu(bond, slave) {
if (bond_is_last_slave(bond, slave))
break;
if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
@@ -3955,7 +3957,7 @@ static inline int bond_slave_override(struct bonding *bond,
return 1;
/* Find out if any slaves have the same mapping as this skb. */
- bond_for_each_slave(bond, check_slave) {
+ bond_for_each_slave_rcu(bond, check_slave) {
if (check_slave->queue_id == skb->queue_mapping) {
slave = check_slave;
break;
@@ -4040,14 +4042,12 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (is_netpoll_tx_blocked(dev))
return NETDEV_TX_BUSY;
- read_lock(&bond->lock);
-
+ rcu_read_lock();
if (!list_empty(&bond->slave_list))
ret = __bond_start_xmit(skb, dev);
else
kfree_skb(skb);
-
- read_unlock(&bond->lock);
+ rcu_read_unlock();
return ret;
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 0702e91..0f539de 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1243,16 +1243,16 @@ static ssize_t bonding_show_active_slave(struct device *d,
struct device_attribute *attr,
char *buf)
{
- struct slave *curr;
struct bonding *bond = to_bond(d);
+ struct slave *curr;
int count = 0;
- read_lock(&bond->curr_slave_lock);
- curr = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
-
+ rcu_read_lock();
+ curr = rcu_dereference(bond->curr_active_slave);
if (USES_PRIMARY(bond->params.mode) && curr)
count = sprintf(buf, "%s\n", curr->dev->name);
+ rcu_read_unlock();
+
return count;
}
@@ -1284,7 +1284,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
if (!strlen(ifname) || buf[0] == '\n') {
pr_info("%s: Clearing current active slave.\n",
bond->dev->name);
- bond->curr_active_slave = NULL;
+ rcu_assign_pointer(bond->curr_active_slave, NULL);
bond_select_active_slave(bond);
goto out;
}
@@ -1347,14 +1347,9 @@ static ssize_t bonding_show_mii_status(struct device *d,
struct device_attribute *attr,
char *buf)
{
- struct slave *curr;
struct bonding *bond = to_bond(d);
- read_lock(&bond->curr_slave_lock);
- curr = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
-
- return sprintf(buf, "%s\n", curr ? "up" : "down");
+ return sprintf(buf, "%s\n", bond->curr_active_slave ? "up" : "down");
}
static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0995974..4bf52d5 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -116,6 +116,10 @@
#define bond_for_each_slave(bond, pos) \
list_for_each_entry(pos, &(bond)->slave_list, list)
+/* Caller must have rcu_read_lock */
+#define bond_for_each_slave_rcu(bond, pos) \
+ list_for_each_entry_rcu(pos, &(bond)->slave_list, list)
+
/**
* bond_for_each_slave_reverse - iterate in reverse from a given position
* @bond: the bond holding this list
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next v3 4/5] bonding: factor out slave id tx code and simplify xmit paths
From: Nikolay Aleksandrov @ 2013-08-01 14:54 UTC (permalink / raw)
To: netdev; +Cc: davem, andy, fubar
In-Reply-To: <1375368891-9979-1-git-send-email-nikolay@redhat.com>
From: Nikolay Aleksandrov <razor@BlackWall.org>
I factored out the tx xmit code which relies on slave id in
bond_xmit_slave_id. It is global because later it can be used also in
3ad mode xmit. Unnecessary obvious comments are removed. Active-backup
mode is simplified because bond_dev_queue_xmit always consumes the skb.
bond_xmit_xor becomes one line because of bond_xmit_slave_id.
bond_for_each_slave_from is not used in bond_xmit_slave_id because later
when RCU is used we can avoid important race condition by using standard
rculist routines.
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
v3: no change
v2: no need to NULL slave in xmit_roundrobin
drivers/net/bonding/bond_main.c | 118 +++++++++++++++++-----------------------
drivers/net/bonding/bonding.h | 10 ++++
2 files changed, 61 insertions(+), 67 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 5f9d2fa..196febb 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3795,12 +3795,50 @@ unwind:
return res;
}
+/**
+ * bond_xmit_slave_id - transmit skb through slave with slave_id
+ * @bond: bonding device that is transmitting
+ * @skb: buffer to transmit
+ * @slave_id: slave id up to slave_cnt-1 through which to transmit
+ *
+ * This function tries to transmit through slave with slave_id but in case
+ * it fails, it tries to find the first available slave for transmission.
+ * The skb is consumed in all cases, thus the function is void.
+ */
+void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
+{
+ struct slave *slave;
+ int i = slave_id;
+
+ /* Here we start from the slave with slave_id */
+ bond_for_each_slave(bond, slave) {
+ if (--i < 0) {
+ if (slave_can_tx(slave)) {
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ return;
+ }
+ }
+ }
+
+ /* Here we start from the first slave up to slave_id */
+ i = slave_id;
+ bond_for_each_slave(bond, slave) {
+ if (--i < 0)
+ break;
+ if (slave_can_tx(slave)) {
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ return;
+ }
+ }
+ /* no slave that can tx has been found */
+ kfree_skb(skb);
+}
+
static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave, *start_at;
- int i, slave_no, res = 1;
struct iphdr *iph = ip_hdr(skb);
+ struct slave *slave;
/*
* Start with the curr_active_slave that joined the bond as the
@@ -3809,46 +3847,20 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
* send the join/membership reports. The curr_active_slave found
* will send all of this type of traffic.
*/
- if ((iph->protocol == IPPROTO_IGMP) &&
- (skb->protocol == htons(ETH_P_IP))) {
+ if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
slave = bond->curr_active_slave;
- if (!slave)
- goto out;
+ if (slave && slave_can_tx(slave))
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ else
+ bond_xmit_slave_id(bond, skb, 0);
} else {
- /*
- * Concurrent TX may collide on rr_tx_counter; we accept
- * that as being rare enough not to justify using an
- * atomic op here.
- */
- slave_no = bond->rr_tx_counter++ % bond->slave_cnt;
-
- bond_for_each_slave(bond, slave) {
- slave_no--;
- if (slave_no < 0)
- break;
- }
- }
-
- start_at = slave;
- bond_for_each_slave_from(bond, slave, i, start_at) {
- if (IS_UP(slave->dev) &&
- (slave->link == BOND_LINK_UP) &&
- bond_is_active_slave(slave)) {
- res = bond_dev_queue_xmit(bond, skb, slave->dev);
- break;
- }
- }
-
-out:
- if (res) {
- /* no suitable interface, frame not sent */
- kfree_skb(skb);
+ bond_xmit_slave_id(bond, skb,
+ bond->rr_tx_counter++ % bond->slave_cnt);
}
return NETDEV_TX_OK;
}
-
/*
* in active-backup mode, we know that bond->curr_active_slave is always valid if
* the bond has a usable interface.
@@ -3857,14 +3869,11 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave;
- int res = 1;
slave = bond->curr_active_slave;
if (slave)
- res = bond_dev_queue_xmit(bond, skb, slave->dev);
-
- if (res)
- /* no suitable interface, frame not sent */
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ else
kfree_skb(skb);
return NETDEV_TX_OK;
@@ -3878,34 +3887,9 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave, *start_at;
- int slave_no;
- int i;
- int res = 1;
-
- slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
-
- bond_for_each_slave(bond, slave) {
- slave_no--;
- if (slave_no < 0)
- break;
- }
-
- start_at = slave;
- bond_for_each_slave_from(bond, slave, i, start_at) {
- if (IS_UP(slave->dev) &&
- (slave->link == BOND_LINK_UP) &&
- bond_is_active_slave(slave)) {
- res = bond_dev_queue_xmit(bond, skb, slave->dev);
- break;
- }
- }
-
- if (res) {
- /* no suitable interface, frame not sent */
- kfree_skb(skb);
- }
+ bond_xmit_slave_id(bond, skb,
+ bond->xmit_hash_policy(skb, bond->slave_cnt));
return NETDEV_TX_OK;
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index cfd9b49..0995974 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -426,10 +426,20 @@ static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be3
return addr;
}
+static inline bool slave_can_tx(struct slave *slave)
+{
+ if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP &&
+ bond_is_active_slave(slave))
+ return true;
+ else
+ return false;
+}
+
struct bond_net;
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
+void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id);
int bond_create(struct net *net, const char *name);
int bond_create_sysfs(struct bond_net *net);
void bond_destroy_sysfs(struct bond_net *net);
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next v3 2/5] bonding: remove unnecessary read_locks of curr_slave_lock
From: Nikolay Aleksandrov @ 2013-08-01 14:54 UTC (permalink / raw)
To: netdev; +Cc: davem, andy, fubar
In-Reply-To: <1375368891-9979-1-git-send-email-nikolay@redhat.com>
In all the cases we already hold bond->lock for reading, so the slave
can't get away and the check != NULL is sufficient. curr_active_slave
can still change after the read_lock is unlocked prior to use of the
dereferenced value, so there's no need for it. It either contains a
valid slave which we use (and can't get away), or it is NULL which is
checked.
In some places the read_lock of curr_slave_lock was left because we need
it not to change while performing some action (e.g. syncing current
active slave's addresses, sending ARP requests through the active slave)
such cases will be dealt with individually while converting to RCU.
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
v2, v3: no change
drivers/net/bonding/bond_main.c | 33 ++++++++-------------------------
1 file changed, 8 insertions(+), 25 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 3636a04..9bdc701 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2092,23 +2092,19 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
read_lock(&bond->lock);
- read_lock(&bond->curr_slave_lock);
old_active = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
-
new_active = bond_get_slave_by_dev(bond, slave_dev);
-
/*
* Changing to the current active: do nothing; return success.
*/
- if (new_active && (new_active == old_active)) {
+ if (new_active && new_active == old_active) {
read_unlock(&bond->lock);
return 0;
}
- if ((new_active) &&
- (old_active) &&
- (new_active->link == BOND_LINK_UP) &&
+ if (new_active &&
+ old_active &&
+ new_active->link == BOND_LINK_UP &&
IS_UP(new_active->dev)) {
block_netpoll_tx();
write_lock_bh(&bond->curr_slave_lock);
@@ -2660,10 +2656,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
if (list_empty(&bond->slave_list))
goto re_arm;
- read_lock(&bond->curr_slave_lock);
oldcurrent = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
-
/* see if any of the previous devices are up now (i.e. they have
* xmt and rcv traffic). the curr_active_slave does not come into
* the picture unless it is null. also, slave->jiffies is not needed
@@ -3818,11 +3811,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
*/
if ((iph->protocol == IPPROTO_IGMP) &&
(skb->protocol == htons(ETH_P_IP))) {
-
- read_lock(&bond->curr_slave_lock);
slave = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
-
if (!slave)
goto out;
} else {
@@ -3867,15 +3856,12 @@ out:
static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
int res = 1;
- read_lock(&bond->curr_slave_lock);
-
- if (bond->curr_active_slave)
- res = bond_dev_queue_xmit(bond, skb,
- bond->curr_active_slave->dev);
-
- read_unlock(&bond->curr_slave_lock);
+ slave = bond->curr_active_slave;
+ if (slave)
+ res = bond_dev_queue_xmit(bond, skb, slave->dev);
if (res)
/* no suitable interface, frame not sent */
@@ -3935,10 +3921,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
int i;
int res = 1;
- read_lock(&bond->curr_slave_lock);
start_at = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
-
if (!start_at)
goto out;
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next v3 1/5] bonding: convert to list API and replace bond's custom list
From: Nikolay Aleksandrov @ 2013-08-01 14:54 UTC (permalink / raw)
To: netdev; +Cc: davem, andy, fubar
In-Reply-To: <1375368891-9979-1-git-send-email-nikolay@redhat.com>
This patch aims to remove struct bonding's first_slave and struct
slave's next and prev pointers, and replace them with the standard Linux
list API. The old macros are converted to list API as well and some new
primitives are available now. The checks if there're slaves that used
slave_cnt have been replaced by the list_empty macro.
Also a few small style fixes, changing longest -> shortest line in local
variable declarations, leaving an empty line before return and removing
unnecessary brackets.
This is the first step to gradual RCU conversion.
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
v3: fix 3ad next_slave bug (no end of list check), it was introduced while
making v2
v2: introduce new primitives, keep using bond_for_each_slave, make
bond_first/last_slave return NULL on empty list, eliminate the use
of slave_cnt for checking if there're slaves in the bond and use
list_empty for that, make bond_for_each_slave_from check for NULL pos
Because of these changes one macro goes to 82 chars, but I think it would
look ugly if I break it, also I think we fix an ALB bug in
bond_alb_deinit_slave because we have to check if any slaves have the
released slave's MAC address, and in case we have 2 slaves > 1 would fail
since this one has been already detached
drivers/net/bonding/bond_3ad.c | 42 +++++---
drivers/net/bonding/bond_alb.c | 51 ++++-----
drivers/net/bonding/bond_main.c | 220 ++++++++++++++++----------------------
drivers/net/bonding/bond_procfs.c | 12 +--
drivers/net/bonding/bond_sysfs.c | 43 ++++----
drivers/net/bonding/bonding.h | 71 ++++++------
6 files changed, 203 insertions(+), 236 deletions(-)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 390061d..7d46fa8 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -143,10 +143,9 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
*/
static inline struct port *__get_first_port(struct bonding *bond)
{
- if (bond->slave_cnt == 0)
- return NULL;
+ struct slave *first_slave = bond_first_slave(bond);
- return &(SLAVE_AD_INFO(bond->first_slave).port);
+ return first_slave ? &(SLAVE_AD_INFO(first_slave).port) : NULL;
}
/**
@@ -159,13 +158,16 @@ static inline struct port *__get_first_port(struct bonding *bond)
static inline struct port *__get_next_port(struct port *port)
{
struct bonding *bond = __get_bond_by_port(port);
- struct slave *slave = port->slave;
+ struct slave *slave = port->slave, *slave_next;
// If there's no bond for this port, or this is the last slave
- if ((bond == NULL) || (slave->next == bond->first_slave))
+ if (bond == NULL)
+ return NULL;
+ slave_next = bond_next_slave(bond, slave);
+ if (!slave_next || bond_is_first_slave(bond, slave_next))
return NULL;
- return &(SLAVE_AD_INFO(slave->next).port);
+ return &(SLAVE_AD_INFO(slave_next).port);
}
/**
@@ -178,12 +180,14 @@ static inline struct port *__get_next_port(struct port *port)
static inline struct aggregator *__get_first_agg(struct port *port)
{
struct bonding *bond = __get_bond_by_port(port);
+ struct slave *first_slave;
// If there's no bond for this port, or bond has no slaves
- if ((bond == NULL) || (bond->slave_cnt == 0))
+ if (bond == NULL)
return NULL;
+ first_slave = bond_first_slave(bond);
- return &(SLAVE_AD_INFO(bond->first_slave).aggregator);
+ return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL;
}
/**
@@ -195,14 +199,17 @@ static inline struct aggregator *__get_first_agg(struct port *port)
*/
static inline struct aggregator *__get_next_agg(struct aggregator *aggregator)
{
- struct slave *slave = aggregator->slave;
+ struct slave *slave = aggregator->slave, *slave_next;
struct bonding *bond = bond_get_bond_by_slave(slave);
// If there's no bond for this aggregator, or this is the last slave
- if ((bond == NULL) || (slave->next == bond->first_slave))
+ if (bond == NULL)
+ return NULL;
+ slave_next = bond_next_slave(bond, slave);
+ if (!slave_next || bond_is_first_slave(bond, slave_next))
return NULL;
- return &(SLAVE_AD_INFO(slave->next).aggregator);
+ return &(SLAVE_AD_INFO(slave_next).aggregator);
}
/*
@@ -2110,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
read_lock(&bond->lock);
//check if there are any slaves
- if (bond->slave_cnt == 0)
+ if (list_empty(&bond->slave_list))
goto re_arm;
// check if agg_select_timer timer after initialize is timed out
@@ -2336,8 +2343,12 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
int bond_3ad_set_carrier(struct bonding *bond)
{
struct aggregator *active;
+ struct slave *first_slave;
- active = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator));
+ first_slave = bond_first_slave(bond);
+ if (!first_slave)
+ return 0;
+ active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator));
if (active) {
/* are enough slaves available to consider link up? */
if (active->num_of_ports < bond->params.min_links) {
@@ -2432,7 +2443,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
if (agg && (agg->aggregator_identifier == agg_id)) {
@@ -2501,7 +2512,6 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
*/
void bond_3ad_update_lacp_rate(struct bonding *bond)
{
- int i;
struct slave *slave;
struct port *port = NULL;
int lacp_fast;
@@ -2509,7 +2519,7 @@ void bond_3ad_update_lacp_rate(struct bonding *bond)
write_lock_bh(&bond->lock);
lacp_fast = bond->params.lacp_fast;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
port = &(SLAVE_AD_INFO(slave).port);
if (port->slave == NULL)
continue;
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 4ea8ed1..4d35196 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -224,13 +224,12 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
{
struct slave *slave, *least_loaded;
long long max_gap;
- int i;
least_loaded = NULL;
max_gap = LLONG_MIN;
/* Find the slave with the largest gap */
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (SLAVE_IS_OK(slave)) {
long long gap = compute_gap(slave);
@@ -386,11 +385,10 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
struct slave *rx_slave, *slave, *start_at;
int i = 0;
- if (bond_info->next_rx_slave) {
+ if (bond_info->next_rx_slave)
start_at = bond_info->next_rx_slave;
- } else {
- start_at = bond->first_slave;
- }
+ else
+ start_at = bond_first_slave(bond);
rx_slave = NULL;
@@ -405,7 +403,8 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
}
if (rx_slave) {
- bond_info->next_rx_slave = rx_slave->next;
+ slave = bond_next_slave(bond, rx_slave);
+ bond_info->next_rx_slave = slave;
}
return rx_slave;
@@ -1173,9 +1172,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
{
struct slave *tmp_slave1, *free_mac_slave = NULL;
struct slave *has_bond_addr = bond->curr_active_slave;
- int i;
- if (bond->slave_cnt == 0) {
+ if (list_empty(&bond->slave_list)) {
/* this is the first slave */
return 0;
}
@@ -1196,7 +1194,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
/* The slave's address is equal to the address of the bond.
* Search for a spare address in the bond for this slave.
*/
- bond_for_each_slave(bond, tmp_slave1, i) {
+ bond_for_each_slave(bond, tmp_slave1) {
if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
/* no slave has tmp_slave1's perm addr
* as its curr addr
@@ -1246,17 +1244,15 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
*/
static int alb_set_mac_address(struct bonding *bond, void *addr)
{
- struct sockaddr sa;
- struct slave *slave, *stop_at;
char tmp_addr[ETH_ALEN];
+ struct slave *slave;
+ struct sockaddr sa;
int res;
- int i;
- if (bond->alb_info.rlb_enabled) {
+ if (bond->alb_info.rlb_enabled)
return 0;
- }
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
/* save net_device's current hw address */
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
@@ -1276,8 +1272,7 @@ unwind:
sa.sa_family = bond->dev->type;
/* unwind from head to the slave that failed */
- stop_at = slave;
- bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+ bond_for_each_slave_continue_reverse(bond, slave) {
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
dev_set_mac_address(slave->dev, &sa);
memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
@@ -1460,11 +1455,10 @@ void bond_alb_monitor(struct work_struct *work)
alb_work.work);
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *slave;
- int i;
read_lock(&bond->lock);
- if (bond->slave_cnt == 0) {
+ if (list_empty(&bond->slave_list)) {
bond_info->tx_rebalance_counter = 0;
bond_info->lp_counter = 0;
goto re_arm;
@@ -1482,9 +1476,8 @@ void bond_alb_monitor(struct work_struct *work)
*/
read_lock(&bond->curr_slave_lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave)
alb_send_learning_packets(slave, slave->dev->dev_addr);
- }
read_unlock(&bond->curr_slave_lock);
@@ -1496,7 +1489,7 @@ void bond_alb_monitor(struct work_struct *work)
read_lock(&bond->curr_slave_lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
tlb_clear_slave(bond, slave, 1);
if (slave == bond->curr_active_slave) {
SLAVE_TLB_INFO(slave).load =
@@ -1602,9 +1595,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
*/
void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
{
- if (bond->slave_cnt > 1) {
+ if (!list_empty(&bond->slave_list))
alb_change_hw_addr_on_detach(bond, slave);
- }
tlb_clear_slave(bond, slave, 0);
@@ -1661,9 +1653,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
{
struct slave *swap_slave;
- if (bond->curr_active_slave == new_slave) {
+ if (bond->curr_active_slave == new_slave)
return;
- }
if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) {
dev_set_promiscuity(bond->curr_active_slave->dev, -1);
@@ -1674,9 +1665,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
swap_slave = bond->curr_active_slave;
bond->curr_active_slave = new_slave;
- if (!new_slave || (bond->slave_cnt == 0)) {
+ if (!new_slave || list_empty(&bond->slave_list))
return;
- }
/* set the new curr_active_slave to the bonds mac address
* i.e. swap mac addresses of old curr_active_slave and new curr_active_slave
@@ -1689,9 +1679,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
* ignored so we can mess with their MAC addresses without
* fear of interference from transmit activity.
*/
- if (swap_slave) {
+ if (swap_slave)
tlb_clear_slave(bond, swap_slave, 1);
- }
tlb_clear_slave(bond, new_slave, 1);
write_unlock_bh(&bond->curr_slave_lock);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index da3af63..3636a04 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -441,10 +441,10 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
__be16 proto, u16 vid)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave, *stop_at;
- int i, res;
+ struct slave *slave;
+ int res;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
res = vlan_vid_add(slave->dev, proto, vid);
if (res)
goto unwind;
@@ -461,8 +461,7 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
unwind:
/* unwind from head to the slave that failed */
- stop_at = slave;
- bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at)
+ bond_for_each_slave_continue_reverse(bond, slave)
vlan_vid_del(slave->dev, proto, vid);
return res;
@@ -478,9 +477,9 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave;
- int i, res;
+ int res;
- bond_for_each_slave(bond, slave, i)
+ bond_for_each_slave(bond, slave)
vlan_vid_del(slave->dev, proto, vid);
res = bond_del_vlan(bond, vid);
@@ -532,15 +531,14 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
static int bond_set_carrier(struct bonding *bond)
{
struct slave *slave;
- int i;
- if (bond->slave_cnt == 0)
+ if (list_empty(&bond->slave_list))
goto down;
if (bond->params.mode == BOND_MODE_8023AD)
return bond_3ad_set_carrier(bond);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (slave->link == BOND_LINK_UP) {
if (!netif_carrier_ok(bond->dev)) {
netif_carrier_on(bond->dev);
@@ -681,8 +679,8 @@ static int bond_set_promiscuity(struct bonding *bond, int inc)
}
} else {
struct slave *slave;
- int i;
- bond_for_each_slave(bond, slave, i) {
+
+ bond_for_each_slave(bond, slave) {
err = dev_set_promiscuity(slave->dev, inc);
if (err)
return err;
@@ -705,8 +703,8 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
}
} else {
struct slave *slave;
- int i;
- bond_for_each_slave(bond, slave, i) {
+
+ bond_for_each_slave(bond, slave) {
err = dev_set_allmulti(slave->dev, inc);
if (err)
return err;
@@ -935,9 +933,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
new_active = bond->curr_active_slave;
if (!new_active) { /* there were no active slaves left */
- if (bond->slave_cnt > 0) /* found one slave */
- new_active = bond->first_slave;
- else
+ new_active = bond_first_slave(bond);
+ if (!new_active)
return NULL; /* still no slave, return NULL */
}
@@ -1130,17 +1127,7 @@ void bond_select_active_slave(struct bonding *bond)
*/
static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
{
- if (bond->first_slave == NULL) { /* attaching the first slave */
- new_slave->next = new_slave;
- new_slave->prev = new_slave;
- bond->first_slave = new_slave;
- } else {
- new_slave->next = bond->first_slave;
- new_slave->prev = bond->first_slave->prev;
- new_slave->next->prev = new_slave;
- new_slave->prev->next = new_slave;
- }
-
+ list_add_tail(&new_slave->list, &bond->slave_list);
bond->slave_cnt++;
}
@@ -1156,22 +1143,7 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
*/
static void bond_detach_slave(struct bonding *bond, struct slave *slave)
{
- if (slave->next)
- slave->next->prev = slave->prev;
-
- if (slave->prev)
- slave->prev->next = slave->next;
-
- if (bond->first_slave == slave) { /* slave is the first slave */
- if (bond->slave_cnt > 1) { /* there are more slave */
- bond->first_slave = slave->next;
- } else {
- bond->first_slave = NULL; /* slave was the last one */
- }
- }
-
- slave->next = NULL;
- slave->prev = NULL;
+ list_del(&slave->list);
bond->slave_cnt--;
}
@@ -1222,9 +1194,8 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave;
- int i;
- bond_for_each_slave(bond, slave, i)
+ bond_for_each_slave(bond, slave)
if (IS_UP(slave->dev))
slave_disable_netpoll(slave);
}
@@ -1233,9 +1204,9 @@ static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, g
{
struct bonding *bond = netdev_priv(dev);
struct slave *slave;
- int i, err = 0;
+ int err = 0;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
err = slave_enable_netpoll(slave);
if (err) {
bond_netpoll_cleanup(dev);
@@ -1265,11 +1236,10 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
struct slave *slave;
struct bonding *bond = netdev_priv(dev);
netdev_features_t mask;
- int i;
read_lock(&bond->lock);
- if (!bond->first_slave) {
+ if (list_empty(&bond->slave_list)) {
/* Disable adding VLANs to empty bond. But why? --mq */
features |= NETIF_F_VLAN_CHALLENGED;
goto out;
@@ -1279,7 +1249,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
features &= ~NETIF_F_ONE_FOR_ALL;
features |= NETIF_F_ALL_FOR_ALL;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
features = netdev_increment_features(features,
slave->dev->features,
mask);
@@ -1303,15 +1273,14 @@ static void bond_compute_features(struct bonding *bond)
unsigned short max_hard_header_len = ETH_HLEN;
unsigned int gso_max_size = GSO_MAX_SIZE;
u16 gso_max_segs = GSO_MAX_SEGS;
- int i;
unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE;
read_lock(&bond->lock);
- if (!bond->first_slave)
+ if (list_empty(&bond->slave_list))
goto done;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
vlan_features = netdev_increment_features(vlan_features,
slave->dev->vlan_features, BOND_VLAN_FEATURES);
@@ -1499,7 +1468,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
* bond ether type mutual exclusion - don't allow slaves of dissimilar
* ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
*/
- if (bond->slave_cnt == 0) {
+ if (list_empty(&bond->slave_list)) {
if (bond_dev->type != slave_dev->type) {
pr_debug("%s: change device type from %d to %d\n",
bond_dev->name,
@@ -1538,7 +1507,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
if (slave_ops->ndo_set_mac_address == NULL) {
- if (bond->slave_cnt == 0) {
+ if (list_empty(&bond->slave_list)) {
pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.",
bond_dev->name);
bond->params.fail_over_mac = BOND_FOM_ACTIVE;
@@ -1554,7 +1523,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
/* If this is the first slave, then we need to set the master's hardware
* address to be the same as the slave's. */
- if (!bond->slave_cnt && bond->dev->addr_assign_type == NET_ADDR_RANDOM)
+ if (list_empty(&bond->slave_list) &&
+ bond->dev->addr_assign_type == NET_ADDR_RANDOM)
bond_set_dev_addr(bond->dev, slave_dev);
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1562,7 +1532,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
res = -ENOMEM;
goto err_undo_flags;
}
-
+ INIT_LIST_HEAD(&new_slave->list);
/*
* Set the new_slave's queue_id to be zero. Queue ID mapping
* is set via sysfs or module option if desired.
@@ -1748,15 +1718,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
*/
bond_set_slave_inactive_flags(new_slave);
/* if this is the first slave */
- if (bond->slave_cnt == 1) {
+ if (bond_first_slave(bond) == new_slave) {
SLAVE_AD_INFO(new_slave).id = 1;
/* Initialize AD with the number of times that the AD timer is called in 1 second
* can be called only after the mac address of the bond is set
*/
bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL);
} else {
+ struct slave *prev_slave;
+
+ prev_slave = bond_prev_slave(bond, new_slave);
SLAVE_AD_INFO(new_slave).id =
- SLAVE_AD_INFO(new_slave->prev).id + 1;
+ SLAVE_AD_INFO(prev_slave).id + 1;
}
bond_3ad_bind_slave(new_slave);
@@ -1875,7 +1848,7 @@ err_free:
err_undo_flags:
bond_compute_features(bond);
/* Enslave of first slave has failed and we need to fix master's mac */
- if (bond->slave_cnt == 0 &&
+ if (list_empty(&bond->slave_list) &&
ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr))
eth_hw_addr_random(bond_dev);
@@ -1931,15 +1904,6 @@ static int __bond_release_one(struct net_device *bond_dev,
netdev_rx_handler_unregister(slave_dev);
write_lock_bh(&bond->lock);
- if (!all && !bond->params.fail_over_mac) {
- if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
- bond->slave_cnt > 1)
- pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
- bond_dev->name, slave_dev->name,
- slave->perm_hwaddr,
- bond_dev->name, slave_dev->name);
- }
-
/* Inform AD package of unbinding of slave. */
if (bond->params.mode == BOND_MODE_8023AD) {
/* must be called before the slave is
@@ -1960,6 +1924,15 @@ static int __bond_release_one(struct net_device *bond_dev,
/* release the slave from its bond */
bond_detach_slave(bond, slave);
+ if (!all && !bond->params.fail_over_mac) {
+ if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
+ !list_empty(&bond->slave_list))
+ pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
+ bond_dev->name, slave_dev->name,
+ slave->perm_hwaddr,
+ bond_dev->name, slave_dev->name);
+ }
+
if (bond->primary_slave == slave)
bond->primary_slave = NULL;
@@ -1996,7 +1969,7 @@ static int __bond_release_one(struct net_device *bond_dev,
write_lock_bh(&bond->lock);
}
- if (bond->slave_cnt == 0) {
+ if (list_empty(&bond->slave_list)) {
bond_set_carrier(bond);
eth_hw_addr_random(bond_dev);
@@ -2011,7 +1984,7 @@ static int __bond_release_one(struct net_device *bond_dev,
write_unlock_bh(&bond->lock);
unblock_netpoll_tx();
- if (bond->slave_cnt == 0) {
+ if (list_empty(&bond->slave_list)) {
call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
call_netdevice_notifiers(NETDEV_RELEASE, bond->dev);
}
@@ -2082,7 +2055,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
int ret;
ret = bond_release(bond_dev, slave_dev);
- if ((ret == 0) && (bond->slave_cnt == 0)) {
+ if (ret == 0 && list_empty(&bond->slave_list)) {
bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
pr_info("%s: destroying bond %s.\n",
bond_dev->name, bond_dev->name);
@@ -2167,13 +2140,12 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info)
{
struct bonding *bond = netdev_priv(bond_dev);
+ int i = 0, res = -ENODEV;
struct slave *slave;
- int i, res = -ENODEV;
read_lock(&bond->lock);
-
- bond_for_each_slave(bond, slave, i) {
- if (i == (int)info->slave_id) {
+ bond_for_each_slave(bond, slave) {
+ if (i++ == (int)info->slave_id) {
res = 0;
strcpy(info->slave_name, slave->dev->name);
info->link = slave->link;
@@ -2182,7 +2154,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
break;
}
}
-
read_unlock(&bond->lock);
return res;
@@ -2193,13 +2164,13 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
static int bond_miimon_inspect(struct bonding *bond)
{
+ int link_state, commit = 0;
struct slave *slave;
- int i, link_state, commit = 0;
bool ignore_updelay;
ignore_updelay = !bond->curr_active_slave ? true : false;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
slave->new_link = BOND_LINK_NOCHANGE;
link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2294,9 +2265,8 @@ static int bond_miimon_inspect(struct bonding *bond)
static void bond_miimon_commit(struct bonding *bond)
{
struct slave *slave;
- int i;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
switch (slave->new_link) {
case BOND_LINK_NOCHANGE:
continue;
@@ -2401,7 +2371,7 @@ void bond_mii_monitor(struct work_struct *work)
delay = msecs_to_jiffies(bond->params.miimon);
- if (bond->slave_cnt == 0)
+ if (list_empty(&bond->slave_list))
goto re_arm;
should_notify_peers = bond_should_notify_peers(bond);
@@ -2681,14 +2651,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
struct slave *slave, *oldcurrent;
int do_failover = 0;
int delta_in_ticks, extra_ticks;
- int i;
read_lock(&bond->lock);
delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
extra_ticks = delta_in_ticks / 2;
- if (bond->slave_cnt == 0)
+ if (list_empty(&bond->slave_list))
goto re_arm;
read_lock(&bond->curr_slave_lock);
@@ -2703,7 +2672,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
* TODO: what about up/down delay in arp mode? it wasn't here before
* so it can wait
*/
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
unsigned long trans_start = dev_trans_start(slave->dev);
if (slave->link != BOND_LINK_UP) {
@@ -2800,10 +2769,10 @@ re_arm:
*/
static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
{
- struct slave *slave;
- int i, commit = 0;
unsigned long trans_start;
+ struct slave *slave;
int extra_ticks;
+ int commit = 0;
/* All the time comparisons below need some extra time. Otherwise, on
* fast networks the ARP probe/reply may arrive within the same jiffy
@@ -2812,7 +2781,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
*/
extra_ticks = delta_in_ticks / 2;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
slave->new_link = BOND_LINK_NOCHANGE;
if (slave->link != BOND_LINK_UP) {
@@ -2891,11 +2860,10 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
*/
static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
{
- struct slave *slave;
- int i;
unsigned long trans_start;
+ struct slave *slave;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
switch (slave->new_link) {
case BOND_LINK_NOCHANGE:
continue;
@@ -2968,7 +2936,7 @@ do_failover:
*/
static void bond_ab_arp_probe(struct bonding *bond)
{
- struct slave *slave;
+ struct slave *slave, *next_slave;
int i;
read_lock(&bond->curr_slave_lock);
@@ -2992,7 +2960,7 @@ static void bond_ab_arp_probe(struct bonding *bond)
*/
if (!bond->current_arp_slave) {
- bond->current_arp_slave = bond->first_slave;
+ bond->current_arp_slave = bond_first_slave(bond);
if (!bond->current_arp_slave)
return;
}
@@ -3000,7 +2968,8 @@ static void bond_ab_arp_probe(struct bonding *bond)
bond_set_slave_inactive_flags(bond->current_arp_slave);
/* search for next candidate */
- bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
+ next_slave = bond_next_slave(bond, bond->current_arp_slave);
+ bond_for_each_slave_from(bond, slave, i, next_slave) {
if (IS_UP(slave->dev)) {
slave->link = BOND_LINK_BACK;
bond_set_slave_active_flags(slave);
@@ -3041,7 +3010,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
- if (bond->slave_cnt == 0)
+ if (list_empty(&bond->slave_list))
goto re_arm;
should_notify_peers = bond_should_notify_peers(bond);
@@ -3361,13 +3330,12 @@ static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave;
- int i;
/* reset slave->backup and slave->inactive */
read_lock(&bond->lock);
- if (bond->slave_cnt > 0) {
+ if (!list_empty(&bond->slave_list)) {
read_lock(&bond->curr_slave_lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
&& (slave != bond->curr_active_slave)) {
bond_set_slave_inactive_flags(slave);
@@ -3435,13 +3403,11 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
struct bonding *bond = netdev_priv(bond_dev);
struct rtnl_link_stats64 temp;
struct slave *slave;
- int i;
memset(stats, 0, sizeof(*stats));
read_lock_bh(&bond->lock);
-
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
const struct rtnl_link_stats64 *sstats =
dev_get_stats(slave->dev, &temp);
@@ -3471,7 +3437,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
stats->tx_window_errors += sstats->tx_window_errors;
}
-
read_unlock_bh(&bond->lock);
return stats;
@@ -3610,7 +3575,6 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave;
- int i;
read_lock(&bond->lock);
@@ -3623,7 +3587,7 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
}
read_unlock(&bond->curr_slave_lock);
} else {
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
dev_uc_sync_multiple(slave->dev, bond_dev);
dev_mc_sync_multiple(slave->dev, bond_dev);
}
@@ -3635,16 +3599,15 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
static int bond_neigh_init(struct neighbour *n)
{
struct bonding *bond = netdev_priv(n->dev);
- struct slave *slave = bond->first_slave;
const struct net_device_ops *slave_ops;
struct neigh_parms parms;
+ struct slave *slave;
int ret;
+ slave = bond_first_slave(bond);
if (!slave)
return 0;
-
slave_ops = slave->dev->netdev_ops;
-
if (!slave_ops->ndo_neigh_setup)
return 0;
@@ -3687,9 +3650,8 @@ static int bond_neigh_setup(struct net_device *dev,
static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave, *stop_at;
+ struct slave *slave;
int res = 0;
- int i;
pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
(bond_dev ? bond_dev->name : "None"), new_mtu);
@@ -3709,10 +3671,10 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
* call to the base driver.
*/
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
pr_debug("s %p s->p %p c_m %p\n",
slave,
- slave->prev,
+ bond_prev_slave(bond, slave),
slave->dev->netdev_ops->ndo_change_mtu);
res = dev_set_mtu(slave->dev, new_mtu);
@@ -3737,8 +3699,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
unwind:
/* unwind from head to the slave that failed */
- stop_at = slave;
- bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+ bond_for_each_slave_continue_reverse(bond, slave) {
int tmp_res;
tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
@@ -3762,9 +3723,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
{
struct bonding *bond = netdev_priv(bond_dev);
struct sockaddr *sa = addr, tmp_sa;
- struct slave *slave, *stop_at;
+ struct slave *slave;
int res = 0;
- int i;
if (bond->params.mode == BOND_MODE_ALB)
return bond_alb_set_mac_address(bond_dev, addr);
@@ -3797,7 +3757,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
* call to the base driver.
*/
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
pr_debug("slave %p %s\n", slave, slave->dev->name);
@@ -3829,8 +3789,7 @@ unwind:
tmp_sa.sa_family = bond_dev->type;
/* unwind from head to the slave that failed */
- stop_at = slave;
- bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+ bond_for_each_slave_continue_reverse(bond, slave) {
int tmp_res;
tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
@@ -3874,7 +3833,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
*/
slave_no = bond->rr_tx_counter++ % bond->slave_cnt;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
slave_no--;
if (slave_no < 0)
break;
@@ -3940,7 +3899,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
slave_no--;
if (slave_no < 0)
break;
@@ -4041,15 +4000,15 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
static inline int bond_slave_override(struct bonding *bond,
struct sk_buff *skb)
{
- int i, res = 1;
struct slave *slave = NULL;
struct slave *check_slave;
+ int res = 1;
if (!skb->queue_mapping)
return 1;
/* Find out if any slaves have the same mapping as this skb. */
- bond_for_each_slave(bond, check_slave, i) {
+ bond_for_each_slave(bond, check_slave) {
if (check_slave->queue_id == skb->queue_mapping) {
slave = check_slave;
break;
@@ -4136,7 +4095,7 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
read_lock(&bond->lock);
- if (bond->slave_cnt)
+ if (!list_empty(&bond->slave_list))
ret = __bond_start_xmit(skb, dev);
else
kfree_skb(skb);
@@ -4182,9 +4141,8 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
struct ethtool_cmd *ecmd)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct slave *slave;
- int i;
unsigned long speed = 0;
+ struct slave *slave;
ecmd->duplex = DUPLEX_UNKNOWN;
ecmd->port = PORT_OTHER;
@@ -4195,7 +4153,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
* this is an accurate maximum.
*/
read_lock(&bond->lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (SLAVE_IS_OK(slave)) {
if (slave->speed != SPEED_UNKNOWN)
speed += slave->speed;
@@ -4206,6 +4164,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
}
ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN);
read_unlock(&bond->lock);
+
return 0;
}
@@ -4269,7 +4228,7 @@ static void bond_setup(struct net_device *bond_dev)
/* initialize rwlocks */
rwlock_init(&bond->lock);
rwlock_init(&bond->curr_slave_lock);
-
+ INIT_LIST_HEAD(&bond->slave_list);
bond->params = bonding_defaults;
/* Initialize pointers */
@@ -4326,13 +4285,14 @@ static void bond_setup(struct net_device *bond_dev)
static void bond_uninit(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave, *tmp_slave;
struct vlan_entry *vlan, *tmp;
bond_netpoll_cleanup(bond_dev);
/* Release the bonded slaves */
- while (bond->first_slave != NULL)
- __bond_release_one(bond_dev, bond->first_slave->dev, true);
+ list_for_each_entry_safe(slave, tmp_slave, &bond->slave_list, list)
+ __bond_release_one(bond_dev, slave->dev, true);
pr_info("%s: released all slaves\n", bond_dev->name);
list_del(&bond->bond_list);
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 4060d41..20a6ee2 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -12,7 +12,6 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
struct bonding *bond = seq->private;
loff_t off = 0;
struct slave *slave;
- int i;
/* make sure the bond won't be taken away */
rcu_read_lock();
@@ -21,10 +20,9 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0)
return SEQ_START_TOKEN;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave)
if (++off == *pos)
return slave;
- }
return NULL;
}
@@ -36,11 +34,13 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
++*pos;
if (v == SEQ_START_TOKEN)
- return bond->first_slave;
+ return bond_first_slave(bond);
- slave = slave->next;
+ if (bond_is_last_slave(bond, slave))
+ return NULL;
+ slave = bond_next_slave(bond, slave);
- return (slave == bond->first_slave) ? NULL : slave;
+ return slave;
}
static void bond_info_seq_stop(struct seq_file *seq, void *v)
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ae02c19..0702e91 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -209,12 +209,12 @@ void bond_destroy_slave_symlinks(struct net_device *master,
static ssize_t bonding_show_slaves(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct slave *slave;
- int i, res = 0;
struct bonding *bond = to_bond(d);
+ struct slave *slave;
+ int res = 0;
read_lock(&bond->lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */
if ((PAGE_SIZE - res) > 10)
@@ -227,6 +227,7 @@ static ssize_t bonding_show_slaves(struct device *d,
read_unlock(&bond->lock);
if (res)
buf[res-1] = '\n'; /* eat the leftover space */
+
return res;
}
@@ -325,7 +326,7 @@ static ssize_t bonding_store_mode(struct device *d,
goto out;
}
- if (bond->slave_cnt > 0) {
+ if (!list_empty(&bond->slave_list)) {
pr_err("unable to update mode of %s because it has slaves.\n",
bond->dev->name);
ret = -EPERM;
@@ -507,7 +508,7 @@ static ssize_t bonding_store_fail_over_mac(struct device *d,
if (!rtnl_trylock())
return restart_syscall();
- if (bond->slave_cnt != 0) {
+ if (!list_empty(&bond->slave_list)) {
pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
bond->dev->name);
ret = -EPERM;
@@ -668,7 +669,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
&newtarget);
/* not to race with bond_arp_rcv */
write_lock_bh(&bond->lock);
- bond_for_each_slave(bond, slave, i)
+ bond_for_each_slave(bond, slave)
slave->target_last_arp_rx[ind] = jiffies;
targets[ind] = newtarget;
write_unlock_bh(&bond->lock);
@@ -694,7 +695,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
&newtarget);
write_lock_bh(&bond->lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
targets_rx = slave->target_last_arp_rx;
j = ind;
for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)
@@ -1085,10 +1086,9 @@ static ssize_t bonding_store_primary(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
- int i;
- struct slave *slave;
struct bonding *bond = to_bond(d);
char ifname[IFNAMSIZ];
+ struct slave *slave;
if (!rtnl_trylock())
return restart_syscall();
@@ -1114,7 +1114,7 @@ static ssize_t bonding_store_primary(struct device *d,
goto out;
}
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
pr_info("%s: Setting %s as primary slave.\n",
bond->dev->name, slave->dev->name);
@@ -1260,16 +1260,14 @@ static ssize_t bonding_store_active_slave(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
- int i;
- struct slave *slave;
- struct slave *old_active = NULL;
- struct slave *new_active = NULL;
+ struct slave *slave, *old_active, *new_active;
struct bonding *bond = to_bond(d);
char ifname[IFNAMSIZ];
if (!rtnl_trylock())
return restart_syscall();
+ old_active = new_active = NULL;
block_netpoll_tx();
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
@@ -1291,7 +1289,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
goto out;
}
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
old_active = bond->curr_active_slave;
new_active = slave;
@@ -1475,15 +1473,15 @@ static ssize_t bonding_show_queue_id(struct device *d,
struct device_attribute *attr,
char *buf)
{
- struct slave *slave;
- int i, res = 0;
struct bonding *bond = to_bond(d);
+ struct slave *slave;
+ int res = 0;
if (!rtnl_trylock())
return restart_syscall();
read_lock(&bond->lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
/* not enough space for another interface_name:queue_id pair */
if ((PAGE_SIZE - res) > 10)
@@ -1498,6 +1496,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
if (res)
buf[res-1] = '\n'; /* eat the leftover space */
rtnl_unlock();
+
return res;
}
@@ -1512,7 +1511,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
struct slave *slave, *update_slave;
struct bonding *bond = to_bond(d);
u16 qid;
- int i, ret = count;
+ int ret = count;
char *delim;
struct net_device *sdev = NULL;
@@ -1547,7 +1546,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
/* Search for thes slave and check for duplicate qids */
update_slave = NULL;
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (sdev == slave->dev)
/*
* We don't need to check the matching
@@ -1599,8 +1598,8 @@ static ssize_t bonding_store_slaves_active(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
- int i, new_value, ret = count;
struct bonding *bond = to_bond(d);
+ int new_value, ret = count;
struct slave *slave;
if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1623,7 +1622,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
}
read_lock(&bond->lock);
- bond_for_each_slave(bond, slave, i) {
+ bond_for_each_slave(bond, slave) {
if (!bond_is_active_slave(slave)) {
if (new_value)
slave->inactive = 0;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 42d1c65..cfd9b49 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -71,6 +71,28 @@
set_fs(fs); \
res; })
+/* slave list primitives */
+#define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
+
+/* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
+#define bond_first_slave(bond) \
+ list_first_entry_or_null(&(bond)->slave_list, struct slave, list)
+#define bond_last_slave(bond) \
+ (list_empty(&(bond)->slave_list) ? NULL : \
+ bond_to_slave((bond)->slave_list.prev))
+
+#define bond_is_first_slave(bond, pos) ((pos)->list.prev == &(bond)->slave_list)
+#define bond_is_last_slave(bond, pos) ((pos)->list.next == &(bond)->slave_list)
+
+/* Since bond_first/last_slave can return NULL, these can return NULL too */
+#define bond_next_slave(bond, pos) \
+ (bond_is_last_slave(bond, pos) ? bond_first_slave(bond) : \
+ bond_to_slave((pos)->list.next))
+
+#define bond_prev_slave(bond, pos) \
+ (bond_is_first_slave(bond, pos) ? bond_last_slave(bond) : \
+ bond_to_slave((pos)->list.prev))
+
/**
* bond_for_each_slave_from - iterate the slaves list from a starting point
* @bond: the bond holding this list.
@@ -80,37 +102,29 @@
*
* Caller must hold bond->lock
*/
-#define bond_for_each_slave_from(bond, pos, cnt, start) \
- for (cnt = 0, pos = start; \
- cnt < (bond)->slave_cnt; \
- cnt++, pos = (pos)->next)
+#define bond_for_each_slave_from(bond, pos, cnt, start) \
+ for (cnt = 0, pos = start; pos && cnt < (bond)->slave_cnt; \
+ cnt++, pos = bond_next_slave(bond, pos))
/**
- * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point
- * @bond: the bond holding this list.
- * @pos: current slave.
- * @cnt: counter for number max of moves
- * @start: start point.
- * @stop: stop point.
+ * bond_for_each_slave - iterate over all slaves
+ * @bond: the bond holding this list
+ * @pos: current slave
*
* Caller must hold bond->lock
*/
-#define bond_for_each_slave_from_to(bond, pos, cnt, start, stop) \
- for (cnt = 0, pos = start; \
- ((cnt < (bond)->slave_cnt) && (pos != (stop)->next)); \
- cnt++, pos = (pos)->next)
+#define bond_for_each_slave(bond, pos) \
+ list_for_each_entry(pos, &(bond)->slave_list, list)
/**
- * bond_for_each_slave - iterate the slaves list from head
- * @bond: the bond holding this list.
- * @pos: current slave.
- * @cnt: counter for max number of moves
+ * bond_for_each_slave_reverse - iterate in reverse from a given position
+ * @bond: the bond holding this list
+ * @pos: slave to continue from
*
* Caller must hold bond->lock
*/
-#define bond_for_each_slave(bond, pos, cnt) \
- bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave)
-
+#define bond_for_each_slave_continue_reverse(bond, pos) \
+ list_for_each_entry_continue_reverse(pos, &(bond)->slave_list, list)
#ifdef CONFIG_NET_POLL_CONTROLLER
extern atomic_t netpoll_block_tx;
@@ -174,8 +188,7 @@ struct vlan_entry {
struct slave {
struct net_device *dev; /* first - useful for panic debug */
- struct slave *next;
- struct slave *prev;
+ struct list_head list;
struct bonding *bond; /* our master */
int delay;
unsigned long jiffies;
@@ -215,7 +228,7 @@ struct slave {
*/
struct bonding {
struct net_device *dev; /* first - useful for panic debug */
- struct slave *first_slave;
+ struct list_head slave_list;
struct slave *curr_active_slave;
struct slave *current_arp_slave;
struct slave *primary_slave;
@@ -270,13 +283,10 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
struct net_device *slave_dev)
{
struct slave *slave = NULL;
- int i;
- bond_for_each_slave(bond, slave, i) {
- if (slave->dev == slave_dev) {
+ bond_for_each_slave(bond, slave)
+ if (slave->dev == slave_dev)
return slave;
- }
- }
return NULL;
}
@@ -477,10 +487,9 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn)
static inline struct slave *bond_slave_has_mac(struct bonding *bond,
const u8 *mac)
{
- int i = 0;
struct slave *tmp;
- bond_for_each_slave(bond, tmp, i)
+ bond_for_each_slave(bond, tmp)
if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
return tmp;
--
1.8.1.4
^ permalink raw reply related
* [PATCH net-next v3 0/5] bonding: groundwork and initial conversion to RCU
From: Nikolay Aleksandrov @ 2013-08-01 14:54 UTC (permalink / raw)
To: netdev; +Cc: davem, andy, fubar
From: Nikolay Aleksandrov <Nikolay Aleksandrov nikolay@redhat.com>
Hello,
This patchset aims to lay the groundwork, and do the initial conversion to
RCUism. I decided that it'll be much better to make the bonding RCU
conversion gradual, so patches can be reviewed and tested better rather
than having one huge patch (which I did in the beginning, before this).
The first patch is straightforward and it converts the bonding to the
standard list API, simplifying a lot of code, removing unnecessary local
variables and allowing to use the nice rculist API later. It also takes
care of some minor styling issues (re-arranging local variables longest ->
shortest, removing brackets for single statement if/else, leaving new line
before return statement etc.).
The second patch simplifies the conversion by removing unnecessary
read_lock(&bond->curr_slave_lock) in xmit paths that are to be converted
later, because we only care if the pointer is NULL or a slave there, since
we already have bond->lock the slave can't go away.
The third patch simplifies the broadcast xmit function by removing
the use of curr_active_slave and converting to standard list API. Also this
design of the broadcast xmit function avoids a subtle double packet tx race
when converted to RCU.
The fourth patch factors out the code that transmits skb through a slave
with given id (i.e. rr_tx_counter in rr mode, hashed value in xor mode) and
simplifies the active-backup xmit path because bond_dev_queue_xmit always
consumes the skb. The new bond_xmit_slave_id function is used in rr and xor
modes currently, but the plans are to use it in 3ad mode as well thus it's
made global. I've left the function prototype to be 81 chars so I wouldn't
break it, if this is an issue I can always break it in more lines.
The fifth patch introduces RCU by converting attach/detach and release to
RCU. It also converts dereferencing of curr_active_slave to rcu_dereference
although it's not fully converted to RCU, that is needed for the converted
xmit paths. And it converts roundrobin, broadcast, xor and active-backup
xmit paths to RCU. The 3ad and ALB/TLB modes acquire read_lock(&bond->lock)
to make sure that no slave will be removed and to sync properly with
enslave and release as before.
This way for the price of a little complexity, we'll be able to convert
individual parts of the bonding to RCU, and test them easier in the
process. If this patchset is accepted in some form, I'll post followups
in the next weeks that gradually convert the bonding to RCU and remove the
need for the rwlocks.
For performance notes please refer to patch 5 (RCU conversion one).
v3 summary:
patch 1 - fix 3ad bug where next_slave wasn't checked if we've crossed
to the first slave again (v2 introduced bug).
Note: I know that it's not necessary to check next_slave for NULL but
later when the mode is converted to RCU that'll be necessary so I put
it there from now
v2 summary:
patch 1 - new primitives as suggested, removal of slave_cnt for checking
if there're slaves in the bonding (using list_empty instead), using
bond_for_each_slave and introducing bond_for_each_slave_continue_reverse
for consistency, also making bond_next/prev_slave return NULL and
simplifying further, also make bond_for_each_slave_from check if pos is
NULL, also I think we fix an ALB bug in bond_alb_deinit_slave because
we have to check if any slaves have the released slave's MAC address, and
in case we have 2 slaves "> 1" would fail since this one has been already
detached and slave_cnt is == 1 exactly, so switch to !list_empty
patch 4 - don't set slave to NULL in roundrobin, it's not necessary
patch 5 - included the performance notes, converted curr_active_slave in
bond_sysfs.c to rcu_dereference, fixed a potential latency issue in slave
release because TX was unblocked after synchronize_rcu which might take a
while
Nikolay Aleksandrov (5):
bonding: convert to list API and replace bond's custom list
bonding: remove unnecessary read_locks of curr_slave_lock
bonding: simplify broadcast_xmit function
bonding: factor out slave id tx code and simplify xmit paths
bonding: initial RCU conversion
drivers/net/bonding/bond_3ad.c | 44 ++--
drivers/net/bonding/bond_alb.c | 57 +++--
drivers/net/bonding/bond_main.c | 433 +++++++++++++++-----------------------
drivers/net/bonding/bond_procfs.c | 12 +-
drivers/net/bonding/bond_sysfs.c | 62 +++---
drivers/net/bonding/bonding.h | 85 +++++---
6 files changed, 310 insertions(+), 383 deletions(-)
--
1.8.1.4
^ permalink raw reply
* Re: [PATCH] macvlan: validate flags
From: Michael S. Tsirkin @ 2013-08-01 14:45 UTC (permalink / raw)
To: Sergei Shtylyov
Cc: linux-kernel, David S. Miller, Roopa Prabhu, John Fastabend,
Patrick McHardy, netdev
In-Reply-To: <51FA7255.1070102@cogentembedded.com>
On Thu, Aug 01, 2013 at 06:36:05PM +0400, Sergei Shtylyov wrote:
> Hello.
>
> On 01-08-2013 14:48, Michael S. Tsirkin wrote:
>
> >commit df8ef8f3aaa6692970a436204c4429210addb23a
>
> Please also specify that commit's summary line in parens.
> This is the only way to uniquely identify the commit, and it's the
> requirement that came originally from Linus AFAIK.
Ouch, no idea why do I keep making this mistake.
Will do, thanks.
> >added a flags field to macvlan, which can be
> >controlled from userspace.
> >The idea is to make the interface future-proof
> >so we can add flags and not new fields.
>
> >However, flags value isn't validated, as a result,
> >userspace can't detect which flags are supported.
>
> >Cc: "David S. Miller" <davem@davemloft.net>
> >CC: Roopa Prabhu <roprabhu@cisco.com>
> >Cc: John Fastabend <john.r.fastabend@intel.com>
> >Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> WBR, Sergei
^ permalink raw reply
* Re: PROBLEM: 3.11.0-rc2+ lost of connectivity
From: Sebastiano Spicuglia @ 2013-08-01 14:40 UTC (permalink / raw)
To: Sebastiano Spicuglia, linux-kernel, jeffrey.t.kirsher,
jesse.brandeburg, bruce.w.allan, carolyn.wyborny,
donald.c.skidmore, gregory.v.rose, peter.p.waskiewicz.jr,
alexander.h.duyck, john.ronciak, tushar.n.dave, davem, netdev,
kuznet, jmorris, yoshfuji, kaber
In-Reply-To: <20130801143650.GB22250@order.stressinduktion.org>
Hi Hannes,
here the info about the commit:
commit 6c504ecf506705a6575541b28824e13090bd223b
Merge: 2408c2e bf903e4
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date: Fri Jul 26 14:40:10 2013 -0700
Regards
Sebastiano
On Thu, Aug 1, 2013 at 4:36 PM, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> On Thu, Aug 01, 2013 at 04:34:00PM +0200, Sebastiano Spicuglia wrote:
>> [Kernel version from /proc/version ]
>>
>> Linux version 3.11.0-rc2+ (root@cache.pdbg) (gcc version 4.7.2 (Debian
>> 4.7.2-5) ) #5 SMP Thu Aug 1 14:20:35 CEST 2013
>
> Which commit exactly?
>
> Thanks,
>
> Hannes
>
^ permalink raw reply
* Re: PROBLEM: 3.11.0-rc2+ lost of connectivity
From: Hannes Frederic Sowa @ 2013-08-01 14:36 UTC (permalink / raw)
To: Sebastiano Spicuglia
Cc: linux-kernel, jeffrey.t.kirsher, jesse.brandeburg, bruce.w.allan,
carolyn.wyborny, donald.c.skidmore, gregory.v.rose,
peter.p.waskiewicz.jr, alexander.h.duyck, john.ronciak,
tushar.n.dave, davem, netdev, kuznet, jmorris, yoshfuji, kaber
In-Reply-To: <CAOSRKdTOcYOZ4fD5gXe_57dA028rGmR30T32FQ6MeruAq2p04g@mail.gmail.com>
On Thu, Aug 01, 2013 at 04:34:00PM +0200, Sebastiano Spicuglia wrote:
> [Kernel version from /proc/version ]
>
> Linux version 3.11.0-rc2+ (root@cache.pdbg) (gcc version 4.7.2 (Debian
> 4.7.2-5) ) #5 SMP Thu Aug 1 14:20:35 CEST 2013
Which commit exactly?
Thanks,
Hannes
^ permalink raw reply
* Re: [PATCH] macvlan: validate flags
From: Sergei Shtylyov @ 2013-08-01 14:36 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: linux-kernel, David S. Miller, Roopa Prabhu, John Fastabend,
Patrick McHardy, netdev
In-Reply-To: <1375353992-7181-1-git-send-email-mst@redhat.com>
Hello.
On 01-08-2013 14:48, Michael S. Tsirkin wrote:
> commit df8ef8f3aaa6692970a436204c4429210addb23a
Please also specify that commit's summary line in parens.
This is the only way to uniquely identify the commit, and it's the requirement
that came originally from Linus AFAIK.
> added a flags field to macvlan, which can be
> controlled from userspace.
> The idea is to make the interface future-proof
> so we can add flags and not new fields.
> However, flags value isn't validated, as a result,
> userspace can't detect which flags are supported.
> Cc: "David S. Miller" <davem@davemloft.net>
> CC: Roopa Prabhu <roprabhu@cisco.com>
> Cc: John Fastabend <john.r.fastabend@intel.com>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
WBR, Sergei
^ permalink raw reply
* PROBLEM: 3.11.0-rc2+ lost of connectivity
From: Sebastiano Spicuglia @ 2013-08-01 14:34 UTC (permalink / raw)
To: linux-kernel, jeffrey.t.kirsher, jesse.brandeburg, bruce.w.allan,
carolyn.wyborny, donald.c.skidmore, gregory.v.rose,
peter.p.waskiewicz.jr, alexander.h.duyck, john.ronciak,
tushar.n.dave, davem, netdev, kuznet, jmorris, yoshfuji, kaber
[Summary]
the network layer stops to work without any message.
[Description]
The machine suddenly stops to be connected to the network.
Running "ifdown eth0" "ifup eth0" the network starts to work
again for few minutes and then the failure happens again.
It is not even possible to ping the machine.
/var/log/messages does not report anything wrong.
I instrumented the kernel with SystemTap to see what happens when the
machine is in the failure state.
the function ip_rcv is invoked.
the function ip_rcv_finish is invoked.
the function ip_local_deliver is invoked
the function ip_local_deliver_finish is invoked
the function tcp_v4_rcv is NOT invoked
When the network works the function tcp_v4_rcv is invoked.
Let me know if you need more information.
Below all the detail about the machine.
Thank you in advance
Sebastiano
[Kernel version from /proc/version ]
Linux version 3.11.0-rc2+ (root@cache.pdbg) (gcc version 4.7.2 (Debian
4.7.2-5) ) #5 SMP Thu Aug 1 14:20:35 CEST 2013
[Processor information from /proc/cpuinfo]
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 Duo CPU E6550 @ 2.33GHz
stepping : 11
microcode : 0xb3
cpu MHz : 1998.000
cache size : 4096 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
lm constant_tsc arch_perfmon pebs bts rep_good nopl aperfmperf pni
dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm lahf_lm
dtherm tpr_shadow vnmi flexpriority
bogomips : 4654.65
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 Duo CPU E6550 @ 2.33GHz
stepping : 11
microcode : 0xb3
cpu MHz : 1998.000
cache size : 4096 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
lm constant_tsc arch_perfmon pebs bts rep_good nopl aperfmperf pni
dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm lahf_lm
dtherm tpr_shadow vnmi flexpriority
bogomips : 4654.65
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
[Module information from /proc/modules]
nfnetlink_log 17396 0 - Live 0xffffffffa0325000
nfnetlink 12989 1 nfnetlink_log, Live 0xffffffffa01b5000
nfsd 192144 2 - Live 0xffffffffa0360000
auth_rpcgss 39122 1 nfsd, Live 0xffffffffa0355000
oid_registry 12419 1 auth_rpcgss, Live 0xffffffffa0107000
nfs_acl 12511 1 nfsd, Live 0xffffffffa00ba000
nfs 105664 0 - Live 0xffffffffa033a000
lockd 55654 2 nfsd,nfs, Live 0xffffffffa0316000
fscache 38267 1 nfs, Live 0xffffffffa032f000
sunrpc 160404 6 nfsd,auth_rpcgss,nfs_acl,nfs,lockd, Live 0xffffffffa02ed000
loop 22869 0 - Live 0xffffffffa023d000
snd_hda_codec_analog 78587 1 - Live 0xffffffffa0228000
snd_hda_intel 31234 0 - Live 0xffffffffa0157000
snd_hda_codec 122851 2 snd_hda_codec_analog,snd_hda_intel, Live
0xffffffffa0209000
snd_hwdep 13189 1 snd_hda_codec, Live 0xffffffffa00a5000
snd_pcm 68479 2 snd_hda_intel,snd_hda_codec, Live 0xffffffffa01a3000
snd_page_alloc 13018 2 snd_hda_intel,snd_pcm, Live 0xffffffffa00b5000
snd_timer 22773 1 snd_pcm, Live 0xffffffffa0126000
snd 53014 6 snd_hda_codec_analog,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_pcm,snd_timer,
Live 0xffffffffa00ce000
i915 518452 1 - Live 0xffffffffa026d000
tpm_infineon 12985 0 - Live 0xffffffffa0060000
coretemp 12898 0 - Live 0xffffffffa00c9000
hid_apple 12633 0 - Live 0xffffffffa00aa000
drm_kms_helper 31837 1 i915, Live 0xffffffffa0057000
drm 208643 2 i915,drm_kms_helper, Live 0xffffffffa016f000
kvm_intel 123456 0 - Live 0xffffffffa024d000
kvm 309880 1 kvm_intel, Live 0xffffffffa01bc000
usbhid 40964 0 - Live 0xffffffffa0163000
hid 81894 2 hid_apple,usbhid, Live 0xffffffffa0142000
hp_wmi 13362 0 - Live 0xffffffffa0121000
psmouse 74786 0 - Live 0xffffffffa012e000
soundcore 13026 1 snd, Live 0xffffffffa011c000
sparse_keymap 12760 1 hp_wmi, Live 0xffffffffa0117000
iTCO_wdt 12831 0 - Live 0xffffffffa010d000
iTCO_vendor_support 12704 1 iTCO_wdt, Live 0xffffffffa0112000
rfkill 19242 1 hp_wmi, Live 0xffffffffa0101000
parport_pc 22409 0 - Live 0xffffffffa00eb000
parport 31855 1 parport_pc, Live 0xffffffffa00f8000
lpc_ich 16764 0 - Live 0xffffffffa00df000
mfd_core 12601 1 lpc_ich, Live 0xffffffffa00f3000
evdev 17610 10 - Live 0xffffffffa00e5000
acpi_cpufreq 13277 0 - Live 0xffffffffa00a0000
tpm_tis 17320 0 - Live 0xffffffffa00bf000
mperf 12411 1 acpi_cpufreq, Live 0xffffffffa007c000
tpm 18071 2 tpm_infineon,tpm_tis, Live 0xffffffffa0092000
tpm_bios 17540 1 tpm, Live 0xffffffffa0086000
processor 28184 3 acpi_cpufreq, Live 0xffffffffa0098000
video 17844 1 i915, Live 0xffffffffa008c000
serio_raw 12940 0 - Live 0xffffffffa0081000
i2c_algo_bit 12841 1 i915, Live 0xffffffffa0077000
pcspkr 12595 0 - Live 0xffffffffa00b0000
thermal_sys 23293 2 processor,video, Live 0xffffffffa0069000
wmi 13243 1 hp_wmi, Live 0xffffffffa0072000
microcode 26065 0 - Live 0xffffffffa0024000
button 12944 1 i915, Live 0xffffffffa0039000
floppy 53102 0 - Live 0xffffffffa0049000
sr_mod 21988 0 - Live 0xffffffffa003e000
cdrom 35173 1 sr_mod, Live 0xffffffffa002f000
e1000e 139582 0 - Live 0xffffffffa0000000
[Loaded driver and hardware information from /proc/ioports]
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0064-0064 : keyboard
0070-0071 : rtc0
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
0170-0177 : 0000:00:1f.2
0170-0177 : ata_piix
01f0-01f7 : 0000:00:1f.2
01f0-01f7 : ata_piix
0376-0376 : 0000:00:1f.2
0376-0376 : ata_piix
0378-037a : parport0
03c0-03df : vga+
03f2-03f2 : floppy
03f4-03f5 : floppy
03f6-03f6 : 0000:00:1f.2
03f6-03f6 : ata_piix
03f7-03f7 : floppy
03f8-03ff : serial
0400-041f : pnp 00:0d
0420-043f : pnp 00:0d
0440-045f : pnp 00:0d
0460-047f : pnp 00:0d
0460-0461 : ACPI PM1b_CNT_BLK
0480-048f : pnp 00:0d
04d0-04d1 : pnp 00:0e
0cf8-0cff : PCI conf1
1100-111f : 0000:00:19.0
1120-113f : 0000:00:1a.0
1120-113f : uhci_hcd
1140-115f : 0000:00:1a.1
1140-115f : uhci_hcd
1160-117f : 0000:00:1a.2
1160-117f : uhci_hcd
1180-119f : 0000:00:1d.0
1180-119f : uhci_hcd
11a0-11bf : 0000:00:1d.1
11a0-11bf : uhci_hcd
11e0-11ef : 0000:00:03.2
11e0-11ef : ata_generic
11f0-11ff : 0000:00:1f.2
11f0-11ff : ata_piix
1200-120f : 0000:00:1f.2
1200-120f : ata_piix
1210-121f : 0000:00:1f.5
1210-121f : ata_piix
1220-122f : 0000:00:1f.5
1220-122f : ata_piix
1230-1237 : 0000:00:02.0
1238-123f : 0000:00:03.2
1238-123f : ata_generic
1240-1247 : 0000:00:03.2
1240-1247 : ata_generic
1248-124f : 0000:00:03.3
1248-124f : serial
1260-1267 : 0000:00:1f.5
1260-1267 : ata_piix
1268-126f : 0000:00:1f.5
1268-126f : ata_piix
1270-1273 : 0000:00:03.2
1270-1273 : ata_generic
1274-1277 : 0000:00:03.2
1274-1277 : ata_generic
1280-1283 : 0000:00:1f.5
1280-1283 : ata_piix
1284-1287 : 0000:00:1f.5
1284-1287 : ata_piix
2000-2fff : PCI Bus 0000:20
3000-3fff : PCI Bus 0000:30
f800-f803 : ACPI PM1a_EVT_BLK
f804-f805 : ACPI PM1a_CNT_BLK
f808-f80b : ACPI PM_TMR
f810-f815 : ACPI CPU throttle
f820-f82f : ACPI GPE0_BLK
f828-f82f : gpio_ich
f830-f833 : iTCO_wdt
f830-f833 : iTCO_wdt
f860-f87f : iTCO_wdt
f860-f87f : iTCO_wdt
fa00-fa3f : gpio_ich
fa00-fa3f : 0000:00:1f.0
fa00-fa3f : pnp 00:0d
fc00-fc7f : pnp 00:0d
fc80-fcff : pnp 00:0d
fe00-fe7f : pnp 00:0d
fe80-feff : pnp 00:0d
[Loaded driver and hardware information from /proc/iomem]
00000000-00000fff : reserved
00001000-0009fbff : System RAM
0009fc00-0009ffff : reserved
000c0000-000c7fff : Video ROM
000cd400-000e3fff : pnp 00:0f
000e8000-000fffff : reserved
000f0000-000fffff : System ROM
00100000-7d2afdff : System RAM
01000000-0169bda8 : Kernel code
0169bda9-01ccf6ff : Kernel data
01dc0000-01eb1fff : Kernel bss
7d2afe00-7d2b1e9f : ACPI Non-volatile Storage
7d2b1ea0-7dffffff : reserved
7e000000-7fffffff : RAM buffer
80000000-801fffff : PCI Bus 0000:20
80200000-803fffff : PCI Bus 0000:20
80400000-805fffff : PCI Bus 0000:30
80600000-807fffff : PCI Bus 0000:30
80800000-80800fff : Intel Flush Page
80804000-80807fff : i915 MCHBAR
e0000000-efffffff : 0000:00:02.0
f0000000-f00fffff : 0000:00:02.0
f0100000-f017ffff : 0000:00:02.0
f0180000-f019ffff : 0000:00:19.0
f0180000-f019ffff : e1000e
f01a0000-f01a3fff : 0000:00:1b.0
f01a0000-f01a3fff : ICH HD audio
f01a4000-f01a4fff : 0000:00:03.3
f01a5000-f01a5fff : 0000:00:19.0
f01a5000-f01a5fff : e1000e
f01a6000-f01a63ff : 0000:00:1a.7
f01a6000-f01a63ff : ehci_hcd
f01a6400-f01a67ff : 0000:00:1d.7
f01a6400-f01a67ff : ehci_hcd
f01a6900-f01a690f : 0000:00:03.0
f4000000-f7ffffff : PCI MMCONFIG 0000 [bus 00-3f]
f4000000-f7ffffff : reserved
f4000000-f7ffffff : pnp 00:0f
fec00000-fed3ffff : reserved
fec00000-fec003ff : IOAPIC 0
fec01000-fecfffff : pnp 00:0f
fed00000-fed003ff : HPET 0
fed00400-fed3ffff : pnp 00:0f
fed1f410-fed1f414 : iTCO_wdt
fed1f410-fed1f414 : iTCO_wdt
fed45000-ffffffff : reserved
fed90000-fed90fff : dmar0
fed91000-fed91fff : dmar1
fed92000-fed92fff : dmar2
fed93000-fed93fff : dmar3
fee00000-fee00fff : Local APIC
[PCI information with 'lspci -vvv' as root]
00:00.0 Host bridge: Intel Corporation 82Q35 Express DRAM Controller (rev 02)
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort+ >SERR- <PERR- INTx-
Latency: 0
Capabilities: [e0] Vendor Specific Information: Len=0b <?>
Kernel driver in use: agpgart-intel
00:02.0 VGA compatible controller: Intel Corporation 82Q35 Express
Integrated Graphics Controller (rev 02) (prog-if 00 [VGA controller])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 43
Region 0: Memory at f0100000 (32-bit, non-prefetchable) [size=512K]
Region 1: I/O ports at 1230 [size=8]
Region 2: Memory at e0000000 (32-bit, prefetchable) [size=256M]
Region 3: Memory at f0000000 (32-bit, non-prefetchable) [size=1M]
Expansion ROM at <unassigned> [disabled]
Capabilities: [90] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0300c Data: 41e1
Capabilities: [d0] Power Management version 2
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Kernel driver in use: i915
00:03.0 Communication controller: Intel Corporation 82Q35 Express MEI
Controller (rev 02)
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx+
Latency: 0
Interrupt: pin A routed to IRQ 5
Region 0: Memory at f01a6900 (64-bit, non-prefetchable) [size=16]
Capabilities: [50] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [8c] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
00:03.2 IDE interface: Intel Corporation 82Q35 Express PT IDER
Controller (rev 02) (prog-if 85 [Master SecO PriO])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin C routed to IRQ 18
Region 0: I/O ports at 1238 [size=8]
Region 1: I/O ports at 1270 [size=4]
Region 2: I/O ports at 1240 [size=8]
Region 3: I/O ports at 1274 [size=4]
Region 4: I/O ports at 11e0 [size=16]
Capabilities: [c8] Power Management version 3
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [d0] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
Kernel driver in use: ata_generic
00:03.3 Serial controller: Intel Corporation 82Q35 Express Serial KT
Controller (rev 02) (prog-if 02 [16550])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 17
Region 0: I/O ports at 1248 [size=8]
Region 1: Memory at f01a4000 (32-bit, non-prefetchable) [size=4K]
Capabilities: [c8] Power Management version 3
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [d0] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
Kernel driver in use: serial
00:19.0 Ethernet controller: Intel Corporation 82566DM-2 Gigabit
Network Connection (rev 02)
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 42
Region 0: Memory at f0180000 (32-bit, non-prefetchable) [size=128K]
Region 1: Memory at f01a5000 (32-bit, non-prefetchable) [size=4K]
Region 2: I/O ports at 1100 [size=32]
Capabilities: [c8] Power Management version 2
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=1 PME-
Capabilities: [d0] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 00000000fee0300c Data: 41d2
Capabilities: [e0] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: e1000e
00:1a.0 USB controller: Intel Corporation 82801I (ICH9 Family) USB
UHCI Controller #4 (rev 02) (prog-if 00 [UHCI])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 20
Region 4: I/O ports at 1120 [size=32]
Capabilities: [50] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: uhci_hcd
00:1a.1 USB controller: Intel Corporation 82801I (ICH9 Family) USB
UHCI Controller #5 (rev 02) (prog-if 00 [UHCI])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 21
Region 4: I/O ports at 1140 [size=32]
Capabilities: [50] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: uhci_hcd
00:1a.2 USB controller: Intel Corporation 82801I (ICH9 Family) USB
UHCI Controller #6 (rev 02) (prog-if 00 [UHCI])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin C routed to IRQ 22
Region 4: I/O ports at 1160 [size=32]
Capabilities: [50] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: uhci_hcd
00:1a.7 USB controller: Intel Corporation 82801I (ICH9 Family) USB2
EHCI Controller #2 (rev 02) (prog-if 20 [EHCI])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin C routed to IRQ 22
Region 0: Memory at f01a6000 (32-bit, non-prefetchable) [size=1K]
Capabilities: [50] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [58] Debug port: BAR=1 offset=00a0
Capabilities: [98] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: ehci-pci
00:1b.0 Audio device: Intel Corporation 82801I (ICH9 Family) HD Audio
Controller (rev 02)
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 44
Region 0: Memory at f01a0000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [50] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 00000000fee0300c Data: 4122
Capabilities: [70] Express (v1) Root Complex Integrated Endpoint, MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
ExtTag- RBE- FLReset+
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop+
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #0, Speed unknown, Width x0, ASPM unknown, Latency L0
<64ns, L1 <1us
ClockPM- Surprise- LLActRep- BwNot-
LnkCtl: ASPM Disabled; Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed unknown, Width x0, TrErr- Train- SlotClk- DLActive-
BWMgmt- ABWMgmt-
Capabilities: [100 v1] Virtual Channel
Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
Arb: Fixed- WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=01
Status: NegoPending- InProgress-
VC1: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=1 ArbSelect=Fixed TC/VC=80
Status: NegoPending- InProgress-
Capabilities: [130 v1] Root Complex Link
Desc: PortNumber=0f ComponentID=02 EltType=Config
Link0: Desc: TargetPort=00 TargetComponent=02 AssocRCRB-
LinkType=MemMapped LinkValid+
Addr: 00000000fed1c000
Kernel driver in use: snd_hda_intel
00:1c.0 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express
Port 1 (rev 02) (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary=00, secondary=20, subordinate=20, sec-latency=0
I/O behind bridge: 00002000-00002fff
Memory behind bridge: 80000000-801fffff
Prefetchable memory behind bridge: 0000000080200000-00000000803fffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- <SERR- <PERR-
BridgeCtl: Parity- SERR+ NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Express (v1) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
ExtTag- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #1, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <1us, L1 <4us
ClockPM- Surprise- LLActRep+ BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x0, TrErr- Train- SlotClk+ DLActive-
BWMgmt- ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+
Slot #2, PowerLimit 10.000W; Interlock- NoCompl-
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet- Interlock-
Changed: MRL- PresDet- LinkState-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0300c Data: 4171
Capabilities: [90] Subsystem: Hewlett-Packard Company Device 2818
Capabilities: [a0] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [100 v1] Virtual Channel
Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
Arb: Fixed+ WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed+ WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=ff
Status: NegoPending- InProgress-
Capabilities: [180 v1] Root Complex Link
Desc: PortNumber=01 ComponentID=02 EltType=Config
Link0: Desc: TargetPort=00 TargetComponent=02 AssocRCRB-
LinkType=MemMapped LinkValid+
Addr: 00000000fed1c000
Kernel driver in use: pcieport
00:1c.1 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express
Port 2 (rev 02) (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary=00, secondary=30, subordinate=30, sec-latency=0
I/O behind bridge: 00003000-00003fff
Memory behind bridge: 80400000-805fffff
Prefetchable memory behind bridge: 0000000080600000-00000000807fffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- <SERR- <PERR-
BridgeCtl: Parity- SERR+ NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Express (v1) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
ExtTag- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #2, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <1us, L1 <4us
ClockPM- Surprise- LLActRep+ BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x0, TrErr- Train- SlotClk+ DLActive-
BWMgmt- ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+
Slot #0, PowerLimit 0.000W; Interlock- NoCompl-
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet- Interlock-
Changed: MRL- PresDet- LinkState-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0300c Data: 4181
Capabilities: [90] Subsystem: Hewlett-Packard Company Device 2818
Capabilities: [a0] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [100 v1] Virtual Channel
Caps: LPEVC=0 RefClk=100ns PATEntryBits=1
Arb: Fixed+ WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed+ WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VC=ff
Status: NegoPending- InProgress-
Capabilities: [180 v1] Root Complex Link
Desc: PortNumber=02 ComponentID=02 EltType=Config
Link0: Desc: TargetPort=00 TargetComponent=02 AssocRCRB-
LinkType=MemMapped LinkValid+
Addr: 00000000fed1c000
Kernel driver in use: pcieport
00:1d.0 USB controller: Intel Corporation 82801I (ICH9 Family) USB
UHCI Controller #1 (rev 02) (prog-if 00 [UHCI])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 20
Region 4: I/O ports at 1180 [size=32]
Capabilities: [50] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: uhci_hcd
00:1d.1 USB controller: Intel Corporation 82801I (ICH9 Family) USB
UHCI Controller #2 (rev 02) (prog-if 00 [UHCI])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 21
Region 4: I/O ports at 11a0 [size=32]
Capabilities: [50] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: uhci_hcd
00:1d.7 USB controller: Intel Corporation 82801I (ICH9 Family) USB2
EHCI Controller #1 (rev 02) (prog-if 20 [EHCI])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 20
Region 0: Memory at f01a6400 (32-bit, non-prefetchable) [size=1K]
Capabilities: [50] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [58] Debug port: BAR=1 offset=00a0
Capabilities: [98] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: ehci-pci
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev 92)
(prog-if 01 [Subtractive decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Bus: primary=00, secondary=07, subordinate=07, sec-latency=32
I/O behind bridge: 0000f000-00000fff
Memory behind bridge: fff00000-000fffff
Prefetchable memory behind bridge: 00000000fff00000-00000000000fffff
Secondary status: 66MHz- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort+ <SERR- <PERR-
BridgeCtl: Parity- SERR+ NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [50] Subsystem: Hewlett-Packard Company Device 2818
00:1f.0 ISA bridge: Intel Corporation 82801IO (ICH9DO) LPC Interface
Controller (rev 02)
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Capabilities: [e0] Vendor Specific Information: Len=0c <?>
Kernel driver in use: lpc_ich
00:1f.2 IDE interface: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 4
port SATA Controller [IDE mode] (rev 02) (prog-if 8a [Master SecP
PriP])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 18
Region 0: I/O ports at 01f0 [size=8]
Region 1: I/O ports at 03f4 [size=1]
Region 2: I/O ports at 0170 [size=8]
Region 3: I/O ports at 0374 [size=1]
Region 4: I/O ports at 11f0 [size=16]
Region 5: I/O ports at 1200 [size=16]
Capabilities: [70] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [b0] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: ata_piix
00:1f.5 IDE interface: Intel Corporation 82801I (ICH9 Family) 2 port
SATA Controller [IDE mode] (rev 02) (prog-if 85 [Master SecO PriO])
Subsystem: Hewlett-Packard Company Device 2818
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin B routed to IRQ 18
Region 0: I/O ports at 1260 [size=8]
Region 1: I/O ports at 1280 [size=4]
Region 2: I/O ports at 1268 [size=8]
Region 3: I/O ports at 1284 [size=4]
Region 4: I/O ports at 1210 [size=16]
Region 5: I/O ports at 1220 [size=16]
Capabilities: [70] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [b0] PCI Advanced Features
AFCap: TP+ FLR+
AFCtrl: FLR-
AFStatus: TP-
Kernel driver in use: ata_piix
^ permalink raw reply
* [PATCH net-next] bnx2x: Revising locking scheme for MAC configuration
From: Yuval Mintz @ 2013-08-01 14:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Yuval Mintz, Ariel Elior, Eilon Greenstein
On very rare occasions, repeated load/unload stress test in the presence of
our storage driver (bnx2i/bnx2fc) causes a kernel panic in bnx2x code
(NULL pointer dereference). Stack traces indicate the issue happens during MAC
configuration; thorough code review showed that indeed several races exist
in which one thread can iterate over the list of configured MACs while another
deletes entries from the same list.
This patch adds a varient on the single-writer/Multiple-reader lock mechanism -
It utilizes an already exsiting bottom-half lock, using it so that Whenever
a writer is unable to continue due to the existence of another writer/reader,
it pends its request for future deliverance.
The writer / last readers will check for the existence of such requests and
perform them instead of the original initiator.
This prevents the writer from having to sleep while waiting for the lock
to be accessible, which might cause deadlocks given the locks already
held by the writer.
Another result of this patch is that setting of Rx Mode is now made in
sleepable context - Setting of Rx Mode is made under a bottom-half lock, which
was always nontrivial for the bnx2x driver, as the HW/FW configuration requires
wait for completions.
Since sleep was impossible (due to the sleepless-context), various mechanisms
were utilized to prevent the calling thread from sleep, but the truth was that
when the caller thread (i.e, the one calling ndo_set_rx_mode()) returned, the
Rx mode was still not set in HW/FW.
bnx2x_set_rx_mode() will now overtly schedule for the Rx changes to be
configured by the sp_rtnl_task which hold the RTNL lock and is sleepable
context.
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Ariel Elior <ariele@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
Dave, this is a relatively large fix for a relatively small (and rare)
bug - thus we're designating it to `net-next'.
Please consider applying the patch.
Thanks,
Yuval
---
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 16 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 1 +
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 56 ++--
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 299 ++++++++++++++++++++--
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 16 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 10 +-
7 files changed, 340 insertions(+), 60 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index dedbd76..439387b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1331,7 +1331,7 @@ enum {
BNX2X_SP_RTNL_ENABLE_SRIOV,
BNX2X_SP_RTNL_VFPF_MCAST,
BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
- BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+ BNX2X_SP_RTNL_RX_MODE,
BNX2X_SP_RTNL_HYPERVISOR_VLAN,
};
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index ee350bd..11abdcc 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -2060,7 +2060,11 @@ void bnx2x_squeeze_objects(struct bnx2x *bp)
rparam.mcast_obj = &bp->mcast_obj;
__set_bit(RAMROD_DRV_CLR_ONLY, &rparam.ramrod_flags);
- /* Add a DEL command... */
+ /* Add a DEL command... - Since we're doing a driver cleanup only,
+ * we take a lock surrounding both the initial send and the CONTs,
+ * as we don't want a true completion to disrupt us in the middle.
+ */
+ netif_addr_lock_bh(bp->dev);
rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL);
if (rc < 0)
BNX2X_ERR("Failed to add a new DEL command to a multi-cast object: %d\n",
@@ -2072,11 +2076,13 @@ void bnx2x_squeeze_objects(struct bnx2x *bp)
if (rc < 0) {
BNX2X_ERR("Failed to clean multi-cast object: %d\n",
rc);
+ netif_addr_unlock_bh(bp->dev);
return;
}
rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT);
}
+ netif_addr_unlock_bh(bp->dev);
}
#ifndef BNX2X_STOP_ON_ERROR
@@ -2432,9 +2438,7 @@ int bnx2x_load_cnic(struct bnx2x *bp)
}
/* Initialize Rx filter. */
- netif_addr_lock_bh(bp->dev);
- bnx2x_set_rx_mode(bp->dev);
- netif_addr_unlock_bh(bp->dev);
+ bnx2x_set_rx_mode_inner(bp);
/* re-read iscsi info */
bnx2x_get_iscsi_info(bp);
@@ -2704,9 +2708,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Start fast path */
/* Initialize Rx filter. */
- netif_addr_lock_bh(bp->dev);
- bnx2x_set_rx_mode(bp->dev);
- netif_addr_unlock_bh(bp->dev);
+ bnx2x_set_rx_mode_inner(bp);
/* Start the Tx */
switch (load_mode) {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index c07a6d0..38be494 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -418,6 +418,7 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set);
* netif_addr_lock_bh()
*/
void bnx2x_set_rx_mode(struct net_device *dev);
+void bnx2x_set_rx_mode_inner(struct bnx2x *bp);
/**
* bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW.
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index e5da078..bd064c6 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -9628,11 +9628,9 @@ sp_rtnl_not_reset:
}
}
- if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
- &bp->sp_rtnl_state)) {
- DP(BNX2X_MSG_SP,
- "sending set storm rx mode vf pf channel message from rtnl sp-task\n");
- bnx2x_vfpf_storm_rx_mode(bp);
+ if (test_and_clear_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state)) {
+ DP(BNX2X_MSG_SP, "Handling Rx Mode setting\n");
+ bnx2x_set_rx_mode_inner(bp);
}
if (test_and_clear_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
@@ -11849,34 +11847,48 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
void bnx2x_set_rx_mode(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
- u32 rx_mode = BNX2X_RX_MODE_NORMAL;
if (bp->state != BNX2X_STATE_OPEN) {
DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
return;
+ } else {
+ /* Schedule an SP task to handle rest of change */
+ DP(NETIF_MSG_IFUP, "Scheduling an Rx mode change\n");
+ smp_mb__before_clear_bit();
+ set_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state);
+ smp_mb__after_clear_bit();
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
}
+}
+
+void bnx2x_set_rx_mode_inner(struct bnx2x *bp)
+{
+ u32 rx_mode = BNX2X_RX_MODE_NORMAL;
DP(NETIF_MSG_IFUP, "dev->flags = %x\n", bp->dev->flags);
- if (dev->flags & IFF_PROMISC)
+ netif_addr_lock_bh(bp->dev);
+
+ if (bp->dev->flags & IFF_PROMISC) {
rx_mode = BNX2X_RX_MODE_PROMISC;
- else if ((dev->flags & IFF_ALLMULTI) ||
- ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) &&
- CHIP_IS_E1(bp)))
+ } else if ((bp->dev->flags & IFF_ALLMULTI) ||
+ ((netdev_mc_count(bp->dev) > BNX2X_MAX_MULTICAST) &&
+ CHIP_IS_E1(bp))) {
rx_mode = BNX2X_RX_MODE_ALLMULTI;
- else {
+ } else {
if (IS_PF(bp)) {
/* some multicasts */
if (bnx2x_set_mc_list(bp) < 0)
rx_mode = BNX2X_RX_MODE_ALLMULTI;
+ /* release bh lock, as bnx2x_set_uc_list might sleep */
+ netif_addr_unlock_bh(bp->dev);
if (bnx2x_set_uc_list(bp) < 0)
rx_mode = BNX2X_RX_MODE_PROMISC;
+ netif_addr_lock_bh(bp->dev);
} else {
/* configuring mcast to a vf involves sleeping (when we
- * wait for the pf's response). Since this function is
- * called from non sleepable context we must schedule
- * a work item for this purpose
+ * wait for the pf's response).
*/
smp_mb__before_clear_bit();
set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
@@ -11894,22 +11906,20 @@ void bnx2x_set_rx_mode(struct net_device *dev)
/* Schedule the rx_mode command */
if (test_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state)) {
set_bit(BNX2X_FILTER_RX_MODE_SCHED, &bp->sp_state);
+ netif_addr_unlock_bh(bp->dev);
return;
}
if (IS_PF(bp)) {
bnx2x_set_storm_rx_mode(bp);
+ netif_addr_unlock_bh(bp->dev);
} else {
- /* configuring rx mode to storms in a vf involves sleeping (when
- * we wait for the pf's response). Since this function is
- * called from non sleepable context we must schedule
- * a work item for this purpose
+ /* VF will need to request the PF to make this change, and so
+ * the VF needs to release the bottom-half lock prior to the
+ * request (as it will likely require sleep on the VF side)
*/
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
- &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ netif_addr_unlock_bh(bp->dev);
+ bnx2x_vfpf_storm_rx_mode(bp);
}
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 8f03c98..1d46b68 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -159,16 +159,6 @@ static inline void __bnx2x_exe_queue_reset_pending(
}
}
-static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp,
- struct bnx2x_exe_queue_obj *o)
-{
- spin_lock_bh(&o->lock);
-
- __bnx2x_exe_queue_reset_pending(bp, o);
-
- spin_unlock_bh(&o->lock);
-}
-
/**
* bnx2x_exe_queue_step - execute one execution chunk atomically
*
@@ -176,7 +166,7 @@ static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp,
* @o: queue
* @ramrod_flags: flags
*
- * (Atomicity is ensured using the exe_queue->lock).
+ * (Should be called while holding the exe_queue->lock).
*/
static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
struct bnx2x_exe_queue_obj *o,
@@ -187,8 +177,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
memset(&spacer, 0, sizeof(spacer));
- spin_lock_bh(&o->lock);
-
/* Next step should not be performed until the current is finished,
* unless a DRV_CLEAR_ONLY bit is set. In this case we just want to
* properly clear object internals without sending any command to the FW
@@ -200,7 +188,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: resetting a pending_comp list\n");
__bnx2x_exe_queue_reset_pending(bp, o);
} else {
- spin_unlock_bh(&o->lock);
return 1;
}
}
@@ -228,10 +215,8 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
}
/* Sanity check */
- if (!cur_len) {
- spin_unlock_bh(&o->lock);
+ if (!cur_len)
return 0;
- }
rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags);
if (rc < 0)
@@ -245,7 +230,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
*/
__bnx2x_exe_queue_reset_pending(bp, o);
- spin_unlock_bh(&o->lock);
return rc;
}
@@ -432,12 +416,219 @@ static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
return true;
}
+/**
+ * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details: Non-blocking implementation; should be called under execution
+ * queue lock.
+ */
+static int __bnx2x_vlan_mac_h_write_trylock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ if (o->head_reader) {
+ DP(BNX2X_MSG_SP, "vlan_mac_lock writer - There are readers; Busy\n");
+ return -EBUSY;
+ }
+
+ DP(BNX2X_MSG_SP, "vlan_mac_lock writer - Taken\n");
+ return 0;
+}
+
+/**
+ * __bnx2x_vlan_mac_h_exec_pending - execute step instead of a previous step
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details Should be called under execution queue lock; notice it might release
+ * and reclaim it during its run.
+ */
+static void __bnx2x_vlan_mac_h_exec_pending(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ int rc;
+ unsigned long ramrod_flags = o->saved_ramrod_flags;
+
+ DP(BNX2X_MSG_SP, "vlan_mac_lock execute pending command with ramrod flags %lu\n",
+ ramrod_flags);
+ o->head_exe_request = false;
+ o->saved_ramrod_flags = 0;
+ rc = bnx2x_exe_queue_step(bp, &o->exe_queue, &ramrod_flags);
+ if (rc != 0) {
+ BNX2X_ERR("execution of pending commands failed with rc %d\n",
+ rc);
+#ifdef BNX2X_STOP_ON_ERROR
+ bnx2x_panic();
+#endif
+ }
+}
+
+/**
+ * __bnx2x_vlan_mac_h_pend - Pend an execution step which couldn't run
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ * @ramrod_flags: ramrod flags of missed execution
+ *
+ * @details Should be called under execution queue lock.
+ */
+static void __bnx2x_vlan_mac_h_pend(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o,
+ unsigned long ramrod_flags)
+{
+ o->head_exe_request = true;
+ o->saved_ramrod_flags = ramrod_flags;
+ DP(BNX2X_MSG_SP, "Placing pending execution with ramrod flags %lu\n",
+ ramrod_flags);
+}
+
+/**
+ * __bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details Should be called under execution queue lock. Notice if a pending
+ * execution exists, it would perform it - possibly releasing and
+ * reclaiming the execution queue lock.
+ */
+static void __bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ /* It's possible a new pending execution was added since this writer
+ * executed. If so, execute again. [Ad infinitum]
+ */
+ while (o->head_exe_request) {
+ DP(BNX2X_MSG_SP, "vlan_mac_lock - writer release encountered a pending request\n");
+ __bnx2x_vlan_mac_h_exec_pending(bp, o);
+ }
+}
+
+/**
+ * bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details Notice if a pending execution exists, it would perform it -
+ * possibly releasing and reclaiming the execution queue lock.
+ */
+void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ spin_lock_bh(&o->exe_queue.lock);
+ __bnx2x_vlan_mac_h_write_unlock(bp, o);
+ spin_unlock_bh(&o->exe_queue.lock);
+}
+
+/**
+ * __bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details Should be called under the execution queue lock. May sleep. May
+ * release and reclaim execution queue lock during its run.
+ */
+static int __bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ /* If we got here, we're holding lock --> no WRITER exists */
+ o->head_reader++;
+ DP(BNX2X_MSG_SP, "vlan_mac_lock - locked reader - number %d\n",
+ o->head_reader);
+
+ return 0;
+}
+
+/**
+ * bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details May sleep. Claims and releases execution queue lock during its run.
+ */
+int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ int rc;
+
+ spin_lock_bh(&o->exe_queue.lock);
+ rc = __bnx2x_vlan_mac_h_read_lock(bp, o);
+ spin_unlock_bh(&o->exe_queue.lock);
+
+ return rc;
+}
+
+/**
+ * __bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details Should be called under execution queue lock. Notice if a pending
+ * execution exists, it would be performed if this was the last
+ * reader. possibly releasing and reclaiming the execution queue lock.
+ */
+static void __bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ if (!o->head_reader) {
+ BNX2X_ERR("Need to release vlan mac reader lock, but lock isn't taken\n");
+#ifdef BNX2X_STOP_ON_ERROR
+ bnx2x_panic();
+#endif
+ } else {
+ o->head_reader--;
+ DP(BNX2X_MSG_SP, "vlan_mac_lock - decreased readers to %d\n",
+ o->head_reader);
+ }
+
+ /* It's possible a new pending execution was added, and that this reader
+ * was last - if so we need to execute the command.
+ */
+ if (!o->head_reader && o->head_exe_request) {
+ DP(BNX2X_MSG_SP, "vlan_mac_lock - reader release encountered a pending request\n");
+
+ /* Writer release will do the trick */
+ __bnx2x_vlan_mac_h_write_unlock(bp, o);
+ }
+}
+
+/**
+ * bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock
+ *
+ * @bp: device handle
+ * @o: vlan_mac object
+ *
+ * @details Notice if a pending execution exists, it would be performed if this
+ * was the last reader. Claims and releases the execution queue lock
+ * during its run.
+ */
+void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o)
+{
+ spin_lock_bh(&o->exe_queue.lock);
+ __bnx2x_vlan_mac_h_read_unlock(bp, o);
+ spin_unlock_bh(&o->exe_queue.lock);
+}
+
static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
int n, u8 *base, u8 stride, u8 size)
{
struct bnx2x_vlan_mac_registry_elem *pos;
u8 *next = base;
int counter = 0;
+ int read_lock;
+
+ DP(BNX2X_MSG_SP, "get_n_elements - taking vlan_mac_lock (reader)\n");
+ read_lock = bnx2x_vlan_mac_h_read_lock(bp, o);
+ if (read_lock != 0)
+ BNX2X_ERR("get_n_elements failed to get vlan mac reader lock; Access without lock\n");
/* traverse list */
list_for_each_entry(pos, &o->head, link) {
@@ -449,6 +640,12 @@ static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
next += stride + size;
}
}
+
+ if (read_lock == 0) {
+ DP(BNX2X_MSG_SP, "get_n_elements - releasing vlan_mac_lock (reader)\n");
+ bnx2x_vlan_mac_h_read_unlock(bp, o);
+ }
+
return counter * ETH_ALEN;
}
@@ -1397,6 +1594,32 @@ static int bnx2x_wait_vlan_mac(struct bnx2x *bp,
return -EBUSY;
}
+static int __bnx2x_vlan_mac_execute_step(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o,
+ unsigned long *ramrod_flags)
+{
+ int rc = 0;
+
+ spin_lock_bh(&o->exe_queue.lock);
+
+ DP(BNX2X_MSG_SP, "vlan_mac_execute_step - trying to take writer lock\n");
+ rc = __bnx2x_vlan_mac_h_write_trylock(bp, o);
+
+ if (rc != 0) {
+ __bnx2x_vlan_mac_h_pend(bp, o, *ramrod_flags);
+
+ /* Calling function should not diffrentiate between this case
+ * and the case in which there is already a pending ramrod
+ */
+ rc = 1;
+ } else {
+ rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
+ }
+ spin_unlock_bh(&o->exe_queue.lock);
+
+ return rc;
+}
+
/**
* bnx2x_complete_vlan_mac - complete one VLAN-MAC ramrod
*
@@ -1414,19 +1637,27 @@ static int bnx2x_complete_vlan_mac(struct bnx2x *bp,
struct bnx2x_raw_obj *r = &o->raw;
int rc;
+ /* Clearing the pending list & raw state should be made
+ * atomically (as execution flow assumes they represent the same).
+ */
+ spin_lock_bh(&o->exe_queue.lock);
+
/* Reset pending list */
- bnx2x_exe_queue_reset_pending(bp, &o->exe_queue);
+ __bnx2x_exe_queue_reset_pending(bp, &o->exe_queue);
/* Clear pending */
r->clear_pending(r);
+ spin_unlock_bh(&o->exe_queue.lock);
+
/* If ramrod failed this is most likely a SW bug */
if (cqe->message.error)
return -EINVAL;
/* Run the next bulk of pending commands if requested */
if (test_bit(RAMROD_CONT, ramrod_flags)) {
- rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
+ rc = __bnx2x_vlan_mac_execute_step(bp, o, ramrod_flags);
+
if (rc < 0)
return rc;
}
@@ -1719,9 +1950,8 @@ static inline int bnx2x_vlan_mac_push_new_cmd(
* @p:
*
*/
-int bnx2x_config_vlan_mac(
- struct bnx2x *bp,
- struct bnx2x_vlan_mac_ramrod_params *p)
+int bnx2x_config_vlan_mac(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_ramrod_params *p)
{
int rc = 0;
struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj;
@@ -1752,7 +1982,8 @@ int bnx2x_config_vlan_mac(
/* Execute commands if required */
if (cont || test_bit(RAMROD_EXEC, ramrod_flags) ||
test_bit(RAMROD_COMP_WAIT, ramrod_flags)) {
- rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags);
+ rc = __bnx2x_vlan_mac_execute_step(bp, p->vlan_mac_obj,
+ &p->ramrod_flags);
if (rc < 0)
return rc;
}
@@ -1775,8 +2006,9 @@ int bnx2x_config_vlan_mac(
return rc;
/* Make a next step */
- rc = bnx2x_exe_queue_step(bp, &o->exe_queue,
- ramrod_flags);
+ rc = __bnx2x_vlan_mac_execute_step(bp,
+ p->vlan_mac_obj,
+ &p->ramrod_flags);
if (rc < 0)
return rc;
}
@@ -1806,10 +2038,11 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
unsigned long *ramrod_flags)
{
struct bnx2x_vlan_mac_registry_elem *pos = NULL;
- int rc = 0;
struct bnx2x_vlan_mac_ramrod_params p;
struct bnx2x_exe_queue_obj *exeq = &o->exe_queue;
struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n;
+ int read_lock;
+ int rc = 0;
/* Clear pending commands first */
@@ -1844,6 +2077,11 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
__clear_bit(RAMROD_EXEC, &p.ramrod_flags);
__clear_bit(RAMROD_CONT, &p.ramrod_flags);
+ DP(BNX2X_MSG_SP, "vlan_mac_del_all -- taking vlan_mac_lock (reader)\n");
+ read_lock = bnx2x_vlan_mac_h_read_lock(bp, o);
+ if (read_lock != 0)
+ return read_lock;
+
list_for_each_entry(pos, &o->head, link) {
if (pos->vlan_mac_flags == *vlan_mac_flags) {
p.user_req.vlan_mac_flags = pos->vlan_mac_flags;
@@ -1851,11 +2089,15 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
rc = bnx2x_config_vlan_mac(bp, &p);
if (rc < 0) {
BNX2X_ERR("Failed to add a new DEL command\n");
+ bnx2x_vlan_mac_h_read_unlock(bp, o);
return rc;
}
}
}
+ DP(BNX2X_MSG_SP, "vlan_mac_del_all -- releasing vlan_mac_lock (reader)\n");
+ bnx2x_vlan_mac_h_read_unlock(bp, o);
+
p.ramrod_flags = *ramrod_flags;
__set_bit(RAMROD_CONT, &p.ramrod_flags);
@@ -1887,6 +2129,9 @@ static inline void bnx2x_init_vlan_mac_common(struct bnx2x_vlan_mac_obj *o,
struct bnx2x_credit_pool_obj *vlans_pool)
{
INIT_LIST_HEAD(&o->head);
+ o->head_reader = 0;
+ o->head_exe_request = false;
+ o->saved_ramrod_flags = 0;
o->macs_pool = macs_pool;
o->vlans_pool = vlans_pool;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index 798dfe9..533a3ab 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -285,6 +285,12 @@ struct bnx2x_vlan_mac_obj {
* entries.
*/
struct list_head head;
+ /* Implement a simple reader/writer lock on the head list.
+ * all these fields should only be accessed under the exe_queue lock
+ */
+ u8 head_reader; /* Num. of readers accessing head list */
+ bool head_exe_request; /* Pending execution request. */
+ unsigned long saved_ramrod_flags; /* Ramrods of pending execution */
/* TODO: Add it's initialization in the init functions */
struct bnx2x_exe_queue_obj exe_queue;
@@ -1302,8 +1308,16 @@ void bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
struct bnx2x_credit_pool_obj *macs_pool,
struct bnx2x_credit_pool_obj *vlans_pool);
+int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o);
+void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o);
+int bnx2x_vlan_mac_h_write_lock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o);
+void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o);
int bnx2x_config_vlan_mac(struct bnx2x *bp,
- struct bnx2x_vlan_mac_ramrod_params *p);
+ struct bnx2x_vlan_mac_ramrod_params *p);
int bnx2x_vlan_mac_move(struct bnx2x *bp,
struct bnx2x_vlan_mac_ramrod_params *p,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 95861ef..6291324 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -491,12 +491,20 @@ static inline void bnx2x_vfop_credit(struct bnx2x *bp,
* and a valid credit counter
*/
if (!vfop->rc && args->credit) {
- int cnt = 0;
struct list_head *pos;
+ int read_lock;
+ int cnt = 0;
+
+ read_lock = bnx2x_vlan_mac_h_read_lock(bp, obj);
+ if (read_lock)
+ DP(BNX2X_MSG_SP, "Failed to take vlan mac read head; continuing anyway\n");
list_for_each(pos, &obj->head)
cnt++;
+ if (!read_lock)
+ bnx2x_vlan_mac_h_read_unlock(bp, obj);
+
atomic_set(args->credit, cnt);
}
}
--
1.8.1.227.g44fe835
^ permalink raw reply related
* Re: [PATCH net-next] ax88179_178a: avoid copy of tx tcp packets
From: Eric Dumazet @ 2013-08-01 13:52 UTC (permalink / raw)
To: Ming Lei
Cc: David S. Miller, Greg Kroah-Hartman, Oliver Neukum, Freddy Xin,
Ben Hutchings, Grant Grundler, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1375364992.10515.141.camel@edumazet-glaptop>
On Thu, 2013-08-01 at 06:49 -0700, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
>
> ax88179_tx_fixup() has quite complex code trying to push 8 bytes
> of control data (len/mss), but fails to do it properly for TCP packets,
> incurring an extra copy and point of memory allocation failure.
I forgot to say this patch is for net-next, but depends on following fix
from net tree being applied.
commit 20f0170377264e8449b6987041f0bcc4d746d3ed
("usbnet: do not pretend to support SG/TSO")
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH net-next] ax88179_178a: avoid copy of tx tcp packets
From: Eric Dumazet @ 2013-08-01 13:49 UTC (permalink / raw)
To: Ming Lei
Cc: David S. Miller, Greg Kroah-Hartman, Oliver Neukum, Freddy Xin,
Ben Hutchings, Grant Grundler, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1375363300.10515.135.camel@edumazet-glaptop>
From: Eric Dumazet <edumazet-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
ax88179_tx_fixup() has quite complex code trying to push 8 bytes
of control data (len/mss), but fails to do it properly for TCP packets,
incurring an extra copy and point of memory allocation failure.
Lets use the simple and approved way.
dev->needed_headroom being 8, all frames should have 8 bytes of
headroom, so the extra copy should be unlikely anyway.
This patch should improve performance for TCP xmits.
Reported-by: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Tested-by: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric Dumazet <edumazet-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
---
drivers/net/usb/ax88179_178a.c | 21 ++++-----------------
1 file changed, 4 insertions(+), 17 deletions(-)
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 2bc87e3..e2120d6 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1166,31 +1166,18 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
int frame_size = dev->maxpacket;
int mss = skb_shinfo(skb)->gso_size;
int headroom;
- int tailroom;
tx_hdr1 = skb->len;
tx_hdr2 = mss;
if (((skb->len + 8) % frame_size) == 0)
tx_hdr2 |= 0x80008000; /* Enable padding */
- headroom = skb_headroom(skb);
- tailroom = skb_tailroom(skb);
+ headroom = skb_headroom(skb) - 8;
- if (!skb_header_cloned(skb) &&
- !skb_cloned(skb) &&
- (headroom + tailroom) >= 8) {
- if (headroom < 8) {
- skb->data = memmove(skb->head + 8, skb->data, skb->len);
- skb_set_tail_pointer(skb, skb->len);
- }
- } else {
- struct sk_buff *skb2;
^ permalink raw reply related
* Re: [PATCH 4/4] USBNET: ax88179_178a: enable tso if host supports sg dma
From: Eric Dumazet @ 2013-08-01 13:21 UTC (permalink / raw)
To: Ming Lei
Cc: David S. Miller, Greg Kroah-Hartman, Oliver Neukum, Freddy Xin,
Ben Hutchings, Grant Grundler, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CACVXFVMt-TgRVU+iA3NVuUzJSeXUPGvV89OnDdHaLEB1Ua6aAw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Thu, 2013-08-01 at 16:10 +0800, Ming Lei wrote:
> On Thu, Aug 1, 2013 at 1:04 PM, Eric Dumazet <eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > On Thu, 2013-08-01 at 12:41 +0800, Ming Lei wrote:
> >
> >> From my trace result, lots of linear SKBs are cloned or header-cloned, so
> >> it needs skb copy too.
> >>
> >> Is it normal in xmit path to see cloned SKBs for driver? If not, I can add check
> >> to avoid allocation of 8 bytes header for non-cloned skb.
> >
> > Existing code is not very friendly and very complex.
> >
> > Sure TCP stack does a clone for every skb from socket write queue,
> > but header should be available for pushing 8 bytes.
> >
> > The !skb_cloned(skb) test should be removed if the memmove() is not
> > needed.
> >
> > Could you try following patch ?
>
> Tested-by: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
>
> This patch does work, and it will make the patch 4/4 become very
> simple, :-)
>
> I will rewrite this one against your patch.
OK I'll post an official patch then. I presume you got performance
increase, since we no longer do a copy of the TCP packets.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH net-next v2 0/5] bonding: groundwork and initial conversion to RCU
From: Nikolay Aleksandrov @ 2013-08-01 13:14 UTC (permalink / raw)
To: netdev; +Cc: andy, davem, fubar
In-Reply-To: <1375359029-25889-1-git-send-email-nikolay@redhat.com>
Self-nack, sorry for the noise but I found a problem with the new 3ad code, we
need to check if the list has been traversed when extracting the next port.
v3 will follow after I run some more tests.
Nik
^ permalink raw reply
* Re: bonding + arp monitoring fails if interface is a vlan
From: Erik Hugne @ 2013-08-01 13:00 UTC (permalink / raw)
To: Santiago Garcia Mantinan; +Cc: netdev
In-Reply-To: <20130801121142.GA444@www.manty.net>
On Thu, Aug 01, 2013 at 02:11:42PM +0200, Santiago Garcia Mantinan wrote:
> Hi!
>
> I'm trying to setup a bond of a couple of vlans, these vlans are different
> paths to an upstream switch from a local switch. I want to do arp
> monitoring of the link in order for the bonding interface to know which path
> is ok and wich one is broken. If I set it up using arp monitoring and
> without using vlans it works ok, it also works if I set it up using vlans
> but without arp monitoring, so the broken setup seems to be with bonding +
> arp monitoring + vlans.
This have helped me troubleshoot various bonding problems in the past:
mount -t debugfs none /sys/kernel/debug/
ln -s /sys/kernel/debug /debug
echo -n 'module bonding +p' > /debug/dynamic_debug/control
> The broken setup seems to work but arp monitoring makes it loose the logical
> link from time to time, thus changing to other slave if available. What I
> saw when monitoring this with tcpdump is that all the arp requests were
> going out and that all the replies where coming in, so acording to the
> traffic seen on tcpdump the link should have been stable, but
> /proc/net/bonding/bond0 showed the link failures increasing and when testing
> with just a vlan interface I was loosing ping when the link was going down.
Did you sniff externally, on the native device, bond slaves or on bond0?
//E
^ permalink raw reply
* Re: [PATCH net-next v5 6/7] vxlan: Add tx-vlan offload support.
From: Sergei Shtylyov @ 2013-08-01 13:11 UTC (permalink / raw)
To: Pravin B Shelar; +Cc: netdev, stephen
In-Reply-To: <1375312487-18789-1-git-send-email-pshelar@nicira.com>
Hello.
On 01-08-2013 3:14, Pravin B Shelar wrote:
> Following patch allows transmit side vlan offload for vxlan
> devices.
> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
> ---
> v2-v3:
> - Set NETIF_F_HW_VLAN_STAG_TX feature.
> - Added WARN on vlan tag push.
> - Fixed hw_features.
> ---
> drivers/net/vxlan.c | 18 +++++++++++++++++-
> 1 files changed, 17 insertions(+), 1 deletions(-)
> diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
> index f9c7c75..2f35a2b 100644
> --- a/drivers/net/vxlan.c
> +++ b/drivers/net/vxlan.c
[...]
> @@ -1123,13 +1124,25 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
[...]
> + if (vlan_tx_tag_present(skb)) {
> + if (unlikely(!__vlan_put_tag(skb,
> + skb->vlan_proto,
> + vlan_tx_tag_get(skb)))) {
> + WARN_ON(1);
> + return -ENOMEM;
> + }
if (WARN_ON(!__vlan_put_tag(skb,
skb->vlan_proto,
vlan_tx_tag_get(skb))))
return -ENOMEM;
should be equivalent.
WBR, Sergei
^ permalink raw reply
* Re: [PATCH] checkpatch: Warn when using extern with function prototypes in .h files
From: Arend van Spriel @ 2013-08-01 13:00 UTC (permalink / raw)
To: David Howells
Cc: Joe Perches, Andrew Morton, Andy Whitcroft, Hannes Frederic Sowa,
Cong Wang, linux-kernel, netdev
In-Reply-To: <25105.1375359664@warthog.procyon.org.uk>
On 08/01/2013 02:21 PM, David Howells wrote:
> Joe Perches <joe@perches.com> wrote:
>
>> Using the extern keyword on function prototypes is superfluous
>> visual noise so suggest removing it.
>>
>> Using extern can cause unnecessary line wrapping at 80 columns
>> and unnecessarily long multi-line function prototypes.
>>
>> Suggested-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
>> Signed-off-by: Joe Perches <joe@perches.com>
>
> Nak.
>
> The "extern" makes it much easier to pick out at a glance.
Really? Grouping function prototypes within the header file is much more
helpful for spotting them.
Regards,
Arend
> Please standardise on there _being_ externs if you must do this.
>
> It's gratuitous change anyway and not worth the churn.
>
> David
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
^ permalink raw reply
* [PATCH-net v2] tipc: fix oops when creating server socket fails
From: Paul Gortmaker @ 2013-08-01 12:29 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Ying Xue, Jon Maloy, Paul Gortmaker
In-Reply-To: <20130731.152020.219915207900769828.davem@davemloft.net>
From: Ying Xue <ying.xue@windriver.com>
When creation of TIPC internal server socket fails,
we get an oops with the following dump:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000020
IP: [<ffffffffa0011f49>] tipc_close_conn+0x59/0xb0 [tipc]
PGD 13719067 PUD 12008067 PMD 0
Oops: 0000 [#1] SMP DEBUG_PAGEALLOC
Modules linked in: tipc(+)
CPU: 4 PID: 4340 Comm: insmod Not tainted 3.10.0+ #1
Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007
task: ffff880014360000 ti: ffff88001374c000 task.ti: ffff88001374c000
RIP: 0010:[<ffffffffa0011f49>] [<ffffffffa0011f49>] tipc_close_conn+0x59/0xb0 [tipc]
RSP: 0018:ffff88001374dc98 EFLAGS: 00010292
RAX: 0000000000000000 RBX: ffff880012ac09d8 RCX: 0000000000000000
RDX: 0000000000000046 RSI: 0000000000000001 RDI: ffff880014360000
RBP: ffff88001374dcb8 R08: 0000000000000001 R09: 0000000000000001
R10: 0000000000000000 R11: 0000000000000000 R12: ffffffffa0016fa0
R13: ffffffffa0017010 R14: ffffffffa0017010 R15: ffff880012ac09d8
FS: 0000000000000000(0000) GS:ffff880016600000(0063) knlGS:00000000f76668d0
CS: 0010 DS: 002b ES: 002b CR0: 000000008005003b
CR2: 0000000000000020 CR3: 0000000012227000 CR4: 00000000000006e0
Stack:
ffff88001374dcb8 ffffffffa0016fa0 0000000000000000 0000000000000001
ffff88001374dcf8 ffffffffa0012922 ffff88001374dce8 00000000ffffffea
ffffffffa0017100 0000000000000000 ffff8800134241a8 ffffffffa0017150
Call Trace:
[<ffffffffa0012922>] tipc_server_stop+0xa2/0x1b0 [tipc]
[<ffffffffa0009995>] tipc_subscr_stop+0x15/0x20 [tipc]
[<ffffffffa00130f5>] tipc_core_stop+0x1d/0x33 [tipc]
[<ffffffffa001f0d4>] tipc_init+0xd4/0xf8 [tipc]
[<ffffffffa001f000>] ? 0xffffffffa001efff
[<ffffffff8100023f>] do_one_initcall+0x3f/0x150
[<ffffffff81082f4d>] ? __blocking_notifier_call_chain+0x7d/0xd0
[<ffffffff810cc58a>] load_module+0x11aa/0x19c0
[<ffffffff810c8d60>] ? show_initstate+0x50/0x50
[<ffffffff8190311c>] ? retint_restore_args+0xe/0xe
[<ffffffff810cce79>] SyS_init_module+0xd9/0x110
[<ffffffff8190dc65>] sysenter_dispatch+0x7/0x1f
Code: 6c 24 70 4c 89 ef e8 b7 04 8f e1 8b 73 04 4c 89 e7 e8 7c 9e 32 e1 41 83 ac 24
b8 00 00 00 01 4c 89 ef e8 eb 0a 8f e1 48 8b 43 08 <4c> 8b 68 20 4d 8d a5 48 03 00
00 4c 89 e7 e8 04 05 8f e1 4c 89
RIP [<ffffffffa0011f49>] tipc_close_conn+0x59/0xb0 [tipc]
RSP <ffff88001374dc98>
CR2: 0000000000000020
---[ end trace b02321f40e4269a3 ]---
We have the following call chain:
tipc_core_start()
ret = tipc_subscr_start()
ret = tipc_server_start(){
server->enabled = 1;
ret = tipc_open_listening_sock()
}
I.e., the server->enabled flag is unconditionally set to 1, whatever
the return value of tipc_open_listening_sock().
This causes a crash when tipc_core_start() tries to clean up
resources after a failed initialization:
if (ret == failed)
tipc_subscr_stop()
tipc_server_stop(){
if (server->enabled)
tipc_close_conn(){
NULL reference of con->sock-sk
OOPS!
}
}
To avoid this, tipc_server_start() should only set server->enabled
to 1 in case of a succesful socket creation. In case of failure, it
should release all allocated resources before returning.
Problem introduced in commit c5fa7b3cf3cb22e4ac60485fc2dc187fe012910f
("tipc: introduce new TIPC server infrastructure") in v3.11-rc1.
Note that it won't be seen often; it takes a module load under memory
constrained conditions in order to trigger the failure condition.
Signed-off-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
[v2: switch back to conventional ID ("shortlog") reference in log]
net/tipc/server.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/net/tipc/server.c b/net/tipc/server.c
index 19da5ab..fd3fa57 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -355,8 +355,12 @@ static int tipc_open_listening_sock(struct tipc_server *s)
return PTR_ERR(con);
sock = tipc_create_listen_sock(con);
- if (!sock)
+ if (!sock) {
+ idr_remove(&s->conn_idr, con->conid);
+ s->idr_in_use--;
+ kfree(con);
return -EINVAL;
+ }
tipc_register_callbacks(sock, con);
return 0;
@@ -563,9 +567,14 @@ int tipc_server_start(struct tipc_server *s)
kmem_cache_destroy(s->rcvbuf_cache);
return ret;
}
+ ret = tipc_open_listening_sock(s);
+ if (ret < 0) {
+ tipc_work_stop(s);
+ kmem_cache_destroy(s->rcvbuf_cache);
+ return ret;
+ }
s->enabled = 1;
-
- return tipc_open_listening_sock(s);
+ return ret;
}
void tipc_server_stop(struct tipc_server *s)
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH] checkpatch: Warn when using extern with function prototypes in .h files
From: David Howells @ 2013-08-01 12:21 UTC (permalink / raw)
To: Joe Perches
Cc: dhowells, Andrew Morton, Andy Whitcroft, Hannes Frederic Sowa,
Cong Wang, linux-kernel, netdev
In-Reply-To: <1374721150.1924.26.camel@joe-AO722>
Joe Perches <joe@perches.com> wrote:
> Using the extern keyword on function prototypes is superfluous
> visual noise so suggest removing it.
>
> Using extern can cause unnecessary line wrapping at 80 columns
> and unnecessarily long multi-line function prototypes.
>
> Suggested-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> Signed-off-by: Joe Perches <joe@perches.com>
Nak.
The "extern" makes it much easier to pick out at a glance.
Please standardise on there _being_ externs if you must do this.
It's gratuitous change anyway and not worth the churn.
David
^ permalink raw reply
* bonding + arp monitoring fails if interface is a vlan
From: Santiago Garcia Mantinan @ 2013-08-01 12:11 UTC (permalink / raw)
To: netdev
Hi!
I'm trying to setup a bond of a couple of vlans, these vlans are different
paths to an upstream switch from a local switch. I want to do arp
monitoring of the link in order for the bonding interface to know which path
is ok and wich one is broken. If I set it up using arp monitoring and
without using vlans it works ok, it also works if I set it up using vlans
but without arp monitoring, so the broken setup seems to be with bonding +
arp monitoring + vlans. Here is a schema:
-------------
|Remote Switch|
-------------
| |
P P
A A
T T
H H
1 2
| |
------------
|Local switch|
------------
|
| VLAN for PATH1
| VLAN for PATH2
|
Linux machine
The broken setup seems to work but arp monitoring makes it loose the logical
link from time to time, thus changing to other slave if available. What I
saw when monitoring this with tcpdump is that all the arp requests were
going out and that all the replies where coming in, so acording to the
traffic seen on tcpdump the link should have been stable, but
/proc/net/bonding/bond0 showed the link failures increasing and when testing
with just a vlan interface I was loosing ping when the link was going down.
I've tried this on Debian wheezy with its 3.2.46 kernel and also the 3.10.3
version in unstable, the tests where done on a couple of machines using a 32
bits kernel with different nics (r8169 and skge).
I created a small lab to replicate the problem, on this setup I avoided all
the switching and I directly connected the machine with bonding to another
Linux on which I just had eth0.1002 configured with ip 192.168.1.1, the
results where the same as in the full scenario, link on the bonding slave
was going down from time to time.
This is the setup on the bonding interface.
auto bond0
iface bond0 inet static
address 192.168.1.2
netmask 255.255.255.0
bond-slaves eth0.1002
bond-mode active-backup
bond-arp_validate 0
bond-arp_interval 5000
bond-arp_ip_target 192.168.1.1
pre-up ip link set eth0 up || true
pre-up ip link add link eth0 name eth0.1002 type vlan id 1002 || true
down ip link delete eth0.1002 || true
These are the messages I was seing on the bonding machines:
[ 452.436750] bonding: bond0: adding ARP target 192.168.1.1.
[ 452.436851] bonding: bond0: Setting ARP monitoring interval to 5000.
[ 452.440287] bonding: bond0: setting mode to active-backup (1).
[ 452.440429] bonding: bond0: setting arp_validate to none (0).
[ 452.458349] bonding: bond0: Adding slave eth0.1002.
[ 452.458964] bonding: bond0: making interface eth0.1002 the new active one.
[ 452.458983] bonding: bond0: first active interface up!
[ 452.458999] bonding: bond0: enslaving eth0.1002 as an active interface with an up link.
[ 452.482560] 8021q: adding VLAN 0 to HW filter on device bond0
[ 467.500143] bonding: bond0: link status definitely down for interface eth0.1002, disabling it
[ 467.500193] bonding: bond0: now running without any active interface !
[ 622.748102] bonding: bond0: link status definitely up for interface eth0.1002.
[ 622.748122] bonding: bond0: making interface eth0.1002 the new active one.
[ 622.748522] bonding: bond0: first active interface up!
[ 637.772179] bonding: bond0: link status definitely down for interface eth0.1002, disabling it
[ 637.772228] bonding: bond0: now running without any active interface !
[ 642.780173] bonding: bond0: link status definitely up for interface eth0.1002.
[ 642.780192] bonding: bond0: making interface eth0.1002 the new active one.
[ 642.780603] bonding: bond0: first active interface up!
[ 657.804154] bonding: bond0: link status definitely down for interface eth0.1002, disabling it
[ 657.804209] bonding: bond0: now running without any active interface !
[ 662.812165] bonding: bond0: link status definitely up for interface eth0.1002.
[ 662.812185] bonding: bond0: making interface eth0.1002 the new active one.
[ 662.812592] bonding: bond0: first active interface up!
[ 677.836167] bonding: bond0: link status definitely down for interface eth0.1002, disabling it
[ 677.836223] bonding: bond0: now running without any active interface !
[ 682.844162] bonding: bond0: link status definitely up for interface eth0.1002.
[ 682.844181] bonding: bond0: making interface eth0.1002 the new active one.
[ 682.844590] bonding: bond0: first active interface up!
[ 697.868153] bonding: bond0: link status definitely down for interface eth0.1002, disabling it
Like I said, running tcpdump on both Linux shows everything fine, all arp
replies and requests are there, but link goes down from time to time, on
this setup the bond is built just with one slave, so network is lost when
link goes down.
Some questions:
am I doing something wrong here?
Is this setup not supported?
If it should work... can anybody reproduce this?
Bug?
What should I do now?
Regards...
--
Manty/BestiaTester -> http://manty.net
^ permalink raw reply
* [PATCH] ip link: fix display and filtering of ifgroups
From: Stefan Tomanek @ 2013-08-01 12:16 UTC (permalink / raw)
To: netdev
This change adds the interface group to the output of "ip link show".
It also makes "ip link" print _all_ devices if no group filter is specified;
previously, only interfaces of the default group (0) were shown.
Signed-off-by: Stefan Tomanek <stefan.tomanek@wertarbyte.de>
---
ip/ipaddress.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 013b4cb..cf4015a 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -418,7 +418,7 @@ int print_linkinfo(const struct sockaddr_nl *who,
if (tb[IFLA_GROUP]) {
int group = *(int*)RTA_DATA(tb[IFLA_GROUP]);
- if (group != filter.group)
+ if (filter.group != -1 && group != filter.group)
return -1;
}
@@ -458,6 +458,11 @@ int print_linkinfo(const struct sockaddr_nl *who,
if (do_link && tb[IFLA_LINKMODE])
print_linkmode(fp, tb[IFLA_LINKMODE]);
+ if (tb[IFLA_GROUP]) {
+ int group = *(int*)RTA_DATA(tb[IFLA_GROUP]);
+ fprintf(fp, "group %d ", group);
+ }
+
if (filter.showqueue)
print_queuelen(fp, tb);
@@ -1050,7 +1055,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
if (filter.family == AF_UNSPEC)
filter.family = preferred_family;
- filter.group = INIT_NETDEV_GROUP;
+ filter.group = -1;
if (action == IPADD_FLUSH) {
if (argc <= 0) {
--
1.7.10.4
^ 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