2010年5月28日 星期五

linux kernel read_proc() in procfs

在 ~linux/fs/proc/generic.c 中找 __proc_file_read() 的實作可以看到相關說明:
/*
* How to be a proc read function
* ------------------------------
* Prototype:
* int f(char *buffer, char **start, off_t offset,
* int count, int *peof, void *dat)
*
* Assume that the buffer is "count" bytes in size.
*
裡面有三種讀 read_proc 的方式說明,底下就是說明的程式碼,
也可以搜尋其他 driver使用 read_proc 的範例。
比如 ~linux/drivers/char/efirtc.c。
*/
n = dp->read_proc(page, &start, *ppos,
count, &eof, dp->data);
...
這邊是當 kernel 讀取 proc 檔呼叫 driver read_proc callback 的地方,也就是用法。因此可以倒推回去我們的 callback function 如何實作:

第一種是 driver 要回傳的資料量小於 read_proc 中的 buffer size(PAGE_SIZE)。
此時不管 *start,將 driver 要傳給 filesystem 的資料擺在 buffer 的 offset 位置,我們只看 offset 跟上次 callback 讀到的 buffer size, n 的差值,在接到的 offset 跟剩餘要傳的 n 差值(n - offset) 為零時,告知 filesystem 我們的 driver 已經傳完資料,才設定 *peof = 1; 否則繼續 callback。

第二種是當你有大量資料要傳輸時使用。
將 *start 設定為介於 buffer 跟零 之間的值,資料是從 buffer 起始位址開始填,return 每次要填的資料長度,如果你的資料還沒填完,第二次進入 read_proc 時 offset 值會增加 *start 的長度,直到你填完資料後再設定 *peof = 1; 就可以完成傳輸大量資料了。

第三種跟第一種一樣,只是把 offset 代換成 *start

參考文獻:
  1. procfs-guide.pdf 3.1 Reading data
  2. linux kernel source: ~linux/fs/proc/generic.c, ~linux/drivers/char/efirtc.c
  3. Linux Modules (3) - procfs