Netdev List
 help / color / mirror / Atom feed
* [PATCH 6/7] netfilter: nf_ct_pptp: Fix comment referring to incorrect RFC
From: pablo @ 2013-02-19  0:10 UTC (permalink / raw)
  To: netdev; +Cc: davem, netfilter-devel
In-Reply-To: <1361232651-5626-1-git-send-email-pablo@netfilter.org>

From: Reese Moore <ram@vt.edu>

The header of this file cites to "RFFC2673" which is "Binary Labels in the
Domain Name System". It should refer to "RFC 2637" which is "Point-to-Point
Tunneling Protocol (PPTP)". This patch also corrects the typo RFFC.

Signed-off-by: Reese Moore <ram@vt.edu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/nf_conntrack_pptp.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index cc7669e..e6678d2 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -14,7 +14,7 @@
  * Limitations:
  * 	 - We blindly assume that control connections are always
  * 	   established in PNS->PAC direction.  This is a violation
- * 	   of RFFC2673
+ *	   of RFC 2637
  * 	 - We can only support one single call within each session
  * TODO:
  *	 - testing of incoming PPTP calls
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 5/7] netfilter: nfnetlink: add mutex per subsystem
From: pablo @ 2013-02-19  0:10 UTC (permalink / raw)
  To: netdev; +Cc: davem, netfilter-devel
In-Reply-To: <1361232651-5626-1-git-send-email-pablo@netfilter.org>

From: Pablo Neira Ayuso <pablo@netfilter.org>

This patch replaces the global lock to one lock per subsystem.
The per-subsystem lock avoids that processes operating
with different subsystems are synchronized.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/linux/netfilter/nfnetlink.h  |    4 +--
 net/netfilter/ipset/ip_set_core.c    |   26 ++++++++---------
 net/netfilter/nf_conntrack_netlink.c |   12 ++++----
 net/netfilter/nfnetlink.c            |   52 +++++++++++++++++++++-------------
 4 files changed, 53 insertions(+), 41 deletions(-)

diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 4966dde..ecbb8e4 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -34,8 +34,8 @@ extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigne
 extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
 extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags);
 
-extern void nfnl_lock(void);
-extern void nfnl_unlock(void);
+extern void nfnl_lock(__u8 subsys_id);
+extern void nfnl_unlock(__u8 subsys_id);
 
 #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
 	MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 6d6d8f2..f82b2e6 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -88,14 +88,14 @@ find_set_type(const char *name, u8 family, u8 revision)
 static bool
 load_settype(const char *name)
 {
-	nfnl_unlock();
+	nfnl_unlock(NFNL_SUBSYS_IPSET);
 	pr_debug("try to load ip_set_%s\n", name);
 	if (request_module("ip_set_%s", name) < 0) {
 		pr_warning("Can't find ip_set type %s\n", name);
-		nfnl_lock();
+		nfnl_lock(NFNL_SUBSYS_IPSET);
 		return false;
 	}
-	nfnl_lock();
+	nfnl_lock(NFNL_SUBSYS_IPSET);
 	return true;
 }
 
@@ -532,7 +532,7 @@ ip_set_nfnl_get(const char *name)
 	ip_set_id_t i, index = IPSET_INVALID_ID;
 	struct ip_set *s;
 
-	nfnl_lock();
+	nfnl_lock(NFNL_SUBSYS_IPSET);
 	for (i = 0; i < ip_set_max; i++) {
 		s = nfnl_set(i);
 		if (s != NULL && STREQ(s->name, name)) {
@@ -541,7 +541,7 @@ ip_set_nfnl_get(const char *name)
 			break;
 		}
 	}
-	nfnl_unlock();
+	nfnl_unlock(NFNL_SUBSYS_IPSET);
 
 	return index;
 }
@@ -561,13 +561,13 @@ ip_set_nfnl_get_byindex(ip_set_id_t index)
 	if (index > ip_set_max)
 		return IPSET_INVALID_ID;
 
-	nfnl_lock();
+	nfnl_lock(NFNL_SUBSYS_IPSET);
 	set = nfnl_set(index);
 	if (set)
 		__ip_set_get(set);
 	else
 		index = IPSET_INVALID_ID;
-	nfnl_unlock();
+	nfnl_unlock(NFNL_SUBSYS_IPSET);
 
 	return index;
 }
@@ -584,11 +584,11 @@ void
 ip_set_nfnl_put(ip_set_id_t index)
 {
 	struct ip_set *set;
-	nfnl_lock();
+	nfnl_lock(NFNL_SUBSYS_IPSET);
 	set = nfnl_set(index);
 	if (set != NULL)
 		__ip_set_put(set);
-	nfnl_unlock();
+	nfnl_unlock(NFNL_SUBSYS_IPSET);
 }
 EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
 
@@ -1763,10 +1763,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
 			goto done;
 		}
 		req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
-		nfnl_lock();
+		nfnl_lock(NFNL_SUBSYS_IPSET);
 		find_set_and_id(req_get->set.name, &id);
 		req_get->set.index = id;
-		nfnl_unlock();
+		nfnl_unlock(NFNL_SUBSYS_IPSET);
 		goto copy;
 	}
 	case IP_SET_OP_GET_BYINDEX: {
@@ -1778,11 +1778,11 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
 			ret = -EINVAL;
 			goto done;
 		}
-		nfnl_lock();
+		nfnl_lock(NFNL_SUBSYS_IPSET);
 		set = nfnl_set(req_get->set.index);
 		strncpy(req_get->set.name, set ? set->name : "",
 			IPSET_MAXNAMELEN);
-		nfnl_unlock();
+		nfnl_unlock(NFNL_SUBSYS_IPSET);
 		goto copy;
 	}
 	default:
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 2334cc5..d490a30 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1256,13 +1256,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
 	if (!parse_nat_setup) {
 #ifdef CONFIG_MODULES
 		rcu_read_unlock();
-		nfnl_unlock();
+		nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
 		if (request_module("nf-nat") < 0) {
-			nfnl_lock();
+			nfnl_lock(NFNL_SUBSYS_CTNETLINK);
 			rcu_read_lock();
 			return -EOPNOTSUPP;
 		}
-		nfnl_lock();
+		nfnl_lock(NFNL_SUBSYS_CTNETLINK);
 		rcu_read_lock();
 		if (nfnetlink_parse_nat_setup_hook)
 			return -EAGAIN;
@@ -1274,13 +1274,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
 	if (err == -EAGAIN) {
 #ifdef CONFIG_MODULES
 		rcu_read_unlock();
-		nfnl_unlock();
+		nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
 		if (request_module("nf-nat-%u", nf_ct_l3num(ct)) < 0) {
-			nfnl_lock();
+			nfnl_lock(NFNL_SUBSYS_CTNETLINK);
 			rcu_read_lock();
 			return -EOPNOTSUPP;
 		}
-		nfnl_lock();
+		nfnl_lock(NFNL_SUBSYS_CTNETLINK);
 		rcu_read_lock();
 #else
 		err = -EOPNOTSUPP;
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 58a09b7..d578ec2 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -36,8 +36,10 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
 
 static char __initdata nfversion[] = "0.30";
 
-static const struct nfnetlink_subsystem __rcu *subsys_table[NFNL_SUBSYS_COUNT];
-static DEFINE_MUTEX(nfnl_mutex);
+static struct {
+	struct mutex				mutex;
+	const struct nfnetlink_subsystem __rcu	*subsys;
+} table[NFNL_SUBSYS_COUNT];
 
 static const int nfnl_group2type[NFNLGRP_MAX+1] = {
 	[NFNLGRP_CONNTRACK_NEW]		= NFNL_SUBSYS_CTNETLINK,
@@ -48,27 +50,32 @@ static const int nfnl_group2type[NFNLGRP_MAX+1] = {
 	[NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
 };
 
-void nfnl_lock(void)
+void nfnl_lock(__u8 subsys_id)
 {
-	mutex_lock(&nfnl_mutex);
+	mutex_lock(&table[subsys_id].mutex);
 }
 EXPORT_SYMBOL_GPL(nfnl_lock);
 
-void nfnl_unlock(void)
+void nfnl_unlock(__u8 subsys_id)
 {
-	mutex_unlock(&nfnl_mutex);
+	mutex_unlock(&table[subsys_id].mutex);
 }
 EXPORT_SYMBOL_GPL(nfnl_unlock);
 
+static struct mutex *nfnl_get_lock(__u8 subsys_id)
+{
+	return &table[subsys_id].mutex;
+}
+
 int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
 {
-	nfnl_lock();
-	if (subsys_table[n->subsys_id]) {
-		nfnl_unlock();
+	nfnl_lock(n->subsys_id);
+	if (table[n->subsys_id].subsys) {
+		nfnl_unlock(n->subsys_id);
 		return -EBUSY;
 	}
-	rcu_assign_pointer(subsys_table[n->subsys_id], n);
-	nfnl_unlock();
+	rcu_assign_pointer(table[n->subsys_id].subsys, n);
+	nfnl_unlock(n->subsys_id);
 
 	return 0;
 }
@@ -76,9 +83,9 @@ EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
 
 int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n)
 {
-	nfnl_lock();
-	subsys_table[n->subsys_id] = NULL;
-	nfnl_unlock();
+	nfnl_lock(n->subsys_id);
+	table[n->subsys_id].subsys = NULL;
+	nfnl_unlock(n->subsys_id);
 	synchronize_rcu();
 	return 0;
 }
@@ -91,7 +98,7 @@ static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t t
 	if (subsys_id >= NFNL_SUBSYS_COUNT)
 		return NULL;
 
-	return rcu_dereference(subsys_table[subsys_id]);
+	return rcu_dereference(table[subsys_id].subsys);
 }
 
 static inline const struct nfnl_callback *
@@ -175,6 +182,7 @@ replay:
 		struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
 		struct nlattr *attr = (void *)nlh + min_len;
 		int attrlen = nlh->nlmsg_len - min_len;
+		__u8 subsys_id = NFNL_SUBSYS_ID(type);
 
 		err = nla_parse(cda, ss->cb[cb_id].attr_count,
 				attr, attrlen, ss->cb[cb_id].policy);
@@ -189,10 +197,9 @@ replay:
 			rcu_read_unlock();
 		} else {
 			rcu_read_unlock();
-			nfnl_lock();
-			if (rcu_dereference_protected(
-					subsys_table[NFNL_SUBSYS_ID(type)],
-					lockdep_is_held(&nfnl_mutex)) != ss ||
+			nfnl_lock(subsys_id);
+			if (rcu_dereference_protected(table[subsys_id].subsys,
+				lockdep_is_held(nfnl_get_lock(subsys_id))) != ss ||
 			    nfnetlink_find_client(type, ss) != nc)
 				err = -EAGAIN;
 			else if (nc->call)
@@ -200,7 +207,7 @@ replay:
 						   (const struct nlattr **)cda);
 			else
 				err = -EINVAL;
-			nfnl_unlock();
+			nfnl_unlock(subsys_id);
 		}
 		if (err == -EAGAIN)
 			goto replay;
@@ -267,6 +274,11 @@ static struct pernet_operations nfnetlink_net_ops = {
 
 static int __init nfnetlink_init(void)
 {
+	int i;
+
+	for (i=0; i<NFNL_SUBSYS_COUNT; i++)
+		mutex_init(&table[i].mutex);
+
 	pr_info("Netfilter messages via NETLINK v%s.\n", nfversion);
 	return register_pernet_subsys(&nfnetlink_net_ops);
 }
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 3/7] netfilter: xt_CT: merge common code of revision 0 and 1
From: pablo @ 2013-02-19  0:10 UTC (permalink / raw)
  To: netdev; +Cc: davem, netfilter-devel
In-Reply-To: <1361232651-5626-1-git-send-email-pablo@netfilter.org>

From: Pablo Neira Ayuso <pablo@netfilter.org>

This patch merges the common code for revision 0 and 1.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/xt_CT.c |  145 +++++++++++++++++++------------------------------
 1 file changed, 56 insertions(+), 89 deletions(-)

diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index bde009e..d69f1c7 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -20,12 +20,8 @@
 #include <net/netfilter/nf_conntrack_timeout.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
-static unsigned int xt_ct_target_v0(struct sk_buff *skb,
-				    const struct xt_action_param *par)
+static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
 {
-	const struct xt_ct_target_info *info = par->targinfo;
-	struct nf_conn *ct = info->ct;
-
 	/* Previously seen (loopback)? Ignore. */
 	if (skb->nfct != NULL)
 		return XT_CONTINUE;
@@ -37,21 +33,22 @@ static unsigned int xt_ct_target_v0(struct sk_buff *skb,
 	return XT_CONTINUE;
 }
 
-static unsigned int xt_ct_target_v1(struct sk_buff *skb,
+static unsigned int xt_ct_target_v0(struct sk_buff *skb,
 				    const struct xt_action_param *par)
 {
-	const struct xt_ct_target_info_v1 *info = par->targinfo;
+	const struct xt_ct_target_info *info = par->targinfo;
 	struct nf_conn *ct = info->ct;
 
-	/* Previously seen (loopback)? Ignore. */
-	if (skb->nfct != NULL)
-		return XT_CONTINUE;
+	return xt_ct_target(skb, ct);
+}
 
-	atomic_inc(&ct->ct_general.use);
-	skb->nfct = &ct->ct_general;
-	skb->nfctinfo = IP_CT_NEW;
+static unsigned int xt_ct_target_v1(struct sk_buff *skb,
+				    const struct xt_action_param *par)
+{
+	const struct xt_ct_target_info_v1 *info = par->targinfo;
+	struct nf_conn *ct = info->ct;
 
-	return XT_CONTINUE;
+	return xt_ct_target(skb, ct);
 }
 
 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
@@ -104,67 +101,6 @@ xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
 	return 0;
 }
 
-static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
-{
-	struct xt_ct_target_info *info = par->targinfo;
-	struct nf_conntrack_tuple t;
-	struct nf_conn *ct;
-	int ret = -EOPNOTSUPP;
-
-	if (info->flags & ~XT_CT_NOTRACK)
-		return -EINVAL;
-
-	if (info->flags & XT_CT_NOTRACK) {
-		ct = nf_ct_untracked_get();
-		atomic_inc(&ct->ct_general.use);
-		goto out;
-	}
-
-#ifndef CONFIG_NF_CONNTRACK_ZONES
-	if (info->zone)
-		goto err1;
-#endif
-
-	ret = nf_ct_l3proto_try_module_get(par->family);
-	if (ret < 0)
-		goto err1;
-
-	memset(&t, 0, sizeof(t));
-	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
-	ret = PTR_ERR(ct);
-	if (IS_ERR(ct))
-		goto err2;
-
-	ret = 0;
-	if ((info->ct_events || info->exp_events) &&
-	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
-				  GFP_KERNEL))
-		goto err3;
-
-	if (info->helper[0]) {
-		ret = xt_ct_set_helper(ct, info->helper, par);
-		if (ret < 0)
-			goto err3;
-	}
-
-	__set_bit(IPS_TEMPLATE_BIT, &ct->status);
-	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
-
-	/* Overload tuple linked list to put us in template list. */
-	hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-				 &par->net->ct.tmpl);
-out:
-	info->ct = ct;
-	return 0;
-
-err3:
-	nf_conntrack_free(ct);
-err2:
-	nf_ct_l3proto_module_put(par->family);
-err1:
-	return ret;
-}
-
 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
 static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
 {
@@ -242,9 +178,9 @@ out:
 #endif
 }
 
-static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
+static int xt_ct_tg_check(const struct xt_tgchk_param *par,
+			  struct xt_ct_target_info_v1 *info)
 {
-	struct xt_ct_target_info_v1 *info = par->targinfo;
 	struct nf_conntrack_tuple t;
 	struct nf_conn *ct;
 	int ret = -EOPNOTSUPP;
@@ -309,20 +245,31 @@ err1:
 	return ret;
 }
 
-static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
+static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 {
 	struct xt_ct_target_info *info = par->targinfo;
-	struct nf_conn *ct = info->ct;
-	struct nf_conn_help *help;
+	struct xt_ct_target_info_v1 info_v1 = {
+		.flags 		= info->flags,
+		.zone		= info->zone,
+		.ct_events	= info->ct_events,
+		.exp_events	= info->exp_events,
+	};
+	int ret;
 
-	if (!nf_ct_is_untracked(ct)) {
-		help = nfct_help(ct);
-		if (help)
-			module_put(help->helper->me);
+	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
 
-		nf_ct_l3proto_module_put(par->family);
-	}
-	nf_ct_put(info->ct);
+	ret = xt_ct_tg_check(par, &info_v1);
+	if (ret < 0)
+		return ret;
+
+	info->ct = info_v1.ct;
+
+	return ret;
+}
+
+static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
+{
+	return xt_ct_tg_check(par, par->targinfo);
 }
 
 static void xt_ct_destroy_timeout(struct nf_conn *ct)
@@ -343,9 +290,9 @@ static void xt_ct_destroy_timeout(struct nf_conn *ct)
 #endif
 }
 
