最近在调试网卡驱动时一直对/proc/net/dev 文件中各网卡参数是如何得来的有很大的疑问。 insmod 以太网卡驱动后,cat /proc/net/dev 可以看到多了eth0的信息。开始,一直以为是驱动的代码调用某个写/proc文件的函数,从而把eth0的信息写到/proc/net/dev文件里。 可是反复看代码也没有发现相关的函数。今天突然想先拿/proc/interrupt 来分析一下,看了看linux-2.6.28的代码,就有了这篇《Linux内核proc文件系统的冰山一角--源自/proc/net/dev文件中各网卡参数的疑问》。 (一)先分析/proc/interrupts linux-2.6.28/arch/arm/kernel/irq.c --> show_interrupt() 在linux-2.6.28/fs/proc/interrupt.c module_init(proc_interrupts_init); | -->proc_interrupts_init() | --> proc_create("interrupts", 0, NULL, &proc_interrupts_operations); /*参数NULL说明是在/proc 目录下创建 名字为interrupts的文件。 */ 一位伟大的程序员说过 -- "代码就是最好的文档". (黄金必杀句) static const struct file_operations proc_interrupts_operations = { .open = interrupts_open, ... }; static int interrupts_open(struct inode *inode, struct file *filp) { return seq_open(filp, &int_seq_ops); } static const struct seq_operations int_seq_ops = { ... .show = show_interrupts }; linux-2.6.28/arch/arm/kernel/irq.c show_interrupts() { ... for_each_present_cpu(cpu) { sprintf(cpuname, "CPU%d", cpu); seq_printf(p, " %10s", cpuname); } ... seq_printf(p, "%3d: ", i); for_each_present_cpu(cpu) seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-"); seq_printf(p, " %s", action->name); for (action = action->next; action; action = action->next) seq_printf(p, ", %s", action->name); ... } 在这里如果能够想到irq_desc[]这个全局的结构数组, 就都明白了。 下面是一个实际运行 cat /proc/interrupts 的结果 CPU0 8: 2 GPIO-l eth0 11: 0 SC pxa25x_udc 14: 404 SC AC97 22: 43 SC FFUART 25: 0 SC DMA 26: 19388 SC ost0 67: 0 GPIO UCB1400 Err: 0 (二)再来看看/proc/net/dev 直接看代码吧,linux-2.6.28/net/core/dev.c static int __net_init dev_proc_net_init(struct net *net) { ... if (!proc_net_fops_create(net, "dev", S_IRUGO, &dev_seq_fops)) goto out; ... } static int dev_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &dev_seq_ops, sizeof(struct seq_net_private)); } static const struct file_operations dev_seq_fops = { ... .open = dev_seq_open, ... }; static int dev_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &dev_seq_ops, sizeof(struct seq_net_private)); } static const struct seq_operations dev_seq_ops = { ... .next = dev_seq_next, ... .show = dev_seq_show, }; /* * Called from the PROCfs module. This now uses the new arbitrary sized * /proc/net interface to create /proc/net/dev */ static int dev_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_puts(seq, "Inter-| Receive " " | Transmit/n" " face |bytes packets errs drop fifo frame " "compressed multicast|bytes packets errs " "drop fifo colls carrier compressed/n"); else dev_seq_printf_stats(seq, v); return 0; } static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) { struct net_device_stats *stats = dev->get_stats(dev); seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu/n", dev->name, stats->rx_bytes, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors, stats->rx_compressed, stats->multicast, stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors + stats->tx_window_errors + stats->tx_heartbeat_errors, stats->tx_compressed); } void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct net *net = seq_file_net(seq); ++*pos; return v == SEQ_START_TOKEN ? first_net_device(net) : next_net_device((struct net_device *)v); } 下面是一个实际运行 cat /proc/net/dev 的结果 Inter-|Receive Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed lo:16200 185 0 0 0 0 0 0 16200 185 0 0 0 0 0 0 eth0:13817124 13810 0 0 0 0 0 0 3416037 13030 0 0 0 0 0 0 "%6s: %8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu/n", 17个参数完全匹配上了。 这里需要指出的是Linux的网卡设备是由linux的链表管理的,dev_seq_next的作用就不言而喻了。 真是无语了,贴了一堆代码。不过最起码还有点代码,要不然岂不成了无code(哈哈哈,多么天真无邪的笑声)。 认 真想一下,突然醒悟了,“驱动的代码调用某个写/proc文件的函数把eth0的信息写到/proc/net/dev文件”的想法是不正确的,起码没有深 刻的理解Linux下文件的含义。Linux 的vfs 里各文件的读写等操作可以有不同的实现, 而上述的几个/proc 文件都没有write的实现,这就是从驱动的角度来跟踪内核代码没有收获的原因了,因为根本就没有去写/proc/net/dev这个文件,自然找不到向 /proc/net/dev添加eth0内容的函数了。 但是为什么cat /proc/net/dev的内容出现了变化呢?先说个看似不相关的话,魔术师大卫.科波菲尔的“消失自由女神像”是真的把自由女神像移走了吗?当然没 有,但是他给观众show出的景象里自由女神像是不存在的,观众就认为自由女神像消失了。Linux的vfs就魔术师一样,/proc的那些文件的操作函 数很特殊,不需要直接对/proc文件的内容进行写操作来添加内容,就能用充满魔力的show函数来给用户提供信息。
Linux内核proc文件系统的冰山一角--源自对/proc/net/dev文件中各网卡参数的疑问
最新推荐文章于 2022-08-22 10:54:39 发布