色偷偷偷久久伊人大杳蕉,色爽交视频免费观看,欧美扒开腿做爽爽爽a片,欧美孕交alscan巨交xxx,日日碰狠狠躁久久躁蜜桃

x
x

linux系統(tǒng)(vfs)支持的 特殊文件系統(tǒng)----proc文件系統(tǒng)

發(fā)布時(shí)間:2009-12-15 13:43    發(fā)布者:linux_Ultra
關(guān)鍵詞: linux , proc , vfs , 文件系統(tǒng)
導(dǎo)言:本文作者M. Tim Jones,不但是一名具有相當(dāng)實(shí)戰(zhàn)經(jīng)驗(yàn)的軟件開發(fā)工程師,而且,我們經(jīng)常地,在IBM的技術(shù)網(wǎng)站上可以看到他撰寫的簡(jiǎn)明扼要文章,實(shí)用且易懂,轉(zhuǎn)載在此。-----------------------------------------------------使用 /proc 文件系統(tǒng)來(lái)訪問 Linux 內(nèi)核的內(nèi)容這個(gè)虛擬文件系統(tǒng)在內(nèi)核空間和用戶空間之間打開了一個(gè)通信窗口


級(jí)別: 初級(jí)
M. Tim Jones ([email=mtj@mtjones.com?subject=%E4%BD%BF%E7%94%A8%20/proc%20%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E6%9D%A5%E8%AE%BF%E9%97%AE%20Linux%20%E5%86%85%E6%A0%B8%E7%9A%84%E5%86%85%E5%AE%B9&cc=tomyoung@us.ibm.com]mtj@mtjones.com[/email]), 資深首席軟件工程師, Emulex

2006 年 4 月 24 日
/proc文件系統(tǒng)是一個(gè)虛擬文件系統(tǒng),通過它可以使用一種新的方法在 Linux® 內(nèi)核空間和用戶空間之間進(jìn)行通信。在 /proc文件系統(tǒng)中,我們可以將對(duì)虛擬文件的讀寫作為與內(nèi)核中實(shí)體進(jìn)行通信的一種手段,但是與普通文件不同的是,這些虛擬文件的內(nèi)容都是動(dòng)態(tài)創(chuàng)建的。本文對(duì)/proc 虛擬文件系統(tǒng)進(jìn)行了介紹,并展示了它的用法。
最初開發(fā) /proc 文件系統(tǒng)是為了提供有關(guān)系統(tǒng)中進(jìn)程的信息。但是由于這個(gè)文件系統(tǒng)非常有用,因此內(nèi)核中的很多元素也開始使用它來(lái)報(bào)告信息,或啟用動(dòng)態(tài)運(yùn)行時(shí)配置。
/proc 文件系統(tǒng)包含了一些目錄(用作組織信息的方式)和虛擬文件。虛擬文件可以向用戶呈現(xiàn)內(nèi)核中的一些信息,也可以用作一種從用戶空間向內(nèi)核發(fā)送信息的手段。實(shí)際上我們并不會(huì)同時(shí)需要實(shí)現(xiàn)這兩點(diǎn),但是本文將向您展示如何配置這個(gè)文件系統(tǒng)進(jìn)行輸入和輸出。
盡管像本文這樣短小的一篇文章無(wú)法詳細(xì)介紹 /proc 的所有用法,但是它依然對(duì)這兩種用法進(jìn)行了展示,從而可以讓我們體會(huì)一下 /proc是多么強(qiáng)大。清單 1 是對(duì) /proc 中部分元素進(jìn)行一次交互查詢的結(jié)果。它顯示的是 /proc文件系統(tǒng)的根目錄中的內(nèi)容。注意,在左邊是一系列數(shù)字編號(hào)的文件。每個(gè)實(shí)際上都是一個(gè)目錄,表示系統(tǒng)中的一個(gè)進(jìn)程。由于在 GNU/Linux中創(chuàng)建的第一個(gè)進(jìn)程是 init 進(jìn)程,因此它的 process-id1。然后對(duì)這個(gè)目錄執(zhí)行一個(gè) ls 命令,這會(huì)顯示很多文件。每個(gè)文件都提供了有關(guān)這個(gè)特殊進(jìn)程的詳細(xì)信息。例如,要查看 init 的 command-line 項(xiàng)的內(nèi)容,只需對(duì) cmdline 文件執(zhí)行 cat 命令。
/proc 中另外一些有趣的文件有:cpuinfo,它標(biāo)識(shí)了處理器的類型和速度;pci,顯示在 PCI 總線上找到的設(shè)備;modules,標(biāo)識(shí)了當(dāng)前加載到內(nèi)核中的模塊。

