diff options
Diffstat (limited to 'net/sched/act_api.c')
-rw-r--r-- | net/sched/act_api.c | 70 |
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 | } |
301 | EXPORT_SYMBOL(tcf_generic_walker); | 301 | EXPORT_SYMBOL(tcf_generic_walker); |
302 | 302 | ||
303 | static bool __tcf_idr_check(struct tc_action_net *tn, u32 index, | 303 | int 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 | |||
327 | int 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 | } | ||
331 | EXPORT_SYMBOL(tcf_idr_search); | 322 | EXPORT_SYMBOL(tcf_idr_search); |
332 | 323 | ||
333 | bool tcf_idr_check(struct tc_action_net *tn, u32 index, struct tc_action **a, | 324 | static 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 | } | ||
338 | EXPORT_SYMBOL(tcf_idr_check); | ||
339 | |||
340 | int 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 | } |
373 | EXPORT_SYMBOL(tcf_idr_delete_index); | ||
374 | 356 | ||
375 | int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est, | 357 | int 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; |
415 | err3: | 396 | err3: |
@@ -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. */ | ||
689 | static void tcf_action_put_many(struct tc_action *actions[]) | 671 | static 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 | ||
1178 | static int tcf_action_delete(struct net *net, struct tc_action *actions[], | 1163 | static 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 | ||
1209 | static int | 1192 | static int |
1210 | tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[], | 1193 | tcf_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 | } |
1289 | err: | 1269 | err: |
1290 | tcf_action_put_many(&actions[acts_deleted]); | 1270 | tcf_action_put_many(actions); |
1291 | return ret; | 1271 | return ret; |
1292 | } | 1272 | } |
1293 | 1273 | ||