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

Commit dfb05553 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tc-filter-cleanup-destroy-delete'



Cong Wang says:

====================
net_sched: clean up tc filter destroy and delete logic

The first patch fixes a potenial race condition, the second one
is pure cleanup.
====================

Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b1d9fc41 43920538
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -204,14 +204,14 @@ struct tcf_proto_ops {
					    const struct tcf_proto *,
					    struct tcf_result *);
	int			(*init)(struct tcf_proto*);
	bool			(*destroy)(struct tcf_proto*, bool);
	void			(*destroy)(struct tcf_proto*);

	unsigned long		(*get)(struct tcf_proto*, u32 handle);
	int			(*change)(struct net *net, struct sk_buff *,
					struct tcf_proto*, unsigned long,
					u32 handle, struct nlattr **,
					unsigned long *, bool);
	int			(*delete)(struct tcf_proto*, unsigned long);
	int			(*delete)(struct tcf_proto*, unsigned long, bool*);
	void			(*walk)(struct tcf_proto*, struct tcf_walker *arg);

	/* rtnetlink specific */
+14 −13
Original line number Diff line number Diff line
@@ -178,14 +178,11 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
	return ERR_PTR(err);
}

static bool tcf_proto_destroy(struct tcf_proto *tp, bool force)
static void tcf_proto_destroy(struct tcf_proto *tp)
{
	if (tp->ops->destroy(tp, force)) {
	tp->ops->destroy(tp);
	module_put(tp->ops->owner);
	kfree_rcu(tp, rcu);
		return true;
	}
	return false;
}

void tcf_destroy_chain(struct tcf_proto __rcu **fl)
@@ -194,7 +191,7 @@ void tcf_destroy_chain(struct tcf_proto __rcu **fl)

	while ((tp = rtnl_dereference(*fl)) != NULL) {
		RCU_INIT_POINTER(*fl, tp->next);
		tcf_proto_destroy(tp, true);
		tcf_proto_destroy(tp);
	}
}
EXPORT_SYMBOL(tcf_destroy_chain);
@@ -361,7 +358,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
			RCU_INIT_POINTER(*back, next);
			tfilter_notify(net, skb, n, tp, fh,
				       RTM_DELTFILTER, false);
			tcf_proto_destroy(tp, true);
			tcf_proto_destroy(tp);
			err = 0;
			goto errout;
		}
@@ -372,24 +369,28 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
			goto errout;
		}
	} else {
		bool last;

		switch (n->nlmsg_type) {
		case RTM_NEWTFILTER:
			if (n->nlmsg_flags & NLM_F_EXCL) {
				if (tp_created)
					tcf_proto_destroy(tp, true);
					tcf_proto_destroy(tp);
				err = -EEXIST;
				goto errout;
			}
			break;
		case RTM_DELTFILTER:
			err = tp->ops->delete(tp, fh);
			err = tp->ops->delete(tp, fh, &last);
			if (err)
				goto errout;
			next = rtnl_dereference(tp->next);
			tfilter_notify(net, skb, n, tp, t->tcm_handle,
				       RTM_DELTFILTER, false);
			if (tcf_proto_destroy(tp, false))
			if (last) {
				RCU_INIT_POINTER(*back, next);
				tcf_proto_destroy(tp);
			}
			goto errout;
		case RTM_GETTFILTER:
			err = tfilter_notify(net, skb, n, tp, fh,
@@ -411,7 +412,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
		tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER, false);
	} else {
		if (tp_created)
			tcf_proto_destroy(tp, true);
			tcf_proto_destroy(tp);
	}

errout:
+4 −6
Original line number Diff line number Diff line
@@ -93,30 +93,28 @@ static void basic_delete_filter(struct rcu_head *head)
	kfree(f);
}

static bool basic_destroy(struct tcf_proto *tp, bool force)
static void basic_destroy(struct tcf_proto *tp)
{
	struct basic_head *head = rtnl_dereference(tp->root);
	struct basic_filter *f, *n;

	if (!force && !list_empty(&head->flist))
		return false;

	list_for_each_entry_safe(f, n, &head->flist, link) {
		list_del_rcu(&f->link);
		tcf_unbind_filter(tp, &f->res);
		call_rcu(&f->rcu, basic_delete_filter);
	}
	kfree_rcu(head, rcu);
	return true;
}

static int basic_delete(struct tcf_proto *tp, unsigned long arg)
static int basic_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
{
	struct basic_head *head = rtnl_dereference(tp->root);
	struct basic_filter *f = (struct basic_filter *) arg;

	list_del_rcu(&f->link);
	tcf_unbind_filter(tp, &f->res);
	call_rcu(&f->rcu, basic_delete_filter);
	*last = list_empty(&head->flist);
	return 0;
}

+5 −6
Original line number Diff line number Diff line
@@ -274,25 +274,24 @@ static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog)
	call_rcu(&prog->rcu, cls_bpf_delete_prog_rcu);
}

static int cls_bpf_delete(struct tcf_proto *tp, unsigned long arg)
static int cls_bpf_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
{
	struct cls_bpf_head *head = rtnl_dereference(tp->root);

	__cls_bpf_delete(tp, (struct cls_bpf_prog *) arg);
	*last = list_empty(&head->plist);
	return 0;
}

static bool cls_bpf_destroy(struct tcf_proto *tp, bool force)
static void cls_bpf_destroy(struct tcf_proto *tp)
{
	struct cls_bpf_head *head = rtnl_dereference(tp->root);
	struct cls_bpf_prog *prog, *tmp;

	if (!force && !list_empty(&head->plist))
		return false;

	list_for_each_entry_safe(prog, tmp, &head->plist, link)
		__cls_bpf_delete(tp, prog);

	kfree_rcu(head, rcu);
	return true;
}

static unsigned long cls_bpf_get(struct tcf_proto *tp, u32 handle)
+2 −6
Original line number Diff line number Diff line
@@ -131,20 +131,16 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
	return err;
}

static bool cls_cgroup_destroy(struct tcf_proto *tp, bool force)
static void cls_cgroup_destroy(struct tcf_proto *tp)
{
	struct cls_cgroup_head *head = rtnl_dereference(tp->root);

	if (!force)
		return false;
	/* Head can still be NULL due to cls_cgroup_init(). */
	if (head)
		call_rcu(&head->rcu, cls_cgroup_destroy_rcu);

	return true;
}

static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg)
static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
{
	return -EOPNOTSUPP;
}
Loading