清單 1. 對(duì) /proc 的交互過程
        
[root@plato]#
ls /proc
1     2040  2347  2874  474          fb           mdstat      sys
104   2061  2356  2930  9            filesystems  meminfo     sysrq-trigger
113   2073  2375  2933  acpi         fs           misc        sysvipc
1375  21    2409  2934  buddyinfo    ide          modules     tty
1395  2189  2445  2935  bus          interrupts   mounts      uptime
1706  2201  2514  2938  cmdline      iomem        mtrr        version
179   2211  2515  2947  cpuinfo      ioports      net         vmstat
180   2223  2607  3     crypto       irq          partitions
181   2278  2608  3004  devices      kallsyms     pci
182   2291  2609  3008  diskstats    kcore        self
2     2301  263   3056  dma          kmsg         slabinfo
2015  2311  2805  394   driver       loadavg      stat
2019  2337  2821  4     execdomains  locks        swaps
[root@plato 1]#
ls /proc/1
auxv     cwd      exe  loginuid  mem     oom_adj    root  statm   task
cmdline  environ  fd   maps      mounts  oom_score  stat  status  wchan
[root@plato]#
cat /proc/1/cmdline
init [5]
[root@plato]#

清單 2 展示了對(duì) /proc 中的一個(gè)虛擬文件進(jìn)行讀寫的過程。這個(gè)例子首先檢查內(nèi)核的 TCP/IP 棧中的 IP 轉(zhuǎn)發(fā)的目前設(shè)置,然后再啟用這種功能。

清單 2. 對(duì) /proc 進(jìn)行讀寫(配置內(nèi)核)
        
[root@plato]#
cat /proc/sys/net/ipv4/ip_forward
0
[root@plato]#
echo "1" > /proc/sys/net/ipv4/ip_forward
[root@plato]#
cat /proc/sys/net/ipv4/ip_forward
1
[root@plato]#

