Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f62d6b93 authored by Thomas Graf's avatar Thomas Graf Committed by Thomas Graf
Browse files

[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: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
parent a8aaa995
Loading
Loading
Loading
Loading
+84 −89
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@
#define D2PRINTK(format,args...)
#endif

#define GRED_DEF_PRIO (MAX_DPs / 2)

struct gred_sched_data;
struct gred_sched;

@@ -432,59 +434,23 @@ 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;
	struct tc_gred_qopt *ctl;
	struct rtattr *tb[TCA_GRED_STAB];

	if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, 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]);

	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;

	ctl = RTA_DATA(tb[TCA_GRED_PARMS-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])
	if (table->tab[dp] == NULL) {
		table->tab[dp] = kmalloc(sizeof(*q), GFP_KERNEL);
		if (table->tab[dp] == NULL)
			return -ENOMEM;
		memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data)));
	}
	q= table->tab[ctl->DP]; 

	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;
		memset(table->tab[dp], 0, sizeof(*q));
	}

	q = table->tab[dp];
	q->DP = dp;
	q->prio = prio;

	q->DP=ctl->DP;
	q->Wlog = ctl->Wlog;
	q->Plog = ctl->Plog;
	q->limit = ctl->limit;
@@ -502,52 +468,81 @@ static int gred_change(struct Qdisc *sch, struct rtattr *opt)
	q->early=0;

	PSCHED_SET_PASTPERFECT(q->qidlestart);
	memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
	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_MAX];
	int err = -EINVAL, prio = GRED_DEF_PRIO;
	u8 *stab;

	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, opt);

	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)
		goto errout;

	if (gred_rio_mode(table)) {
		gred_disable_wred_mode(table);
		if (gred_wred_mode_check(sch))
			gred_enable_wred_mode(table);
		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;
	}

	if (!table->initd) {
		table->initd=1;
		/* 
        	the first entry also goes into the default until
        	over-written 
		*/
	sch_tree_lock(sch);

	err = gred_change_vq(sch, ctl->DP, ctl, prio, stab);
	if (err < 0)
		goto errout_locked;

	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;
		if (gred_rio_mode(table))
			prio = table->tab[ctl->DP]->prio;

			memset(table->tab[table->def], 0,
			       (sizeof(struct gred_sched_data)));
		err = gred_change_vq(sch, table->def, ctl, prio, stab);
		if (err < 0)
			goto errout_locked;
	}
		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;
	table->initd = 1;

		q->qcount = -1;
		PSCHED_SET_PASTPERFECT(q->qidlestart);
		memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
	if (gred_rio_mode(table)) {
		gred_disable_wred_mode(table);
		if (gred_wred_mode_check(sch))
			gred_enable_wred_mode(table);
	}
	return 0;

	err = 0;

errout_locked:
	sch_tree_unlock(sch);
errout:
	return err;
}

static int gred_init(struct Qdisc *sch, struct rtattr *opt)