aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_api.c')
-rw-r--r--net/sched/act_api.c70
1 files changed, 25 insertions, 45 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 229d63c99be2..db83dac1e7f4 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -300,21 +300,17 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
300} 300}
301EXPORT_SYMBOL(tcf_generic_walker); 301EXPORT_SYMBOL(tcf_generic_walker);
302 302
303static bool __tcf_idr_check(struct tc_action_net *tn, u32 index, 303int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
304 struct tc_action **a, int bind)
305{ 304{
306 struct tcf_idrinfo *idrinfo = tn->idrinfo; 305 struct tcf_idrinfo *idrinfo = tn->idrinfo;
307 struct tc_action *p; 306 struct tc_action *p;
308 307
309 spin_lock(&idrinfo->lock); 308 spin_lock(&idrinfo->lock);
310 p = idr_find(&idrinfo->action_idr, index); 309 p = idr_find(&idrinfo->action_idr, index);
311 if (IS_ERR(p)) { 310 if (IS_ERR(p))
312 p = NULL; 311 p = NULL;
313 } else if (p) { 312 else if (p)
314 refcount_inc(&p->tcfa_refcnt); 313 refcount_inc(&p->tcfa_refcnt);
315 if (bind)
316 atomic_inc(&p->tcfa_bindcnt);
317 }
318 spin_unlock(&idrinfo->lock); 314 spin_unlock(&idrinfo->lock);
319 315
320 if (p) { 316 if (p) {
@@ -323,23 +319,10 @@ static bool __tcf_idr_check(struct tc_action_net *tn, u32 index,
323 } 319 }
324 return false; 320 return false;
325} 321}
326
327int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
328{
329 return __tcf_idr_check(tn, index, a, 0);
330}
331EXPORT_SYMBOL(tcf_idr_search); 322EXPORT_SYMBOL(tcf_idr_search);
332 323
333bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a, 324static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index)
334 int bind)
335{ 325{
336 return __tcf_idr_check(tn, index, a, bind);
337}
338EXPORT_SYMBOL(tcf_idr_check);
339
340int tcf_idr_delete_index(struct tc_action_net *tn, u32 index)
341{
342 struct tcf_idrinfo *idrinfo = tn->idrinfo;
343 struct tc_action *p; 326 struct tc_action *p;
344 int ret = 0; 327 int ret = 0;
345 328
@@ -370,7 +353,6 @@ int tcf_idr_delete_index(struct tc_action_net *tn, u32 index)
370 spin_unlock(&idrinfo->lock); 353 spin_unlock(&idrinfo->lock);
371 return ret; 354 return ret;
372} 355}
373EXPORT_SYMBOL(tcf_idr_delete_index);
374 356
375int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, 357int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
376 struct tc_action **a, const struct tc_action_ops *ops, 358 struct tc_action **a, const struct tc_action_ops *ops,
@@ -409,7 +391,6 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
409 391
410 p->idrinfo = idrinfo; 392 p->idrinfo = idrinfo;
411 p->ops = ops; 393 p->ops = ops;
412 INIT_LIST_HEAD(&p->list);
413 *a = p; 394 *a = p;
414 return 0; 395 return 0;
415err3: 396err3:
@@ -686,14 +667,18 @@ static int tcf_action_put(struct tc_action *p)
686 return __tcf_action_put(p, false); 667 return __tcf_action_put(p, false);
687} 668}
688 669
670/* Put all actions in this array, skip those NULL's. */
689static void tcf_action_put_many(struct tc_action *actions[]) 671static void tcf_action_put_many(struct tc_action *actions[])
690{ 672{
691 int i; 673 int i;
692 674
693 for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) { 675 for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
694 struct tc_action *a = actions[i]; 676 struct tc_action *a = actions[i];
695 const struct tc_action_ops *ops = a->ops; 677 const struct tc_action_ops *ops;
696 678
679 if (!a)
680 continue;
681 ops = a->ops;
697 if (tcf_action_put(a)) 682 if (tcf_action_put(a))
698 module_put(ops->owner); 683 module_put(ops->owner);
699 } 684 }
@@ -1175,41 +1160,38 @@ err_out:
1175 return err; 1160 return err;
1176} 1161}
1177 1162
1178static int tcf_action_delete(struct net *net, struct tc_action *actions[], 1163static int tcf_action_delete(struct net *net, struct tc_action *actions[])
1179 int *acts_deleted, struct netlink_ext_ack *extack)
1180{ 1164{
1181 u32 act_index; 1165 int i;
1182 int ret, i;
1183 1166
1184 for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) { 1167 for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) {
1185 struct tc_action *a = actions[i]; 1168 struct tc_action *a = actions[i];
1186 const struct tc_action_ops *ops = a->ops; 1169 const struct tc_action_ops *ops = a->ops;
1187
1188 /* Actions can be deleted concurrently so we must save their 1170 /* Actions can be deleted concurrently so we must save their
1189 * type and id to search again after reference is released. 1171 * type and id to search again after reference is released.
1190 */ 1172 */
1191 act_index = a->tcfa_index; 1173 struct tcf_idrinfo *idrinfo = a->idrinfo;
1174 u32 act_index = a->tcfa_index;
1192 1175
1193 if (tcf_action_put(a)) { 1176 if (tcf_action_put(a)) {
1194 /* last reference, action was deleted concurrently */ 1177 /* last reference, action was deleted concurrently */
1195 module_put(ops->owner); 1178 module_put(ops->owner);
1196 } else { 1179 } else {
1180 int ret;
1181
1197 /* now do the delete */ 1182 /* now do the delete */
1198 ret = ops->delete(net, act_index); 1183 ret = tcf_idr_delete_index(idrinfo, act_index);
1199 if (ret < 0) { 1184 if (ret < 0)
1200 *acts_deleted = i + 1;
1201 return ret; 1185 return ret;
1202 }
1203 } 1186 }
1187 actions[i] = NULL;
1204 } 1188 }
1205 *acts_deleted = i;
1206 return 0; 1189 return 0;
1207} 1190}
1208 1191
1209static int 1192static int
1210tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[], 1193tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
1211 int *acts_deleted, u32 portid, size_t attr_size, 1194 u32 portid, size_t attr_size, struct netlink_ext_ack *extack)
1212 struct netlink_ext_ack *extack)
1213{ 1195{
1214 int ret; 1196 int ret;
1215 struct sk_buff *skb; 1197 struct sk_buff *skb;
@@ -1227,7 +1209,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
1227 } 1209 }
1228 1210
1229 /* now do the delete */ 1211 /* now do the delete */
1230 ret = tcf_action_delete(net, actions, acts_deleted, extack); 1212 ret = tcf_action_delete(net, actions);
1231 if (ret < 0) { 1213 if (ret < 0) {
1232 NL_SET_ERR_MSG(extack, "Failed to delete TC action"); 1214 NL_SET_ERR_MSG(extack, "Failed to delete TC action");
1233 kfree_skb(skb); 1215 kfree_skb(skb);
@@ -1249,8 +1231,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
1249 struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; 1231 struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
1250 struct tc_action *act; 1232 struct tc_action *act;
1251 size_t attr_size = 0; 1233 size_t attr_size = 0;
1252 struct tc_action *actions[TCA_ACT_MAX_PRIO + 1] = {}; 1234 struct tc_action *actions[TCA_ACT_MAX_PRIO] = {};
1253 int acts_deleted = 0;
1254 1235
1255 ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, extack); 1236 ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL, extack);
1256 if (ret < 0) 1237 if (ret < 0)
@@ -1280,14 +1261,13 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
1280 if (event == RTM_GETACTION) 1261 if (event == RTM_GETACTION)
1281 ret = tcf_get_notify(net, portid, n, actions, event, extack); 1262 ret = tcf_get_notify(net, portid, n, actions, event, extack);
1282 else { /* delete */ 1263 else { /* delete */
1283 ret = tcf_del_notify(net, n, actions, &acts_deleted, portid, 1264 ret = tcf_del_notify(net, n, actions, portid, attr_size, extack);
1284 attr_size, extack);
1285 if (ret) 1265 if (ret)
1286 goto err; 1266 goto err;
1287 return ret; 1267 return 0;
1288 } 1268 }
1289err: 1269err:
1290 tcf_action_put_many(&actions[acts_deleted]); 1270 tcf_action_put_many(actions);
1291 return ret; 1271 return ret;
1292} 1272}
1293 1273