另外,我們還可以使用 sysctl 來(lái)配置這些內(nèi)核條目。有關(guān)這個(gè)問題的更多信息,請(qǐng)參閱 參考資料 一節(jié)的內(nèi)容。
順便說一下,/proc 文件系統(tǒng)并不是 GNU/Linux 系統(tǒng)中的惟一一個(gè)虛擬文件系統(tǒng)。在這種系統(tǒng)上,sysfs 是一個(gè)與 /proc 類似的文件系統(tǒng),但是它的組織更好(從 /proc 中學(xué)習(xí)了很多教訓(xùn))。不過 /proc 已經(jīng)確立了自己的地位,因此即使 sysfs 與 /proc 相比有一些優(yōu)點(diǎn),/proc 也依然會(huì)存在。還有一個(gè) debugfs 文件系統(tǒng),不過(顧名思義)它提供的更多是調(diào)試接口。debugfs 的一個(gè)優(yōu)點(diǎn)是它將一個(gè)值導(dǎo)出給用戶空間非常簡(jiǎn)單(實(shí)際上這不過是一個(gè)調(diào)用而已)。
內(nèi)核模塊簡(jiǎn)介
可加載內(nèi)核模塊(LKM)是用來(lái)展示 /proc 文件系統(tǒng)的一種簡(jiǎn)單方法,這是因?yàn)檫@是一種用來(lái)動(dòng)態(tài)地向 Linux 內(nèi)核添加或刪除代碼的新方法。LKM 也是 Linux 內(nèi)核中為設(shè)備驅(qū)動(dòng)程序和文件系統(tǒng)使用的一種流行機(jī)制。
如果您曾經(jīng)重新編譯過 Linux內(nèi)核,就可能會(huì)發(fā)現(xiàn)在內(nèi)核的配置過程中,有很多設(shè)備驅(qū)動(dòng)程序和其他內(nèi)核元素都被編譯成了模塊。如果一個(gè)驅(qū)動(dòng)程序被直接編譯到了內(nèi)核中,那么即使這個(gè)驅(qū)動(dòng)程序沒有運(yùn)行,它的代碼和靜態(tài)數(shù)據(jù)也會(huì)占據(jù)一部分空間。但是如果這個(gè)驅(qū)動(dòng)程序被編譯成一個(gè)模塊,就只有在需要內(nèi)存并將其加載到內(nèi)核時(shí)才會(huì)真正占用內(nèi)存空間。有趣的是,對(duì)于 LKM來(lái)說,我們不會(huì)注意到有什么性能方面的差異,因此這對(duì)于創(chuàng)建一個(gè)適應(yīng)于自己環(huán)境的內(nèi)核來(lái)說是一種功能強(qiáng)大的手段,這樣可以根據(jù)可用硬件和連接的設(shè)備來(lái)加載對(duì)應(yīng)的模塊。
下面是一個(gè)簡(jiǎn)單的 LKM,可以幫助您理解它與在 Linux 內(nèi)核中看到的標(biāo)準(zhǔn)(非動(dòng)態(tài)可加載的)代碼之間的區(qū)別。清單 3 給出了一個(gè)最簡(jiǎn)單的 LKM。(可以從本文的 下載 一節(jié)中下載這個(gè)代碼)。
清單 3 包括了必須的模塊頭(它定義了模塊的 API、類型和宏)。然后使用 MODULE_LICENSE 定義了這個(gè)模塊使用的許可證。此處,我們定義的是 GPL,從而防止會(huì)污染到內(nèi)核。
清單 3 然后又定義了這個(gè)模塊的 initcleanup 函數(shù)。my_module_init 函數(shù)是在加載這個(gè)模塊時(shí)被調(diào)用的,它用來(lái)進(jìn)行一些初始化方面的工作。my_module_cleanup 函數(shù)是在卸載這個(gè)模塊時(shí)被調(diào)用的,它用來(lái)釋放內(nèi)存并清除這個(gè)模塊的蹤跡。注意此處 printk 的用法:這是內(nèi)核的 printf 函數(shù)。KERN_INFO 符號(hào)是一個(gè)字符串,可以用來(lái)對(duì)進(jìn)入內(nèi)核回環(huán)緩沖區(qū)的信息進(jìn)行過濾(非常類似于 syslog)。
最后,清單 3 使用 module_initmodule_exit 宏聲明了入口函數(shù)和出口函數(shù)。這樣我們就可以按照自己的意愿來(lái)對(duì)這個(gè)模塊的 initcleanup 函數(shù)進(jìn)行命名了,不過我們最終要告訴內(nèi)核維護(hù)函數(shù)就是這些函數(shù)。

清單 3. 一個(gè)簡(jiǎn)單的但可以正常工作的 LKM(simple-lkm.c)
        
#include
/* Defines the license for this LKM */
MODULE_LICENSE("GPL");
/* Init function called on module entry */
int my_module_init( void )
{
  printk(KERN_INFO "my_module_init called.  Module is now loaded.\n");
  return 0;
}
/* Cleanup function called on module exit */
void my_module_cleanup( void )
{
  printk(KERN_INFO "my_module_cleanup called.  Module is now unloaded.\n");
  return;
}
/* Declare entry and exit functions */
module_init( my_module_init );
module_exit( my_module_cleanup );

清單 3 盡管非常簡(jiǎn)單,但它卻是一個(gè)真正的 LKM,F(xiàn)在讓我們對(duì)其進(jìn)行編譯并在一個(gè) 2.6 版本的內(nèi)核上進(jìn)行測(cè)試。2.6 版本的內(nèi)核為內(nèi)核模塊的編譯引入了一種新方法,我發(fā)現(xiàn)這種方法比原來(lái)的方法簡(jiǎn)單了很多。對(duì)于文件 simple-lkm.c,我們可以創(chuàng)建一個(gè) makefile,其惟一內(nèi)容如下:
obj-m += simple-lkm.o

要編譯 LKM,請(qǐng)使用 make 命令,如清單 4 所示。

清單 4. 編譯 LKM
        
[root@plato]#
make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules
make: Entering directory `/usr/src/linux-2.6.11'
  CC [M]  /root/projects/misc/module2.6/simple/simple-lkm.o
  Building modules, stage 2.
  MODPOST
  CC      /root/projects/misc/module2.6/simple/simple-lkm.mod.o
  LD [M]  /root/projects/misc/module2.6/simple/simple-lkm.ko
make: Leaving directory `/usr/src/linux-2.6.11'
[root@plato]#