-static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
+static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
+			     struct xt_ct_target_info_v1 *info)
 {
-	struct xt_ct_target_info_v1 *info = par->targinfo;
 	struct nf_conn *ct = info->ct;
 	struct nf_conn_help *help;
 
@@ -361,6 +308,26 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
 	nf_ct_put(info->ct);
 }
 
+static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
+{
+	struct xt_ct_target_info *info = par->targinfo;
+	struct xt_ct_target_info_v1 info_v1 = {
+		.flags 		= info->flags,
+		.zone		= info->zone,
+		.ct_events	= info->ct_events,
+		.exp_events	= info->exp_events,
+		.ct		= info->ct,
+	};
+	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
+
+	xt_ct_tg_destroy(par, &info_v1);
+}
+
+static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
+{
+	xt_ct_tg_destroy(par, par->targinfo);
+}
+
 static struct xt_target xt_ct_tg_reg[] __read_mostly = {
 	{
 		.name		= "CT",
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 0/7] netfilter updates for net-next
From: pablo @ 2013-02-19  0:10 UTC (permalink / raw)
  To: netdev; +Cc: davem, netfilter-devel

From: Pablo Neira Ayuso <pablo@netfilter.org>

Hi David,

The following patchset contain updates for your net-next tree, they are:

* Fix (for just added) connlabel dependencies, from Florian Westphal.

* Add aliasing support for conntrack, thus users can either use -m state
  or -m conntrack from iptables while using the same kernel module, from
  Jozsef Kadlecsik.

* Some code refactoring for the CT target to merge common code in
  revision 0 and 1, from myself.

* Add aliasing support for CT, based on patch from Jozsef Kadlecsik.

* Add one mutex per nfnetlink subsystem, from myself.

* Improved logging for packets that are dropped by helpers, from myself.

You can pull these changes from:

git://1984.lsi.us.es/nf-next master

Thanks!

Florian Westphal (1):
  netfilter: fix missing dependencies for NETFILTER_XT_MATCH_CONNLABEL

Jozsef Kadlecsik (1):
  netfilter: xt_conntrack: Add flag to support aliases

Pablo Neira Ayuso (4):
  netfilter: xt_CT: merge common code of revision 0 and 1
  netfilter: xt_CT: add alias flag
  netfilter: nfnetlink: add mutex per subsystem
  netfilter: nf_ct_helper: better logging for dropped packets

Reese Moore (1):
  netfilter: nf_ct_pptp: Fix comment referring to incorrect RFC

 include/linux/netfilter/nfnetlink.h            |    4 +-
 include/net/netfilter/nf_conntrack_helper.h    |    3 +
 include/uapi/linux/netfilter/xt_CT.h           |    6 +-
 include/uapi/linux/netfilter/xt_conntrack.h    |    1 +
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |   10 +-
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |    8 +-
 net/netfilter/Kconfig                          |    1 +
 net/netfilter/ipset/ip_set_core.c              |   26 ++--
 net/netfilter/nf_conntrack_amanda.c            |    5 +-
 net/netfilter/nf_conntrack_ftp.c               |   10 +-
 net/netfilter/nf_conntrack_h323_main.c         |    6 +-
 net/netfilter/nf_conntrack_helper.c            |   18 +++
 net/netfilter/nf_conntrack_irc.c               |    7 +-
 net/netfilter/nf_conntrack_netlink.c           |   12 +-
 net/netfilter/nf_conntrack_pptp.c              |    2 +-
 net/netfilter/nf_conntrack_sane.c              |    5 +-
 net/netfilter/nf_conntrack_sip.c               |   80 ++++++++---
 net/netfilter/nf_conntrack_tftp.c              |    8 +-
 net/netfilter/nf_nat_amanda.c                  |    8 +-
 net/netfilter/nf_nat_ftp.c                     |    5 +-
 net/netfilter/nf_nat_irc.c                     |    8 +-
 net/netfilter/nf_nat_sip.c                     |   49 +++++--
 net/netfilter/nf_nat_tftp.c                    |    4 +-
 net/netfilter/nfnetlink.c                      |   52 ++++---
 net/netfilter/xt_CT.c                          |  177 ++++++++++++------------
 25 files changed, 315 insertions(+), 200 deletions(-)

-- 
1.7.10.4

^ permalink raw reply

* [PATCH 1/7] netfilter: fix missing dependencies for NETFILTER_XT_MATCH_CONNLABEL
From: pablo @ 2013-02-19  0:10 UTC (permalink / raw)
  To: netdev; +Cc: davem, netfilter-devel
In-Reply-To: <1361232651-5626-1-git-send-email-pablo@netfilter.org>

From: Florian Westphal <fw@strlen.de>

It was possible to set NF_CONNTRACK=n and NF_CONNTRACK_LABELS=y via
NETFILTER_XT_MATCH_CONNLABEL=y.

warning: (NETFILTER_XT_MATCH_CONNLABEL) selects NF_CONNTRACK_LABELS which has
unmet direct dependencies (NET && INET && NETFILTER && NF_CONNTRACK)

Reported-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/Kconfig |    1 +
 1 file changed, 1 insertion(+)

diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index eb2c8eb..d4dd702 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -860,6 +860,7 @@ config NETFILTER_XT_MATCH_CONNBYTES
 config NETFILTER_XT_MATCH_CONNLABEL
 	tristate '"connlabel" match support'
 	select NF_CONNTRACK_LABELS
+	depends on NF_CONNTRACK
 	depends on NETFILTER_ADVANCED
 	---help---
 	  This match allows you to test and assign userspace-defined labels names
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 4/7] netfilter: xt_CT: add alias flag
From: pablo @ 2013-02-19  0:10 UTC (permalink / raw)
  To: netdev; +Cc: davem, netfilter-devel
In-Reply-To: <1361232651-5626-1-git-send-email-pablo@netfilter.org>

From: Pablo Neira Ayuso <pablo@netfilter.org>

