aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_ife.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_ife.c')
-rw-r--r--net/sched/act_ife.c53
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}
107EXPORT_SYMBOL_GPL(ife_get_meta_u16); 107EXPORT_SYMBOL_GPL(ife_get_meta_u16);
108 108
109int ife_alloc_meta_u32(struct tcf_meta_info *mi, void *metaval) 109int 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}
117EXPORT_SYMBOL_GPL(ife_alloc_meta_u32); 117EXPORT_SYMBOL_GPL(ife_alloc_meta_u32);
118 118
119int ife_alloc_meta_u16(struct tcf_meta_info *mi, void *metaval) 119int 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*/
245static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid, 245static 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*/
277static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval, 279static 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 */
389static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb) 393static 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);