結(jié)果會(huì)生成一個(gè) simple-lkm.ko 文件。這個(gè)新的命名約定可以幫助將這些內(nèi)核對(duì)象(LKM)與標(biāo)準(zhǔn)對(duì)象區(qū)分開來(lái),F(xiàn)在可以加載或卸載這個(gè)模塊了,然后可以查看它的輸出。要加載這個(gè)模塊,請(qǐng)使用insmod 命令;反之,要卸載這個(gè)模塊,請(qǐng)使用 rmmod 命令。lsmod 可以顯示當(dāng)前加載的 LKM(參見清單 5)。
本文地址:http://m.54549.cn/thread-6539-1-1.html     【打印本頁(yè)】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
linux_Ultra 發(fā)表于 2009-12-15 13:44:37
清單 5. 插入、檢查和刪除 LKM

        
[root@plato]# insmod simple-lkm.ko
[root@plato]# lsmod
Module                  Size  Used by
simple_lkm              1536  0
autofs4                26244  0
video                  13956  0
button                  5264  0
battery                 7684  0
ac                      3716  0
yenta_socket           18952  3
rsrc_nonstatic          9472  1 yenta_socket
uhci_hcd               32144  0
i2c_piix4               7824  0
dm_mod                 56468  3
[root@plato]# rmmod simple-lkm
[root@plato]#


注意,內(nèi)核的輸出進(jìn)到了內(nèi)核回環(huán)緩沖區(qū)中,而不是打印到 stdout 上,這是因?yàn)?stdout 是進(jìn)程特有的環(huán)境。要查看內(nèi)核回環(huán)緩沖區(qū)中的消息,可以使用 dmesg 工具(或者通過 /proc 本身使用 cat /proc/kmsg 命令)。清單 6 給出了 dmesg 顯示的最后幾條消息。

清單 6. 查看來(lái)自 LKM 的內(nèi)核輸出

        
[root@plato]# dmesg | tail -5
cs: IO port probe 0xa00-0xaff: clean.
eth0: Link is down
eth0: Link is up, running at 100Mbit half-duplex
my_module_init called.  Module is now loaded.
my_module_cleanup called.  Module is now unloaded.
[root@plato]#


可以在內(nèi)核輸出中看到這個(gè)模塊的消息,F(xiàn)在讓我們暫時(shí)離開這個(gè)簡(jiǎn)單的例子,來(lái)看幾個(gè)可以用來(lái)開發(fā)有用 LKM 的內(nèi)核 API。






集成到 /proc 文件系統(tǒng)中

內(nèi)核程序員可以使用的標(biāo)準(zhǔn) API,LKM 程序員也可以使用。LKM 甚至可以導(dǎo)出內(nèi)核使用的新變量和函數(shù)。有關(guān) API 的完整介紹已經(jīng)超出了本文的范圍,因此我們?cè)谶@里只是簡(jiǎn)單地介紹后面在展示一個(gè)更有用的 LKM 時(shí)所使用的幾個(gè)元素。

創(chuàng)建并刪除 /proc 項(xiàng)

要在 /proc 文件系統(tǒng)中創(chuàng)建一個(gè)虛擬文件,請(qǐng)使用 create_proc_entry 函數(shù)。這個(gè)函數(shù)可以接收一個(gè)文件名、一組權(quán)限和這個(gè)文件在 /proc 文件系統(tǒng)中出現(xiàn)的位置。create_proc_entry 的返回值是一個(gè)proc_dir_entry 指針(或者為 NULL,說明在 create 時(shí)發(fā)生了錯(cuò)誤)。然后就可以使用這個(gè)返回的指針來(lái)配置這個(gè)虛擬文件的其他參數(shù),例如在對(duì)該文件執(zhí)行讀操作時(shí)應(yīng)該調(diào)用的函數(shù)。create_proc_entry的原型和 proc_dir_entry 結(jié)構(gòu)中的一部分如清單 7 所示。

清單 7. 用來(lái)管理 /proc 文件系統(tǒng)項(xiàng)的元素

        
struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode,
                                             struct proc_dir_entry *parent );
struct proc_dir_entry {
        const char *name;                        // virtual file name
        mode_t mode;                                // mode permissions
        uid_t uid;                                // File's user id
        gid_t gid;                                // File's group id
        struct inode_operations *proc_iops;        // Inode operations functions
        struct file_operations *proc_fops;        // File operations functions
        struct proc_dir_entry *parent;                // Parent directory
        ...
        read_proc_t *read_proc;                        // /proc read function
        write_proc_t *write_proc;                // /proc write function
        void *data;                                // Pointer to private data
        atomic_t count;                                // use count
        ...
};
void remove_proc_entry( const char *name, struct proc_dir_entry *parent );