This patch adds the alias flag to support full NOTRACK target
aliasing.

Based on initial patch from Jozsef Kadlecsik.

Acked-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hi>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/xt_CT.h |    6 +++++-
 net/netfilter/xt_CT.c                |   32 +++++++++++++++++++++++++++++---
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/netfilter/xt_CT.h b/include/uapi/linux/netfilter/xt_CT.h
index a064b8a..5a688c1 100644
--- a/include/uapi/linux/netfilter/xt_CT.h
+++ b/include/uapi/linux/netfilter/xt_CT.h
@@ -3,7 +3,11 @@
 
 #include <linux/types.h>
 
-#define XT_CT_NOTRACK	0x1
+enum {
+	XT_CT_NOTRACK		= 1 << 0,
+	XT_CT_NOTRACK_ALIAS	= 1 << 1,
+	XT_CT_MASK		= XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS,
+};
 
 struct xt_ct_target_info {
 	__u16 flags;
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index d69f1c7..a60261c 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -185,9 +185,6 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
 	struct nf_conn *ct;
 	int ret = -EOPNOTSUPP;
 
-	if (info->flags & ~XT_CT_NOTRACK)
-		return -EINVAL;
-
 	if (info->flags & XT_CT_NOTRACK) {
 		ct = nf_ct_untracked_get();
 		atomic_inc(&ct->ct_general.use);
@@ -256,6 +253,9 @@ static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 	};
 	int ret;
 
+	if (info->flags & ~XT_CT_NOTRACK)
+		return -EINVAL;
+
 	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
 
 	ret = xt_ct_tg_check(par, &info_v1);
@@ -269,6 +269,21 @@ static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 
 static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
 {
+	struct xt_ct_target_info_v1 *info = par->targinfo;
+
+	if (info->flags & ~XT_CT_NOTRACK)
+		return -EINVAL;
+
+	return xt_ct_tg_check(par, par->targinfo);
+}
+
+static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
+{
+	struct xt_ct_target_info_v1 *info = par->targinfo;
+
+	if (info->flags & ~XT_CT_MASK)
+		return -EINVAL;
+
 	return xt_ct_tg_check(par, par->targinfo);
 }
 
@@ -350,6 +365,17 @@ static struct xt_target xt_ct_tg_reg[] __read_mostly = {
 		.table		= "raw",
 		.me		= THIS_MODULE,
 	},
+	{
+		.name		= "CT",
+		.family		= NFPROTO_UNSPEC,
+		.revision	= 2,
+		.targetsize	= sizeof(struct xt_ct_target_info_v1),
+		.checkentry	= xt_ct_tg_check_v2,
+		.destroy	= xt_ct_tg_destroy_v1,
+		.target		= xt_ct_target_v1,
+		.table		= "raw",
+		.me		= THIS_MODULE,
+	},
 };
 
 static unsigned int
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 2/7] netfilter: xt_conntrack: Add flag to support aliases
From: pablo @ 2013-02-19  0:10 UTC (permalink / raw)
  To: netdev; +Cc: davem, netfilter-devel
In-Reply-To: <1361232651-5626-1-git-send-email-pablo@netfilter.org>

From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

The patch adds the flag to denote the "state" alias as of the subset
of the "conntrack" match.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/xt_conntrack.h |    1 +
 1 file changed, 1 insertion(+)

diff --git a/include/uapi/linux/netfilter/xt_conntrack.h b/include/uapi/linux/netfilter/xt_conntrack.h
index e3c041d..e5bd308 100644
--- a/include/uapi/linux/netfilter/xt_conntrack.h
+++ b/include/uapi/linux/netfilter/xt_conntrack.h
@@ -31,6 +31,7 @@ enum {
 	XT_CONNTRACK_REPLSRC_PORT = 1 << 10,
 	XT_CONNTRACK_REPLDST_PORT = 1 << 11,
 	XT_CONNTRACK_DIRECTION    = 1 << 12,
+	XT_CONNTRACK_STATE_ALIAS  = 1 << 13,
 };
 
 struct xt_conntrack_mtinfo1 {
-- 
1.7.10.4


^ permalink raw reply related

* [RFC] ipv6: rt6_update_expires() seems racy
From: Eric Dumazet @ 2013-02-18 23:55 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Gao feng, Neil Horman, Jiri Bohac

Some strange crashes happen in rt6_check_expired(), with access
to random addresses.

At first glance, it looks like the RTF_EXPIRES and
stuff added in commit 1716a96101c49186b
(ipv6: fix problem with expired dst cache)
are racy : same dst could be manipulated at the same time
on different cpus.

At some point, our stack believes rt->dst.from contains a dst pointer,
while its really a jiffie value (as rt->dst.expires shares the same area
of memory)

rt6_update_expires() should be fixed, or am I missing something ?

CC Neil because of https://bugzilla.redhat.com/show_bug.cgi?id=892060

^ permalink raw reply

* [PATCH v2 net-next 5/6] qlcnic: fix ping resumption to a VM after a live migration
From: Jitendra Kalsaria @ 2013-02-18 23:22 UTC (permalink / raw)
  To: davem; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver, Shahed Shaikh

From: Shahed Shaikh <shahed.shaikh@qlogic.com>

Delete the MAC address of a VM, from the adapter's embedded switch,
after the VM had been migrated out of this adapter/server.

Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h      |    5 +
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c   |   18 +++-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c   |  145 ++++++++++++++++++++--
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |   21 +++
 4 files changed, 177 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 61b594c..01e9ea1 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1008,9 +1008,12 @@ struct qlcnic_adapter {
 	struct delayed_work idc_aen_work;
 
 	struct qlcnic_filter_hash fhash;
+	struct qlcnic_filter_hash rx_fhash;
 
 	spinlock_t tx_clean_lock;
 	spinlock_t mac_learn_lock;
+	/* spinlock for catching rcv filters for eswitch traffic */
+	spinlock_t rx_mac_learn_lock;
 	u32 file_prd_off;	/*File fw product offset*/
 	u32 fw_version;
 	const struct firmware *fw;
@@ -1506,6 +1509,8 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *);
 int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
 int qlcnic_reset_npar_config(struct qlcnic_adapter *);
 int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
+void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int,
+			  __le16);
 /*
  * QLOGIC Board information
  */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 51716ab..325e11e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -578,7 +578,8 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
 	struct qlcnic_filter *tmp_fil;
 	struct hlist_node *tmp_hnode, *n;
 	struct hlist_head *head;
-	int i, time;
+	int i;
+	unsigned long time;
 	u8 cmd;
 
 	for (i = 0; i < adapter->fhash.fbucket_size; i++) {
@@ -600,6 +601,21 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
 			}
 		}
 	}
+	for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) {
+		head = &(adapter->rx_fhash.fhead[i]);
+
+		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
+		{
+			time = tmp_fil->ftime;
+			if (jiffies > (QLCNIC_FILTER_AGE * HZ + time)) {
+				spin_lock_bh(&adapter->rx_mac_learn_lock);
+				adapter->rx_fhash.fnum--;
+				hlist_del(&tmp_fil->fnode);
+				spin_unlock_bh(&adapter->rx_mac_learn_lock);
+				kfree(tmp_fil);
+			}
+		}
+	}
 }
 
 void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 2990f45..6387e0c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -152,6 +152,89 @@ static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
 		return handle;
 }
 
+static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
+{
+	return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
+}
+
+void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
+			  int loopback_pkt, __le16 vlan_id)
+{
+	struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+	struct qlcnic_filter *fil, *tmp_fil;
+	struct hlist_node *tmp_hnode, *n;
+	struct hlist_head *head;
+	unsigned long time;
+	u64 src_addr = 0;
+	u8 hindex, found = 0, op;
+	int ret;
+
+	memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+
+	if (loopback_pkt) {
+		if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
+			return;
+
+		hindex = qlcnic_mac_hash(src_addr) &
+			 (adapter->fhash.fbucket_size - 1);
+		head = &(adapter->rx_fhash.fhead[hindex]);
+
+		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+			if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+			    tmp_fil->vlan_id == vlan_id) {
+				time = tmp_fil->ftime;
+				if (jiffies > (QLCNIC_READD_AGE * HZ + time))
+					tmp_fil->ftime = jiffies;
+				return;
+			}
+		}
+
+		fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
+		if (!fil)
+			return;
+
+		fil->ftime = jiffies;
+		memcpy(fil->faddr, &src_addr, ETH_ALEN);
+		fil->vlan_id = vlan_id;
+		spin_lock(&adapter->rx_mac_learn_lock);
+		hlist_add_head(&(fil->fnode), head);
+		adapter->rx_fhash.fnum++;
+		spin_unlock(&adapter->rx_mac_learn_lock);
+	} else {
+		hindex = qlcnic_mac_hash(src_addr) &
+			 (adapter->fhash.fbucket_size - 1);
+		head = &(adapter->rx_fhash.fhead[hindex]);
+		spin_lock(&adapter->rx_mac_learn_lock);
+		hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+			if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+			    tmp_fil->vlan_id == vlan_id) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			spin_unlock(&adapter->rx_mac_learn_lock);
+			return;
+		}
+
+		op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+		ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr,
+						vlan_id, op);
+		if (!ret) {
+			op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
+			ret = qlcnic_sre_macaddr_change(adapter,
+							(u8 *)&src_addr,
+							vlan_id, op);
+			if (!ret) {
+				hlist_del(&(tmp_fil->fnode));
+				adapter->rx_fhash.fnum--;
+			}
+		}
+		spin_unlock(&adapter->rx_mac_learn_lock);
+	}
+}
+
 void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
 			       __le16 vlan_id)
 {
@@ -207,9 +290,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
 		return;
 	}
 
-	/* Only NPAR capable devices support vlan based learning */
-	if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
-		vlan_id = first_desc->vlan_TCI;
 	memcpy(&src_addr, phdr->h_source, ETH_ALEN);
 	hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
 	head = &(adapter->fhash.fhead[hindex]);
@@ -920,8 +1000,8 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
 	struct qlcnic_rx_buffer *buffer;
 	struct sk_buff *skb;
 	struct qlcnic_host_rds_ring *rds_ring;
-	int index, length, cksum, pkt_offset;
-	u16 vid = 0xffff;
+	int index, length, cksum, pkt_offset, is_lb_pkt;
+	u16 vid = 0xffff, t_vid;
 
 	if (unlikely(ring >= adapter->max_rds_rings))
 		return NULL;
@@ -941,6 +1021,14 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
 	if (!skb)
 		return buffer;
 
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
+
 	if (length > rds_ring->skb_size)
 		skb_put(skb, rds_ring->skb_size);
 	else
@@ -985,8 +1073,8 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
 	struct ipv6hdr *ipv6h;
 	struct tcphdr *th;
 	bool push, timestamp;
-	int index, l2_hdr_offset, l4_hdr_offset;
-	u16 lro_length, length, data_offset, vid = 0xffff;
+	int index, l2_hdr_offset, l4_hdr_offset, is_lb_pkt;
+	u16 lro_length, length, data_offset, t_vid, vid = 0xffff;
 	u32 seq_number;
 
 	if (unlikely(ring > adapter->max_rds_rings))
@@ -1011,6 +1099,14 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
 	if (!skb)
 		return buffer;
 
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
+
 	if (timestamp)
 		data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
 	else
@@ -1357,6 +1453,17 @@ void qlcnic_82xx_napi_disable(struct qlcnic_adapter *adapter)
 	}
 }
 
