Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa9fd9a3 authored by Alexander Aring's avatar Alexander Aring Committed by David S. Miller
Browse files

sched: act: ife: update parameters via rcu handling



This patch changes the parameter updating via RCU and not protected by a
spinlock anymore. This reduce the time that the spinlock is being held.

Signed-off-by: default avatarAlexander Aring <aring@mojatatu.com>
Acked-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ced273ea
Loading
Loading
Loading
Loading
+8 −2
Original line number Original line Diff line number Diff line
@@ -6,12 +6,18 @@
#include <linux/rtnetlink.h>
#include <linux/rtnetlink.h>
#include <linux/module.h>
#include <linux/module.h>


struct tcf_ife_info {
struct tcf_ife_params {
	struct tc_action common;
	u8 eth_dst[ETH_ALEN];
	u8 eth_dst[ETH_ALEN];
	u8 eth_src[ETH_ALEN];
	u8 eth_src[ETH_ALEN];
	u16 eth_type;
	u16 eth_type;
	u16 flags;
	u16 flags;

	struct rcu_head rcu;
};

struct tcf_ife_info {
	struct tc_action common;
	struct tcf_ife_params __rcu *params;
	/* list of metaids allowed */
	/* list of metaids allowed */
	struct list_head metalist;
	struct list_head metalist;
};
};
+59 −28
Original line number Original line Diff line number Diff line
@@ -406,10 +406,14 @@ static void _tcf_ife_cleanup(struct tc_action *a, int bind)
static void tcf_ife_cleanup(struct tc_action *a, int bind)
static void tcf_ife_cleanup(struct tc_action *a, int bind)
{
{
	struct tcf_ife_info *ife = to_ife(a);
	struct tcf_ife_info *ife = to_ife(a);
	struct tcf_ife_params *p;


	spin_lock_bh(&ife->tcf_lock);
	spin_lock_bh(&ife->tcf_lock);
	_tcf_ife_cleanup(a, bind);
	_tcf_ife_cleanup(a, bind);
	spin_unlock_bh(&ife->tcf_lock);
	spin_unlock_bh(&ife->tcf_lock);

	p = rcu_dereference_protected(ife->params, 1);
	kfree_rcu(p, rcu);
}
}


/* under ife->tcf_lock for existing action */
/* under ife->tcf_lock for existing action */
@@ -446,6 +450,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
	struct tc_action_net *tn = net_generic(net, ife_net_id);
	struct tc_action_net *tn = net_generic(net, ife_net_id);
	struct nlattr *tb[TCA_IFE_MAX + 1];
	struct nlattr *tb[TCA_IFE_MAX + 1];
	struct nlattr *tb2[IFE_META_MAX + 1];
	struct nlattr *tb2[IFE_META_MAX + 1];
	struct tcf_ife_params *p, *p_old;
	struct tcf_ife_info *ife;
	struct tcf_ife_info *ife;
	u16 ife_type = ETH_P_IFE;
	u16 ife_type = ETH_P_IFE;
	struct tc_ife *parm;
	struct tc_ife *parm;