稍后我們就可以看到如何使用 read_proc 和 write_proc 命令來(lái)插入對(duì)這個(gè)虛擬文件進(jìn)行讀寫的函數(shù)。

要從 /proc 中刪除一個(gè)文件,可以使用 remove_proc_entry 函數(shù)。要使用這個(gè)函數(shù),我們需要提供文件名字符串,以及這個(gè)文件在 /proc 文件系統(tǒng)中的位置(parent)。這個(gè)函數(shù)原型如清單 7 所示。

parent 參數(shù)可以為 NULL(表示 /proc 根目錄),也可以是很多其他值,這取決于我們希望將這個(gè)文件放到什么地方。表 1 列出了可以使用的其他一些父 proc_dir_entry,以及它們?cè)谶@個(gè)文件系統(tǒng)中的位置。

表 1. proc_dir_entry 快捷變量
proc_dir_entry        在文件系統(tǒng)中的位置
proc_root_fs        /proc
proc_net        /proc/net
proc_bus        /proc/bus
proc_root_driver        /proc/driver

回調(diào)函數(shù)

我們可以使用 write_proc 函數(shù)向 /proc 中寫入一項(xiàng)。這個(gè)函數(shù)的原型如下:

int mod_write( struct file *filp, const char __user *buff,
               unsigned long len, void *data );


filp 參數(shù)實(shí)際上是一個(gè)打開文件結(jié)構(gòu)(我們可以忽略這個(gè)參數(shù))。buff 參數(shù)是傳遞給您的字符串?dāng)?shù)據(jù)。緩沖區(qū)地址實(shí)際上是一個(gè)用戶空間的緩沖區(qū),因此我們不能直接讀取它。len 參數(shù)定義了在 buff 中有多少數(shù)據(jù)要被寫入。data 參數(shù)是一個(gè)指向私有數(shù)據(jù)的指針(參見 清單 7)。在這個(gè)模塊中,我們聲明了一個(gè)這種類型的函數(shù)來(lái)處理到達(dá)的數(shù)據(jù)。

Linux 提供了一組 API 來(lái)在用戶空間和內(nèi)核空間之間移動(dòng)數(shù)據(jù)。對(duì)于 write_proc 的情況來(lái)說,我們使用了 copy_from_user 函數(shù)來(lái)維護(hù)用戶空間的數(shù)據(jù)。

讀回調(diào)函數(shù)

我們可以使用 read_proc 函數(shù)從一個(gè) /proc 項(xiàng)中讀取數(shù)據(jù)(從內(nèi)核空間到用戶空間)。這個(gè)函數(shù)的原型如下:

int mod_read( char *page, char **start, off_t off,
              int count, int *eof, void *data );


page 參數(shù)是這些數(shù)據(jù)寫入到的位置,其中 count 定義了可以寫入的最大字符數(shù)。在返回多頁(yè)數(shù)據(jù)(通常一頁(yè)是 4KB)時(shí),我們需要使用 start 和 off 參數(shù)。當(dāng)所有數(shù)據(jù)全部寫入之后,就需要設(shè)置 eof(文件結(jié)束參數(shù))。與 write 類似,data 表示的也是私有數(shù)據(jù)。此處提供的 page 緩沖區(qū)在內(nèi)核空間中。因此,我們可以直接寫入,而不用調(diào)用 copy_to_user。

其他有用的函數(shù)

我們還可以使用 proc_mkdir、symlinks 以及 proc_symlink 在 /proc 文件系統(tǒng)中創(chuàng)建目錄。對(duì)于只需要一個(gè) read 函數(shù)的簡(jiǎn)單 /proc 項(xiàng)來(lái)說,可以使用 create_proc_read_entry,這會(huì)創(chuàng)建一個(gè) /proc 項(xiàng),并在一個(gè)調(diào)用中對(duì) read_proc 函數(shù)進(jìn)行初始化。這些函數(shù)的原型如清單 8 所示。

清單 8. 其他有用的 /proc 函數(shù)

        
/* Create a directory in the proc filesystem */
struct proc_dir_entry *proc_mkdir( const char *name,
                                     struct proc_dir_entry *parent );
/* Create a symlink in the proc filesystem */
struct proc_dir_entry *proc_symlink( const char *name,
                                       struct proc_dir_entry *parent,
                                       const char *dest );