+#define QLC_83XX_NORMAL_LB_PKT	(1ULL << 36)
+#define QLC_83XX_LRO_LB_PKT	(1ULL << 46)
+
+static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)
+{
+	if (lro_pkt)
+		return (sts_data & QLC_83XX_LRO_LB_PKT) ? 1 : 0;
+	else
+		return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;
+}
+
 static struct qlcnic_rx_buffer *
 qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
 			struct qlcnic_host_sds_ring *sds_ring,
@@ -1367,8 +1474,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
 	struct qlcnic_rx_buffer *buffer;
 	struct sk_buff *skb;
 	struct qlcnic_host_rds_ring *rds_ring;
-	int index, length, cksum;
-	u16 vid = 0xffff;
+	int index, length, cksum, is_lb_pkt;
+	u16 vid = 0xffff, t_vid;
 
 	if (unlikely(ring >= adapter->max_rds_rings))
 		return NULL;
@@ -1386,6 +1493,14 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
 	if (!skb)
 		return buffer;
 
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
+
 	if (length > rds_ring->skb_size)
 		skb_put(skb, rds_ring->skb_size);
 	else
@@ -1424,9 +1539,9 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
 	struct tcphdr *th;
 	bool push;
 	int l2_hdr_offset, l4_hdr_offset;
-	int index;
+	int index, is_lb_pkt;
 	u16 lro_length, length, data_offset, gso_size;
-	u16 vid = 0xffff;
+	u16 vid = 0xffff, t_vid;
 
 	if (unlikely(ring > adapter->max_rds_rings))
 		return NULL;
@@ -1447,6 +1562,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
 	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
 	if (!skb)
 		return buffer;
+
+	if (adapter->drv_mac_learn &&
+	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+		t_vid = 0;
+		is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
+		qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
+				     cpu_to_le16(t_vid));
+	}
 	if (qlcnic_83xx_is_tstamp(sts_data[1]))
 		data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
 	else
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index e03017a..5d5fd06 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2208,6 +2208,7 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
 
 	act_pci_func = adapter->ahw->act_pci_func;
 	spin_lock_init(&adapter->mac_learn_lock);
+	spin_lock_init(&adapter->rx_mac_learn_lock);
 
 	if (qlcnic_82xx_check(adapter)) {
 		filter_size = QLCNIC_LB_MAX_FILTERS;
@@ -2231,6 +2232,20 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
 
 	for (i = 0; i < adapter->fhash.fbucket_size; i++)
 		INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
+
+	adapter->rx_fhash.fbucket_size = adapter->fhash.fbucket_size;
+
+	head = kcalloc(adapter->rx_fhash.fbucket_size,
+		       sizeof(struct hlist_head), GFP_ATOMIC);
+
+	if (!head)
+		return;
+
+	adapter->rx_fhash.fmax = (filter_size / act_pci_func);
+	adapter->rx_fhash.fhead = head;
+
+	for (i = 0; i < adapter->rx_fhash.fbucket_size; i++)
+		INIT_HLIST_HEAD(&adapter->rx_fhash.fhead[i]);
 }
 
 static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
@@ -2240,6 +2255,12 @@ static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
 
 	adapter->fhash.fhead = NULL;
 	adapter->fhash.fmax = 0;
+
+	if (adapter->rx_fhash.fmax && adapter->rx_fhash.fhead)
+		kfree(adapter->rx_fhash.fhead);
+
+	adapter->rx_fhash.fmax = 0;
+	adapter->rx_fhash.fhead = NULL;
 }
 
 int qlcnic_check_temp(struct qlcnic_adapter *adapter)
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCHv2 vringh 3/3] caif_virtio: Introduce caif over virtio
From: Rusty Russell @ 2013-02-18 23:37 UTC (permalink / raw)
  To: sjur.brandeland, David S. Miller, Ohad Ben-Cohen
  Cc: sjur, netdev, virtualization, linux-kernel, Dmitry Tarnyagin,
	Linus Walleij, Erwan Yvin, Vikram ARV, Sjur Brændeland,
	Ido Yariv
In-Reply-To: <1360669793-6921-4-git-send-email-sjur.brandeland@stericsson.com>

sjur.brandeland@stericsson.com writes:
> From: Vikram ARV <vikram.arv@stericsson.com>
>
> Add the the Virtio shared memory driver for STE Modems.
> caif_virtio is implemented utilizing the virtio framework
> for data transport and is managed with the remoteproc frameworks.
>
> The Virtio queue is used for transmitting data to the modem, and
> the new vringh implementation is receiving data over the vring.
>
> Signed-off-by: Vikram ARV <vikram.arv@stericsson.com>
> Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>

I have applied 1 and 3 (2 is already in virtio-next); they're in my
pending-rebases branch behind the vringh patches which are pending
a final review.

Here's the warning fix patch I applied:

diff --git a/drivers/net/caif/caif_virtio.c b/drivers/net/caif/caif_virtio.c
index d4f339c..df832e7 100644
--- a/drivers/net/caif/caif_virtio.c
+++ b/drivers/net/caif/caif_virtio.c
@@ -483,7 +483,7 @@ static int cfv_probe(struct virtio_device *vdev)
 
 	vdev->priv = cfv;
 
-	vringh_iov_init(&cfv->ctx.riov, NULL, 0);
+	vringh_kiov_init(&cfv->ctx.riov, NULL, 0);
 	cfv->ctx.head = USHRT_MAX;
 
 	netif_napi_add(netdev, &cfv->napi, cfv_rx_poll, CFV_DEFAULT_QUOTA);
@@ -517,7 +517,7 @@ static void cfv_remove(struct virtio_device *vdev)
 	struct cfv_info *cfv = vdev->priv;
 
 	tasklet_kill(&cfv->tx_release_tasklet);
-	vringh_iov_cleanup(&cfv->ctx.riov);
+	vringh_kiov_cleanup(&cfv->ctx.riov);
 	vdev->config->reset(vdev);
 	rproc_virtio_del_vringh(vdev, RX_RING_INDEX);
 	cfv->vr_rx = NULL;

Cheers,
Rusty.

^ permalink raw reply related

* Re: [PATCH net-next 3/3] bonding: fix bond_release_all inconsistencies
From: Jay Vosburgh @ 2013-02-18 23:17 UTC (permalink / raw)
  To: Nikolay Aleksandrov; +Cc: netdev, davem, andy
In-Reply-To: <5122A7A1.4010803@redhat.com>

Nikolay Aleksandrov <nikolay@redhat.com> wrote:

>On 18/02/13 22:56, Jay Vosburgh wrote:
>> Nikolay Aleksandrov <nikolay@redhat.com> wrote:
>> 
>>> This patch fixes the following inconsistencies in bond_release_all:
>>> - IFF_BONDING flag is not stripped from slaves
>>> - MTU is not restored
>>> - no netdev notifiers are sent
>>> Instead of trying to keep bond_release and bond_release_all in sync
>>> I think we can re-use bond_release as the environment for calling it
>>> is correct (RTNL is held). I have been running tests for the past
>>> week and they came out successful. The only way for bond_release to fail
>>> is for the slave to be attached in a different bond or to not be a slave
>>> but that cannot happen as RTNL is held and no slave manipulations can be
>>> achieved.
>> 
>> 	It might be worthwhile to add an "all" argument to bond_release
>> that skips some things that don't make sense if all slaves are being
>> released.  I'm thinking in particular of this block:
>> 
>> 	if (oldcurrent == slave) {
>> 		/*
>> 		 * Note that we hold RTNL over this sequence, so there
>> 		 * is no concern that another slave add/remove event
>> 		 * will interfere.
>> 		 */
>> 		write_unlock_bh(&bond->lock);
>> 		read_lock(&bond->lock);
>> 		write_lock_bh(&bond->curr_slave_lock);
>> 
>> 		bond_select_active_slave(bond);
>> 
>> 		write_unlock_bh(&bond->curr_slave_lock);
>> 		read_unlock(&bond->lock);
>> 		write_lock_bh(&bond->lock);
>> 	}
>> 
>> 	as it's written now, for the release all case, the code may go
>> to the trouble of assigning a new active slave each time one slave is
>> removed (including various log messages, maybe sending IGMPs, etc).  If
>> all slaves are being removed, that's pointless.  This could be something
>> like:
>> 
>> 	if (release_all) {
>> 		bond->curr_active_slave = NULL;
>> 	} else if (oldcurrent == slave) {
>> 		[ the current block of stuff ]
>> 	}
>> 
>> 	it's safe here to unconditionally set curr_active_slave to NULL
>> because we hold bond->lock for write.  The lock dance stuff for the
>> bond_select_active_slave() call is to satisfy its locking requirements.
>> 
>> 	-J
>I see your point and I agree. I will prepare another version that
>incorporates it, although I can't add it as an argument since
>bond_release is used as ndo_del_slave. I'll have to make it a global
>variable.

	No, just rename the current bond_release to __bond_release_one,
add the extra argument, and create a new bond_release .ndo_del_slave
that calls __bond_release_one with "all=0".  Then, bond_release_all
calls __bond_release_one with all=1.

	Also, there's only one caller of bond_release_all, and since the
new & improved bond_release_all is trivial, it could be open coded into
bond_uninit, eliminating bond_release_all as a function.

	-J

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com

^ permalink raw reply

* Re: SYSFS "errors"
From: Borislav Petkov @ 2013-02-18 22:44 UTC (permalink / raw)
  To: Greg KH
  Cc: Mauro Carvalho Chehab, balbi, Linux Kernel Mailing List,
	Steven Rostedt, Frederic Weisbecker, Ingo Molnar, JBottomley,
	linux-scsi, davem, netdev, Doug Thompson, linux-edac, rjw,
	linux-pm
In-Reply-To: <20130218222618.GA21818@kroah.com>

On Mon, Feb 18, 2013 at 02:26:18PM -0800, Greg KH wrote:
> I don't know, it depends on if userspace can handle this properly or
> not. What tools rely on this sysfs file? WHat happens when they get a
> non-number in the file?

I'm not aware of any, frankly speaking.

If there are any, those tools should be able to handle the -ENODEV
they get. Now, if this gets changed this way, the read would succeed
but they'll have to parse the returned value and see that it is not an
integer.

So I don't know either.

But my gut feeling says to stay concervative and not touch this code -
we don't know what uses it and how much we would break by "fixing" it.
The current situation is not that big of a deal IMVHO and I'd be willing
to accept the small inconcistency versus possibly breaking userspace.

Thanks.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--

^ permalink raw reply

* Re: [PATCH] Don't allow multiple TPGs or targets to share a portal
From: Andy Grover @ 2013-02-18 22:41 UTC (permalink / raw)
  To: Nicholas A. Bellinger; +Cc: target-devel, netdev
In-Reply-To: <1360943188.13707.114.camel@haakon2.linux-iscsi.org>

On 02/15/2013 07:46 AM, Nicholas A. Bellinger wrote:
> The wording in section Section 3.4.1, e) that your referring to:
>
> "Each Network Portal, as utilized by a given iSCSI Node, belongs to
> exactly one portal group within that node."
>
> does not mean that individual network portals are limited to a single
> network entity, but that network portals are linked to a single TPG
> within an individual TargetName.  Eg, 'that node' does not mean the
> entire physical machine (network entity), that may contain multiple
> nodes (TargetName+TargetPortalGroupTag endpoints).
>
> However, in practice I've not yet seen a target implementation that
> supports multiple TPGs actually enforce this, considering this is not
> accompanied by a "SHOULD not" or "MUST not" anywhere in the spec.  So
> unless you have a specific problem case where this is causing an issue
> with an initiator, I'm likely not going to accept a kernel patch to
> change existing behavior.

