static void tcf_police_destroy(struct tcf_police *p) { unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); struct tcf_common **p1p; for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->tcfc_next) { if (*p1p == &p->common) { write_lock_bh(&police_lock); *p1p = p->tcf_next; write_unlock_bh(&police_lock); gen_kill_estimator(&p->tcf_bstats, &p->tcf_rate_est); if (p->tcfp_R_tab) qdisc_put_rtab(p->tcfp_R_tab); if (p->tcfp_P_tab) qdisc_put_rtab(p->tcfp_P_tab); /* * gen_estimator est_timer() might access p->tcf_lock * or bstats, wait a RCU grace period before freeing p */ kfree_rcu(p, tcf_rcu); return; } } WARN_ON(1); }
static void tbf_destroy(struct Qdisc *sch) { struct tbf_sched_data *q = qdisc_priv(sch); del_timer(&q->wd_timer); if (q->P_tab) qdisc_put_rtab(q->P_tab); if (q->R_tab) qdisc_put_rtab(q->R_tab); qdisc_destroy(q->qdisc); }
static void tbf_destroy(struct Qdisc *sch) { struct tbf_sched_data *q = qdisc_priv(sch); qdisc_watchdog_cancel(&q->watchdog); if (q->P_tab) qdisc_put_rtab(q->P_tab); if (q->R_tab) qdisc_put_rtab(q->R_tab); qdisc_destroy(q->qdisc); }
static void tbf_destroy(struct Qdisc *sch) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; del_timer(&q->wd_timer); if (q->P_tab) qdisc_put_rtab(q->P_tab); if (q->R_tab) qdisc_put_rtab(q->R_tab); MOD_DEC_USE_COUNT; }
static void tbf_destroy(struct Qdisc *sch) { struct tbf_sched_data *q = qdisc_priv(sch); qdisc_watchdog_cancel(&q->watchdog); if (q->P_tab) qdisc_put_rtab(q->P_tab); if (q->R_tab) qdisc_put_rtab(q->R_tab); qdisc_destroy(q->qdisc); #if defined(CONFIG_ASF_EGRESS_SHAPER) || defined(CONFIG_ASF_HW_SHAPER) _tbf_del_hook(sch); #endif }
static void tcf_police_destroy(struct tcf_police *p) { unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); struct tcf_common **p1p; for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->tcfc_next) { if (*p1p == &p->common) { write_lock_bh(&police_lock); *p1p = p->tcf_next; write_unlock_bh(&police_lock); gen_kill_estimator(&p->tcf_bstats, &p->tcf_rate_est); if (p->tcfp_R_tab) qdisc_put_rtab(p->tcfp_R_tab); if (p->tcfp_P_tab) qdisc_put_rtab(p->tcfp_P_tab); kfree(p); return; } } BUG_TRAP(0); }
void tcf_police_destroy(struct tcf_police *p) { unsigned h = tcf_police_hash(p->index); struct tcf_police **p1p; for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->next) { if (*p1p == p) { write_lock_bh(&police_lock); *p1p = p->next; write_unlock_bh(&police_lock); #ifdef CONFIG_NET_ESTIMATOR qdisc_kill_estimator(&p->stats); #endif if (p->R_tab) qdisc_put_rtab(p->R_tab); if (p->P_tab) qdisc_put_rtab(p->P_tab); kfree(p); return; } } BUG_TRAP(0); }
static int tbf_init(struct Qdisc* sch, struct rtattr *opt) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; struct rtattr *tb[TCA_TBF_PTAB]; struct tc_tbf_qopt *qopt; MOD_INC_USE_COUNT; if (opt == NULL || rtattr_parse(tb, TCA_TBF_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) || tb[TCA_TBF_PARMS-1] == NULL || RTA_PAYLOAD(tb[TCA_TBF_PARMS-1]) < sizeof(*qopt)) { MOD_DEC_USE_COUNT; return -EINVAL; } qopt = RTA_DATA(tb[TCA_TBF_PARMS-1]); q->R_tab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB-1]); if (q->R_tab == NULL) { MOD_DEC_USE_COUNT; return -EINVAL; } if (qopt->peakrate.rate) { q->P_tab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_PTAB-1]); if (q->P_tab == NULL) { MOD_DEC_USE_COUNT; qdisc_put_rtab(q->R_tab); return -EINVAL; } } PSCHED_GET_TIME(q->t_c); init_timer(&q->wd_timer); q->wd_timer.function = tbf_watchdog; q->wd_timer.data = (unsigned long)sch; q->limit = qopt->limit; q->mtu = qopt->mtu; if (q->mtu == 0) q->mtu = psched_mtu(sch->dev); q->buffer = qopt->buffer; q->tokens = q->buffer; q->ptokens = q->mtu; return 0; }
struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) { unsigned h; struct tcf_police *p; struct rtattr *tb[TCA_POLICE_MAX]; struct tc_police *parm; if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) return NULL; if (tb[TCA_POLICE_TBF-1] == NULL) return NULL; parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { p->refcnt++; return p; } p = kmalloc(sizeof(*p), GFP_KERNEL); if (p == NULL) return NULL; memset(p, 0, sizeof(*p)); p->refcnt = 1; spin_lock_init(&p->lock); p->stats.lock = &p->lock; if (parm->rate.rate) { if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) goto failure; if (parm->peakrate.rate && (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) goto failure; } if (tb[TCA_POLICE_RESULT-1]) p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); #ifdef CONFIG_NET_ESTIMATOR if (tb[TCA_POLICE_AVRATE-1]) p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); #endif p->toks = p->burst = parm->burst; p->mtu = parm->mtu; if (p->mtu == 0) { p->mtu = ~0; if (p->R_tab) p->mtu = 255<<p->R_tab->rate.cell_log; } if (p->P_tab) p->ptoks = L2T_P(p, p->mtu); PSCHED_GET_TIME(p->t_c); p->index = parm->index ? : tcf_police_new_index(); p->action = parm->action; #ifdef CONFIG_NET_ESTIMATOR if (est) qdisc_new_estimator(&p->stats, est); #endif h = tcf_police_hash(p->index); write_lock_bh(&police_lock); p->next = tcf_police_ht[h]; tcf_police_ht[h] = p; write_unlock_bh(&police_lock); return p; failure: if (p->R_tab) qdisc_put_rtab(p->R_tab); kfree(p); return NULL; }
static int tbf_change(struct Qdisc* sch, struct rtattr *opt) { int err = -EINVAL; struct tbf_sched_data *q = qdisc_priv(sch); struct rtattr *tb[TCA_TBF_PTAB]; struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; struct Qdisc *child = NULL; int max_size,n; if (rtattr_parse_nested(tb, TCA_TBF_PTAB, opt) || tb[TCA_TBF_PARMS-1] == NULL || RTA_PAYLOAD(tb[TCA_TBF_PARMS-1]) < sizeof(*qopt)) goto done; qopt = RTA_DATA(tb[TCA_TBF_PARMS-1]); rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB-1]); if (rtab == NULL) goto done; if (qopt->peakrate.rate) { if (qopt->peakrate.rate > qopt->rate.rate) ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB-1]); if (ptab == NULL) goto done; } for (n = 0; n < 256; n++) if (rtab->data[n] > qopt->buffer) break; max_size = (n << qopt->rate.cell_log)-1; if (ptab) { int size; for (n = 0; n < 256; n++) if (ptab->data[n] > qopt->mtu) break; size = (n << qopt->peakrate.cell_log)-1; if (size < max_size) max_size = size; } if (max_size < 0) goto done; if (qopt->limit > 0) { if ((child = tbf_create_dflt_qdisc(sch, qopt->limit)) == NULL) goto done; } sch_tree_lock(sch); if (child) { qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); qdisc_destroy(xchg(&q->qdisc, child)); } q->limit = qopt->limit; q->mtu = qopt->mtu; q->max_size = max_size; q->buffer = qopt->buffer; q->tokens = q->buffer; q->ptokens = q->mtu; rtab = xchg(&q->R_tab, rtab); ptab = xchg(&q->P_tab, ptab); sch_tree_unlock(sch); err = 0; done: if (rtab) qdisc_put_rtab(rtab); if (ptab) qdisc_put_rtab(ptab); return err; }
static int tbf_change(struct Qdisc *sch, struct nlattr *opt) { int err; struct tbf_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_TBF_PTAB + 1]; struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; struct Qdisc *child = NULL; int max_size, n; err = nla_parse_nested(tb, TCA_TBF_PTAB, opt, tbf_policy); if (err < 0) return err; err = -EINVAL; if (tb[TCA_TBF_PARMS] == NULL) goto done; qopt = nla_data(tb[TCA_TBF_PARMS]); rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB]); if (rtab == NULL) goto done; if (qopt->peakrate.rate) { if (qopt->peakrate.rate > qopt->rate.rate) ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB]); if (ptab == NULL) goto done; } for (n = 0; n < 256; n++) if (rtab->data[n] > qopt->buffer) break; max_size = (n << qopt->rate.cell_log) - 1; if (ptab) { int size; for (n = 0; n < 256; n++) if (ptab->data[n] > qopt->mtu) break; size = (n << qopt->peakrate.cell_log) - 1; if (size < max_size) max_size = size; } if (max_size < 0) goto done; if (q->qdisc != &noop_qdisc) { err = fifo_set_limit(q->qdisc, qopt->limit); if (err) goto done; } else if (qopt->limit > 0) { child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit); if (IS_ERR(child)) { err = PTR_ERR(child); goto done; } } sch_tree_lock(sch); if (child) { qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); qdisc_destroy(q->qdisc); q->qdisc = child; } q->limit = qopt->limit; q->mtu = qopt->mtu; q->max_size = max_size; q->buffer = qopt->buffer; q->tokens = q->buffer; q->ptokens = q->mtu; swap(q->R_tab, rtab); swap(q->P_tab, ptab); sch_tree_unlock(sch); err = 0; done: if (rtab) qdisc_put_rtab(rtab); if (ptab) qdisc_put_rtab(ptab); return err; }
static int tbf_change(struct Qdisc *sch, struct nlattr *opt) { int err; struct tbf_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_TBF_MAX + 1]; struct tc_tbf_qopt *qopt; struct Qdisc *child = NULL; struct psched_ratecfg rate; struct psched_ratecfg peak; u64 max_size; s64 buffer, mtu; u64 rate64 = 0, prate64 = 0; err = nla_parse_nested(tb, TCA_TBF_MAX, opt, tbf_policy); if (err < 0) return err; err = -EINVAL; if (tb[TCA_TBF_PARMS] == NULL) goto done; qopt = nla_data(tb[TCA_TBF_PARMS]); if (qopt->rate.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB])); if (qopt->peakrate.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB])); buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U); mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U); if (tb[TCA_TBF_RATE64]) rate64 = nla_get_u64(tb[TCA_TBF_RATE64]); psched_ratecfg_precompute(&rate, &qopt->rate, rate64); max_size = min_t(u64, psched_ns_t2l(&rate, buffer), ~0U); if (qopt->peakrate.rate) { if (tb[TCA_TBF_PRATE64]) prate64 = nla_get_u64(tb[TCA_TBF_PRATE64]); psched_ratecfg_precompute(&peak, &qopt->peakrate, prate64); if (peak.rate_bytes_ps <= rate.rate_bytes_ps) { pr_warn_ratelimited("sch_tbf: peakrate %llu is lower than or equals to rate %llu !\n", peak.rate_bytes_ps, rate.rate_bytes_ps); err = -EINVAL; goto done; } max_size = min_t(u64, max_size, psched_ns_t2l(&peak, mtu)); } if (max_size < psched_mtu(qdisc_dev(sch))) pr_warn_ratelimited("sch_tbf: burst %llu is lower than device %s mtu (%u) !\n", max_size, qdisc_dev(sch)->name, psched_mtu(qdisc_dev(sch))); if (!max_size) { err = -EINVAL; goto done; } if (q->qdisc != &noop_qdisc) { err = fifo_set_limit(q->qdisc, qopt->limit); if (err) goto done; } else if (qopt->limit > 0) { child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit); if (IS_ERR(child)) { err = PTR_ERR(child); goto done; } } sch_tree_lock(sch); if (child) { qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); qdisc_destroy(q->qdisc); q->qdisc = child; } q->limit = qopt->limit; q->mtu = PSCHED_TICKS2NS(qopt->mtu); q->max_size = max_size; q->buffer = PSCHED_TICKS2NS(qopt->buffer); q->tokens = q->buffer; q->ptokens = q->mtu; memcpy(&q->rate, &rate, sizeof(struct psched_ratecfg)); if (qopt->peakrate.rate) { memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg)); q->peak_present = true; } else { q->peak_present = false; } sch_tree_unlock(sch); err = 0; done: return err; }
static int tbf_change(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { int err; struct tbf_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_TBF_MAX + 1]; struct tc_tbf_qopt *qopt; struct Qdisc *child = NULL; struct psched_ratecfg rate; struct psched_ratecfg peak; u64 max_size; s64 buffer, mtu; u64 rate64 = 0, prate64 = 0; err = nla_parse_nested_deprecated(tb, TCA_TBF_MAX, opt, tbf_policy, NULL); if (err < 0) return err; err = -EINVAL; if (tb[TCA_TBF_PARMS] == NULL) goto done; qopt = nla_data(tb[TCA_TBF_PARMS]); if (qopt->rate.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB], NULL)); if (qopt->peakrate.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB], NULL)); buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U); mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U); if (tb[TCA_TBF_RATE64]) rate64 = nla_get_u64(tb[TCA_TBF_RATE64]); psched_ratecfg_precompute(&rate, &qopt->rate, rate64); if (tb[TCA_TBF_BURST]) { max_size = nla_get_u32(tb[TCA_TBF_BURST]); buffer = psched_l2t_ns(&rate, max_size); } else { max_size = min_t(u64, psched_ns_t2l(&rate, buffer), ~0U); } if (qopt->peakrate.rate) { if (tb[TCA_TBF_PRATE64]) prate64 = nla_get_u64(tb[TCA_TBF_PRATE64]); psched_ratecfg_precompute(&peak, &qopt->peakrate, prate64); if (peak.rate_bytes_ps <= rate.rate_bytes_ps) { pr_warn_ratelimited("sch_tbf: peakrate %llu is lower than or equals to rate %llu !\n", peak.rate_bytes_ps, rate.rate_bytes_ps); err = -EINVAL; goto done; } if (tb[TCA_TBF_PBURST]) { u32 pburst = nla_get_u32(tb[TCA_TBF_PBURST]); max_size = min_t(u32, max_size, pburst); mtu = psched_l2t_ns(&peak, pburst); } else { max_size = min_t(u64, max_size, psched_ns_t2l(&peak, mtu)); } } else { memset(&peak, 0, sizeof(peak)); } if (max_size < psched_mtu(qdisc_dev(sch))) pr_warn_ratelimited("sch_tbf: burst %llu is lower than device %s mtu (%u) !\n", max_size, qdisc_dev(sch)->name, psched_mtu(qdisc_dev(sch))); if (!max_size) { err = -EINVAL; goto done; } if (q->qdisc != &noop_qdisc) { err = fifo_set_limit(q->qdisc, qopt->limit); if (err) goto done; } else if (qopt->limit > 0) { child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit, extack); if (IS_ERR(child)) { err = PTR_ERR(child); goto done; } /* child is fifo, no need to check for noop_qdisc */ qdisc_hash_add(child, true); } sch_tree_lock(sch); if (child) { qdisc_tree_flush_backlog(q->qdisc); qdisc_put(q->qdisc); q->qdisc = child; } q->limit = qopt->limit; if (tb[TCA_TBF_PBURST]) q->mtu = mtu; else q->mtu = PSCHED_TICKS2NS(qopt->mtu); q->max_size = max_size; if (tb[TCA_TBF_BURST]) q->buffer = buffer; else q->buffer = PSCHED_TICKS2NS(qopt->buffer); q->tokens = q->buffer; q->ptokens = q->mtu; memcpy(&q->rate, &rate, sizeof(struct psched_ratecfg)); memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg)); sch_tree_unlock(sch); err = 0; done: return err; }
static int tcf_act_police_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, int ovr, int bind) { int ret = 0, err; struct nlattr *tb[TCA_POLICE_MAX + 1]; struct tc_police *parm; struct tcf_police *police; struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; struct tc_action_net *tn = net_generic(net, police_net_id); bool exists = false; int size; if (nla == NULL) return -EINVAL; err = nla_parse_nested(tb, TCA_POLICE_MAX, nla, police_policy, NULL); if (err < 0) return err; if (tb[TCA_POLICE_TBF] == NULL) return -EINVAL; size = nla_len(tb[TCA_POLICE_TBF]); if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat)) return -EINVAL; parm = nla_data(tb[TCA_POLICE_TBF]); exists = tcf_idr_check(tn, parm->index, a, bind); if (exists && bind) return 0; if (!exists) { ret = tcf_idr_create(tn, parm->index, NULL, a, &act_police_ops, bind, false); if (ret) return ret; ret = ACT_P_CREATED; } else { tcf_idr_release(*a, bind); if (!ovr) return -EEXIST; } police = to_police(*a); if (parm->rate.rate) { err = -ENOMEM; R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE], NULL); if (R_tab == NULL) goto failure; if (parm->peakrate.rate) { P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE], NULL); if (P_tab == NULL) goto failure; } } if (est) { err = gen_replace_estimator(&police->tcf_bstats, NULL, &police->tcf_rate_est, &police->tcf_lock, NULL, est); if (err) goto failure; } else if (tb[TCA_POLICE_AVRATE] && (ret == ACT_P_CREATED || !gen_estimator_active(&police->tcf_rate_est))) { err = -EINVAL; goto failure; } spin_lock_bh(&police->tcf_lock); /* No failure allowed after this point */ police->tcfp_mtu = parm->mtu; if (police->tcfp_mtu == 0) { police->tcfp_mtu = ~0; if (R_tab) police->tcfp_mtu = 255 << R_tab->rate.cell_log; } if (R_tab) { police->rate_present = true; psched_ratecfg_precompute(&police->rate, &R_tab->rate, 0); qdisc_put_rtab(R_tab); } else { police->rate_present = false; } if (P_tab) { police->peak_present = true; psched_ratecfg_precompute(&police->peak, &P_tab->rate, 0); qdisc_put_rtab(P_tab); } else { police->peak_present = false; } if (tb[TCA_POLICE_RESULT]) police->tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]); police->tcfp_burst = PSCHED_TICKS2NS(parm->burst); police->tcfp_toks = police->tcfp_burst; if (police->peak_present) { police->tcfp_mtu_ptoks = (s64) psched_l2t_ns(&police->peak, police->tcfp_mtu); police->tcfp_ptoks = police->tcfp_mtu_ptoks; } police->tcf_action = parm->action; if (tb[TCA_POLICE_AVRATE]) police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]); spin_unlock_bh(&police->tcf_lock); if (ret != ACT_P_CREATED) return ret; police->tcfp_t_c = ktime_get_ns(); tcf_idr_insert(tn, *a); return ret; failure: qdisc_put_rtab(P_tab); qdisc_put_rtab(R_tab); if (ret == ACT_P_CREATED) tcf_idr_cleanup(*a, est); return err; }
static int tbf_change(struct Qdisc *sch, struct nlattr *opt) { int err; struct tbf_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_TBF_PTAB + 1]; struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; struct Qdisc *child = NULL; int max_size, n; err = nla_parse_nested(tb, TCA_TBF_PTAB, opt, tbf_policy); if (err < 0) return err; err = -EINVAL; if (tb[TCA_TBF_PARMS] == NULL) goto done; qopt = nla_data(tb[TCA_TBF_PARMS]); rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB]); if (rtab == NULL) goto done; if (qopt->peakrate.rate) { if (qopt->peakrate.rate > qopt->rate.rate) ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB]); if (ptab == NULL) goto done; } for (n = 0; n < 256; n++) if (rtab->data[n] > qopt->buffer) break; max_size = (n << qopt->rate.cell_log) - 1; if (ptab) { int size; for (n = 0; n < 256; n++) if (ptab->data[n] > qopt->mtu) break; size = (n << qopt->peakrate.cell_log) - 1; if (size < max_size) max_size = size; } if (max_size < 0) goto done; if (max_size < psched_mtu(qdisc_dev(sch))) pr_warn_ratelimited("sch_tbf: burst %u is lower than device %s mtu (%u) !\n", max_size, qdisc_dev(sch)->name, psched_mtu(qdisc_dev(sch))); if (q->qdisc != &noop_qdisc) { err = fifo_set_limit(q->qdisc, qopt->limit); if (err) goto done; } else if (qopt->limit > 0) { child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit); if (IS_ERR(child)) { err = PTR_ERR(child); goto done; } } sch_tree_lock(sch); if (child) { qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); qdisc_destroy(q->qdisc); q->qdisc = child; } q->limit = qopt->limit; q->mtu = PSCHED_TICKS2NS(qopt->mtu); q->max_size = max_size; q->buffer = PSCHED_TICKS2NS(qopt->buffer); q->tokens = q->buffer; q->ptokens = q->mtu; psched_ratecfg_precompute(&q->rate, &rtab->rate); if (ptab) { psched_ratecfg_precompute(&q->peak, &ptab->rate); q->peak_present = true; } else { q->peak_present = false; } sch_tree_unlock(sch); err = 0; done: if (rtab) qdisc_put_rtab(rtab); if (ptab) qdisc_put_rtab(ptab); return err; }