/* Create a proc_dir_entry with a read_proc_t in one call */
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 );
/* Copy buffer to user-space from kernel-space */
unsigned long copy_to_user( void __user *to,
                              const void *from,
                              unsigned long n );
/* Copy buffer to kernel-space from user-space */
unsigned long copy_from_user( void *to,
                                const void __user *from,
                                unsigned long n );
/* Allocate a 'virtually' contiguous block of memory */
void *vmalloc( unsigned long size );
/* Free a vmalloc'd block of memory */
void vfree( void *addr );
/* Export a symbol to the kernel (make it visible to the kernel) */
EXPORT_SYMBOL( symbol );
/* Export all symbols in a file to the kernel (declare before module.h) */
EXPORT_SYMTAB






        回頁(yè)首


通過 /proc 文件系統(tǒng)實(shí)現(xiàn)財(cái)富分發(fā)

下面是一個(gè)可以支持讀寫的 LKM。這個(gè)簡(jiǎn)單的程序提供了一個(gè)財(cái)富甜點(diǎn)分發(fā)。在加載這個(gè)模塊之后,用戶就可以使用 echo 命令向其中導(dǎo)入文本財(cái)富,然后再使用 cat 命令逐一讀出。

清單 9 給出了基本的模塊函數(shù)和變量。init 函數(shù)(init_fortune_module)負(fù)責(zé)使用 vmalloc 來(lái)為這個(gè)點(diǎn)心罐分配空間,然后使用 memset 將其全部清零。使用所分配并已經(jīng)清空的 cookie_pot 內(nèi)存,我們?cè)?/proc 中創(chuàng)建了一個(gè) proc_dir_entry 項(xiàng),并將其稱為 fortune。當(dāng) proc_entry 成功創(chuàng)建之后,對(duì)自己的本地變量和 proc_entry 結(jié)構(gòu)進(jìn)行了初始化。我們加載了 /proc read 和 write 函數(shù)(如清單 9 和清單 10 所示),并確定這個(gè)模塊的所有者。cleanup 函數(shù)簡(jiǎn)單地從 /proc 文件系統(tǒng)中刪除這一項(xiàng),然后釋放 cookie_pot 所占據(jù)的內(nèi)存。

cookie_pot 是一個(gè)固定大。4KB)的頁(yè),它使用兩個(gè)索引進(jìn)行管理。第一個(gè)是 cookie_index,標(biāo)識(shí)了要將下一個(gè) cookie 寫到哪里去。變量 next_fortune 標(biāo)識(shí)了下一個(gè) cookie 應(yīng)該從哪里讀取以便進(jìn)行輸出。在所有的 fortune 項(xiàng)都讀取之后,我們簡(jiǎn)單地回到了 next_fortune。

清單 9. 模塊的 init/cleanup 和變量

        
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");
#define MAX_COOKIE_LENGTH       PAGE_SIZE
static struct proc_dir_entry *proc_entry;
static char *cookie_pot;  // Space for fortune strings
static int cookie_index;  // Index to write next fortune
static int next_fortune;  // Index to read next fortune
int init_fortune_module( void )
{
  int ret = 0;
  cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );
  if (!cookie_pot) {
    ret = -ENOMEM;
  } else {
    memset( cookie_pot, 0, MAX_COOKIE_LENGTH );
    proc_entry = create_proc_entry( "fortune", 0644, NULL );
    if (proc_entry == NULL) {
      ret = -ENOMEM;
      vfree(cookie_pot);
      printk(KERN_INFO "fortune: Couldn't create proc entry\n");
    } else {
      cookie_index = 0;
      next_fortune = 0;
      proc_entry->read_proc = fortune_read;
      proc_entry->write_proc = fortune_write;
      proc_entry->owner = THIS_MODULE;
      printk(KERN_INFO "fortune: Module loaded.\n");
    }
  }
  return ret;
}
void cleanup_fortune_module( void )
{
  remove_proc_entry("fortune", &proc_root);
  vfree(cookie_pot);
  printk(KERN_INFO "fortune: Module unloaded.\n");
}
module_init( init_fortune_module );
module_exit( cleanup_fortune_module );


