sch_atm: Convert to use standard list_head facilities.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c1f19b51d1
commit
6accec76f6
|
@ -52,7 +52,7 @@ struct atm_flow_data {
|
||||||
int ref; /* reference count */
|
int ref; /* reference count */
|
||||||
struct gnet_stats_basic_packed bstats;
|
struct gnet_stats_basic_packed bstats;
|
||||||
struct gnet_stats_queue qstats;
|
struct gnet_stats_queue qstats;
|
||||||
struct atm_flow_data *next;
|
struct list_head list;
|
||||||
struct atm_flow_data *excess; /* flow for excess traffic;
|
struct atm_flow_data *excess; /* flow for excess traffic;
|
||||||
NULL to set CLP instead */
|
NULL to set CLP instead */
|
||||||
int hdr_len;
|
int hdr_len;
|
||||||
|
@ -61,34 +61,23 @@ struct atm_flow_data {
|
||||||
|
|
||||||
struct atm_qdisc_data {
|
struct atm_qdisc_data {
|
||||||
struct atm_flow_data link; /* unclassified skbs go here */
|
struct atm_flow_data link; /* unclassified skbs go here */
|
||||||
struct atm_flow_data *flows; /* NB: "link" is also on this
|
struct list_head flows; /* NB: "link" is also on this
|
||||||
list */
|
list */
|
||||||
struct tasklet_struct task; /* dequeue tasklet */
|
struct tasklet_struct task; /* dequeue tasklet */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------------------- Class/flow operations ------------------------- */
|
/* ------------------------- Class/flow operations ------------------------- */
|
||||||
|
|
||||||
static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow)
|
|
||||||
{
|
|
||||||
struct atm_flow_data *walk;
|
|
||||||
|
|
||||||
pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
|
|
||||||
for (walk = qdisc->flows; walk; walk = walk->next)
|
|
||||||
if (walk == flow)
|
|
||||||
return 1;
|
|
||||||
pr_debug("find_flow: not found\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
|
static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
|
||||||
{
|
{
|
||||||
struct atm_qdisc_data *p = qdisc_priv(sch);
|
struct atm_qdisc_data *p = qdisc_priv(sch);
|
||||||
struct atm_flow_data *flow;
|
struct atm_flow_data *flow;
|
||||||
|
|
||||||
for (flow = p->flows; flow; flow = flow->next)
|
list_for_each_entry(flow, &p->flows, list) {
|
||||||
if (flow->classid == classid)
|
if (flow->classid == classid)
|
||||||
break;
|
return flow;
|
||||||
return flow;
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
|
static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
|
||||||
|
@ -99,7 +88,7 @@ static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
|
||||||
|
|
||||||
pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
|
pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
|
||||||
sch, p, flow, new, old);
|
sch, p, flow, new, old);
|
||||||
if (!find_flow(p, flow))
|
if (list_empty(&flow->list))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!new)
|
if (!new)
|
||||||
new = &noop_qdisc;
|
new = &noop_qdisc;
|
||||||
|
@ -146,20 +135,12 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
|
||||||
{
|
{
|
||||||
struct atm_qdisc_data *p = qdisc_priv(sch);
|
struct atm_qdisc_data *p = qdisc_priv(sch);
|
||||||
struct atm_flow_data *flow = (struct atm_flow_data *)cl;
|
struct atm_flow_data *flow = (struct atm_flow_data *)cl;
|
||||||
struct atm_flow_data **prev;
|
|
||||||
|
|
||||||
pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
|
pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
|
||||||
if (--flow->ref)
|
if (--flow->ref)
|
||||||
return;
|
return;
|
||||||
pr_debug("atm_tc_put: destroying\n");
|
pr_debug("atm_tc_put: destroying\n");
|
||||||
for (prev = &p->flows; *prev; prev = &(*prev)->next)
|
list_del_init(&flow->list);
|
||||||
if (*prev == flow)
|
|
||||||
break;
|
|
||||||
if (!*prev) {
|
|
||||||
printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*prev = flow->next;
|
|
||||||
pr_debug("atm_tc_put: qdisc %p\n", flow->q);
|
pr_debug("atm_tc_put: qdisc %p\n", flow->q);
|
||||||
qdisc_destroy(flow->q);
|
qdisc_destroy(flow->q);
|
||||||
tcf_destroy_chain(&flow->filter_list);
|
tcf_destroy_chain(&flow->filter_list);
|
||||||
|
@ -274,7 +255,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (find_flow(p, flow)) {
|
if (!list_empty(&flow->list)) {
|
||||||
error = -EEXIST;
|
error = -EEXIST;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
@ -313,8 +294,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
|
||||||
flow->classid = classid;
|
flow->classid = classid;
|
||||||
flow->ref = 1;
|
flow->ref = 1;
|
||||||
flow->excess = excess;
|
flow->excess = excess;
|
||||||
flow->next = p->link.next;
|
list_add(&flow->list, &p->link.list);
|
||||||
p->link.next = flow;
|
|
||||||
flow->hdr_len = hdr_len;
|
flow->hdr_len = hdr_len;
|
||||||
if (hdr)
|
if (hdr)
|
||||||
memcpy(flow->hdr, hdr, hdr_len);
|
memcpy(flow->hdr, hdr, hdr_len);
|
||||||
|
@ -335,7 +315,7 @@ static int atm_tc_delete(struct Qdisc *sch, unsigned long arg)
|
||||||
struct atm_flow_data *flow = (struct atm_flow_data *)arg;
|
struct atm_flow_data *flow = (struct atm_flow_data *)arg;
|
||||||
|
|
||||||
pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
|
pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
|
||||||
if (!find_flow(qdisc_priv(sch), flow))
|
if (list_empty(&flow->list))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (flow->filter_list || flow == &p->link)
|
if (flow->filter_list || flow == &p->link)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -361,12 +341,12 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
|
||||||
pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
|
pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
|
||||||
if (walker->stop)
|
if (walker->stop)
|
||||||
return;
|
return;
|
||||||
for (flow = p->flows; flow; flow = flow->next) {
|
list_for_each_entry(flow, &p->flows, list) {
|
||||||
if (walker->count >= walker->skip)
|
if (walker->count >= walker->skip &&
|
||||||
if (walker->fn(sch, (unsigned long)flow, walker) < 0) {
|
walker->fn(sch, (unsigned long)flow, walker) < 0) {
|
||||||
walker->stop = 1;
|
walker->stop = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
walker->count++;
|
walker->count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,16 +365,17 @@ static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl)
|
||||||
static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
{
|
{
|
||||||
struct atm_qdisc_data *p = qdisc_priv(sch);
|
struct atm_qdisc_data *p = qdisc_priv(sch);
|
||||||
struct atm_flow_data *flow = NULL; /* @@@ */
|
struct atm_flow_data *flow;
|
||||||
struct tcf_result res;
|
struct tcf_result res;
|
||||||
int result;
|
int result;
|
||||||
int ret = NET_XMIT_POLICED;
|
int ret = NET_XMIT_POLICED;
|
||||||
|
|
||||||
pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
|
pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
|
||||||
result = TC_POLICE_OK; /* be nice to gcc */
|
result = TC_POLICE_OK; /* be nice to gcc */
|
||||||
|
flow = NULL;
|
||||||
if (TC_H_MAJ(skb->priority) != sch->handle ||
|
if (TC_H_MAJ(skb->priority) != sch->handle ||
|
||||||
!(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority)))
|
!(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) {
|
||||||
for (flow = p->flows; flow; flow = flow->next)
|
list_for_each_entry(flow, &p->flows, list) {
|
||||||
if (flow->filter_list) {
|
if (flow->filter_list) {
|
||||||
result = tc_classify_compat(skb,
|
result = tc_classify_compat(skb,
|
||||||
flow->filter_list,
|
flow->filter_list,
|
||||||
|
@ -404,8 +385,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
|
||||||
flow = (struct atm_flow_data *)res.class;
|
flow = (struct atm_flow_data *)res.class;
|
||||||
if (!flow)
|
if (!flow)
|
||||||
flow = lookup_flow(sch, res.classid);
|
flow = lookup_flow(sch, res.classid);
|
||||||
break;
|
goto done;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
flow = NULL;
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
if (!flow)
|
if (!flow)
|
||||||
flow = &p->link;
|
flow = &p->link;
|
||||||
else {
|
else {
|
||||||
|
@ -477,7 +463,9 @@ static void sch_atm_dequeue(unsigned long data)
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
|
pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
|
||||||
for (flow = p->link.next; flow; flow = flow->next)
|
list_for_each_entry(flow, &p->flows, list) {
|
||||||
|
if (flow == &p->link)
|
||||||
|
continue;
|
||||||
/*
|
/*
|
||||||
* If traffic is properly shaped, this won't generate nasty
|
* If traffic is properly shaped, this won't generate nasty
|
||||||
* little bursts. Otherwise, it may ... (but that's okay)
|
* little bursts. Otherwise, it may ... (but that's okay)
|
||||||
|
@ -512,6 +500,7 @@ static void sch_atm_dequeue(unsigned long data)
|
||||||
/* atm.atm_options are already set by atm_tc_enqueue */
|
/* atm.atm_options are already set by atm_tc_enqueue */
|
||||||
flow->vcc->send(flow->vcc, skb);
|
flow->vcc->send(flow->vcc, skb);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
|
static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
|
||||||
|
@ -543,9 +532,10 @@ static unsigned int atm_tc_drop(struct Qdisc *sch)
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
|
||||||
pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
|
pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
|
||||||
for (flow = p->flows; flow; flow = flow->next)
|
list_for_each_entry(flow, &p->flows, list) {
|
||||||
if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
|
if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
|
||||||
return len;
|
return len;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,7 +544,9 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
|
||||||
struct atm_qdisc_data *p = qdisc_priv(sch);
|
struct atm_qdisc_data *p = qdisc_priv(sch);
|
||||||
|
|
||||||
pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
|
pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
|
||||||
p->flows = &p->link;
|
INIT_LIST_HEAD(&p->flows);
|
||||||
|
INIT_LIST_HEAD(&p->link.list);
|
||||||
|
list_add(&p->link.list, &p->flows);
|
||||||
p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
|
p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
|
||||||
&pfifo_qdisc_ops, sch->handle);
|
&pfifo_qdisc_ops, sch->handle);
|
||||||
if (!p->link.q)
|
if (!p->link.q)
|
||||||
|
@ -565,7 +557,6 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
|
||||||
p->link.sock = NULL;
|
p->link.sock = NULL;
|
||||||
p->link.classid = sch->handle;
|
p->link.classid = sch->handle;
|
||||||
p->link.ref = 1;
|
p->link.ref = 1;
|
||||||
p->link.next = NULL;
|
|
||||||
tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);
|
tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +567,7 @@ static void atm_tc_reset(struct Qdisc *sch)
|
||||||
struct atm_flow_data *flow;
|
struct atm_flow_data *flow;
|
||||||
|
|
||||||
pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
|
pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
|
||||||
for (flow = p->flows; flow; flow = flow->next)
|
list_for_each_entry(flow, &p->flows, list)
|
||||||
qdisc_reset(flow->q);
|
qdisc_reset(flow->q);
|
||||||
sch->q.qlen = 0;
|
sch->q.qlen = 0;
|
||||||
}
|
}
|
||||||
|
@ -584,24 +575,17 @@ static void atm_tc_reset(struct Qdisc *sch)
|
||||||
static void atm_tc_destroy(struct Qdisc *sch)
|
static void atm_tc_destroy(struct Qdisc *sch)
|
||||||
{
|
{
|
||||||
struct atm_qdisc_data *p = qdisc_priv(sch);
|
struct atm_qdisc_data *p = qdisc_priv(sch);
|
||||||
struct atm_flow_data *flow;
|
struct atm_flow_data *flow, *tmp;
|
||||||
|
|
||||||
pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
|
pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
|
||||||
for (flow = p->flows; flow; flow = flow->next)
|
list_for_each_entry(flow, &p->flows, list)
|
||||||
tcf_destroy_chain(&flow->filter_list);
|
tcf_destroy_chain(&flow->filter_list);
|
||||||
|
|
||||||
/* races ? */
|
list_for_each_entry_safe(flow, tmp, &p->flows, list) {
|
||||||
while ((flow = p->flows)) {
|
|
||||||
if (flow->ref > 1)
|
if (flow->ref > 1)
|
||||||
printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
|
printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
|
||||||
flow->ref);
|
flow->ref);
|
||||||
atm_tc_put(sch, (unsigned long)flow);
|
atm_tc_put(sch, (unsigned long)flow);
|
||||||
if (p->flows == flow) {
|
|
||||||
printk(KERN_ERR "atm_destroy: putting flow %p didn't "
|
|
||||||
"kill it\n", flow);
|
|
||||||
p->flows = flow->next; /* brute force */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tasklet_kill(&p->task);
|
tasklet_kill(&p->task);
|
||||||
}
|
}
|
||||||
|
@ -615,7 +599,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
|
||||||
|
|
||||||
pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
|
pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
|
||||||
sch, p, flow, skb, tcm);
|
sch, p, flow, skb, tcm);
|
||||||
if (!find_flow(p, flow))
|
if (list_empty(&flow->list))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
tcm->tcm_handle = flow->classid;
|
tcm->tcm_handle = flow->classid;
|
||||||
tcm->tcm_info = flow->q->handle;
|
tcm->tcm_info = flow->q->handle;
|
||||||
|
|
Loading…
Reference in New Issue