日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

利用proc 实现内核和用户态交换数据

發布時間:2024/8/22 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用proc 实现内核和用户态交换数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近寫程序需要內核得到用戶態的參數,比較苦逼幸福的是雖然ioctrl 用不了,可以用proc實現,proc文件系統提供了一種內核和用戶態交互的方法。

proc文件系統的詳細接口看<linux/proc_fs.h>

主要需要關注的是這幾個函數:

struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent); void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

?

函數 proc_mkdir用于在proc文件系統下創建文件夾, proc_mkdir的第一個參數是要創建的目錄的名字,第二個參數是指向父目錄結構的指針。需要注意一下幾點:

1. 創建過程沒有對于名字的檢查,完全可以調用proc_mkdir 創建出一堆同樣名字的文件(檢查一下會死啊!)

2. 其實名字可以包含路徑,例如“dev/new_proc”, 如果存在dev目錄,函數會在dev目錄下創建new_proc目錄。

3. 如果第二個參數是NULL,會在根目錄也就是/proc/目錄下創建目錄

函數的返回值就是 新創建目錄對應的proc_dir_entry, 保存這個就可以用來在此目錄下創建文件啦,其實,即使不保存,利用上面介紹的第二點性質也可以在目錄下創建文件,而且刪除目錄只用知道路徑就可以了~

?

函數create_proc_entry用來創建文件,mode 參數如果為NULL的話默認的文件訪問權限是 755,其他的參數與proc_mkdir 類似

?

函數remove_proc_entry用來刪除創建的目錄或者文件,有意思的是,這個函數只需要知道名字和父目錄就可以刪除了。

?

說了這么多,怎么交換數據尼?

需要了解下proc_dir_entry 的結構了

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; };

其他的參數可以忽略,這里需要注意的是兩個成員變量:

read_proc 和 write_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);

?

對proc文件的讀寫操作,最終將轉化為對read_proc和write_proc的調用。

看到這里明白了吧,只要在內核里注冊proc文件,實現read_proc 和write_proc函數,然后設置proc_dir_entry對應成員變量的值,在用戶態進行讀寫就可以和內核交互了

?

解釋這兩個函數的參數:

對于read_proc_t

1. 第一個參數:為啥叫page?答案就是如果對proc文件調用讀操作,內核會分配一個頁大小的緩沖區。如何輸出大于一個頁的數據呢,這得依賴于第二個和第三個參數了。

為了理解第二三個參數,回憶下與文件操作相關的系統調用:

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);對于proc文件,一次read操作最多只能讀取一個page的數據,如果需要讀取大于一個頁的數據需要保存read的返回值,然后使用lseek設定offset,然后再次調用read。回到參數的說明:

2. start和off參數:off對應于lseek里面的offset(lseek whence為SEEK_END,offset為負 的情況下,傳進來的off為零,具體原因待考古)。

如果不設置*start的值,off的取值只能在[0, count - 1]之間,且能夠讀取的數據大小為:count - off。可以理解系統拷貝了 [page + off, page+count - 1]之間的數據到用戶的buffer里。如果off的取值超出范圍,read將讀不到數據。

如果設置了*start的值,系統認為*start指向的地址就是off指定的地址,off的值會被忽略,系統會拷貝[start, start+count-1]之間的數據到用戶空間。當然我們在實現start地址的定位時,可能會需要off的值。


3. count 參數與read中的count一致


4. eof參數,設置了這個參數表明不想再提供數據了,神馬意思呢?

如果不設置這個參數,對于上面說的start為空的情況,read_proc返回后,系統如果發現 (count - off) < count 會接著下發寫請求,讀取off大小的數據。

例如:有這樣的讀取操作:

lseek(fd, 2, SEEK_SET); read(fd, buff_r, 30)

第一次調用read_proc, off=2, count=30, 由于我們沒有設置start的值,將讀取28字節的數據,由于沒有設置*eof, 系統會再次下發read_proc

第二次調用read_proc, off=30, count=2, 在參數start的說明里提到,對于這個調用,系統默認讀不到數據(怨念啊,為啥要下發)

于是read返回28


如果設置了這個參數就不會有第二次的下發了。


5. data參數,這個是給驅動程序預留的參數。


對于write_proc函數,參數是很簡單的,需要說明的只有一點,就是write_proc的第二個參數buffer是用戶態的地址,需要用copy_from_user從用戶態把數據拷到內核態的緩沖區里。

作者:ziziwu 發表于2011-10-20 14:40:08 原文鏈接 閱讀:7 評論:0 查看評論

轉載于:https://www.cnblogs.com/ziziwu/archive/2011/10/20/2218975.html

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的利用proc 实现内核和用户态交换数据的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。