向這個(gè)罐中新寫入一個(gè) cookie 非常簡(jiǎn)單(如清單 10 所示)。使用這個(gè)寫入 cookie 的長(zhǎng)度,我們可以檢查是否有這么多空間可用。如果沒有,就返回 -ENOSPC,它會(huì)返回給用戶空間。否則,就說明空間存在,我們使用 copy_from_user 將用戶緩沖區(qū)中的數(shù)據(jù)直接拷貝到 cookie_pot 中。然后增大 cookie_index(基于用戶緩沖區(qū)的長(zhǎng)度)并使用 NULL 來(lái)結(jié)束這個(gè)字符串。最后,返回實(shí)際寫入 cookie_pot的字符的個(gè)數(shù),它會(huì)返回到用戶進(jìn)程。

清單 10. 對(duì) fortune 進(jìn)行寫入操作所使用的函數(shù)

        
ssize_t fortune_write( struct file *filp, const char __user *buff,
                        unsigned long len, void *data )
{
  int space_available = (MAX_COOKIE_LENGTH-cookie_index)+1;
  if (len > space_available) {
    printk(KERN_INFO "fortune: cookie pot is full!\n");
    return -ENOSPC;
  }
  if (copy_from_user( &cookie_pot[cookie_index], buff, len )) {
    return -EFAULT;
  }
  cookie_index += len;
  cookie_pot[cookie_index-1] = 0;
  return len;
}


對(duì) fortune 進(jìn)行讀取也非常簡(jiǎn)單,如清單 11 所示。由于我們剛才寫入數(shù)據(jù)的緩沖區(qū)(page)已經(jīng)在內(nèi)核空間中了,因此可以直接對(duì)其進(jìn)行操作,并使用 sprintf 來(lái)寫入下一個(gè) fortune。如果next_fortune 索引大于 cookie_index(要寫入的下一個(gè)位置),那么我們就將 next_fortune 返回為 0,這是第一個(gè) fortune 的索引。在將這個(gè) fortune 寫入用戶緩沖區(qū)之后,在 next_fortune 索引上增加剛才寫入的 fortune 的長(zhǎng)度。這樣就變成了下一個(gè)可用 fortune 的索引。這個(gè) fortune 的長(zhǎng)度會(huì)被返回并傳遞給用戶。

清單 11. 對(duì) fortune 進(jìn)行讀取操作所使用的函數(shù)

        
int fortune_read( char *page, char **start, off_t off,
                   int count, int *eof, void *data )
{
  int len;
  if (off > 0) {
    *eof = 1;
    return 0;
  }
  /* Wrap-around */
  if (next_fortune >= cookie_index) next_fortune = 0;
  len = sprintf(page, "%s\n", &cookie_pot[next_fortune]);
  next_fortune += len;
  return len;
}


從這個(gè)簡(jiǎn)單的例子中,我們可以看出通過 /proc 文件系統(tǒng)與內(nèi)核進(jìn)行通信實(shí)際上是件非常簡(jiǎn)單的事情,F(xiàn)在讓我們來(lái)看一下這個(gè) fortune 模塊的用法(參見清單 12)。

清單 12. 展示 fortune cookie LKM 的用法

        
[root@plato]# insmod fortune.ko
[root@plato]# echo "Success is an individual proposition.  Thomas Watson" > /proc/fortune
[root@plato]# echo "If a man does his best, what else is there?  Gen. Patton" > /proc/fortune
[root@plato]# echo "Cats: All your base are belong to us.  Zero Wing" > /proc/fortune
[root@plato]# cat /proc/fortune
Success is an individual proposition.  Thomas Watson
[root@plato]# cat /proc/fortune
If a man does his best, what else is there?  General Patton
[root@plato]#


/proc 虛擬文件系統(tǒng)可以廣泛地用來(lái)報(bào)告內(nèi)核的信息,也可以用來(lái)進(jìn)行動(dòng)態(tài)配置。我們會(huì)發(fā)現(xiàn)它對(duì)于驅(qū)動(dòng)程序和模塊編程來(lái)說都是非常完整的。在下面的 參考資料 中,我們可以學(xué)習(xí)到更多相關(guān)知識(shí)。
geyingzhen 發(fā)表于 2009-12-15 15:24:09
我有個(gè)問題請(qǐng)教,當(dāng)用insmod 加載完驅(qū)動(dòng)后為什么用lsmod顯示不出,是文件系統(tǒng)不健全嗎?如果是在文件系統(tǒng)中應(yīng)該怎樣設(shè)置?謝謝!
您需要登錄后才可以發(fā)表評(píng)論 登錄 | 立即注冊(cè)

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號(hào) | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表