diff options
Diffstat (limited to 'net/sched')
30 files changed, 228 insertions, 145 deletions
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 8126b26f125e..04b7bd4ec751 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -285,6 +285,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, struct tcf_bpf *prog; bool is_bpf, is_ebpf; int ret, res = 0; + u32 index; if (!nla) return -EINVAL; @@ -298,13 +299,13 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_ACT_BPF_PARMS]); - - ret = tcf_idr_check_alloc(tn, &parm->index, act, bind); + index = parm->index; + ret = tcf_idr_check_alloc(tn, &index, act, bind); if (!ret) { - ret = tcf_idr_create(tn, parm->index, est, act, + ret = tcf_idr_create(tn, index, est, act, &act_bpf_ops, bind, true); if (ret < 0) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -421,7 +422,7 @@ static __net_init int bpf_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, bpf_net_id); - return tc_action_net_init(tn, &act_bpf_ops); + return tc_action_net_init(net, tn, &act_bpf_ops); } static void __net_exit bpf_exit_net(struct list_head *net_list) diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c index ce36b0f7e1dc..2b43cacf82af 100644 --- a/net/sched/act_connmark.c +++ b/net/sched/act_connmark.c @@ -103,6 +103,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla, struct tcf_connmark_info *ci; struct tc_connmark *parm; int ret = 0, err; + u32 index; if (!nla) return -EINVAL; @@ -116,13 +117,13 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_CONNMARK_PARMS]); - - ret = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + ret = tcf_idr_check_alloc(tn, &index, a, bind); if (!ret) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_connmark_ops, bind, false); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -230,7 +231,7 @@ static __net_init int connmark_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, connmark_net_id); - return tc_action_net_init(tn, &act_connmark_ops); + return tc_action_net_init(net, tn, &act_connmark_ops); } static void __net_exit connmark_exit_net(struct list_head *net_list) diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 621fb22ce2a9..d3cfad88dc3a 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -52,6 +52,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla, struct tc_csum *parm; struct tcf_csum *p; int ret = 0, err; + u32 index; if (nla == NULL) return -EINVAL; @@ -64,13 +65,13 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla, if (tb[TCA_CSUM_PARMS] == NULL) return -EINVAL; parm = nla_data(tb[TCA_CSUM_PARMS]); - - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (!err) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_csum_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } ret = ACT_P_CREATED; @@ -713,7 +714,7 @@ static __net_init int csum_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, csum_net_id); - return tc_action_net_init(tn, &act_csum_ops); + return tc_action_net_init(net, tn, &act_csum_ops); } static void __net_exit csum_exit_net(struct list_head *net_list) diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index b501ce0cf116..cdd6f3818097 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -666,6 +666,7 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla, struct tc_ct *parm; struct tcf_ct *c; int err, res = 0; + u32 index; if (!nla) { NL_SET_ERR_MSG_MOD(extack, "Ct requires attributes to be passed"); @@ -681,16 +682,16 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla, return -EINVAL; } parm = nla_data(tb[TCA_CT_PARMS]); - - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; if (!err) { - err = tcf_idr_create(tn, parm->index, est, a, + err = tcf_idr_create(tn, index, est, a, &act_ct_ops, bind, true); if (err) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return err; } res = ACT_P_CREATED; @@ -938,7 +939,7 @@ static __net_init int ct_init_net(struct net *net) tn->labels = true; } - return tc_action_net_init(&tn->tn, &act_ct_ops); + return tc_action_net_init(net, &tn->tn, &act_ct_ops); } static void __net_exit ct_exit_net(struct list_head *net_list) diff --git a/net/sched/act_ctinfo.c b/net/sched/act_ctinfo.c index 10eb2bb99861..0dbcfd1dca7b 100644 --- a/net/sched/act_ctinfo.c +++ b/net/sched/act_ctinfo.c @@ -157,10 +157,10 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla, struct netlink_ext_ack *extack) { struct tc_action_net *tn = net_generic(net, ctinfo_net_id); + u32 dscpmask = 0, dscpstatemask, index; struct nlattr *tb[TCA_CTINFO_MAX + 1]; struct tcf_ctinfo_params *cp_new; struct tcf_chain *goto_ch = NULL; - u32 dscpmask = 0, dscpstatemask; struct tc_ctinfo *actparm; struct tcf_ctinfo *ci; u8 dscpmaskshift; @@ -206,12 +206,13 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla, } /* done the validation:now to the actual action allocation */ - err = tcf_idr_check_alloc(tn, &actparm->index, a, bind); + index = actparm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (!err) { - ret = tcf_idr_create(tn, actparm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_ctinfo_ops, bind, false); if (ret) { - tcf_idr_cleanup(tn, actparm->index); + tcf_idr_cleanup(tn, index); return ret; } ret = ACT_P_CREATED; @@ -375,7 +376,7 @@ static __net_init int ctinfo_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, ctinfo_net_id); - return tc_action_net_init(tn, &act_ctinfo_ops); + return tc_action_net_init(net, tn, &act_ctinfo_ops); } static void __net_exit ctinfo_exit_net(struct list_head *net_list) diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index b2380c5284e6..324f1d1f6d47 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -61,6 +61,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, struct tc_gact *parm; struct tcf_gact *gact; int ret = 0; + u32 index; int err; #ifdef CONFIG_GACT_PROB struct tc_gact_p *p_parm = NULL; @@ -77,6 +78,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, if (tb[TCA_GACT_PARMS] == NULL) return -EINVAL; parm = nla_data(tb[TCA_GACT_PARMS]); + index = parm->index; #ifndef CONFIG_GACT_PROB if (tb[TCA_GACT_PROB] != NULL) @@ -94,12 +96,12 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, } #endif - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + err = tcf_idr_check_alloc(tn, &index, a, bind); if (!err) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_gact_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } ret = ACT_P_CREATED; @@ -276,7 +278,7 @@ static __net_init int gact_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, gact_net_id); - return tc_action_net_init(tn, &act_gact_ops); + return tc_action_net_init(net, tn, &act_gact_ops); } static void __net_exit gact_exit_net(struct list_head *net_list) diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index 41d5398dd2f2..3a31e241c647 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -479,8 +479,14 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, u8 *saddr = NULL; bool exists = false; int ret = 0; + u32 index; int err; + if (!nla) { + NL_SET_ERR_MSG_MOD(extack, "IFE requires attributes to be passed"); + return -EINVAL; + } + err = nla_parse_nested_deprecated(tb, TCA_IFE_MAX, nla, ife_policy, NULL); if (err < 0) @@ -502,7 +508,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla, if (!p) return -ENOMEM; - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) { kfree(p); return err; @@ -514,10 +521,10 @@ 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, + ret = tcf_idr_create(tn, index, est, a, &act_ife_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); kfree(p); return ret; } @@ -883,7 +890,7 @@ static __net_init int ife_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, ife_net_id); - return tc_action_net_init(tn, &act_ife_ops); + return tc_action_net_init(net, tn, &act_ife_ops); } static void __net_exit ife_exit_net(struct list_head *net_list) diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index ce2c30a591d2..214a03d405cf 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -61,12 +61,13 @@ static int ipt_init_target(struct net *net, struct xt_entry_target *t, return 0; } -static void ipt_destroy_target(struct xt_entry_target *t) +static void ipt_destroy_target(struct xt_entry_target *t, struct net *net) { struct xt_tgdtor_param par = { .target = t->u.kernel.target, .targinfo = t->data, .family = NFPROTO_IPV4, + .net = net, }; if (par.target->destroy != NULL) par.target->destroy(&par); @@ -78,7 +79,7 @@ static void tcf_ipt_release(struct tc_action *a) struct tcf_ipt *ipt = to_ipt(a); if (ipt->tcfi_t) { - ipt_destroy_target(ipt->tcfi_t); + ipt_destroy_target(ipt->tcfi_t, a->idrinfo->net); kfree(ipt->tcfi_t); } kfree(ipt->tcfi_tname); @@ -180,7 +181,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla, spin_lock_bh(&ipt->tcf_lock); if (ret != ACT_P_CREATED) { - ipt_destroy_target(ipt->tcfi_t); + ipt_destroy_target(ipt->tcfi_t, net); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); } @@ -350,7 +351,7 @@ static __net_init int ipt_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, ipt_net_id); - return tc_action_net_init(tn, &act_ipt_ops); + return tc_action_net_init(net, tn, &act_ipt_ops); } static void __net_exit ipt_exit_net(struct list_head *net_list) @@ -399,7 +400,7 @@ static __net_init int xt_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, xt_net_id); - return tc_action_net_init(tn, &act_xt_ops); + return tc_action_net_init(net, tn, &act_xt_ops); } static void __net_exit xt_exit_net(struct list_head *net_list) diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 055faa298c8e..9d1bf508075a 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -104,6 +104,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, struct net_device *dev; bool exists = false; int ret, err; + u32 index; if (!nla) { NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed"); @@ -118,8 +119,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, return -EINVAL; } parm = nla_data(tb[TCA_MIRRED_PARMS]); - - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -136,21 +137,21 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option"); return -EINVAL; } if (!exists) { if (!parm->ifindex) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist"); return -EINVAL; } - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_mirred_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } ret = ACT_P_CREATED; @@ -452,7 +453,7 @@ static __net_init int mirred_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, mirred_net_id); - return tc_action_net_init(tn, &act_mirred_ops); + return tc_action_net_init(net, tn, &act_mirred_ops); } static void __net_exit mirred_exit_net(struct list_head *net_list) diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c index ca2597ce4ac9..e168df0e008a 100644 --- a/net/sched/act_mpls.c +++ b/net/sched/act_mpls.c @@ -138,6 +138,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, struct tcf_mpls *m; int ret = 0, err; u8 mpls_ttl = 0; + u32 index; if (!nla) { NL_SET_ERR_MSG_MOD(extack, "Missing netlink attributes"); @@ -153,6 +154,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, return -EINVAL; } parm = nla_data(tb[TCA_MPLS_PARMS]); + index = parm->index; /* Verify parameters against action type. */ switch (parm->m_action) { @@ -209,7 +211,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, return -EINVAL; } - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -217,10 +219,10 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, return 0; if (!exists) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_mpls_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -373,7 +375,7 @@ static __net_init int mpls_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, mpls_net_id); - return tc_action_net_init(tn, &act_mpls_ops); + return tc_action_net_init(net, tn, &act_mpls_ops); } static void __net_exit mpls_exit_net(struct list_head *net_list) diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 45923ebb7a4f..ea4c5359e7df 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -44,6 +44,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_nat *parm; int ret = 0, err; struct tcf_nat *p; + u32 index; if (nla == NULL) return -EINVAL; @@ -56,13 +57,13 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, if (tb[TCA_NAT_PARMS] == NULL) return -EINVAL; parm = nla_data(tb[TCA_NAT_PARMS]); - - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (!err) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_nat_ops, bind, false); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } ret = ACT_P_CREATED; @@ -326,7 +327,7 @@ static __net_init int nat_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, nat_net_id); - return tc_action_net_init(tn, &act_nat_ops); + return tc_action_net_init(net, tn, &act_nat_ops); } static void __net_exit nat_exit_net(struct list_head *net_list) diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 45e9d6bfddb3..cdfaa79382a2 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -149,6 +149,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, struct tcf_pedit *p; int ret = 0, err; int ksize; + u32 index; if (!nla) { NL_SET_ERR_MSG_MOD(extack, "Pedit requires attributes to be passed"); @@ -179,18 +180,19 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, if (IS_ERR(keys_ex)) return PTR_ERR(keys_ex); - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (!err) { if (!parm->nkeys) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed"); ret = -EINVAL; goto out_free; } - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_pedit_ops, bind, false); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); goto out_free; } ret = ACT_P_CREATED; @@ -496,7 +498,7 @@ static __net_init int pedit_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, pedit_net_id); - return tc_action_net_init(tn, &act_pedit_ops); + return tc_action_net_init(net, tn, &act_pedit_ops); } static void __net_exit pedit_exit_net(struct list_head *net_list) diff --git a/net/sched/act_police.c b/net/sched/act_police.c index a065f62fa79c..6315e0f8d26e 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -57,6 +57,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, struct tc_action_net *tn = net_generic(net, police_net_id); struct tcf_police_params *new; bool exists = false; + u32 index; if (nla == NULL) return -EINVAL; @@ -73,7 +74,8 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_POLICE_TBF]); - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -81,10 +83,10 @@ static int tcf_police_init(struct net *net, struct nlattr *nla, return 0; if (!exists) { - ret = tcf_idr_create(tn, parm->index, NULL, a, + ret = tcf_idr_create(tn, index, NULL, a, &act_police_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } ret = ACT_P_CREATED; @@ -369,7 +371,7 @@ static __net_init int police_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, police_net_id); - return tc_action_net_init(tn, &act_police_ops); + return tc_action_net_init(net, tn, &act_police_ops); } static void __net_exit police_exit_net(struct list_head *net_list) diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index 274d7a0c0e25..10229124a992 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -41,8 +41,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, struct tc_action_net *tn = net_generic(net, sample_net_id); struct nlattr *tb[TCA_SAMPLE_MAX + 1]; struct psample_group *psample_group; + u32 psample_group_num, rate, index; struct tcf_chain *goto_ch = NULL; - u32 psample_group_num, rate; struct tc_sample *parm; struct tcf_sample *s; bool exists = false; @@ -59,8 +59,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_SAMPLE_PARMS]); - - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -68,10 +68,10 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, return 0; if (!exists) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_sample_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } ret = ACT_P_CREATED; @@ -102,13 +102,17 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); s->rate = rate; s->psample_group_num = psample_group_num; - RCU_INIT_POINTER(s->psample_group, psample_group); + rcu_swap_protected(s->psample_group, psample_group, + lockdep_is_held(&s->tcf_lock)); if (tb[TCA_SAMPLE_TRUNC_SIZE]) { s->truncate = true; s->trunc_size = nla_get_u32(tb[TCA_SAMPLE_TRUNC_SIZE]); } spin_unlock_bh(&s->tcf_lock); + + if (psample_group) + psample_group_put(psample_group); if (goto_ch) tcf_chain_put_by_act(goto_ch); @@ -265,7 +269,7 @@ static __net_init int sample_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, sample_net_id); - return tc_action_net_init(tn, &act_sample_ops); + return tc_action_net_init(net, tn, &act_sample_ops); } static void __net_exit sample_exit_net(struct list_head *net_list) diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index f28ddbabff76..6120e56117ca 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -95,6 +95,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, struct tcf_defact *d; bool exists = false; int ret = 0, err; + u32 index; if (nla == NULL) return -EINVAL; @@ -108,7 +109,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return -EINVAL; parm = nla_data(tb[TCA_DEF_PARMS]); - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -119,15 +121,15 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return -EINVAL; } if (!exists) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_simp_ops, bind, false); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -230,7 +232,7 @@ static __net_init int simp_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, simp_net_id); - return tc_action_net_init(tn, &act_simp_ops); + return tc_action_net_init(net, tn, &act_simp_ops); } static void __net_exit simp_exit_net(struct list_head *net_list) diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 215a06705cef..6a8d3337c577 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -99,6 +99,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, u16 *queue_mapping = NULL, *ptype = NULL; bool exists = false; int ret = 0, err; + u32 index; if (nla == NULL) return -EINVAL; @@ -146,8 +147,8 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, } parm = nla_data(tb[TCA_SKBEDIT_PARMS]); - - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -158,15 +159,15 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return -EINVAL; } if (!exists) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_skbedit_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -306,6 +307,17 @@ static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index) return tcf_idr_search(tn, a, index); } +static size_t tcf_skbedit_get_fill_size(const struct tc_action *act) +{ + return nla_total_size(sizeof(struct tc_skbedit)) + + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_PRIORITY */ + + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_QUEUE_MAPPING */ + + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MARK */ + + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_PTYPE */ + + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MASK */ + + nla_total_size_64bit(sizeof(u64)); /* TCA_SKBEDIT_FLAGS */ +} + static struct tc_action_ops act_skbedit_ops = { .kind = "skbedit", .id = TCA_ID_SKBEDIT, @@ -315,6 +327,7 @@ static struct tc_action_ops act_skbedit_ops = { .init = tcf_skbedit_init, .cleanup = tcf_skbedit_cleanup, .walk = tcf_skbedit_walker, + .get_fill_size = tcf_skbedit_get_fill_size, .lookup = tcf_skbedit_search, .size = sizeof(struct tcf_skbedit), }; @@ -323,7 +336,7 @@ static __net_init int skbedit_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, skbedit_net_id); - return tc_action_net_init(tn, &act_skbedit_ops); + return tc_action_net_init(net, tn, &act_skbedit_ops); } static void __net_exit skbedit_exit_net(struct list_head *net_list) diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index 4f07706eff07..888437f97ba6 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -87,12 +87,12 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, struct tcf_skbmod_params *p, *p_old; struct tcf_chain *goto_ch = NULL; struct tc_skbmod *parm; + u32 lflags = 0, index; struct tcf_skbmod *d; bool exists = false; u8 *daddr = NULL; u8 *saddr = NULL; u16 eth_type = 0; - u32 lflags = 0; int ret = 0, err; if (!nla) @@ -122,10 +122,11 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, } parm = nla_data(tb[TCA_SKBMOD_PARMS]); + index = parm->index; if (parm->flags & SKBMOD_F_SWAPMAC) lflags = SKBMOD_F_SWAPMAC; - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -136,15 +137,15 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return -EINVAL; } if (!exists) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_skbmod_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -286,7 +287,7 @@ static __net_init int skbmod_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, skbmod_net_id); - return tc_action_net_init(tn, &act_skbmod_ops); + return tc_action_net_init(net, tn, &act_skbmod_ops); } static void __net_exit skbmod_exit_net(struct list_head *net_list) diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index 10dffda1d5cc..2f83a79f76aa 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -225,6 +225,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, __be16 flags = 0; u8 tos, ttl; int ret = 0; + u32 index; int err; if (!nla) { @@ -245,7 +246,8 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, } parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]); - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -345,7 +347,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, } if (!exists) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_tunnel_key_ops, bind, true); if (ret) { NL_SET_ERR_MSG(extack, "Cannot create TC IDR"); @@ -403,7 +405,7 @@ err_out: if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -598,7 +600,7 @@ static __net_init int tunnel_key_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); - return tc_action_net_init(tn, &act_tunnel_key_ops); + return tc_action_net_init(net, tn, &act_tunnel_key_ops); } static void __net_exit tunnel_key_exit_net(struct list_head *net_list) diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index 9269d350fb8a..287a30bf8930 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -116,6 +116,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, u8 push_prio = 0; bool exists = false; int ret = 0, err; + u32 index; if (!nla) return -EINVAL; @@ -128,7 +129,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]); - err = tcf_idr_check_alloc(tn, &parm->index, a, bind); + index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); if (err < 0) return err; exists = err; @@ -144,7 +146,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return -EINVAL; } push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); @@ -152,7 +154,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return -ERANGE; } @@ -166,7 +168,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return -EPROTONOSUPPORT; } } else { @@ -180,16 +182,16 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, if (exists) tcf_idr_release(*a, bind); else - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return -EINVAL; } action = parm->v_action; if (!exists) { - ret = tcf_idr_create(tn, parm->index, est, a, + ret = tcf_idr_create(tn, index, est, a, &act_vlan_ops, bind, true); if (ret) { - tcf_idr_cleanup(tn, parm->index); + tcf_idr_cleanup(tn, index); return ret; } @@ -306,6 +308,14 @@ static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index) return tcf_idr_search(tn, a, index); } +static size_t tcf_vlan_get_fill_size(const struct tc_action *act) +{ + return nla_total_size(sizeof(struct tc_vlan)) + + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_ID */ + + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_PROTOCOL */ + + nla_total_size(sizeof(u8)); /* TCA_VLAN_PUSH_VLAN_PRIORITY */ +} + static struct tc_action_ops act_vlan_ops = { .kind = "vlan", .id = TCA_ID_VLAN, @@ -315,6 +325,7 @@ static struct tc_action_ops act_vlan_ops = { .init = tcf_vlan_init, .cleanup = tcf_vlan_cleanup, .walk = tcf_vlan_walker, + .get_fill_size = tcf_vlan_get_fill_size, .lookup = tcf_vlan_search, .size = sizeof(struct tcf_vlan), }; @@ -323,7 +334,7 @@ static __net_init int vlan_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, vlan_net_id); - return tc_action_net_init(tn, &act_vlan_ops); + return tc_action_net_init(net, tn, &act_vlan_ops); } static void __net_exit vlan_exit_net(struct list_head *net_list) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index d144233423c5..efd3cfb80a2a 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -691,6 +691,8 @@ static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev, if (!indr_dev->block) return; + bo.block = &indr_dev->block->flow_block; + indr_block_cb->cb(indr_dev->dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK, &bo); tcf_block_setup(indr_dev->block, &bo); @@ -775,6 +777,7 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev, .command = command, .binder_type = ei->binder_type, .net = dev_net(dev), + .block = &block->flow_block, .block_shared = tcf_block_shared(block), .extack = extack, }; @@ -810,6 +813,7 @@ static int tcf_block_offload_cmd(struct tcf_block *block, bo.net = dev_net(dev); bo.command = command; bo.binder_type = ei->binder_type; + bo.block = &block->flow_block; bo.block_shared = tcf_block_shared(block); bo.extack = extack; INIT_LIST_HEAD(&bo.cb_list); @@ -987,8 +991,8 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, return ERR_PTR(-ENOMEM); } mutex_init(&block->lock); + flow_block_init(&block->flow_block); INIT_LIST_HEAD(&block->chain_list); - INIT_LIST_HEAD(&block->cb_list); INIT_LIST_HEAD(&block->owner_list); INIT_LIST_HEAD(&block->chain0.filter_chain_list); @@ -1514,7 +1518,7 @@ void tcf_block_put(struct tcf_block *block) EXPORT_SYMBOL(tcf_block_put); static int -tcf_block_playback_offloads(struct tcf_block *block, tc_setup_cb_t *cb, +tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb, void *cb_priv, bool add, bool offload_in_use, struct netlink_ext_ack *extack) { @@ -1570,7 +1574,7 @@ static int tcf_block_bind(struct tcf_block *block, i++; } - list_splice(&bo->cb_list, &block->cb_list); + list_splice(&bo->cb_list, &block->flow_block.cb_list); return 0; @@ -2152,7 +2156,9 @@ replay: tfilter_notify(net, skb, n, tp, block, q, parent, fh, RTM_NEWTFILTER, false, rtnl_held); tfilter_put(tp, fh); - q->flags &= ~TCQ_F_CAN_BYPASS; + /* q pointer is NULL for shared blocks */ + if (q) + q->flags &= ~TCQ_F_CAN_BYPASS; } errout: @@ -3156,7 +3162,7 @@ int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, if (block->nooffloaddevcnt && err_stop) return -EOPNOTSUPP; - list_for_each_entry(block_cb, &block->cb_list, list) { + list_for_each_entry(block_cb, &block->flow_block.cb_list, list) { err = block_cb->cb(type, type_data, block_cb->cb_priv); if (err) { if (err_stop) diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c index 691f71830134..3f7a9c02b70c 100644 --- a/net/sched/cls_bpf.c +++ b/net/sched/cls_bpf.c @@ -651,7 +651,7 @@ skip: } } -static int cls_bpf_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, +static int cls_bpf_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, void *cb_priv, struct netlink_ext_ack *extack) { struct cls_bpf_head *head = rtnl_dereference(tp->root); diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 38d6e85693fc..054123742e32 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -1800,7 +1800,7 @@ fl_get_next_hw_filter(struct tcf_proto *tp, struct cls_fl_filter *f, bool add) return NULL; } -static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, +static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, void *cb_priv, struct netlink_ext_ack *extack) { struct tcf_block *block = tp->chain->block; diff --git a/net/sched/cls_matchall.c b/net/sched/cls_matchall.c index a30d2f8feb32..455ea2793f9b 100644 --- a/net/sched/cls_matchall.c +++ b/net/sched/cls_matchall.c @@ -282,7 +282,7 @@ skip: arg->count++; } -static int mall_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, +static int mall_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, void *cb_priv, struct netlink_ext_ack *extack) { struct cls_mall_head *head = rtnl_dereference(tp->root); diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index be9e46c77e8b..8614088edd1b 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -1152,7 +1152,7 @@ static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg, } static int u32_reoffload_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, - bool add, tc_setup_cb_t *cb, void *cb_priv, + bool add, flow_setup_cb_t *cb, void *cb_priv, struct netlink_ext_ack *extack) { struct tc_cls_u32_offload cls_u32 = {}; @@ -1172,7 +1172,7 @@ static int u32_reoffload_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht, } static int u32_reoffload_knode(struct tcf_proto *tp, struct tc_u_knode *n, - bool add, tc_setup_cb_t *cb, void *cb_priv, + bool add, flow_setup_cb_t *cb, void *cb_priv, struct netlink_ext_ack *extack) { struct tc_u_hnode *ht = rtnl_dereference(n->ht_down); @@ -1213,7 +1213,7 @@ static int u32_reoffload_knode(struct tcf_proto *tp, struct tc_u_knode *n, return 0; } -static int u32_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb, +static int u32_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb, void *cb_priv, struct netlink_ext_ack *extack) { struct tc_u_common *tp_c = tp->data; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 04faee7ccbce..1047825d9f48 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1920,6 +1920,8 @@ static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid, cl = cops->find(q, portid); if (!cl) return; + if (!cops->tcf_block) + return; block = cops->tcf_block(q, cl, NULL); if (!block) return; diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index 732e109c3055..810645b5c086 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -181,11 +181,6 @@ static struct sk_buff *cbs_dequeue_soft(struct Qdisc *sch) s64 credits; int len; - if (atomic64_read(&q->port_rate) == -1) { - WARN_ONCE(1, "cbs: dequeue() called with unknown port rate."); - return NULL; - } - if (q->credits < 0) { credits = timediff_to_credits(now - q->last, q->idleslope); @@ -303,11 +298,19 @@ static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q, static void cbs_set_port_rate(struct net_device *dev, struct cbs_sched_data *q) { struct ethtool_link_ksettings ecmd; + int speed = SPEED_10; int port_rate = -1; + int err; + + err = __ethtool_get_link_ksettings(dev, &ecmd); + if (err < 0) + goto skip; + + if (ecmd.base.speed != SPEED_UNKNOWN) + speed = ecmd.base.speed; - if (!__ethtool_get_link_ksettings(dev, &ecmd) && - ecmd.base.speed != SPEED_UNKNOWN) - port_rate = ecmd.base.speed * 1000 * BYTES_PER_KBIT; +skip: + port_rate = speed * 1000 * BYTES_PER_KBIT; atomic64_set(&q->port_rate, port_rate); netdev_dbg(dev, "cbs: set %s's port_rate to: %lld, linkspeed: %d\n", diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index 25ef172c23df..30169b3adbbb 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -71,10 +71,10 @@ static struct sk_buff *dequeue_func(struct codel_vars *vars, void *ctx) struct Qdisc *sch = ctx; struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); - if (skb) + if (skb) { sch->qstats.backlog -= qdisc_pkt_len(skb); - - prefetch(&skb->end); /* we'll need skb_shinfo() */ + prefetch(&skb->end); /* we'll need skb_shinfo() */ + } return skb; } diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 11c03cf4aa74..ac28f6a5d70e 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -46,6 +46,8 @@ EXPORT_SYMBOL(default_qdisc_ops); * - updates to tree and tree walking are only done under the rtnl mutex. */ +#define SKB_XOFF_MAGIC ((struct sk_buff *)1UL) + static inline struct sk_buff *__skb_dequeue_bad_txq(struct Qdisc *q) { const struct netdev_queue *txq = q->dev_queue; @@ -71,7 +73,7 @@ static inline struct sk_buff *__skb_dequeue_bad_txq(struct Qdisc *q) q->q.qlen--; } } else { - skb = NULL; + skb = SKB_XOFF_MAGIC; } } @@ -253,8 +255,11 @@ validate: return skb; skb = qdisc_dequeue_skb_bad_txq(q); - if (unlikely(skb)) + if (unlikely(skb)) { + if (skb == SKB_XOFF_MAGIC) + return NULL; goto bulk; + } skb = q->dequeue(q); if (skb) { bulk: @@ -624,8 +629,12 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, err = skb_array_produce(q, skb); - if (unlikely(err)) - return qdisc_drop_cpu(skb, qdisc, to_free); + if (unlikely(err)) { + if (qdisc_is_percpu_stats(qdisc)) + return qdisc_drop_cpu(skb, qdisc, to_free); + else + return qdisc_drop(skb, qdisc, to_free); + } qdisc_update_stats_at_enqueue(qdisc, pkt_len); return NET_XMIT_SUCCESS; @@ -688,11 +697,14 @@ static void pfifo_fast_reset(struct Qdisc *qdisc) kfree_skb(skb); } - for_each_possible_cpu(i) { - struct gnet_stats_queue *q = per_cpu_ptr(qdisc->cpu_qstats, i); + if (qdisc_is_percpu_stats(qdisc)) { + for_each_possible_cpu(i) { + struct gnet_stats_queue *q; - q->backlog = 0; - q->qlen = 0; + q = per_cpu_ptr(qdisc->cpu_qstats, i); + q->backlog = 0; + q->qlen = 0; + } } } diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index cee6971c1c82..23cd1c873a2c 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -531,7 +531,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt, new_hhf_non_hh_weight = nla_get_u32(tb[TCA_HHF_NON_HH_WEIGHT]); non_hh_quantum = (u64)new_quantum * new_hhf_non_hh_weight; - if (non_hh_quantum > INT_MAX) + if (non_hh_quantum == 0 || non_hh_quantum > INT_MAX) return -EINVAL; sch_tree_lock(sch); diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index c39db507ba3f..8d8bc2ec5cd6 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -477,11 +477,6 @@ static struct sk_buff *taprio_dequeue(struct Qdisc *sch) u32 gate_mask; int i; - if (atomic64_read(&q->picos_per_byte) == -1) { - WARN_ONCE(1, "taprio: dequeue() called with unknown picos per byte."); - return NULL; - } - rcu_read_lock(); entry = rcu_dereference(q->current_entry); /* if there's no entry, it means that the schedule didn't @@ -958,12 +953,20 @@ static void taprio_set_picos_per_byte(struct net_device *dev, struct taprio_sched *q) { struct ethtool_link_ksettings ecmd; - int picos_per_byte = -1; + int speed = SPEED_10; + int picos_per_byte; + int err; - if (!__ethtool_get_link_ksettings(dev, &ecmd) && - ecmd.base.speed != SPEED_UNKNOWN) - picos_per_byte = div64_s64(NSEC_PER_SEC * 1000LL * 8, - ecmd.base.speed * 1000 * 1000); + err = __ethtool_get_link_ksettings(dev, &ecmd); + if (err < 0) + goto skip; + + if (ecmd.base.speed != SPEED_UNKNOWN) + speed = ecmd.base.speed; + +skip: + picos_per_byte = div64_s64(NSEC_PER_SEC * 1000LL * 8, + speed * 1000 * 1000); atomic64_set(&q->picos_per_byte, picos_per_byte); netdev_dbg(dev, "taprio: set %s's picos_per_byte to: %lld, linkspeed: %d\n", @@ -1195,7 +1198,8 @@ unlock: spin_unlock_bh(qdisc_lock(sch)); free_sched: - kfree(new_admin); + if (new_admin) + call_rcu(&new_admin->rcu, taprio_free_sched_cb); return err; } @@ -1248,6 +1252,10 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt, */ q->clockid = -1; + spin_lock(&taprio_list_lock); + list_add(&q->taprio_list, &taprio_list); + spin_unlock(&taprio_list_lock); + if (sch->parent != TC_H_ROOT) return -EOPNOTSUPP; @@ -1265,10 +1273,6 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt, if (!opt) return -EINVAL; - spin_lock(&taprio_list_lock); - list_add(&q->taprio_list, &taprio_list); - spin_unlock(&taprio_list_lock); - for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *dev_queue; struct Qdisc *qdisc; |