aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_cgroup.c')
-rw-r--r--net/sched/cls_cgroup.c79
1 files changed, 48 insertions, 31 deletions
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index cacf01bd04f0..d61a801222c1 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -22,17 +22,17 @@ struct cls_cgroup_head {
22 u32 handle; 22 u32 handle;
23 struct tcf_exts exts; 23 struct tcf_exts exts;
24 struct tcf_ematch_tree ematches; 24 struct tcf_ematch_tree ematches;
25 struct tcf_proto *tp;
26 struct rcu_head rcu;
25}; 27};
26 28
27static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, 29static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp,
28 struct tcf_result *res) 30 struct tcf_result *res)
29{ 31{
30 struct cls_cgroup_head *head = tp->root; 32 struct cls_cgroup_head *head = rcu_dereference_bh(tp->root);
31 u32 classid; 33 u32 classid;
32 34
33 rcu_read_lock();
34 classid = task_cls_state(current)->classid; 35 classid = task_cls_state(current)->classid;
35 rcu_read_unlock();
36 36
37 /* 37 /*
38 * Due to the nature of the classifier it is required to ignore all 38 * Due to the nature of the classifier it is required to ignore all
@@ -80,13 +80,25 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = {
80 [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, 80 [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED },
81}; 81};
82 82
83static void cls_cgroup_destroy_rcu(struct rcu_head *root)
84{
85 struct cls_cgroup_head *head = container_of(root,
86 struct cls_cgroup_head,
87 rcu);
88
89 tcf_exts_destroy(&head->exts);
90 tcf_em_tree_destroy(&head->ematches);
91 kfree(head);
92}
93
83static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, 94static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
84 struct tcf_proto *tp, unsigned long base, 95 struct tcf_proto *tp, unsigned long base,
85 u32 handle, struct nlattr **tca, 96 u32 handle, struct nlattr **tca,
86 unsigned long *arg, bool ovr) 97 unsigned long *arg, bool ovr)
87{ 98{
88 struct nlattr *tb[TCA_CGROUP_MAX + 1]; 99 struct nlattr *tb[TCA_CGROUP_MAX + 1];
89 struct cls_cgroup_head *head = tp->root; 100 struct cls_cgroup_head *head = rtnl_dereference(tp->root);
101 struct cls_cgroup_head *new;
90 struct tcf_ematch_tree t; 102 struct tcf_ematch_tree t;
91 struct tcf_exts e; 103 struct tcf_exts e;
92 int err; 104 int err;
@@ -94,53 +106,58 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
94 if (!tca[TCA_OPTIONS]) 106 if (!tca[TCA_OPTIONS])
95 return -EINVAL; 107 return -EINVAL;
96 108
97 if (head == NULL) { 109 if (!head && !handle)
98 if (!handle) 110 return -EINVAL;
99 return -EINVAL;
100
101 head = kzalloc(sizeof(*head), GFP_KERNEL);
102 if (head == NULL)
103 return -ENOBUFS;
104 111
105 tcf_exts_init(&head->exts, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); 112 if (head && handle != head->handle)
106 head->handle = handle; 113 return -ENOENT;
107 114
108 tcf_tree_lock(tp); 115 new = kzalloc(sizeof(*head), GFP_KERNEL);
109 tp->root = head; 116 if (!new)
110 tcf_tree_unlock(tp); 117 return -ENOBUFS;
111 }
112 118
113 if (handle != head->handle) 119 tcf_exts_init(&new->exts, TCA_CGROUP_ACT, TCA_CGROUP_POLICE);
114 return -ENOENT; 120 if (head)
121 new->handle = head->handle;
122 else
123 new->handle = handle;
115 124
125 new->tp = tp;
116 err = nla_parse_nested(tb, TCA_CGROUP_MAX, tca[TCA_OPTIONS], 126 err = nla_parse_nested(tb, TCA_CGROUP_MAX, tca[TCA_OPTIONS],
117 cgroup_policy); 127 cgroup_policy);
118 if (err < 0) 128 if (err < 0)
119 return err; 129 goto errout;
120 130
121 tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE); 131 tcf_exts_init(&e, TCA_CGROUP_ACT, TCA_CGROUP_POLICE);
122 err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr); 132 err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &e, ovr);
123 if (err < 0) 133 if (err < 0)
124 return err; 134 goto errout;
125 135
126 err = tcf_em_tree_validate(tp, tb[TCA_CGROUP_EMATCHES], &t); 136 err = tcf_em_tree_validate(tp, tb[TCA_CGROUP_EMATCHES], &t);
127 if (err < 0) 137 if (err < 0) {
128 return err; 138 tcf_exts_destroy(&e);
139 goto errout;
140 }
129 141
130 tcf_exts_change(tp, &head->exts, &e); 142 tcf_exts_change(tp, &new->exts, &e);
131 tcf_em_tree_change(tp, &head->ematches, &t); 143 tcf_em_tree_change(tp, &new->ematches, &t);
132 144
145 rcu_assign_pointer(tp->root, new);
146 if (head)
147 call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
133 return 0; 148 return 0;
149errout:
150 kfree(new);
151 return err;
134} 152}
135 153
136static void cls_cgroup_destroy(struct tcf_proto *tp) 154static void cls_cgroup_destroy(struct tcf_proto *tp)
137{ 155{
138 struct cls_cgroup_head *head = tp->root; 156 struct cls_cgroup_head *head = rtnl_dereference(tp->root);
139 157
140 if (head) { 158 if (head) {
141 tcf_exts_destroy(tp, &head->exts); 159 RCU_INIT_POINTER(tp->root, NULL);
142 tcf_em_tree_destroy(tp, &head->ematches); 160 call_rcu(&head->rcu, cls_cgroup_destroy_rcu);
143 kfree(head);
144 } 161 }
145} 162}
146 163
@@ -151,7 +168,7 @@ static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg)
151 168
152static void cls_cgroup_walk(struct tcf_proto *tp, struct tcf_walker *arg) 169static void cls_cgroup_walk(struct tcf_proto *tp, struct tcf_walker *arg)
153{ 170{
154 struct cls_cgroup_head *head = tp->root; 171 struct cls_cgroup_head *head = rtnl_dereference(tp->root);
155 172
156 if (arg->count < arg->skip) 173 if (arg->count < arg->skip)
157 goto skip; 174 goto skip;
@@ -167,7 +184,7 @@ skip:
167static int cls_cgroup_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, 184static int cls_cgroup_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
168 struct sk_buff *skb, struct tcmsg *t) 185 struct sk_buff *skb, struct tcmsg *t)
169{ 186{
170 struct cls_cgroup_head *head = tp->root; 187 struct cls_cgroup_head *head = rtnl_dereference(tp->root);
171 unsigned char *b = skb_tail_pointer(skb); 188 unsigned char *b = skb_tail_pointer(skb);
172 struct nlattr *nest; 189 struct nlattr *nest;
173 190