summaryrefslogtreecommitdiff
path: root/net/sched/sch_gred.c
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2005-11-05 23:14:15 +0300
committerThomas Graf <tgr@axs.localdomain>2005-11-06 00:02:27 +0300
commitf62d6b936df500247474c13360eb23e1b602bad0 (patch)
tree2517635e3005c5bcdc50d6a0f719d7a5df1815ea /net/sched/sch_gred.c
parenta8aaa9958eea2420e13d5a00c3fae934e0a3889e (diff)
downloadlinux-f62d6b936df500247474c13360eb23e1b602bad0.tar.xz
[PKT_SCHED]: GRED: Use central VQ change procedure
Introduces a function gred_change_vq() acting as a central point to change VQ parameters. Fixes priority inheritance in rio mode when the default DP equals 0. Adds proper locking during changes. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/sched/sch_gred.c')
-rw-r--r--net/sched/sch_gred.c173
1 files changed, 84 insertions, 89 deletions
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index b04b07fcc2cf..ca6cb271493b 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -58,6 +58,8 @@
#define D2PRINTK(format,args...)
#endif
+#define GRED_DEF_PRIO (MAX_DPs / 2)
+
struct gred_sched_data;
struct gred_sched;
@@ -432,77 +434,102 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct rtattr *dps)
return 0;
}
-static int gred_change(struct Qdisc *sch, struct rtattr *opt)
+static inline int gred_change_vq(struct Qdisc *sch, int dp,
+ struct tc_gred_qopt *ctl, int prio, u8 *stab)
{
struct gred_sched *table = qdisc_priv(sch);
struct gred_sched_data *q;
+
+ if (table->tab[dp] == NULL) {
+ table->tab[dp] = kmalloc(sizeof(*q), GFP_KERNEL);
+ if (table->tab[dp] == NULL)
+ return -ENOMEM;
+ memset(table->tab[dp], 0, sizeof(*q));
+ }
+
+ q = table->tab[dp];
+ q->DP = dp;
+ q->prio = prio;
+
+ q->Wlog = ctl->Wlog;
+ q->Plog = ctl->Plog;
+ q->limit = ctl->limit;
+ q->Scell_log = ctl->Scell_log;
+ q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
+ q->Scell_max = (255<<q->Scell_log);
+ q->qth_min = ctl->qth_min<<ctl->Wlog;
+ q->qth_max = ctl->qth_max<<ctl->Wlog;
+ q->qave=0;
+ q->backlog=0;
+ q->qcount = -1;
+ q->other=0;
+ q->forced=0;
+ q->pdrop=0;
+ q->early=0;
+
+ PSCHED_SET_PASTPERFECT(q->qidlestart);
+ memcpy(q->Stab, stab, 256);
+
+ return 0;
+}
+
+static int gred_change(struct Qdisc *sch, struct rtattr *opt)
+{
+ struct gred_sched *table = qdisc_priv(sch);
struct tc_gred_qopt *ctl;
- struct rtattr *tb[TCA_GRED_STAB];
+ struct rtattr *tb[TCA_GRED_MAX];
+ int err = -EINVAL, prio = GRED_DEF_PRIO;
+ u8 *stab;
- if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt))
+ if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_MAX, opt))
return -EINVAL;
if (tb[TCA_GRED_PARMS-1] == NULL && tb[TCA_GRED_STAB-1] == NULL)
- return gred_change_table_def(sch, tb[TCA_GRED_DPS-1]);
+ return gred_change_table_def(sch, opt);
- if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 ||
- RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) ||
- RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256)
- return -EINVAL;
+ if (tb[TCA_GRED_PARMS-1] == NULL ||
+ RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) ||
+ tb[TCA_GRED_STAB-1] == NULL ||
+ RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256)
+ return -EINVAL;
ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]);
+ stab = RTA_DATA(tb[TCA_GRED_STAB-1]);
if (ctl->DP >= table->DPs)
- return -EINVAL;
-
- if (table->tab[ctl->DP] == NULL) {
- table->tab[ctl->DP]=kmalloc(sizeof(struct gred_sched_data),
- GFP_KERNEL);
- if (NULL == table->tab[ctl->DP])
- return -ENOMEM;
- memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data)));
- }
- q= table->tab[ctl->DP];
+ goto errout;
if (gred_rio_mode(table)) {
- if (ctl->prio <=0) {
- if (table->def && table->tab[table->def]) {
- DPRINTK("\nGRED: DP %u does not have a prio"
- "setting default to %d\n",ctl->DP,
- table->tab[table->def]->prio);
- q->prio=table->tab[table->def]->prio;
- } else {
- DPRINTK("\nGRED: DP %u does not have a prio"
- " setting default to 8\n",ctl->DP);
- q->prio=8;
- }
- } else {
- q->prio=ctl->prio;
- }
- } else {
- q->prio=8;
+ if (ctl->prio == 0) {
+ int def_prio = GRED_DEF_PRIO;
+
+ if (table->tab[table->def])
+ def_prio = table->tab[table->def]->prio;
+
+ printk(KERN_DEBUG "GRED: DP %u does not have a prio "
+ "setting default to %d\n", ctl->DP, def_prio);
+
+ prio = def_prio;
+ } else
+ prio = ctl->prio;
}
+ sch_tree_lock(sch);
- q->DP=ctl->DP;
- q->Wlog = ctl->Wlog;
- q->Plog = ctl->Plog;
- q->limit = ctl->limit;
- q->Scell_log = ctl->Scell_log;
- q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
- q->Scell_max = (255<<q->Scell_log);
- q->qth_min = ctl->qth_min<<ctl->Wlog;
- q->qth_max = ctl->qth_max<<ctl->Wlog;
- q->qave=0;
- q->backlog=0;
- q->qcount = -1;
- q->other=0;
- q->forced=0;
- q->pdrop=0;
- q->early=0;
+ err = gred_change_vq(sch, ctl->DP, ctl, prio, stab);
+ if (err < 0)
+ goto errout_locked;
- PSCHED_SET_PASTPERFECT(q->qidlestart);
- memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
+ if (table->tab[table->def] == NULL) {
+ if (gred_rio_mode(table))
+ prio = table->tab[ctl->DP]->prio;
+
+ err = gred_change_vq(sch, table->def, ctl, prio, stab);
+ if (err < 0)
+ goto errout_locked;
+ }
+
+ table->initd = 1;
if (gred_rio_mode(table)) {
gred_disable_wred_mode(table);
@@ -510,44 +537,12 @@ static int gred_change(struct Qdisc *sch, struct rtattr *opt)
gred_enable_wred_mode(table);
}
- if (!table->initd) {
- table->initd=1;
- /*
- the first entry also goes into the default until
- over-written
- */
-
- if (table->tab[table->def] == NULL) {
- table->tab[table->def]=
- kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL);
- if (NULL == table->tab[table->def])
- return -ENOMEM;
-
- memset(table->tab[table->def], 0,
- (sizeof(struct gred_sched_data)));
- }
- q= table->tab[table->def];
- q->DP=table->def;
- q->Wlog = ctl->Wlog;
- q->Plog = ctl->Plog;
- q->limit = ctl->limit;
- q->Scell_log = ctl->Scell_log;
- q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
- q->Scell_max = (255<<q->Scell_log);
- q->qth_min = ctl->qth_min<<ctl->Wlog;
- q->qth_max = ctl->qth_max<<ctl->Wlog;
-
- if (gred_rio_mode(table))
- q->prio=table->tab[ctl->DP]->prio;
- else
- q->prio=8;
-
- q->qcount = -1;
- PSCHED_SET_PASTPERFECT(q->qidlestart);
- memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
- }
- return 0;
+ err = 0;
+errout_locked:
+ sch_tree_unlock(sch);
+errout:
+ return err;
}
static int gred_init(struct Qdisc *sch, struct rtattr *opt)