@@ -471,24 +476,34 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
	if (parm->flags & ~IFE_ENCODE)
	if (parm->flags & ~IFE_ENCODE)
		return -EINVAL;
		return -EINVAL;


	p = kzalloc(sizeof(*p), GFP_KERNEL);
	if (!p)
		return -ENOMEM;

	exists = tcf_idr_check(tn, parm->index, a, bind);
	exists = tcf_idr_check(tn, parm->index, a, bind);
	if (exists && bind)
	if (exists && bind) {
		kfree(p);
		return 0;
		return 0;
	}


	if (!exists) {
	if (!exists) {
		ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
		ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
				     bind, true);
				     bind, true);
		if (ret)
		if (ret) {
			kfree(p);
			return ret;
			return ret;
		}
		ret = ACT_P_CREATED;
		ret = ACT_P_CREATED;
	} else {
	} else {
		tcf_idr_release(*a, bind);
		tcf_idr_release(*a, bind);
		if (!ovr)
		if (!ovr) {
			kfree(p);
			return -EEXIST;
			return -EEXIST;
		}
		}
	}


	ife = to_ife(*a);
	ife = to_ife(*a);
	ife->flags = parm->flags;
	p->flags = parm->flags;


	if (parm->flags & IFE_ENCODE) {
	if (parm->flags & IFE_ENCODE) {
		if (tb[TCA_IFE_TYPE])
		if (tb[TCA_IFE_TYPE])
@@ -499,24 +514,25 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
			saddr = nla_data(tb[TCA_IFE_SMAC]);
			saddr = nla_data(tb[TCA_IFE_SMAC]);
	}
	}


	if (exists)
		spin_lock_bh(&ife->tcf_lock);
	ife->tcf_action = parm->action;
	ife->tcf_action = parm->action;


	if (parm->flags & IFE_ENCODE) {
	if (parm->flags & IFE_ENCODE) {
		if (daddr)
		if (daddr)
			ether_addr_copy(ife->eth_dst, daddr);
			ether_addr_copy(p->eth_dst, daddr);
		else
		else
			eth_zero_addr(ife->eth_dst);
			eth_zero_addr(p->eth_dst);


		if (saddr)
		if (saddr)
			ether_addr_copy(ife->eth_src, saddr);
			ether_addr_copy(p->eth_src, saddr);
		else
		else
			eth_zero_addr(ife->eth_src);
			eth_zero_addr(p->eth_src);


		ife->eth_type = ife_type;
		p->eth_type = ife_type;
	}
	}


	if (exists)
		spin_lock_bh(&ife->tcf_lock);

	if (ret == ACT_P_CREATED)
	if (ret == ACT_P_CREATED)
		INIT_LIST_HEAD(&ife->metalist);
		INIT_LIST_HEAD(&ife->metalist);


@@ -532,6 +548,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,


			if (exists)
			if (exists)
				spin_unlock_bh(&ife->tcf_lock);
				spin_unlock_bh(&ife->tcf_lock);
			kfree(p);
			return err;
			return err;
		}
		}


@@ -552,6 +569,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,


			if (exists)
			if (exists)
				spin_unlock_bh(&ife->tcf_lock);
				spin_unlock_bh(&ife->tcf_lock);
			kfree(p);
			return err;
			return err;
		}
		}
	}
	}
@@ -559,6 +577,11 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
	if (exists)
	if (exists)
		spin_unlock_bh(&ife->tcf_lock);
		spin_unlock_bh(&ife->tcf_lock);


	p_old = rtnl_dereference(ife->params);
	rcu_assign_pointer(ife->params, p);
	if (p_old)
		kfree_rcu(p_old, rcu);

	if (ret == ACT_P_CREATED)
	if (ret == ACT_P_CREATED)
		tcf_idr_insert(tn, *a);
		tcf_idr_insert(tn, *a);