OK, so I'm clear now that a NetworkPortal can be shared among 
TargetNames, but not among TPGs within a TargetName.

But LIO currently allows it.
See https://bugzilla.redhat.com/show_bug.cgi?id=908368 .

The tester's actual issue may not be related to this area, but if you 
look at the attachment in comment 2, this configuration was allowed.

I don't think this is an issue where we need to worry about existing 
behavior. This *can't* work because the initiator passes the desired 
TargetName during iSCSI login, but not TargetPortalGroupTag. There's no 
way a target can tell which TPG the initiator wants if the TargetName 
for two are the same.

We could add a check for this to the rtslib userspace library, but this 
would mean the kernel could still be configured this way, if rtslib was 
not used to wrap configfs accesses. Therefore I'd push for the kernel to 
check for this. Would a patch for that fly?

Thanks -- Regards -- Andy

^ permalink raw reply

* Re: [PATCH vringh 2/2] caif_virtio: Introduce caif over virtio
From: Rusty Russell @ 2013-02-18 22:30 UTC (permalink / raw)
  To: Sjur Brændeland
  Cc: David S. Miller, Ohad Ben-Cohen, Vikram ARV, Dmitry TARNYAGIN,
	Linus Walleij, linux-kernel@vger.kernel.org, Erwan YVIN,
	virtualization@lists.linux-foundation.org, netdev@vger.kernel.org,
	Ido Yariv, mst
In-Reply-To: <CAJK669ZATh8FojTGdFH_x7ovMvA2L7XFUratiptJmPFZPhv31g@mail.gmail.com>

Sjur Brændeland <sjurbren@gmail.com> writes:

>> Sjur Brændeland <sjurbren@gmail.com> writes:
>>> How about supporting struct vringh_kiov and struct kvec as well?
>>> I currently get the following complaints with my V2 patch-set:
>>>
>>> drivers/net/caif/caif_virtio.c:486:2: warning: passing argument 1 of
>>> ‘vringh_iov_init’ from incompatible pointer type [enabled by default]
>>
>> vringh_kiov_init()?  Did I miss something else?
>
> I get a warning for my useof vringh_iov_cleanup() in
> addition to the one above.
>
> How about adding kiov variants of  vringh_iov_cleanup()
> and vringh_iov_reset() as well?

Hmm, I have those here too (in the header):

+static inline void vringh_kiov_reset(struct vringh_kiov *kiov)
+{
+	kiov->off = 0;
+	kiov->i = 0;
+}
+
+static inline void vringh_kiov_cleanup(struct vringh_kiov *kiov)
+{
+	if (kiov->max_num & VRINGH_IOV_ALLOCATED)
+		kfree(kiov->iov);
+	kiov->max_num = kiov->used = kiov->i = kiov->off = 0;
+	kiov->iov = NULL;
+}

I've folded the patches and put them into my pending-rebases branch,
ready for virtio-next.

I'd really like MST's ack on this, too, so I'll repost the series.

Cheers,
Rusty.

^ permalink raw reply

* [PATCH v2 net-next 6/6] qlcnic: Bump up the version to 5.1.34
From: Jitendra Kalsaria @ 2013-02-18 22:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver, Jitendra Kalsaria
In-Reply-To: <1361225178-4363-1-git-send-email-jitendra.kalsaria@qlogic.com>

From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>

Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 01e9ea1..11c3db6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -38,8 +38,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 1
-#define _QLCNIC_LINUX_SUBVERSION 33
-#define QLCNIC_LINUX_VERSIONID  "5.1.33"
+#define _QLCNIC_LINUX_SUBVERSION 34
+#define QLCNIC_LINUX_VERSIONID  "5.1.34"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 net-next 4/6] qlcnic: fix estimation of receive MSS in case of LRO for 83xx adapter
From: Jitendra Kalsaria @ 2013-02-18 22:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver, Shahed Shaikh
In-Reply-To: <1361225178-4363-1-git-send-email-jitendra.kalsaria@qlogic.com>

From: Shahed Shaikh <shahed.shaikh@qlogic.com>

Set gso_size to MSS obtained from adapter to avoid incorrect estimation
of receive MSS, which would lead to delayed ACKs in some traffic patterns

Example:
Send two or three packets and wait for ack and only then send
remaining packets.

Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h    |    1 +
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c     |   13 ++++++++++-
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |   24 +++++++++++++------
 3 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 127fa27..61f81f6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -223,6 +223,7 @@ struct qlc_83xx_idc {
 #define QLC_83XX_GET_LSO_CAPABILITY(val)		(val & 0x40)
 #define QLC_83XX_GET_HW_LRO_CAPABILITY(val)		(val & 0x400)
 #define QLC_83XX_GET_VLAN_ALIGN_CAPABILITY(val)	(val & 0x4000)
+#define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val)	(val & 0x20000)
 #define QLC_83XX_VIRTUAL_NIC_MODE			0xFF
 #define QLC_83XX_DEFAULT_MODE				0x0
 #define QLCNIC_BRDTYPE_83XX_10G			0x0083
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 662292d..2990f45 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -88,6 +88,8 @@
 #define qlcnic_get_lro_sts_mss(sts_data1)		\
 	((sts_data1 >> 32) & 0x0FFFF)
 
+#define qlcnic_83xx_get_lro_sts_mss(sts) ((sts) & 0xffff)
+
 /* opcode field in status_desc */
 #define QLCNIC_SYN_OFFLOAD	0x03
 #define QLCNIC_RXPKT_DESC  	0x04
@@ -1423,7 +1425,7 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
 	bool push;
 	int l2_hdr_offset, l4_hdr_offset;
 	int index;
-	u16 lro_length, length, data_offset;
+	u16 lro_length, length, data_offset, gso_size;
 	u16 vid = 0xffff;
 
 	if (unlikely(ring > adapter->max_rds_rings))
@@ -1478,6 +1480,15 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
 	th->psh = push;
 	length = skb->len;
 
+	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) {
+		gso_size = qlcnic_83xx_get_lro_sts_mss(sts_data[0]);
+		skb_shinfo(skb)->gso_size = gso_size;
+		if (skb->protocol == htons(ETH_P_IPV6))
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+		else
+			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+	}
+
 	if (vid != 0xffff)
 		__vlan_hwaccel_put_tag(skb, vid);
 
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 3a0f182..e03017a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1339,11 +1339,24 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
 	}
 }
 
+static void qlcnic_get_lro_mss_capability(struct qlcnic_adapter *adapter)
+{
+	u32 capab = 0;
+
+	if (qlcnic_82xx_check(adapter)) {
+		if (adapter->ahw->capabilities2 &
+		    QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+	} else {
+		capab = adapter->ahw->capabilities;
+		if (QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(capab))
+			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+	}
+}
+
 int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
 	int ring;
-	u32 capab2;
-
 	struct qlcnic_host_rds_ring *rds_ring;
 
 	if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1353,12 +1366,7 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 		return 0;
 	if (qlcnic_set_eswitch_port_config(adapter))
 		return -EIO;
-
-	if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
-		capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
-		if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
-			adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
-	}
+	qlcnic_get_lro_mss_capability(adapter);
 
 	if (qlcnic_fw_create_ctx(adapter))
 		return -EIO;
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 net-next 3/6] qlcnic: refactor Legacy interrupt handling for 83xx
From: Jitendra Kalsaria @ 2013-02-18 22:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
In-Reply-To: <1361225178-4363-1-git-send-email-jitendra.kalsaria@qlogic.com>

From: Himanshu Madhani <himanshu.madhani@qlogic.com>

o Cleanly seperate 83xx Legacy interrupt handling code from 82xx
o Update 83xx Legacy interrupt handling code to match with the spec

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    |  130 +++++++++++++++++---
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h    |    3 +
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c     |   30 +----
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |   37 ++++--
 4 files changed, 144 insertions(+), 56 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index e92cc52..cd5ae88 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -388,12 +388,45 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
 	return 0;
 }
 
-inline void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
-				    struct qlcnic_host_sds_ring *sds_ring)
+inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)
+{
+	writel(0, adapter->tgt_mask_reg);
+}
+
+/* Enable MSI-x and INT-x interrupts */
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
+			     struct qlcnic_host_sds_ring *sds_ring)
 {
 	writel(0, sds_ring->crb_intr_mask);
-	if (!QLCNIC_IS_MSI_FAMILY(adapter))
-		writel(0, adapter->tgt_mask_reg);
+}
+
+/* Disable MSI-x and INT-x interrupts */
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *adapter,
+			      struct qlcnic_host_sds_ring *sds_ring)
+{
+	writel(1, sds_ring->crb_intr_mask);
+}
+
+inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter
+						    *adapter)
+{
+	u32 mask;
+
+	/* Mailbox in MSI-x mode and Legacy Interrupt share the same
+	 * source register. We could be here before contexts are created
+	 * and sds_ring->crb_intr_mask has not been initialized, calculate
+	 * BAR offset for Interrupt Source Register
+	 */
+	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+	writel(0, adapter->ahw->pci_base0 + mask);
+}
+
+inline void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter)
+{
+	u32 mask;
+
+	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+	writel(1, adapter->ahw->pci_base0 + mask);
 }
 
 static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
@@ -419,8 +452,12 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
 		adapter->stats.spurious_intr++;
 		return IRQ_NONE;
 	}
+	/* The barrier is required to ensure writes to the registers */
+	wmb();
+
 	/* clear the interrupt trigger control register */
 	writel(0, adapter->isr_int_vec);
+	intr_val = readl(adapter->isr_int_vec);
 	do {
 		intr_val = readl(adapter->tgt_status_reg);
 		if (QLC_83XX_INTX_FUNC(intr_val) != ahw->pci_func)
@@ -429,13 +466,51 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
 	} while (QLC_83XX_VALID_INTX_BIT30(intr_val) &&
 		 (retries < QLC_83XX_LEGACY_INTX_MAX_RETRY));
 
-	if (retries == QLC_83XX_LEGACY_INTX_MAX_RETRY) {
-		dev_info(&adapter->pdev->dev,
-			 "Reached maximum retries to clear legacy interrupt\n");
+	return IRQ_HANDLED;
+}
+
+static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
+{
+	u32 resp, event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+
+	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+	if (!(resp & QLCNIC_SET_OWNER))
+		goto out;
+
+	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
+	if (event &  QLCNIC_MBX_ASYNC_EVENT)
+		qlcnic_83xx_process_aen(adapter);
+out:
+	qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+}
+
+irqreturn_t qlcnic_83xx_intr(int irq, void *data)
+{
+	struct qlcnic_adapter *adapter = data;
+	struct qlcnic_host_sds_ring *sds_ring;
+	struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+	if (qlcnic_83xx_clear_legacy_intr(adapter) == IRQ_NONE)
 		return IRQ_NONE;
+
+	qlcnic_83xx_poll_process_aen(adapter);
+
+	if (ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+		ahw->diag_cnt++;
+		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+		return IRQ_HANDLED;
 	}
 
-	mdelay(QLC_83XX_LEGACY_INTX_DELAY);
+	if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+		qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
+	} else {
+		sds_ring = &adapter->recv_ctx->sds_rings[0];
+		napi_schedule(&sds_ring->napi);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -460,14 +535,20 @@ done:
 
 void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
 {
-	u32 val = 0;
-	u32 num_msix = adapter->ahw->num_msix - 1;
+	u32 val = 0, num_msix = adapter->ahw->num_msix - 1;
 
-	val = (num_msix << 8);
+	if (adapter->flags & QLCNIC_MSIX_ENABLED)
+		num_msix = adapter->ahw->num_msix - 1;
+	else
+		num_msix = 0;
 
 	QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
-	if (adapter->flags & QLCNIC_MSIX_ENABLED)
-		free_irq(adapter->msix_entries[num_msix].vector, adapter);
+
+	qlcnic_83xx_disable_mbx_intr(adapter);
+
+	msleep(20);
+	synchronize_irq(adapter->msix_entries[num_msix].vector);
+	free_irq(adapter->msix_entries[num_msix].vector, adapter);
 }
 
 int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
@@ -486,13 +567,23 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
 		handler = qlcnic_83xx_handle_aen;
 		val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
 		snprintf(name, (IFNAMSIZ + 4),
-			 "%s[%s]", adapter->netdev->name, "aen");
+			 "%s[%s]", "qlcnic", "aen");
 		err = request_irq(val, handler, flags, name, adapter);
 		if (err) {
 			dev_err(&adapter->pdev->dev,
 				"failed to register MBX interrupt\n");
 			return err;
 		}
