在 Linux 系統中,/proc 檔案系統十分有用,它被用於核心向用戶匯出資訊。/proc 檔案系統是一個虛擬檔案系統,通過它可以使用一種新的方法在 Linux 核心空間和使用者空間之間進行通訊。在/proc 檔案系統中,我們可以將對虛擬檔案的讀寫作為與核心中實體進行通訊的一種手段,與普通檔案不同的是,這些虛擬檔案的內容都是動態建立的。Linux 系統的許多命令本身都是通過分析/proc 下的檔案來完成,如 ps、top、uptime 和 free等。
在 Linux 裝置驅動程式中,驅動工程師自定義/proc 節點以向外界傳遞資訊的方法還是比較常見的。

下列函式用於建立/proc 目錄:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
下列函式建立/proc 節點:
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,struct proc_dir_entry *parent);
struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base, read_proc_t *read_proc, void * data);
結合 create_proc_entry()和 proc_mkdir(),可用於先在/proc 下建立一個目錄,而後在該目錄下建立一個檔案。
可用如下函式刪除/proc 節點:
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
上述函式各返回值的 proc_dir_entry 結構體中包含了/proc 節點的讀函式指標(read_proc_t*read_proc)、寫函式指標(write_proc_t *write_proc)以及父節點、子節點資訊等。/proc 節點的讀寫函式的型別分別為:
typedef int (read_proc_t)(char *page, char **start, off_t off,int count, int *eof, void *data);
typedef int (write_proc_t)(struct file *file, const char __user *buffer,unsigned long count, void *data);
這兩函式需要我們來實現。
讀函式中 page 指標指向用於寫入資料的緩衝區,start 用於返回實際的資料寫到記憶體頁的位置,eof 是用於返回讀結束標誌,offset 是讀的偏移,count 是要讀的資料長度。start 引數比較複雜,對於/proc 只包含簡單資料的情況,通常不需要在讀函式中設定*start,意味著核心將認為資料儲存在記憶體頁偏移 0 的地方。如果將*start 設定為非 0 值,意味著核心將認為*start 指向的資料是 offset 偏移處的資料。寫函式與 file_operations 中的 write()成員類似,需要一次從使用者緩衝區到記憶體空間的複製過程。
下面給一個示例,該示例只是簡單的在/proc目錄下建立一個資料夾和檔案,使用者可以在使用者態向該檔案寫入檔案,並讀出檔案內容。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

#define USER_ROOT_DIR   "slndir"
#define USER_ENTRY      "slnfile"

struct proc_dir_entry    *root_dir, *entry;
char                    kbuff[1024];

static int proc_write(struct file *filep, const char __user *buffer,
        unsigned long len, void *data)
{
    if (copy_from_user(kbuff, buffer, len)) {
        return -1;
    }

    kbuff[len] = '\0';
    return len;
}

static int proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
    int     len;

    len = sprintf(page, "%s", kbuff);

    return len;
}

static int __init sln_init(void)
{
    printk("Hello, %s\n", __func__);

    root_dir = proc_mkdir(USER_ROOT_DIR, NULL);
    if (NULL == root_dir) {
        printk("proc_mkdir create dir %s failed!\n", USER_ROOT_DIR);
        return -1;
    }

    entry = create_proc_entry(USER_ENTRY, 0666, root_dir);
    if (NULL == entry) {
        printk("create_proc_entry create entry %s failed\n", USER_ENTRY);
        goto err;
    }

    entry->read_proc = proc_read;
    entry->write_proc = proc_write;
    return 0;

err:
    remove_proc_entry(USER_ROOT_DIR, NULL);
    return -1;
}

static void __exit sln_exit(void)
{
    printk("Bye, %s\n", __func__);

    remove_proc_entry(USER_ENTRY, root_dir);
    remove_proc_entry(USER_ROOT_DIR, NULL);
}

module_init(sln_init);
module_exit(sln_exit);

MODULE_LICENSE("GPL");


.