diff options
Diffstat (limited to 'net/sched/act_ife.c')
-rw-r--r-- | net/sched/act_ife.c | 53 |
1 files changed, 31 insertions, 22 deletions
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index b7fa96926c90..845ab5119c05 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c | |||
@@ -106,9 +106,9 @@ int ife_get_meta_u16(struct sk_buff *skb, struct tcf_meta_info *mi) | |||
106 | } | 106 | } |
107 | EXPORT_SYMBOL_GPL(ife_get_meta_u16); | 107 | EXPORT_SYMBOL_GPL(ife_get_meta_u16); |
108 | 108 | ||
109 | int ife_alloc_meta_u32(struct tcf_meta_info *mi, void *metaval) | 109 | int ife_alloc_meta_u32(struct tcf_meta_info *mi, void *metaval, gfp_t gfp) |
110 | { | 110 | { |
111 | mi->metaval = kmemdup(metaval, sizeof(u32), GFP_KERNEL); | 111 | mi->metaval = kmemdup(metaval, sizeof(u32), gfp); |
112 | if (!mi->metaval) | 112 | if (!mi->metaval) |
113 | return -ENOMEM; | 113 | return -ENOMEM; |
114 | 114 | ||
@@ -116,9 +116,9 @@ int ife_alloc_meta_u32(struct tcf_meta_info *mi, void *metaval) | |||
116 | } | 116 | } |
117 | EXPORT_SYMBOL_GPL(ife_alloc_meta_u32); | 117 | EXPORT_SYMBOL_GPL(ife_alloc_meta_u32); |
118 | 118 | ||
119 | int ife_alloc_meta_u16(struct tcf_meta_info *mi, void *metaval) | 119 | int ife_alloc_meta_u16(struct tcf_meta_info *mi, void *metaval, gfp_t gfp) |
120 | { | 120 | { |
121 | mi->metaval = kmemdup(metaval, sizeof(u16), GFP_KERNEL); | 121 | mi->metaval = kmemdup(metaval, sizeof(u16), gfp); |
122 | if (!mi->metaval) | 122 | if (!mi->metaval) |
123 | return -ENOMEM; | 123 | return -ENOMEM; |
124 | 124 | ||
@@ -240,10 +240,10 @@ static int ife_validate_metatype(struct tcf_meta_ops *ops, void *val, int len) | |||
240 | } | 240 | } |
241 | 241 | ||
242 | /* called when adding new meta information | 242 | /* called when adding new meta information |
243 | * under ife->tcf_lock | 243 | * under ife->tcf_lock for existing action |
244 | */ | 244 | */ |
245 | static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid, | 245 | static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid, |
246 | void *val, int len) | 246 | void *val, int len, bool exists) |
247 | { | 247 | { |
248 | struct tcf_meta_ops *ops = find_ife_oplist(metaid); | 248 | struct tcf_meta_ops *ops = find_ife_oplist(metaid); |
249 | int ret = 0; | 249 | int ret = 0; |
@@ -251,11 +251,13 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid, | |||
251 | if (!ops) { | 251 | if (!ops) { |
252 | ret = -ENOENT; | 252 | ret = -ENOENT; |
253 | #ifdef CONFIG_MODULES | 253 | #ifdef CONFIG_MODULES |
254 | spin_unlock_bh(&ife->tcf_lock); | 254 | if (exists) |
255 | spin_unlock_bh(&ife->tcf_lock); | ||
255 | rtnl_unlock(); | 256 | rtnl_unlock(); |
256 | request_module("ifemeta%u", metaid); | 257 | request_module("ifemeta%u", metaid); |
257 | rtnl_lock(); | 258 | rtnl_lock(); |
258 | spin_lock_bh(&ife->tcf_lock); | 259 | if (exists) |
260 | spin_lock_bh(&ife->tcf_lock); | ||
259 | ops = find_ife_oplist(metaid); | 261 | ops = find_ife_oplist(metaid); |
260 | #endif | 262 | #endif |
261 | } | 263 | } |
@@ -272,10 +274,10 @@ static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid, | |||
272 | } | 274 | } |
273 | 275 | ||
274 | /* called when adding new meta information | 276 | /* called when adding new meta information |
275 | * under ife->tcf_lock | 277 | * under ife->tcf_lock for existing action |
276 | */ | 278 | */ |
277 | static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval, | 279 | static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval, |
278 | int len) | 280 | int len, bool atomic) |
279 | { | 281 | { |
280 | struct tcf_meta_info *mi = NULL; | 282 | struct tcf_meta_info *mi = NULL; |
281 | struct tcf_meta_ops *ops = find_ife_oplist(metaid); | 283 | struct tcf_meta_ops *ops = find_ife_oplist(metaid); |
@@ -284,7 +286,7 @@ static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval, | |||
284 | if (!ops) | 286 | if (!ops) |
285 | return -ENOENT; | 287 | return -ENOENT; |
286 | 288 | ||
287 | mi = kzalloc(sizeof(*mi), GFP_KERNEL); | 289 | mi = kzalloc(sizeof(*mi), atomic ? GFP_ATOMIC : GFP_KERNEL); |
288 | if (!mi) { | 290 | if (!mi) { |
289 | /*put back what find_ife_oplist took */ | 291 | /*put back what find_ife_oplist took */ |
290 | module_put(ops->owner); | 292 | module_put(ops->owner); |
@@ -294,7 +296,7 @@ static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval, | |||
294 | mi->metaid = metaid; | 296 | mi->metaid = metaid; |
295 | mi->ops = ops; | 297 | mi->ops = ops; |
296 | if (len > 0) { | 298 | if (len > 0) { |
297 | ret = ops->alloc(mi, metaval); | 299 | ret = ops->alloc(mi, metaval, atomic ? GFP_ATOMIC : GFP_KERNEL); |
298 | if (ret != 0) { | 300 | if (ret != 0) { |
299 | kfree(mi); | 301 | kfree(mi); |
300 | module_put(ops->owner); | 302 | module_put(ops->owner); |
@@ -313,11 +315,13 @@ static int use_all_metadata(struct tcf_ife_info *ife) | |||
313 | int rc = 0; | 315 | int rc = 0; |
314 | int installed = 0; | 316 | int installed = 0; |
315 | 317 | ||
318 | read_lock(&ife_mod_lock); | ||
316 | list_for_each_entry(o, &ifeoplist, list) { | 319 | list_for_each_entry(o, &ifeoplist, list) { |
317 | rc = add_metainfo(ife, o->metaid, NULL, 0); | 320 | rc = add_metainfo(ife, o->metaid, NULL, 0, true); |
318 | if (rc == 0) | 321 | if (rc == 0) |
319 | installed += 1; | 322 | installed += 1; |
320 | } | 323 | } |
324 | read_unlock(&ife_mod_lock); | ||
321 | 325 | ||
322 | if (installed) | 326 | if (installed) |
323 | return 0; | 327 | return 0; |
@@ -385,8 +389,9 @@ static void tcf_ife_cleanup(struct tc_action *a, int bind) | |||
385 | spin_unlock_bh(&ife->tcf_lock); | 389 | spin_unlock_bh(&ife->tcf_lock); |
386 | } | 390 | } |
387 | 391 | ||
388 | /* under ife->tcf_lock */ | 392 | /* under ife->tcf_lock for existing action */ |
389 | static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb) | 393 | static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb, |
394 | bool exists) | ||
390 | { | 395 | { |
391 | int len = 0; | 396 | int len = 0; |
392 | int rc = 0; | 397 | int rc = 0; |
@@ -398,11 +403,11 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb) | |||
398 | val = nla_data(tb[i]); | 403 | val = nla_data(tb[i]); |
399 | len = nla_len(tb[i]); | 404 | len = nla_len(tb[i]); |
400 | 405 | ||
401 | rc = load_metaops_and_vet(ife, i, val, len); | 406 | rc = load_metaops_and_vet(ife, i, val, len, exists); |
402 | if (rc != 0) | 407 | if (rc != 0) |
403 | return rc; | 408 | return rc; |
404 | 409 | ||
405 | rc = add_metainfo(ife, i, val, len); | 410 | rc = add_metainfo(ife, i, val, len, exists); |
406 | if (rc) | 411 | if (rc) |
407 | return rc; | 412 | return rc; |
408 | } | 413 | } |
@@ -475,7 +480,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, | |||
475 | saddr = nla_data(tb[TCA_IFE_SMAC]); | 480 | saddr = nla_data(tb[TCA_IFE_SMAC]); |
476 | } | 481 | } |
477 | 482 | ||
478 | spin_lock_bh(&ife->tcf_lock); | 483 | if (exists) |
484 | spin_lock_bh(&ife->tcf_lock); | ||
479 | ife->tcf_action = parm->action; | 485 | ife->tcf_action = parm->action; |
480 | 486 | ||
481 | if (parm->flags & IFE_ENCODE) { | 487 | if (parm->flags & IFE_ENCODE) { |
@@ -505,11 +511,12 @@ metadata_parse_err: | |||
505 | if (ret == ACT_P_CREATED) | 511 | if (ret == ACT_P_CREATED) |
506 | _tcf_ife_cleanup(a, bind); | 512 | _tcf_ife_cleanup(a, bind); |
507 | 513 | ||
508 | spin_unlock_bh(&ife->tcf_lock); | 514 | if (exists) |
515 | spin_unlock_bh(&ife->tcf_lock); | ||
509 | return err; | 516 | return err; |
510 | } | 517 | } |
511 | 518 | ||
512 | err = populate_metalist(ife, tb2); | 519 | err = populate_metalist(ife, tb2, exists); |
513 | if (err) | 520 | if (err) |
514 | goto metadata_parse_err; | 521 | goto metadata_parse_err; |
515 | 522 | ||
@@ -524,12 +531,14 @@ metadata_parse_err: | |||
524 | if (ret == ACT_P_CREATED) | 531 | if (ret == ACT_P_CREATED) |
525 | _tcf_ife_cleanup(a, bind); | 532 | _tcf_ife_cleanup(a, bind); |
526 | 533 | ||
527 | spin_unlock_bh(&ife->tcf_lock); | 534 | if (exists) |
535 | spin_unlock_bh(&ife->tcf_lock); | ||
528 | return err; | 536 | return err; |
529 | } | 537 | } |
530 | } | 538 | } |
531 | 539 | ||
532 | spin_unlock_bh(&ife->tcf_lock); | 540 | if (exists) |
541 | spin_unlock_bh(&ife->tcf_lock); | ||
533 | 542 | ||
534 | if (ret == ACT_P_CREATED) | 543 | if (ret == ACT_P_CREATED) |
535 | tcf_hash_insert(tn, a); | 544 | tcf_hash_insert(tn, a); |