+	} else {
+		handler = qlcnic_83xx_intr;
+		val = adapter->msix_entries[0].vector;
+		err = request_irq(val, handler, flags, "qlcnic", adapter);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"failed to register INTx interrupt\n");
+			return err;
+		}
+		qlcnic_83xx_clear_legacy_intr_mask(adapter);
 	}
 
 	/* Enable mailbox interrupt */
@@ -604,6 +695,7 @@ void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
 		val = BIT_2;
 
 	QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+	qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
 }
 
 void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,
@@ -700,6 +792,7 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
 	int i;
 	u16 opcode;
 	u8 mbx_err_code;
+	unsigned long flags;
 	u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
 
@@ -711,7 +804,7 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
 		return 0;
 	}
 
-	spin_lock(&ahw->mbx_lock);
+	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
 	mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
 
 	if (mbx_val) {
@@ -721,7 +814,7 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
 		      "Mailbox not available, 0x%x, collect FW dump\n",
 		      mbx_val);
 		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
-		spin_unlock(&ahw->mbx_lock);
+		spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
 		return cmd->rsp.arg[0];
 	}
 
@@ -776,7 +869,7 @@ poll:
 out:
 	/* clear fw mbx control register */
 	QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
-	spin_unlock(&ahw->mbx_lock);
+	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
 	return rsp;
 }
 
@@ -1194,7 +1287,7 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
 	if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
 		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 			sds_ring = &adapter->recv_ctx->sds_rings[ring];
-			writel(1, sds_ring->crb_intr_mask);
+			qlcnic_83xx_disable_intr(adapter, sds_ring);
 		}
 	}
 
@@ -1730,6 +1823,7 @@ irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
 	if (!(resp & QLCNIC_SET_OWNER))
 		goto out;
+
 	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
 	if (event &  QLCNIC_MBX_ASYNC_EVENT)
 		qlcnic_83xx_process_aen(adapter);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index f60e28a..127fa27 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -368,9 +368,12 @@ irqreturn_t qlcnic_83xx_handle_aen(int, void *);
 int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
 void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
 irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_intr(int, void *);
 irqreturn_t qlcnic_83xx_tmp_intr(int, void *);
 void qlcnic_83xx_enable_intr(struct qlcnic_adapter *,
 			     struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_disable_intr(struct qlcnic_adapter *,
+			     struct qlcnic_host_sds_ring *);
 void qlcnic_83xx_check_vf(struct qlcnic_adapter *,
 			  const struct pci_device_id *);
 void qlcnic_83xx_process_aen(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 93839f8..662292d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -1558,24 +1558,6 @@ skip:
 	return count;
 }
 
-static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
-{
-	unsigned long flags;
-	u32 mask, resp, event;
-
-	spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
-	resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
-	if (!(resp & QLCNIC_SET_OWNER))
-		goto out;
-	event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-	if (event &  QLCNIC_MBX_ASYNC_EVENT)
-		qlcnic_83xx_process_aen(adapter);
-out:
-	mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
-	writel(0, adapter->ahw->pci_base0 + mask);
-	spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
-}
-
 static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
 {
 	int tx_complete;
@@ -1589,15 +1571,11 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
 	/* tx ring count = 1 */
 	tx_ring = adapter->tx_ring;
 
-	if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
-		qlcnic_83xx_poll_process_aen(adapter);
-
 	tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
 	work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
 	if ((work_done < budget) && tx_complete) {
 		napi_complete(&sds_ring->napi);
-		if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
-			qlcnic_83xx_enable_intr(adapter, sds_ring);
+		qlcnic_83xx_enable_intr(adapter, sds_ring);
 	}
 
 	return work_done;
@@ -1653,7 +1631,8 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)
 	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 		sds_ring = &recv_ctx->sds_rings[ring];
 		napi_enable(&sds_ring->napi);
-		qlcnic_83xx_enable_intr(adapter, sds_ring);
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			qlcnic_83xx_enable_intr(adapter, sds_ring);
 	}
 
 	if (adapter->flags & QLCNIC_MSIX_ENABLED) {
@@ -1677,7 +1656,8 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)
 
 	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 		sds_ring = &recv_ctx->sds_rings[ring];
-		writel(1, sds_ring->crb_intr_mask);
+		if (adapter->flags & QLCNIC_MSIX_ENABLED)
+			qlcnic_83xx_disable_intr(adapter, sds_ring);
 		napi_synchronize(&sds_ring->napi);
 		napi_disable(&sds_ring->napi);
 	}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index f084dc1..3a0f182 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1269,20 +1269,27 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
 			handler = qlcnic_msi_intr;
 		else {
 			flags |= IRQF_SHARED;
-			handler = qlcnic_intr;
+			if (qlcnic_82xx_check(adapter))
+				handler = qlcnic_intr;
+			else
+				handler = qlcnic_83xx_intr;
 		}
 	}
 	adapter->irq = netdev->irq;
 
 	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
-		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-			sds_ring = &recv_ctx->sds_rings[ring];
-			snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
-				 "%s[%d]", netdev->name, ring);
-			err = request_irq(sds_ring->irq, handler, flags,
-					  sds_ring->name, sds_ring);
-			if (err)
-				return err;
+		if (qlcnic_82xx_check(adapter) ||
+		    (qlcnic_83xx_check(adapter) &&
+		     (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+			for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+				sds_ring = &recv_ctx->sds_rings[ring];
+				snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
+					 "%s[%d]", netdev->name, ring);
+				err = request_irq(sds_ring->irq, handler, flags,
+						  sds_ring->name, sds_ring);
+				if (err)
+					return err;
+			}
 		}
 		if (qlcnic_83xx_check(adapter) &&
 		    (adapter->flags & QLCNIC_MSIX_ENABLED)) {
@@ -1292,7 +1299,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
 				tx_ring = &adapter->tx_ring[ring];
 				snprintf(tx_ring->name, sizeof(int) + IFNAMSIZ,
 					 "%s[%d]", netdev->name,
-				adapter->max_sds_rings + ring);
+					 adapter->max_sds_rings + ring);
 				err = request_irq(tx_ring->irq, handler, flags,
 						  tx_ring->name, tx_ring);
 				if (err)
@@ -1313,9 +1320,13 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
 	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
 	if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
-		for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-			sds_ring = &recv_ctx->sds_rings[ring];
-			free_irq(sds_ring->irq, sds_ring);
+		if (qlcnic_82xx_check(adapter) ||
+		    (qlcnic_83xx_check(adapter) &&
+		     (adapter->flags & QLCNIC_MSIX_ENABLED))) {
+			for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+				sds_ring = &recv_ctx->sds_rings[ring];
+				free_irq(sds_ring->irq, sds_ring);
+			}
 		}
 		if (qlcnic_83xx_check(adapter)) {
 			for (ring = 0; ring < adapter->max_drv_tx_rings;
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 net-next 2/6] qlcnic: fix mailbox interrupt.
From: Jitendra Kalsaria @ 2013-02-18 22:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver,
	Sucheta Chakraborty
In-Reply-To: <1361225178-4363-1-git-send-email-jitendra.kalsaria@qlogic.com>

From: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>

o Config interrupt is not needed for mailbox interrupts.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c    |    4 +--
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c    |   27 +++++++++++++++++--
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c   |   17 +++---------
 3 files changed, 29 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index f7b39d1..e92cc52 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -497,8 +497,6 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
 
 	/* Enable mailbox interrupt */
 	qlcnic_83xx_enable_mbx_intrpt(adapter);
-	if (adapter->flags & QLCNIC_MSIX_ENABLED)
-		err = qlcnic_83xx_config_intrpt(adapter, 1);
 
 	return err;
 }
@@ -1915,7 +1913,7 @@ int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)
 	u32 val, temp;
 	struct qlcnic_cmd_args cmd;
 
-	max_ints = adapter->ahw->num_msix;
+	max_ints = adapter->ahw->num_msix - 1;
 	qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);
 	cmd.req.arg[1] = max_ints;
 	for (i = 0, index = 2; i < max_ints; i++) {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 6308d4d..a69097c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -599,9 +599,17 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
 		dev->flags &= ~QLCNIC_NEED_FLR;
 	}
 
+	if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
+		if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+			err = qlcnic_83xx_config_intrpt(dev, 1);
+			if (err)
+				return err;
+		}
+	}
+
 	err = qlcnic_fw_cmd_create_rx_ctx(dev);
 	if (err)
