Linux核心proc檔案系統的冰山一角--源自對/proc/net/dev檔案中各網卡參數的疑問

來源:互聯網
上載者:User

最近在調試網卡驅動時一直對/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函數來給使用者提供資訊。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.