传输的开启和关闭
出口队列的状态是由net_device->state中的标识__LINK_STATE_XOFF表示。其值可以通过定义在include/linux/device.h中的下列函数操作和检查
netif_state_queue:开启设备的传输,当设备启动时通常就会调用此函数,此外,如果必须重启已停止的设备,也可以再次调用。
netif_stop_queue: 关闭设备的传输,任何企图在设备上传输信息的尝试都会被拒绝。
netif_stop_stopped:返回出口队列的状态
只有设备驱动程序可以开启和关闭设备的传输。
设备停止和启动队列的原因,1,设备可以暂时用尽其内存,使得传输失败。当设备上有足够内存时,程序会调用netif_start_queue。
net_tx_action:
1,当设备的传输功能通过netif_wake_queue开启时,在这种情况下,此函数要确保当所有必需条件都吻合时,等待被传送的帧实际上都被传送出去。
2,当传输已完成而且设备驱动程序通过dev_kfree_skb_irq通知相关联的缓冲区可释放时,在这种情况下,此函数要收回那些已成功传输的缓冲区的sk_buff结构。第二项任务的原因如下,当来自设备驱动程序的程序在中断环境下运行时,就必须尽快执行。释放一个缓冲区会耗时间,所以会受到拖延,而要求net_tx_action软中断予以负责。设备驱动程序不使用dev_kfree_skb,而是使用dev_kfree_skb_irq。dev_kfree_skb_irq只会把要被释放的缓冲区的指针添加到与CPU相关联的softnet_data结构的completion_queue列表中,然后让net_tx_action稍后去做实际工作。
1: static void net_tx_action(struct softirq_action *h)
2: {
3: struct softnet_data *sd = &__get_cpu_var(softnet_data);
4:
5: if (sd->completion_queue) {
6: struct sk_buff *clist;
7:
8: local_irq_disable();
9: clist = sd->completion_queue;
10: sd->completion_queue = NULL;
11: local_irq_enable();
12:
13: while (clist) {
14: struct sk_buff *skb = clist;
15: clist = clist->next;
16:
17: WARN_ON(atomic_read(&skb->users));
18: trace_kfree_skb(skb, net_tx_action);
19: __kfree_skb(skb);
20: }
21: }
22:
23: if (sd->output_queue) {
24: struct Qdisc *head;
25:
26: local_irq_disable();
27: head = sd->output_queue;
28: sd->output_queue = NULL;
29: sd->output_queue_tailp = &sd->output_queue;
30: local_irq_enable();
31:
32: while (head) {
33: struct Qdisc *q = head;
34: spinlock_t *root_lock;
35:
36: head = head->next_sched;
37:
38: root_lock = qdisc_lock(q);
39: if (spin_trylock(root_lock)) {
40: smp_mb__before_clear_bit();
41: clear_bit(__QDISC_STATE_SCHED,
42: &q->state);
43: qdisc_run(q);
44: spin_unlock(root_lock);
45: } else {
46: if (!test_bit(__QDISC_STATE_DEACTIVATED,
47: &q->state)) {
48: __netif_reschedule(q);
49: } else {
50: smp_mb__before_clear_bit();
51: clear_bit(__QDISC_STATE_SCHED,
52: &q->state);
53: }
54: }
55: }
56: }
57: }
函数的前一半任务就是完成对skb的内存释放。关闭中断后,在局部变量中,取下待释放的内存指针,然后开中断,然后遍历,释放内存。