patch-2.3.48 linux/net/sched/sch_atm.c

Next file: linux/net/sched/sch_cbq.c
Previous file: linux/net/packet/af_packet.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.47/linux/net/sched/sch_atm.c linux/net/sched/sch_atm.c
@@ -6,6 +6,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
+#include <linux/interrupt.h>
 #include <linux/atmdev.h>
 #include <linux/atmclip.h>
 #include <linux/netdevice.h>
@@ -20,7 +21,7 @@
 						   __inline__ in socket.c */
 
 
-#if 1 /* control */
+#if 0 /* control */
 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
 #else
 #define DPRINTK(format,args...)
@@ -64,6 +65,7 @@
 	struct tcf_proto	*filter_list;
 	struct atm_vcc		*vcc;		/* VCC; NULL if VCC is closed */
 	void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* chaining */
+	struct atm_qdisc_data	*parent;	/* parent qdisc */
 	struct socket		*sock;		/* for closing */
 	u32			classid;	/* x:y type ID */
 	int			ref;		/* reference count */
@@ -79,6 +81,7 @@
 	struct atm_flow_data	link;		/* unclassified skbs go here */
 	struct atm_flow_data	*flows;		/* NB: "link" is also on this
 						   list */
+	struct tasklet_struct	task;		/* requeue tasklet */
 };
 
 
@@ -153,6 +156,18 @@
 }
 
 
+static void destroy_filters(struct atm_flow_data *flow)
+{
+	struct tcf_proto *filter;
+
+	while ((filter = flow->filter_list)) {
+		DPRINTK("destroy_filters: destroying filter %p\n",filter);
+		flow->filter_list = filter->next;
+		filter->ops->destroy(filter);
+	}
+}
+
+
 /*
  * atm_tc_put handles all destructions, including the ones that are explicitly
  * requested (atm_tc_destroy, etc.). The assumption here is that we never drop
@@ -164,7 +179,6 @@
 	struct atm_qdisc_data *p = PRIV(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *) cl;
 	struct atm_flow_data **prev;
-	struct tcf_proto *filter;
 
 	DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
 	if (--flow->ref) return;
@@ -178,14 +192,10 @@
 	*prev = flow->next;
 	DPRINTK("atm_tc_put: qdisc %p\n",flow->q);
 	qdisc_destroy(flow->q);
-	while ((filter = flow->filter_list)) {
-		DPRINTK("atm_tc_put: destroying filter %p\n",filter);
-		flow->filter_list = filter->next;
-		DPRINTK("atm_tc_put: filter %p\n",filter);
-		filter->ops->destroy(filter);
-	}
+	destroy_filters(flow);
 	if (flow->sock) {
-		DPRINTK("atm_tc_put: f_count %d\n",file_count(flow->sock->file));
+		DPRINTK("atm_tc_put: f_count %d\n",
+		    file_count(flow->sock->file));
 		flow->vcc->pop = flow->old_pop;
 		sockfd_put(flow->sock);
 	}
@@ -200,8 +210,11 @@
 
 static void sch_atm_pop(struct atm_vcc *vcc,struct sk_buff *skb)
 {
+	struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent;
+
+	D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n",vcc,skb,p);
 	VCC2FLOW(vcc)->old_pop(vcc,skb);
-	mark_bh(NET_BH); /* may allow to send more */
+	tasklet_schedule(&p->task);
 }
 
 
@@ -302,6 +315,7 @@
 	flow->vcc->user_back = flow;
         DPRINTK("atm_tc_change: vcc %p\n",flow->vcc);
 	flow->old_pop = flow->vcc->pop;
+	flow->parent = p;
 	flow->vcc->pop = sch_atm_pop;
 	flow->classid = classid;
 	flow->ref = 1;
@@ -440,21 +454,31 @@
 }
 
 
-static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
+/*
+ * Dequeue packets and send them over ATM. Note that we quite deliberately
+ * avoid checking net_device's flow control here, simply because sch_atm
+ * uses its own channels, which have nothing to do with any CLIP/LANE/or
+ * non-ATM interfaces.
+ */
+
+
+static void sch_atm_dequeue(unsigned long data)
 {
+	struct Qdisc *sch = (struct Qdisc *) data;
 	struct atm_qdisc_data *p = PRIV(sch);
 	struct atm_flow_data *flow;
 	struct sk_buff *skb;
 
-	D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n",sch,p);
+	D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n",sch,p);
 	for (flow = p->link.next; flow; flow = flow->next)
 		/*
 		 * If traffic is properly shaped, this won't generate nasty
-		 * little bursts. Otherwise, it may ... @@@
+		 * little bursts. Otherwise, it may ... (but that's okay)
 		 */
 		while ((skb = flow->q->dequeue(flow->q))) {
 			if (!atm_may_send(flow->vcc,skb->truesize)) {
-				flow->q->ops->requeue(skb,flow->q);
+				if (flow->q->ops->requeue(skb,flow->q))
+					sch->q.qlen--;
 				break;
 			}
 			sch->q.qlen--;
@@ -469,7 +493,7 @@
 				if (!new) continue;
 				skb = new;
 			}
-			D2PRINTK("atm_tc_dequeue: ip %p, data %p\n",
+			D2PRINTK("sch_atm_dequeue: ip %p, data %p\n",
 			    skb->nh.iph,skb->data);
 			ATM_SKB(skb)->vcc = flow->vcc;
 			memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
@@ -479,6 +503,16 @@
 			/* atm.atm_options are already set by atm_tc_enqueue */
 			(void) flow->vcc->dev->ops->send(flow->vcc,skb);
 		}
+}
+
+
+static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
+{
+	struct atm_qdisc_data *p = PRIV(sch);
+	struct sk_buff *skb;
+
+	D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n",sch,p);
+	tasklet_schedule(&p->task);
 	skb = p->link.q->dequeue(p->link.q);
 	if (skb) sch->q.qlen--;
 	return skb;
@@ -530,6 +564,7 @@
 	p->link.classid = sch->handle;
 	p->link.ref = 1;
 	p->link.next = NULL;
+	tasklet_init(&p->task,sch_atm_dequeue,(unsigned long) sch);
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -554,6 +589,7 @@
 	DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n",sch,p);
 	/* races ? */
 	while ((flow = p->flows)) {
+		destroy_filters(flow);
 		if (flow->ref > 1)
 			printk(KERN_ERR "atm_destroy: %p->ref = %d\n",flow,
 			    flow->ref);
@@ -565,6 +601,7 @@
 			break;
 		}
 	}
+	tasklet_kill(&p->task);
 	MOD_DEC_USE_COUNT;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)