-		return err;
+		goto err_out;
 
 	for (ring = 0; ring < dev->max_drv_tx_rings; ring++) {
 		err = qlcnic_fw_cmd_create_tx_ctx(dev,
@@ -610,18 +618,25 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
 		if (err) {
 			qlcnic_fw_cmd_destroy_rx_ctx(dev);
 			if (ring == 0)
-				return err;
+				goto err_out;
 
 			for (i = 0; i < ring; i++)
 				qlcnic_fw_cmd_destroy_tx_ctx(dev,
 							     &dev->tx_ring[i]);
 
-			return err;
+			goto err_out;
 		}
 	}
 
 	set_bit(__QLCNIC_FW_ATTACHED, &dev->state);
 	return 0;
+
+err_out:
+	if (qlcnic_83xx_check(dev) && (dev->flags & QLCNIC_MSIX_ENABLED)) {
+		if (dev->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+			qlcnic_83xx_config_intrpt(dev, 0);
+	}
+	return err;
 }
 
 void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
@@ -633,6 +648,12 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
 		for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
 			qlcnic_fw_cmd_destroy_tx_ctx(adapter,
 						     &adapter->tx_ring[ring]);
+
+		if (qlcnic_83xx_check(adapter) &&
+		    (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+			if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+				qlcnic_83xx_config_intrpt(adapter, 0);
+		}
 		/* Allow dma queues to drain after context reset */
 		mdelay(20);
 	}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index b953168..f084dc1 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1965,11 +1965,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return 0;
 
 err_out_disable_mbx_intr:
-	if (qlcnic_83xx_check(adapter)) {
-		if (adapter->flags & QLCNIC_MSIX_ENABLED)
-			qlcnic_83xx_config_intrpt(adapter, 0);
+	if (qlcnic_83xx_check(adapter))
 		qlcnic_83xx_free_mbx_intr(adapter);
-	}
 
 err_out_disable_msi:
 	qlcnic_teardown_intr(adapter);
@@ -2015,8 +2012,6 @@ static void qlcnic_remove(struct pci_dev *pdev)
 	unregister_netdev(netdev);
 
 	if (qlcnic_83xx_check(adapter)) {
-		if (adapter->flags & QLCNIC_MSIX_ENABLED)
-			qlcnic_83xx_config_intrpt(adapter, 0);
 		qlcnic_83xx_free_mbx_intr(adapter);
 		qlcnic_83xx_register_nic_idc_func(adapter, 0);
 		cancel_delayed_work_sync(&adapter->idc_aen_work);
@@ -3107,8 +3102,6 @@ static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
 		qlcnic_down(adapter, netdev);
 
 	if (qlcnic_83xx_check(adapter)) {
-		if (adapter->flags & QLCNIC_MSIX_ENABLED)
-			qlcnic_83xx_config_intrpt(adapter, 0);
 		qlcnic_83xx_free_mbx_intr(adapter);
 		qlcnic_83xx_register_nic_idc_func(adapter, 0);
 		cancel_delayed_work_sync(&adapter->idc_aen_work);
@@ -3203,13 +3196,11 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
 	if (netif_running(netdev))
 		__qlcnic_down(adapter, netdev);
 
-	if (qlcnic_83xx_check(adapter)) {
-		if (adapter->flags & QLCNIC_MSIX_ENABLED)
-			qlcnic_83xx_config_intrpt(adapter, 0);
+	qlcnic_detach(adapter);
+
+	if (qlcnic_83xx_check(adapter))
 		qlcnic_83xx_free_mbx_intr(adapter);
-	}
 
-	qlcnic_detach(adapter);
 	qlcnic_teardown_intr(adapter);
 	err = qlcnic_setup_intr(adapter, data);
 	if (err) {
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 net-next 1/6] qlcnic: fix unsupported CDRP command error message.
From: Jitendra Kalsaria @ 2013-02-18 22:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver, Jitendra Kalsaria
In-Reply-To: <1361225178-4363-1-git-send-email-jitendra.kalsaria@qlogic.com>

From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>

Added detailed error messages for FW CDRP command failure

Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c |   25 +++++++++++++++++++++-
 1 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 4a3bd64..6308d4d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -126,6 +126,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
 	u32 signature;
 	struct pci_dev *pdev = adapter->pdev;
 	struct qlcnic_hardware_context *ahw = adapter->ahw;
+	const char *fmt;
 
 	signature = qlcnic_get_cmd_signature(ahw);
 
@@ -147,8 +148,28 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
 		cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
 	} else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
 		cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
-		dev_err(&pdev->dev, "failed card response code:0x%x\n",
-			cmd->rsp.arg[0]);
+		switch (cmd->rsp.arg[0]) {
+		case QLCNIC_RCODE_INVALID_ARGS:
+			fmt = "CDRP invalid args: [%d]\n";
+			break;
+		case QLCNIC_RCODE_NOT_SUPPORTED:
+		case QLCNIC_RCODE_NOT_IMPL:
+			fmt = "CDRP command not supported: [%d]\n";
+			break;
+		case QLCNIC_RCODE_NOT_PERMITTED:
+			fmt = "CDRP requested action not permitted: [%d]\n";
+			break;
+		case QLCNIC_RCODE_INVALID:
+			fmt = "CDRP invalid or unknown cmd received: [%d]\n";
+			break;
+		case QLCNIC_RCODE_TIMEOUT:
+			fmt = "CDRP command timeout: [%d]\n";
+			break;
+		default:
+			fmt = "CDRP command failed: [%d]\n";
+			break;
+		}
+		dev_err(&pdev->dev, fmt, cmd->rsp.arg[0]);
 	} else if (rsp == QLCNIC_CDRP_RSP_OK)
 		cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH v2 net-next 0/6] qlcnic: bug fixes and feature updates
From: Jitendra Kalsaria @ 2013-02-18 22:06 UTC (permalink / raw)
  To: davem; +Cc: netdev, sony.chacko, Dept_NX_Linux_NIC_Driver, Jitendra Kalsaria

From: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>

Patch#1 "qlcnic: fix unsupported CDRP command error message" with commit id 
"e42ede226c067fef541e4240f919ed2baf25d268" is a re-submission and also respin
as suggested by Joe Perches. We are re-submitting the same patch because this
patch got undone by the recent driver refactoring.

Patch#5 did not get through in the last submission.

Please apply to net-next.

Thanks,
Jitendra

^ permalink raw reply

* Re: SYSFS "errors"
From: Greg KH @ 2013-02-18 22:26 UTC (permalink / raw)
  To: Borislav Petkov, Mauro Carvalho Chehab, balbi,
	Linux Kernel Mailing List, Steven Rostedt, Frederic Weisbecker,
	Ingo Molnar, JBottomley, linux-scsi, davem, netdev, Doug Thompson,
	linux-edac, rjw, linux-pm
In-Reply-To: <20130218221306.GA21493@pd.tnic>

On Mon, Feb 18, 2013 at 11:13:06PM +0100, Borislav Petkov wrote:
> On Mon, Feb 18, 2013 at 01:54:34PM -0800, Greg KH wrote:
> > Because sysfs is "one value per file" the lack of a file showing up
> > shouldn't cause any userspace tools any problems, that is why we did
> > things this way.
> >
> > But, of course, userspace programmers do know how to mess things up...
> 
> How about what I proposed earlier to Felipe:
> 
> --
> diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
> index 0ca1ca71157f..d2eef76d1d46 100644
> --- a/drivers/edac/edac_mc_sysfs.c
> +++ b/drivers/edac/edac_mc_sysfs.c
> @@ -704,7 +704,7 @@ static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
>  	int bandwidth = 0;
>  
>  	if (!mci->get_sdram_scrub_rate)
> -		return -ENODEV;
> +		return sprintf(data, "N/A");
>  
>  	bandwidth = mci->get_sdram_scrub_rate(mci);
>  	if (bandwidth < 0) {
> 
> --
> 
> Would that hurt the sysfs policy? In this case we *can* read the file
> and it correctly tells us that scrub rate reading is not supported
> instead of having a number there.
> 
> Hmm.

I don't know, it depends on if userspace can handle this properly or
not.  What tools rely on this sysfs file?  WHat happens when they get a
non-number in the file?

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH net-next 3/3] bonding: fix bond_release_all inconsistencies
From: Nikolay Aleksandrov @ 2013-02-18 22:13 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: netdev, davem, andy
In-Reply-To: <21474.1361224608@death.nxdomain>

On 18/02/13 22:56, Jay Vosburgh wrote:
> Nikolay Aleksandrov <nikolay@redhat.com> wrote:
> 
>> This patch fixes the following inconsistencies in bond_release_all:
>> - IFF_BONDING flag is not stripped from slaves
>> - MTU is not restored
>> - no netdev notifiers are sent
>> Instead of trying to keep bond_release and bond_release_all in sync
>> I think we can re-use bond_release as the environment for calling it
>> is correct (RTNL is held). I have been running tests for the past
>> week and they came out successful. The only way for bond_release to fail
>> is for the slave to be attached in a different bond or to not be a slave
>> but that cannot happen as RTNL is held and no slave manipulations can be
>> achieved.
> 
> 	It might be worthwhile to add an "all" argument to bond_release
> that skips some things that don't make sense if all slaves are being
> released.  I'm thinking in particular of this block:
> 
> 	if (oldcurrent == slave) {
> 		/*
> 		 * Note that we hold RTNL over this sequence, so there
> 		 * is no concern that another slave add/remove event
> 		 * will interfere.
> 		 */
> 		write_unlock_bh(&bond->lock);
> 		read_lock(&bond->lock);
> 		write_lock_bh(&bond->curr_slave_lock);
> 
> 		bond_select_active_slave(bond);
> 
> 		write_unlock_bh(&bond->curr_slave_lock);
> 		read_unlock(&bond->lock);
> 		write_lock_bh(&bond->lock);
> 	}
> 
> 	as it's written now, for the release all case, the code may go
> to the trouble of assigning a new active slave each time one slave is
> removed (including various log messages, maybe sending IGMPs, etc).  If
> all slaves are being removed, that's pointless.  This could be something
> like:
> 
> 	if (release_all) {
> 		bond->curr_active_slave = NULL;
> 	} else if (oldcurrent == slave) {
> 		[ the current block of stuff ]
> 	}
> 
> 	it's safe here to unconditionally set curr_active_slave to NULL
> because we hold bond->lock for write.  The lock dance stuff for the
> bond_select_active_slave() call is to satisfy its locking requirements.
> 
> 	-J
I see your point and I agree. I will prepare another version that
incorporates it, although I can't add it as an argument since
bond_release is used as ndo_del_slave. I'll have to make it a global
variable.

Nik

^ permalink raw reply

* Re: SYSFS "errors"
From: Borislav Petkov @ 2013-02-18 22:13 UTC (permalink / raw)
  To: Greg KH
  Cc: Mauro Carvalho Chehab, balbi, Linux Kernel Mailing List,
	Steven Rostedt, Frederic Weisbecker, Ingo Molnar, JBottomley,
	linux-scsi, davem, netdev, Doug Thompson, linux-edac, rjw,
	linux-pm
In-Reply-To: <20130218215434.GB16794@kroah.com>

On Mon, Feb 18, 2013 at 01:54:34PM -0800, Greg KH wrote:
> Because sysfs is "one value per file" the lack of a file showing up
> shouldn't cause any userspace tools any problems, that is why we did
> things this way.
>
> But, of course, userspace programmers do know how to mess things up...

How about what I proposed earlier to Felipe:

