Linux系統中的核心互動檔案系統:自構proc詳解
proc是Linux系統中一種特殊的檔案系統,它用來提供內核和用戶空間的交互接口,如顯示內核訊息,修改內核參數,控制內核功能等。 proc的優點是簡單易用,不需要額外的設備或驅動。 proc的實作涉及proc_dir_entry結構體,proc_create函數,seq_file機制等概念。在本文中,我們將介紹Linux內核調試技術之自構proc的原理和方法,包括創建和刪除proc文件,讀取和寫入proc文件,使用seq_file機制等,並舉例說明它們的使用方法和注意事項。
1、簡介
#在核心中使用printk可以講調試資訊保存在log_buf緩衝區中,可以使用命令#cat /proc/kmsg 將緩衝區的數區的數資料列印出來,今天我們就來研究一下,自己寫kmsg這個文件,我們取名叫做mymsg。
2、看核心中 /proc/kmsg怎麼寫的!
在Proc_misc.c (fs\proc) 檔案中:
void __init proc_misc_init(void) { ......................... struct proc_dir_entry *entry; //这里创建了一个proc入口kmsg entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); if (entry) /*构造一个proc_fops结构*/ entry->proc_fops = &proc_kmsg_operations; ......................... }
在Kmsg.c (fs\proc) 檔案中:
const struct file_operations proc_kmsg_operations = { .read = kmsg_read, .poll = kmsg_poll, .open = kmsg_open, .release = kmsg_release, };
在使用者空間使用 cat /proc/kmsg的時候,會呼叫kmsg_open,在呼叫kmsg_read函數,讀取log_buf中的數據,並拷貝到使用者空間顯示。
3、在寫之前,我們需要來學習循環佇列
#環形佇列是在實際程式設計極為有用的資料結構,它有以下特點。
它是一個首尾相連的FIFO的資料結構,採用陣列的線性空間,資料組織簡單,很快就能知道佇列是否滿為空。能以很快速度的來存取資料。
因為有簡單且有效率的原因,甚至在硬體都實作了環形佇列。
環形佇列廣泛用於網路資料收發,和不同程式間資料交換(例如核心與應用程式大量交換數據,從硬體接收大量資料)均使用了環形佇列。
3.1.環形佇列實作原理
記憶體上沒有環形的結構,因此環形佇列實在是數組的線性空間來實現。那當數據到了尾部要如何處理呢?它將轉回到0位置來處理。這個的轉回是透過取模操作來執行的。
<code style="display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px">因此环列队列的是逻辑上将数组元素q[0]与q[MAXN-1]连接,形成一个存放队列的环形空间。 为了方便读写,还要用数组下标来指明队列的读写位置。head/tail.其中head指向可以读的位置,tail指向可以写的位置。 </code>

環形佇列的關鍵是判斷佇列為空,還是為滿。當tail追上head時,佇列為滿時,當head追上tail時,佇列為空。但如何知道誰追上誰。還需要一些輔助的手段來判斷.
如何判斷環形隊列為空,為滿有兩種判斷方法。
一.是附加一個標誌位元tag
當head趕上tail,隊列空,則令tag=0,
當tail趕上head,隊列滿,則令tag=1,
二.限制tail趕上head,即隊尾結點與隊首結點之間至少留有一個元素的空間。
佇列空: head==tail
隊列滿: (tail 1)% MAXN ==head

4、程式編寫
#include \#include \#include \#include \#include \#include \#include \#include \#include \#include \#include \#define MYLOG_BUF_LEN 1024 static char mylog_buf[MYLOG_BUF_LEN]; static char tmp_buf[MYLOG_BUF_LEN]; static int mylog_r = 0; static int mylog_w = 0; static int mylog_r_tmp = 0; /*休眠队列初始化*/ static DECLARE_WAIT_QUEUE_HEAD(mymsg_waitq); /* *判断环形队列是否为空 *返回0:表示不空 返回1:表示空 */ static int is_mylog_empty(void) { return (mylog_r == mylog_w); } /* *判断环形队列是否满 *返回0:表示不满 返回1:表示满 */ static int is_mylog_full(void) { return((mylog_w + 1)% MYLOG_BUF_LEN == mylog_r); } /* *在读取的时候,判断环形队列中数据是否为空 *返回0:表示不空 返回1:表示空 */ static int is_mylog_empty_for_read(void) { return (mylog_r_tmp == mylog_w); } /* *往循环队列中存字符 *输入:c字符 单位:1byte *输出:无 */ static void mylog_putc(char c) { if(is_mylog_full()) { /*如果检测到队列已经满了,则丢弃该数据*/ mylog_r= (mylog_r + 1) % MYLOG_BUF_LEN; /*mylog_r_tmp不能大于mylog_r*/ if((mylog_r_tmp + 1)% MYLOG_BUF_LEN == mylog_r) mylog_r_tmp= mylog_r; } mylog_buf[mylog_w]= c; /*当mylog_w=1023的时候 (mylog_w+1) % MYLOG_BUF_LEN =0,回到队列头,实现循环*/ mylog_w= (mylog_w + 1) % MYLOG_BUF_LEN; /* 唤醒等待数据的进程*/ wake_up_interruptible(&mymsg_waitq); } /* *从循环队列中读字符 *输入:*p 单位:1byte *输出:1表示成功 */ static int mylog_getc(char *p) { /*判断数据是否为空*/ if (is_mylog_empty_for_read()) { return 0; } *p = mylog_buf[mylog_r_tmp ]; mylog_r_tmp = (mylog_r_tmp + 1) % MYLOG_BUF_LEN; return 1; } /* *调用myprintk,和printf用法相同 */ int myprintk(const char *fmt, ...) { va_list args; int i; int j; va_start(args, fmt); i= vsnprintf(tmp_buf, INT_MAX, fmt, args); va_end(args); for (j = 0; j return i; } static ssize_t mymsg_read(struct file *file, char __user *buf, size_t count, loff_t*ppos) { int error=0; size_t i=0; char c; /* 把mylog_buf的数据copy_to_user, return*/ /*非阻塞 和 缓冲区为空的时候返回*/ if ((file->f_flags & O_NONBLOCK) && is_mylog_empty()) return -EAGAIN; /*休眠队列wait_event_interruptible(xxx,0)-->休眠*/ error= wait_event_interruptible(mymsg_waitq, !is_mylog_empty_for_read()); /* copy_to_user*/ while (!error && (mylog_getc(&c)) && i if (!error) error= i; /*返回实际读到的个数*/ return error; } static int mymsg_open(struct inode * inode, struct file * file) { mylog_r_tmp= mylog_r; return 0; } const struct file_operations proc_mymsg_operations = { .read= mymsg_read, .open= mymsg_open, }; static int mymsg_init(void) { struct proc_dir_entry *myentry; kmsg myentry= create_proc_entry("mymsg", S_IRUSR, &proc_root); if (myentry) myentry->proc_fops = &proc_mymsg_operations; return 0; } static void mymsg_exit(void) { remove_proc_entry("mymsg", &proc_root); } module_init(mymsg_init); module_exit(mymsg_exit); /*声名到内核空间*/ EXPORT_SYMBOL(myprintk); MODULE_LICENSE("GPL");
5、測試程式
#注意:在上面程式中 使用了 EXPORT_SYMBOL(myprintk);意思是把myprintk可以在整個核心空間使用。
使用方法:①extern int myprintk(const char *fmt, ...);声明 ② myprintk("first_drv_open : %d\n", ++cnt);使用 \#include \#include \#include \#include \#include \#include \#include \#include \#include \#include static struct class *firstdrv_class; static struct class_device *firstdrv_class_dev; volatile unsigned long *gpfcon = NULL; volatile unsigned long *gpfdat = NULL; extern int myprintk(const char *fmt, ...); static int first_drv_open(struct inode *inode, struct file *file) { static int cnt = 0; myprintk("first_drv_open : %d\n", ++cnt); /* 配置GPF4,5,6为输出*/ *gpfcon &= ~((0x3return 0; } static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { int val; static int cnt = 0; myprintk("first_drv_write : %d\n", ++cnt); copy_from_user(&val, buf, count); // copy_to_user(); if (val == 1) { // 点灯 *gpfdat &= ~((1else { // 灭灯 *gpfdat |= (1return 0; } static struct file_operations first_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量*/ .open = first_drv_open, .write = first_drv_write, }; int major; static int first_drv_init(void) { myprintk("first_drv_init\n"); major= register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核 firstdrv_class= class_create(THIS_MODULE, "firstdrv"); firstdrv_class_dev= class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz*/ gpfcon= (volatile unsigned long *)ioremap(0x56000050, 16); gpfdat= gpfcon + 1; return 0; } static void first_drv_exit(void) { unregister_chrdev(major,"first_drv"); // 卸载 class_device_unregister(firstdrv_class_dev); class_destroy(firstdrv_class); iounmap(gpfcon); } module_init(first_drv_init); module_exit(first_drv_exit); MODULE_LICENSE("GPL");
6、在tty中測試效果
# insmod my_msg.ko``# insmod first_drv.ko``# cat /proc/mymsg``mymsg_open mylog_r_ tmp=0``first_drv_init
通过本文,我们了解了Linux内核调试技术之自构proc的原理和方法,它们可以用来实现对内核的调试和控制。我们应该根据实际需求选择合适的方法,并遵循一些基本原则,如使用正确的文件名,使用正确的读写函数,使用正确的seq_file操作等。proc是Linux系统中一种有用而灵活的文件系统,它可以实现对内核的交互和反馈,也可以提升内核的可维护性和可扩展性。希望本文能够对你有所帮助和启发。
以上是Linux系統中的核心互動檔案系統:自構proc詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

介紹 Linux是一個強大的操作系統,由於其靈活性和效率,開發人員,系統管理員和電源用戶都喜歡。但是,經常使用長而復雜的命令可能是乏味的

Linux適用於服務器、開發環境和嵌入式系統。 1.作為服務器操作系統,Linux穩定高效,常用於部署高並發應用。 2.作為開發環境,Linux提供高效的命令行工具和包管理系統,提升開發效率。 3.在嵌入式系統中,Linux輕量且可定制,適合資源有限的環境。

簡介:通過基於Linux的道德黑客攻擊數字邊界 在我們越來越相互聯繫的世界中,網絡安全至關重要。 道德黑客入侵和滲透測試對於主動識別和減輕脆弱性至關重要

Linux基礎學習從零開始的方法包括:1.了解文件系統和命令行界面,2.掌握基本命令如ls、cd、mkdir,3.學習文件操作,如創建和編輯文件,4.探索高級用法如管道和grep命令,5.掌握調試技巧和性能優化,6.通過實踐和探索不斷提陞技能。

Linux在服務器、嵌入式系統和桌面環境中的應用廣泛。 1)在服務器領域,Linux因其穩定性和安全性成為託管網站、數據庫和應用的理想選擇。 2)在嵌入式系統中,Linux因其高度定制性和高效性而受歡迎。 3)在桌面環境中,Linux提供了多種桌面環境,滿足不同用戶需求。

Linux的缺點包括用戶體驗、軟件兼容性、硬件支持和學習曲線。 1.用戶體驗不如Windows或macOS友好,依賴命令行界面。 2.軟件兼容性不如其他系統,缺乏許多商業軟件的原生版本。 3.硬件支持不如Windows全面,可能需要手動編譯驅動程序。 4.學習曲線較陡峭,掌握命令行操作需要時間和耐心。

Linuxisnothardtolearn,butthedifficultydependsonyourbackgroundandgoals.ForthosewithOSexperience,especiallycommand-linefamiliarity,Linuxisaneasytransition.Beginnersmayfaceasteeperlearningcurvebutcanmanagewithproperresources.Linux'sopen-sourcenature,bas

Linux的五個基本組件是:1.內核,管理硬件資源;2.系統庫,提供函數和服務;3.Shell,用戶與系統交互的接口;4.文件系統,存儲和組織數據;5.應用程序,利用系統資源實現功能。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3漢化版
中文版,非常好用

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能