利用proc 实现内核和用户态交换数据
最近寫程序需要內(nèi)核得到用戶態(tài)的參數(shù),比較苦逼幸福的是雖然ioctrl 用不了,可以用proc實(shí)現(xiàn),proc文件系統(tǒng)提供了一種內(nèi)核和用戶態(tài)交互的方法。
proc文件系統(tǒng)的詳細(xì)接口看<linux/proc_fs.h>
主要需要關(guān)注的是這幾個(gè)函數(shù):
?
函數(shù) proc_mkdir用于在proc文件系統(tǒng)下創(chuàng)建文件夾, proc_mkdir的第一個(gè)參數(shù)是要?jiǎng)?chuàng)建的目錄的名字,第二個(gè)參數(shù)是指向父目錄結(jié)構(gòu)的指針。需要注意一下幾點(diǎn):
1. 創(chuàng)建過程沒有對(duì)于名字的檢查,完全可以調(diào)用proc_mkdir 創(chuàng)建出一堆同樣名字的文件(檢查一下會(huì)死啊!)
2. 其實(shí)名字可以包含路徑,例如“dev/new_proc”, 如果存在dev目錄,函數(shù)會(huì)在dev目錄下創(chuàng)建new_proc目錄。
3. 如果第二個(gè)參數(shù)是NULL,會(huì)在根目錄也就是/proc/目錄下創(chuàng)建目錄
函數(shù)的返回值就是 新創(chuàng)建目錄對(duì)應(yīng)的proc_dir_entry, 保存這個(gè)就可以用來在此目錄下創(chuàng)建文件啦,其實(shí),即使不保存,利用上面介紹的第二點(diǎn)性質(zhì)也可以在目錄下創(chuàng)建文件,而且刪除目錄只用知道路徑就可以了~
?
函數(shù)create_proc_entry用來創(chuàng)建文件,mode 參數(shù)如果為NULL的話默認(rèn)的文件訪問權(quán)限是 755,其他的參數(shù)與proc_mkdir 類似
?
函數(shù)remove_proc_entry用來刪除創(chuàng)建的目錄或者文件,有意思的是,這個(gè)函數(shù)只需要知道名字和父目錄就可以刪除了。
?
說了這么多,怎么交換數(shù)據(jù)尼?
需要了解下proc_dir_entry 的結(jié)構(gòu)了
struct proc_dir_entry {unsigned int low_ino;unsigned short namelen;const char *name;mode_t mode;nlink_t nlink;uid_t uid;gid_t gid;loff_t size;struct inode_operations * proc_iops;const struct file_operations * proc_fops;get_info_t *get_info;struct module *owner;struct proc_dir_entry *next, *parent, *subdir;void *data;read_proc_t *read_proc;write_proc_t *write_proc;atomic_t count; /* use count */int deleted; /* delete flag */void *set; };其他的參數(shù)可以忽略,這里需要注意的是兩個(gè)成員變量:
read_proc 和 write_proc
這兩個(gè)變量的類型如下:
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);?
對(duì)proc文件的讀寫操作,最終將轉(zhuǎn)化為對(duì)read_proc和write_proc的調(diào)用。
看到這里明白了吧,只要在內(nèi)核里注冊(cè)proc文件,實(shí)現(xiàn)read_proc 和write_proc函數(shù),然后設(shè)置proc_dir_entry對(duì)應(yīng)成員變量的值,在用戶態(tài)進(jìn)行讀寫就可以和內(nèi)核交互了
?
解釋這兩個(gè)函數(shù)的參數(shù):
對(duì)于read_proc_t
1. 第一個(gè)參數(shù):為啥叫page?答案就是如果對(duì)proc文件調(diào)用讀操作,內(nèi)核會(huì)分配一個(gè)頁大小的緩沖區(qū)。如何輸出大于一個(gè)頁的數(shù)據(jù)呢,這得依賴于第二個(gè)和第三個(gè)參數(shù)了。
為了理解第二三個(gè)參數(shù),回憶下與文件操作相關(guān)的系統(tǒng)調(diào)用:
int open(const char *pathname, int flags); off_t lseek(int fildes, off_t offset, int whence); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count);對(duì)于proc文件,一次read操作最多只能讀取一個(gè)page的數(shù)據(jù),如果需要讀取大于一個(gè)頁的數(shù)據(jù)需要保存read的返回值,然后使用lseek設(shè)定offset,然后再次調(diào)用read。回到參數(shù)的說明:2. start和off參數(shù):off對(duì)應(yīng)于lseek里面的offset(lseek whence為SEEK_END,offset為負(fù) 的情況下,傳進(jìn)來的off為零,具體原因待考古)。
如果不設(shè)置*start的值,off的取值只能在[0, count - 1]之間,且能夠讀取的數(shù)據(jù)大小為:count - off。可以理解系統(tǒng)拷貝了 [page + off, page+count - 1]之間的數(shù)據(jù)到用戶的buffer里。如果off的取值超出范圍,read將讀不到數(shù)據(jù)。
如果設(shè)置了*start的值,系統(tǒng)認(rèn)為*start指向的地址就是off指定的地址,off的值會(huì)被忽略,系統(tǒng)會(huì)拷貝[start, start+count-1]之間的數(shù)據(jù)到用戶空間。當(dāng)然我們?cè)趯?shí)現(xiàn)start地址的定位時(shí),可能會(huì)需要off的值。
3. count 參數(shù)與read中的count一致
4. eof參數(shù),設(shè)置了這個(gè)參數(shù)表明不想再提供數(shù)據(jù)了,神馬意思呢?
如果不設(shè)置這個(gè)參數(shù),對(duì)于上面說的start為空的情況,read_proc返回后,系統(tǒng)如果發(fā)現(xiàn) (count - off) < count 會(huì)接著下發(fā)寫請(qǐng)求,讀取off大小的數(shù)據(jù)。
例如:有這樣的讀取操作:
lseek(fd, 2, SEEK_SET); read(fd, buff_r, 30)第一次調(diào)用read_proc, off=2, count=30, 由于我們沒有設(shè)置start的值,將讀取28字節(jié)的數(shù)據(jù),由于沒有設(shè)置*eof, 系統(tǒng)會(huì)再次下發(fā)read_proc
第二次調(diào)用read_proc, off=30, count=2, 在參數(shù)start的說明里提到,對(duì)于這個(gè)調(diào)用,系統(tǒng)默認(rèn)讀不到數(shù)據(jù)(怨念啊,為啥要下發(fā))
于是read返回28
如果設(shè)置了這個(gè)參數(shù)就不會(huì)有第二次的下發(fā)了。
5. data參數(shù),這個(gè)是給驅(qū)動(dòng)程序預(yù)留的參數(shù)。
對(duì)于write_proc函數(shù),參數(shù)是很簡單的,需要說明的只有一點(diǎn),就是write_proc的第二個(gè)參數(shù)buffer是用戶態(tài)的地址,需要用copy_from_user從用戶態(tài)把數(shù)據(jù)拷到內(nèi)核態(tài)的緩沖區(qū)里。
作者:ziziwu 發(fā)表于2011-10-20 14:40:08 原文鏈接 閱讀:7 評(píng)論:0 查看評(píng)論轉(zhuǎn)載于:https://www.cnblogs.com/ziziwu/archive/2011/10/20/2218975.html
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的利用proc 实现内核和用户态交换数据的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 平台服务器测试3—接口测试工具实现
- 下一篇: Android UI开发第二篇——多级