|
@@ -117,7 +117,6 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
|
|
{
|
|
{
|
|
struct net *net = sock_net(skb->sk);
|
|
struct net *net = sock_net(skb->sk);
|
|
struct nlattr *tca[TCA_MAX + 1];
|
|
struct nlattr *tca[TCA_MAX + 1];
|
|
- spinlock_t *root_lock;
|
|
|
|
struct tcmsg *t;
|
|
struct tcmsg *t;
|
|
u32 protocol;
|
|
u32 protocol;
|
|
u32 prio;
|
|
u32 prio;
|
|
@@ -125,7 +124,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
|
|
u32 parent;
|
|
u32 parent;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
struct Qdisc *q;
|
|
struct Qdisc *q;
|
|
- struct tcf_proto **back, **chain;
|
|
|
|
|
|
+ struct tcf_proto __rcu **back;
|
|
|
|
+ struct tcf_proto __rcu **chain;
|
|
struct tcf_proto *tp;
|
|
struct tcf_proto *tp;
|
|
const struct tcf_proto_ops *tp_ops;
|
|
const struct tcf_proto_ops *tp_ops;
|
|
const struct Qdisc_class_ops *cops;
|
|
const struct Qdisc_class_ops *cops;
|
|
@@ -197,7 +197,9 @@ replay:
|
|
goto errout;
|
|
goto errout;
|
|
|
|
|
|
/* Check the chain for existence of proto-tcf with this priority */
|
|
/* Check the chain for existence of proto-tcf with this priority */
|
|
- for (back = chain; (tp = *back) != NULL; back = &tp->next) {
|
|
|
|
|
|
+ for (back = chain;
|
|
|
|
+ (tp = rtnl_dereference(*back)) != NULL;
|
|
|
|
+ back = &tp->next) {
|
|
if (tp->prio >= prio) {
|
|
if (tp->prio >= prio) {
|
|
if (tp->prio == prio) {
|
|
if (tp->prio == prio) {
|
|
if (!nprio ||
|
|
if (!nprio ||
|
|
@@ -209,8 +211,6 @@ replay:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- root_lock = qdisc_root_sleeping_lock(q);
|
|
|
|
-
|
|
|
|
if (tp == NULL) {
|
|
if (tp == NULL) {
|
|
/* Proto-tcf does not exist, create new one */
|
|
/* Proto-tcf does not exist, create new one */
|
|
|
|
|
|
@@ -259,7 +259,8 @@ replay:
|
|
}
|
|
}
|
|
tp->ops = tp_ops;
|
|
tp->ops = tp_ops;
|
|
tp->protocol = protocol;
|
|
tp->protocol = protocol;
|
|
- tp->prio = nprio ? : TC_H_MAJ(tcf_auto_prio(*back));
|
|
|
|
|
|
+ tp->prio = nprio ? :
|
|
|
|
+ TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
|
|
tp->q = q;
|
|
tp->q = q;
|
|
tp->classify = tp_ops->classify;
|
|
tp->classify = tp_ops->classify;
|
|
tp->classid = parent;
|
|
tp->classid = parent;
|
|
@@ -280,9 +281,9 @@ replay:
|
|
|
|
|
|
if (fh == 0) {
|
|
if (fh == 0) {
|
|
if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
|
|
if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
|
|
- spin_lock_bh(root_lock);
|
|
|
|
- *back = tp->next;
|
|
|
|
- spin_unlock_bh(root_lock);
|
|
|
|
|
|
+ struct tcf_proto *next = rtnl_dereference(tp->next);
|
|
|
|
+
|
|
|
|
+ RCU_INIT_POINTER(*back, next);
|
|
|
|
|
|
tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
|
|
tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
|
|
tcf_destroy(tp);
|
|
tcf_destroy(tp);
|
|
@@ -322,10 +323,8 @@ replay:
|
|
n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE);
|
|
n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE);
|
|
if (err == 0) {
|
|
if (err == 0) {
|
|
if (tp_created) {
|
|
if (tp_created) {
|
|
- spin_lock_bh(root_lock);
|
|
|
|
- tp->next = *back;
|
|
|
|
- *back = tp;
|
|
|
|
- spin_unlock_bh(root_lock);
|
|
|
|
|
|
+ RCU_INIT_POINTER(tp->next, rtnl_dereference(*back));
|
|
|
|
+ rcu_assign_pointer(*back, tp);
|
|
}
|
|
}
|
|
tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
|
|
tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
|
|
} else {
|
|
} else {
|
|
@@ -420,7 +419,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
|
|
int s_t;
|
|
int s_t;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
struct Qdisc *q;
|
|
struct Qdisc *q;
|
|
- struct tcf_proto *tp, **chain;
|
|
|
|
|
|
+ struct tcf_proto *tp, __rcu **chain;
|
|
struct tcmsg *tcm = nlmsg_data(cb->nlh);
|
|
struct tcmsg *tcm = nlmsg_data(cb->nlh);
|
|
unsigned long cl = 0;
|
|
unsigned long cl = 0;
|
|
const struct Qdisc_class_ops *cops;
|
|
const struct Qdisc_class_ops *cops;
|
|
@@ -454,7 +453,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
|
|
|
s_t = cb->args[0];
|
|
s_t = cb->args[0];
|
|
|
|
|
|
- for (tp = *chain, t = 0; tp; tp = tp->next, t++) {
|
|
|
|
|
|
+ for (tp = rtnl_dereference(*chain), t = 0;
|
|
|
|
+ tp; tp = rtnl_dereference(tp->next), t++) {
|
|
if (t < s_t)
|
|
if (t < s_t)
|
|
continue;
|
|
continue;
|
|
if (TC_H_MAJ(tcm->tcm_info) &&
|
|
if (TC_H_MAJ(tcm->tcm_info) &&
|