Retry check-insert sequence in action init functions if action with same index was inserted concurrently. Signed-off-by: Vlad Buslov <vladbu@xxxxxxxxxxxx> --- net/sched/act_bpf.c | 8 +++++++- net/sched/act_connmark.c | 8 +++++++- net/sched/act_csum.c | 8 +++++++- net/sched/act_gact.c | 8 +++++++- net/sched/act_ife.c | 8 +++++++- net/sched/act_ipt.c | 8 +++++++- net/sched/act_mirred.c | 8 +++++++- net/sched/act_nat.c | 8 +++++++- net/sched/act_pedit.c | 8 +++++++- net/sched/act_police.c | 9 ++++++++- net/sched/act_sample.c | 8 +++++++- net/sched/act_simple.c | 9 ++++++++- net/sched/act_skbedit.c | 8 +++++++- net/sched/act_skbmod.c | 8 +++++++- net/sched/act_tunnel_key.c | 9 ++++++++- net/sched/act_vlan.c | 9 ++++++++- 16 files changed, 116 insertions(+), 16 deletions(-) diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 5554bf7..7e20fdc 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -299,10 +299,16 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, parm = nla_data(tb[TCA_ACT_BPF_PARMS]); +replay: if (!tcf_idr_check(tn, parm->index, act, bind)) { ret = tcf_idr_create(tn, parm->index, est, act, &act_bpf_ops, bind, true); - if (ret < 0) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; res = ACT_P_CREATED; diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c index 2a4c3da..6ff45af 100644 --- a/net/sched/act_connmark.c +++ b/net/sched/act_connmark.c @@ -118,10 +118,16 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla, parm = nla_data(tb[TCA_CONNMARK_PARMS]); +replay: if (!tcf_idr_check(tn, parm->index, a, bind)) { ret = tcf_idr_create(tn, parm->index, est, a, &act_connmark_ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ci = to_connmark(*a); diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 74f5dce..49d06c3 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -67,10 +67,16 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_CSUM_PARMS]); +replay: if (!tcf_idr_check(tn, parm->index, a, bind)) { ret = tcf_idr_create(tn, parm->index, est, a, &act_csum_ops, bind, true); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; } else { diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 9d7d000..2edefeb 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -91,10 +91,16 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, } #endif +replay: if (!tcf_idr_check(tn, parm->index, a, bind)) { ret = tcf_idr_create(tn, parm->index, est, a, &act_gact_ops, bind, true); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; } else { diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index b57c5ba..665790f 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -483,6 +483,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, if (!p) return -ENOMEM; +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) { kfree(p); @@ -492,7 +493,12 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops, bind, true); - if (ret) { + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) { + goto replay; + } else if (ret) { kfree(p); return ret; } diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 7c26ce1..946193e 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -119,6 +119,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, if (tb[TCA_IPT_INDEX] != NULL) index = nla_get_u32(tb[TCA_IPT_INDEX]); +replay: exists = tcf_idr_check(tn, index, a, bind); if (exists && bind) return 0; @@ -139,7 +140,12 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, index, est, a, ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; } else { diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index b9b7b96..4c8bd26 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -94,6 +94,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, } parm = nla_data(tb[TCA_MIRRED_PARMS]); +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -129,7 +130,12 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, } ret = tcf_idr_create(tn, parm->index, est, a, &act_mirred_ops, bind, true); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; } else if (!ovr) { diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 77badb2..a1a1885 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -57,10 +57,16 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, return -EINVAL; parm = nla_data(tb[TCA_NAT_PARMS]); +replay: if (!tcf_idr_check(tn, parm->index, a, bind)) { ret = tcf_idr_create(tn, parm->index, est, a, &act_nat_ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; } else { diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 8c39adc..e5e93e2 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -167,12 +167,18 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, if (IS_ERR(keys_ex)) return PTR_ERR(keys_ex); +replay: if (!tcf_idr_check(tn, parm->index, a, bind)) { if (!parm->nkeys) return -EINVAL; ret = tcf_idr_create(tn, parm->index, est, a, &act_pedit_ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; p = to_pedit(*a); keys = kmalloc(ksize, GFP_KERNEL); diff --git a/net/sched/act_police.c b/net/sched/act_police.c index c480d68..ced6b1f 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -101,6 +101,8 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_POLICE_TBF]); + +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -108,7 +110,12 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, NULL, a, &act_police_ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; } else if (!ovr) { diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index d2b0394..7411805 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -59,6 +59,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, parm = nla_data(tb[TCA_SAMPLE_PARMS]); +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -66,7 +67,12 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_sample_ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; } else if (!ovr) { diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 26eb153..a4b2aca 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -101,6 +101,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_DEF_PARMS]); + +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -116,7 +118,12 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_simp_ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; d = to_defact(*a); diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index bb416b7..7750b77 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -117,6 +117,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, parm = nla_data(tb[TCA_SKBEDIT_PARMS]); +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -129,7 +130,12 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_skbedit_ops, bind, false); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; d = to_skbedit(*a); diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index e1c2e1c..bbc5092 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -128,6 +128,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, if (parm->flags & SKBMOD_F_SWAPMAC) lflags = SKBMOD_F_SWAPMAC; +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -138,7 +139,12 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_skbmod_ops, bind, true); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index d88c151..4367962 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -99,6 +99,8 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]); + +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -161,7 +163,12 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_tunnel_key_ops, bind, true); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index f747fb6..adc4e6e 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -134,6 +134,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, if (!tb[TCA_VLAN_PARMS]) return -EINVAL; parm = nla_data(tb[TCA_VLAN_PARMS]); + +replay: exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; @@ -181,7 +183,12 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, if (!exists) { ret = tcf_idr_create(tn, parm->index, est, a, &act_vlan_ops, bind, true); - if (ret) + /* Action with specified index was created concurrently. + * Check again. + */ + if (parm->index && ret == -ENOSPC) + goto replay; + else if (ret) return ret; ret = ACT_P_CREATED; -- 2.7.5 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html