--
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 0ca1ca71157f..d2eef76d1d46 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -704,7 +704,7 @@ static ssize_t mci_sdram_scrub_rate_show(struct device *dev,
 	int bandwidth = 0;
 
 	if (!mci->get_sdram_scrub_rate)
-		return -ENODEV;
+		return sprintf(data, "N/A");
 
 	bandwidth = mci->get_sdram_scrub_rate(mci);
 	if (bandwidth < 0) {

--

Would that hurt the sysfs policy? In this case we *can* read the file
and it correctly tells us that scrub rate reading is not supported
instead of having a number there.

Hmm.

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--

^ permalink raw reply related

* Re: SYSFS "errors"
From: Felipe Balbi @ 2013-02-18 21:57 UTC (permalink / raw)
  To: Alan Stern
  Cc: Felipe Balbi, Greg KH, Linux Kernel Mailing List, Steven Rostedt,
	Frederic Weisbecker, Ingo Molnar, JBottomley, linux-scsi, davem,
	netdev, Doug Thompson, linux-edac, rjw, linux-pm
In-Reply-To: <Pine.LNX.4.44L0.1302181644260.6790-100000@netrider.rowland.org>

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

On Mon, Feb 18, 2013 at 04:48:06PM -0500, Alan Stern wrote:
> On Mon, 18 Feb 2013, Felipe Balbi wrote:
> 
> > Hi, On Mon, Feb 18, 2013 at 09:49:16AM -0800, Greg KH wrote:
> > > > Input/output error - /sys/devices/cpu/power/autosuspend_delay_ms
> > > 
> > > The issue with this file is, if the power.use_autosuspend flag is not
> > > set for the device, then it can't be read or written to.  This flag
> > > changes dynamically with the system state
> > > (__pm_runtime_use_autosuspend() can change it), so we can't just not
> > > show the file if the flag is not set properly, sorry.
> > > 
> > > So the "error" is correct here, as is the 0644 file value.
> > 
> > hmm... we could create the file at pm_runtime_enable() time and remove
> > it on pm_runtime_disable() time, no ? Addin Rafael to Cc
> 
> In theory this could be done, although the times would be when runtime 
> autosuspend is turned on or off, not when pm_runtime_enable is called.

Right, I got that after replying. Here's a patch I plan to test
tomorrow:

8<------------------------ cut here ----------------------------

From 2cdeeb483383490946cc98727a167843c40d7d27 Mon Sep 17 00:00:00 2001
From: Felipe Balbi <balbi@ti.com>
Date: Mon, 18 Feb 2013 21:20:28 +0200
Subject: [PATCH] base: power: create autosuspend_delay_ms from
 pm_runtime_use_autosuspend()

this patch moves the creation of autosuspend_delay_ms
sysfs file to pm_runtime_use_autosuspend() and, conversely,
its deletion to pm_runtime_dont_use_autosuspend.

The idea behind this patch is such that the file in
question is only readable after pm_runtime_use_autosuspend()
has been called for a particular device, so we might
as well move the creation of the file to that place.

Signed-off-by: Felipe Balbi <balbi@ti.com>
---
 drivers/base/power/power.h   |  4 ++++
 drivers/base/power/runtime.c |  6 ++++++
 drivers/base/power/sysfs.c   | 25 ++++++++++++++++++++++++-
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index b16686a..3822b94 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -90,6 +90,8 @@ static inline void device_pm_init(struct device *dev)
 
 extern int dpm_sysfs_add(struct device *dev);
 extern void dpm_sysfs_remove(struct device *dev);
+extern int dpm_autosuspend_sysfs_add(struct device *dev);
+extern void dpm_autosuspend_sysfs_remove(struct device *dev);
 extern void rpm_sysfs_remove(struct device *dev);
 extern int wakeup_sysfs_add(struct device *dev);
 extern void wakeup_sysfs_remove(struct device *dev);
@@ -102,6 +104,8 @@ extern void pm_qos_sysfs_remove_flags(struct device *dev);
 
 static inline int dpm_sysfs_add(struct device *dev) { return 0; }
 static inline void dpm_sysfs_remove(struct device *dev) {}
+static inline int dpm_autosuspend_sysfs_add(struct device *dev) { return 0; }
+static inline void dpm_autosuspend_sysfs_remove(struct device *dev) {}
 static inline void rpm_sysfs_remove(struct device *dev) {}
 static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
 static inline void wakeup_sysfs_remove(struct device *dev) {}
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 3148b10..a162ba5 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1266,6 +1266,12 @@ void __pm_runtime_use_autosuspend(struct device *dev, bool use)
 	old_use = dev->power.use_autosuspend;
 	dev->power.use_autosuspend = use;
 	update_autosuspend(dev, old_delay, old_use);
+
+	if (use)
+		dpm_autosuspend_sysfs_add(dev);
+	else
+		dpm_autosuspend_sysfs_remove(dev);
+
 	spin_unlock_irq(&dev->power.lock);
 }
 EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 50d16e3..ef2a41c 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -609,15 +609,26 @@ static struct attribute *runtime_attrs[] = {
 	&dev_attr_control.attr,
 	&dev_attr_runtime_suspended_time.attr,
 	&dev_attr_runtime_active_time.attr,
-	&dev_attr_autosuspend_delay_ms.attr,
 #endif /* CONFIG_PM_RUNTIME */
 	NULL,
 };
+
 static struct attribute_group pm_runtime_attr_group = {
 	.name	= power_group_name,
 	.attrs	= runtime_attrs,
 };
 
+static struct attribute *runtime_autosuspend_attrs[] = {
+#ifdef CONFIG_PM_RUNTIME
+	&dev_attr_autosuspend_delay_ms.attr,
+#endif /* CONFIG_PM_RUNTIME */
+};
+
+static struct attribute_group pm_runtime_autosuspend_attr_group = {
+	.name	= power_group_name,
+	.attrs	= runtime_autosuspend_attrs,
+};
+
 static struct attribute *pm_qos_latency_attrs[] = {
 #ifdef CONFIG_PM_RUNTIME
 	&dev_attr_pm_qos_resume_latency_us.attr,
@@ -671,6 +682,12 @@ int dpm_sysfs_add(struct device *dev)
 	return rc;
 }
 
+int dpm_autosuspend_sysfs_add(struct device *dev)
+{
+	return sysfs_merge_group(&dev->kobj,
+			&pm_runtime_autosuspend_attr_group);
+}
+
 int wakeup_sysfs_add(struct device *dev)
 {
 	return sysfs_merge_group(&dev->kobj, &pm_wakeup_attr_group);
@@ -712,3 +729,9 @@ void dpm_sysfs_remove(struct device *dev)
 	sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
 	sysfs_remove_group(&dev->kobj, &pm_attr_group);
 }
+
+void dpm_autosuspend_sysfs_remove(struct device *dev)
+{
+	sysfs_unmerge_group(&dev->kobj,
+			&pm_runtime_autosuspend_attr_group);
+}
-- 
1.8.1.rc1.5.g7e0651a

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply related

* Re: [PATCH net-next 3/3] bonding: fix bond_release_all inconsistencies
From: Jay Vosburgh @ 2013-02-18 21:56 UTC (permalink / raw)
  To: Nikolay Aleksandrov; +Cc: netdev, davem, andy
In-Reply-To: <1361210344-14907-3-git-send-email-nikolay@redhat.com>

Nikolay Aleksandrov <nikolay@redhat.com> wrote:

>This patch fixes the following inconsistencies in bond_release_all:
>- IFF_BONDING flag is not stripped from slaves
>- MTU is not restored
>- no netdev notifiers are sent
>Instead of trying to keep bond_release and bond_release_all in sync
>I think we can re-use bond_release as the environment for calling it
>is correct (RTNL is held). I have been running tests for the past
>week and they came out successful. The only way for bond_release to fail
>is for the slave to be attached in a different bond or to not be a slave
>but that cannot happen as RTNL is held and no slave manipulations can be
>achieved.

	It might be worthwhile to add an "all" argument to bond_release
that skips some things that don't make sense if all slaves are being
released.  I'm thinking in particular of this block:

	if (oldcurrent == slave) {
		/*
		 * Note that we hold RTNL over this sequence, so there
		 * is no concern that another slave add/remove event
		 * will interfere.
		 */
		write_unlock_bh(&bond->lock);
		read_lock(&bond->lock);
		write_lock_bh(&bond->curr_slave_lock);

		bond_select_active_slave(bond);

		write_unlock_bh(&bond->curr_slave_lock);
		read_unlock(&bond->lock);
		write_lock_bh(&bond->lock);
	}

	as it's written now, for the release all case, the code may go
to the trouble of assigning a new active slave each time one slave is
removed (including various log messages, maybe sending IGMPs, etc).  If
all slaves are being removed, that's pointless.  This could be something
like:

	if (release_all) {
		bond->curr_active_slave = NULL;
	} else if (oldcurrent == slave) {
		[ the current block of stuff ]
	}

	it's safe here to unconditionally set curr_active_slave to NULL
because we hold bond->lock for write.  The lock dance stuff for the
bond_select_active_slave() call is to satisfy its locking requirements.

	-J


>Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
>---
> drivers/net/bonding/bond_main.c | 106 ++--------------------------------------
> 1 file changed, 5 insertions(+), 101 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index 94c1534..fcfc880 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -2140,113 +2140,17 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
> /*
>  * This function releases all slaves.
>  */
>-static int bond_release_all(struct net_device *bond_dev)
>+static void bond_release_all(struct net_device *bond_dev)
> {
> 	struct bonding *bond = netdev_priv(bond_dev);
>-	struct slave *slave;
>-	struct net_device *slave_dev;
>-	struct sockaddr addr;
>-
>-	write_lock_bh(&bond->lock);
>-
>-	netif_carrier_off(bond_dev);
>
> 	if (bond->slave_cnt == 0)
>-		goto out;
>-
>-	bond->current_arp_slave = NULL;
>-	bond->primary_slave = NULL;
>-	bond_change_active_slave(bond, NULL);
>-
>-	while ((slave = bond->first_slave) != NULL) {
>-		/* Inform AD package of unbinding of slave
>-		 * before slave is detached from the list.
>-		 */
>-		if (bond->params.mode == BOND_MODE_8023AD)
>-			bond_3ad_unbind_slave(slave);
>-
>-		slave_dev = slave->dev;
>-		bond_detach_slave(bond, slave);
>-
>-		/* now that the slave is detached, unlock and perform
>-		 * all the undo steps that should not be called from
>-		 * within a lock.
>-		 */
>-		write_unlock_bh(&bond->lock);
>-
>-		/* unregister rx_handler early so bond_handle_frame wouldn't
>-		 * be called for this slave anymore.
>-		 */
>-		netdev_rx_handler_unregister(slave_dev);
>-		synchronize_net();
>-
>-		if (bond_is_lb(bond)) {
>-			/* must be called only after the slave
>-			 * has been detached from the list
>-			 */
>-			bond_alb_deinit_slave(bond, slave);
>-		}
>-
>-		bond_destroy_slave_symlinks(bond_dev, slave_dev);
>-		bond_del_vlans_from_slave(bond, slave_dev);
>-
>-		/* If the mode USES_PRIMARY, then we should only remove its
>-		 * promisc and mc settings if it was the curr_active_slave, but that was
>-		 * already taken care of above when we detached the slave
>-		 */
>-		if (!USES_PRIMARY(bond->params.mode)) {
>-			/* unset promiscuity level from slave */
>-			if (bond_dev->flags & IFF_PROMISC)
>-				dev_set_promiscuity(slave_dev, -1);
>-
>-			/* unset allmulti level from slave */
>-			if (bond_dev->flags & IFF_ALLMULTI)
>-				dev_set_allmulti(slave_dev, -1);
>-
>-			/* flush master's mc_list from slave */
>-			netif_addr_lock_bh(bond_dev);
>-			bond_mc_list_flush(bond_dev, slave_dev);
>-			netif_addr_unlock_bh(bond_dev);
>-		}
>-
>-		bond_upper_dev_unlink(bond_dev, slave_dev);
>-
>-		slave_disable_netpoll(slave);
>-
>-		/* close slave before restoring its mac address */
>-		dev_close(slave_dev);
>-
>-		if (!bond->params.fail_over_mac) {
>-			/* restore original ("permanent") mac address*/
>-			memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
>-			addr.sa_family = slave_dev->type;
>-			dev_set_mac_address(slave_dev, &addr);
>-		}
>-
>-		kfree(slave);
>-
>-		/* re-acquire the lock before getting the next slave */
>-		write_lock_bh(&bond->lock);
>-	}
>-
>-	eth_hw_addr_random(bond_dev);
>-	bond->dev_addr_from_first = true;
>-
>-	if (bond_vlan_used(bond)) {
>-		pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
>-			   bond_dev->name, bond_dev->name);
>-		pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
>-			   bond_dev->name);
>-	}
>-
>+		return;
>+	while (bond->first_slave != NULL)
>+		bond_release(bond_dev, bond->first_slave->dev);
> 	pr_info("%s: released all slaves\n", bond_dev->name);
>
>-out:
>-	write_unlock_bh(&bond->lock);
>-
>-	bond_compute_features(bond);
>-
>-	return 0;
>+	return;
> }
>
> /*
>-- 
>1.7.11.7

---
	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com

^ permalink raw reply


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