@@ -570,12 +593,13 @@ static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind,
{
{
	unsigned char *b = skb_tail_pointer(skb);
	unsigned char *b = skb_tail_pointer(skb);
	struct tcf_ife_info *ife = to_ife(a);
	struct tcf_ife_info *ife = to_ife(a);
	struct tcf_ife_params *p = rtnl_dereference(ife->params);
	struct tc_ife opt = {
	struct tc_ife opt = {
		.index = ife->tcf_index,
		.index = ife->tcf_index,
		.refcnt = ife->tcf_refcnt - ref,
		.refcnt = ife->tcf_refcnt - ref,
		.bindcnt = ife->tcf_bindcnt - bind,
		.bindcnt = ife->tcf_bindcnt - bind,
		.action = ife->tcf_action,
		.action = ife->tcf_action,
		.flags = ife->flags,
		.flags = p->flags,
	};
	};
	struct tcf_t t;
	struct tcf_t t;


@@ -586,17 +610,17 @@ static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind,
	if (nla_put_64bit(skb, TCA_IFE_TM, sizeof(t), &t, TCA_IFE_PAD))
	if (nla_put_64bit(skb, TCA_IFE_TM, sizeof(t), &t, TCA_IFE_PAD))
		goto nla_put_failure;
		goto nla_put_failure;


	if (!is_zero_ether_addr(ife->eth_dst)) {
	if (!is_zero_ether_addr(p->eth_dst)) {
		if (nla_put(skb, TCA_IFE_DMAC, ETH_ALEN, ife->eth_dst))
		if (nla_put(skb, TCA_IFE_DMAC, ETH_ALEN, p->eth_dst))
			goto nla_put_failure;
			goto nla_put_failure;
	}
	}


	if (!is_zero_ether_addr(ife->eth_src)) {
	if (!is_zero_ether_addr(p->eth_src)) {
		if (nla_put(skb, TCA_IFE_SMAC, ETH_ALEN, ife->eth_src))
		if (nla_put(skb, TCA_IFE_SMAC, ETH_ALEN, p->eth_src))
			goto nla_put_failure;
			goto nla_put_failure;
	}
	}


	if (nla_put(skb, TCA_IFE_TYPE, 2, &ife->eth_type))
	if (nla_put(skb, TCA_IFE_TYPE, 2, &p->eth_type))
		goto nla_put_failure;
		goto nla_put_failure;


	if (dump_metalist(skb, ife)) {
	if (dump_metalist(skb, ife)) {
@@ -698,7 +722,7 @@ static int ife_get_sz(struct sk_buff *skb, struct tcf_ife_info *ife)
}
}


static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
			  struct tcf_result *res)
			  struct tcf_result *res, struct tcf_ife_params *p)
{
{
	struct tcf_ife_info *ife = to_ife(a);
	struct tcf_ife_info *ife = to_ife(a);
	int action = ife->tcf_action;
	int action = ife->tcf_action;
@@ -762,19 +786,18 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
		}
		}
		skboff += err;
		skboff += err;
	}
	}
	spin_unlock(&ife->tcf_lock);
	oethh = (struct ethhdr *)skb->data;
	oethh = (struct ethhdr *)skb->data;


	if (!is_zero_ether_addr(ife->eth_src))
	if (!is_zero_ether_addr(p->eth_src))
		ether_addr_copy(oethh->h_source, ife->eth_src);
		ether_addr_copy(oethh->h_source, p->eth_src);
	if (!is_zero_ether_addr(ife->eth_dst))
	if (!is_zero_ether_addr(p->eth_dst))
		ether_addr_copy(oethh->h_dest, ife->eth_dst);
		ether_addr_copy(oethh->h_dest, p->eth_dst);
	oethh->h_proto = htons(ife->eth_type);
	oethh->h_proto = htons(p->eth_type);


	if (skb_at_tc_ingress(skb))
	if (skb_at_tc_ingress(skb))
		skb_pull(skb, skb->dev->hard_header_len);
		skb_pull(skb, skb->dev->hard_header_len);


	spin_unlock(&ife->tcf_lock);

	return action;
	return action;
}
}


@@ -782,9 +805,17 @@ static int tcf_ife_act(struct sk_buff *skb, const struct tc_action *a,
		       struct tcf_result *res)
		       struct tcf_result *res)
{
{
	struct tcf_ife_info *ife = to_ife(a);
	struct tcf_ife_info *ife = to_ife(a);

	struct tcf_ife_params *p;
	if (ife->flags & IFE_ENCODE)
	int ret;
		return tcf_ife_encode(skb, a, res);

	rcu_read_lock();
	p = rcu_dereference(ife->params);
	if (p->flags & IFE_ENCODE) {
		ret = tcf_ife_encode(skb, a, res, p);
		rcu_read_unlock();
		return ret;
	}
	rcu_read_unlock();


	return tcf_ife_decode(skb, a, res);
	return tcf_ife_decode(skb, a, res);
}
}