使用proc文件系統(tǒng)
在Linux系統(tǒng)中, “/proc”文件系統(tǒng)十分有用, 它被內(nèi)核用于向用戶導(dǎo)出信息。 “/proc”文件系統(tǒng)是一個(gè)虛擬文件系統(tǒng), 通過(guò)它可以在Linux內(nèi)核空間和用戶空間之間進(jìn)行通信。 在/proc文件系統(tǒng)中, 我們可以將對(duì)虛擬文件的讀寫作為與內(nèi)核中實(shí)體進(jìn)行通信的一種手段, 與普通文件不同的是, 這些虛擬文件的內(nèi)容都是動(dòng)態(tài)創(chuàng)建的。
“/proc”下的絕大多數(shù)文件是只讀的, 以顯示內(nèi)核信息為主。 但是“/proc”下的文件也并不是完全只讀的, 若節(jié)點(diǎn)可寫, 還可用于一定的控制或配置目的, 例如前面介紹的寫/proc/sys/kernel/printk可以改變printk() 的打印級(jí)別。
Linux系統(tǒng)的許多命令本身都是通過(guò)分析“/proc”下的文件來(lái)完成的, 如ps、 top、 uptime和free等。 例如, free命令通過(guò)分析/proc/meminfo文件得到可用內(nèi)存信息, 下面顯示了對(duì)應(yīng)的meminfo文件和free命令的結(jié)果。
1.meminfo文件
2. free命令
3、創(chuàng)建 /proc 節(jié)點(diǎn)
- struct proc_dir_entry
內(nèi)核使用
proc_dir_entry 結(jié)構(gòu)體來(lái)描述
/proc 文件系統(tǒng)中的一個(gè)目錄或者文件節(jié)點(diǎn)
/* 進(jìn)程目錄項(xiàng)結(jié)構(gòu)體 /
struct proc_dir_entry {
unsigned int low_ino; / 低位 inode 編號(hào) /
umode_t mode; / 文件訪問(wèn)權(quán)限 /
nlink_t nlink; / 鏈接計(jì)數(shù) /
kuid_t uid; / 用戶 ID /
kgid_t gid; / 組 ID /
loff_t size; / 文件大小 */
const struct inode_operations proc_iops; / inode 操作函數(shù)集指針 */
const struct file_operations proc_fops; / 文件操作函數(shù)集指針 */
struct proc_dir_entry *next, *parent, subdir; / 目錄項(xiàng)指針 */
void data; / 自定義數(shù)據(jù)指針 /
atomic_t count; / 使用計(jì)數(shù) /
atomic_t in_use; / 調(diào)用模塊的進(jìn)程數(shù);負(fù)數(shù)表示正在卸載 */
struct completion pde_unload_completion; / 卸載完成信號(hào)量指針 /
struct list_head pde_openers; / 打開(kāi)文件的進(jìn)程鏈表頭 /
spinlock_t pde_unload_lock; / 卸載鎖 /
u8 namelen; / 名稱長(zhǎng)度 /
char name[]; / 名稱 */
};
- proc_create
內(nèi)核提供了一套
API用于在
proc 文件系統(tǒng)中創(chuàng)建 文件節(jié)點(diǎn)
/目錄:
static struct proc_dir_entry *proc_create( const char *name, umode_t mode,
struct proc_dir_entry *parent,
const struct file_operations *proc_fops);
@ name: 節(jié)點(diǎn)名
@ mode: 權(quán)限位
@ parent:父目錄
@ proc_fops: 文件操作結(jié)構(gòu)體
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
@ name: 目錄名
@ parent:父目錄
- remove_proc_entry()
內(nèi)核提供
remove_proc_entry 來(lái)移除
proc 文件系統(tǒng)中的 文件
/目錄 項(xiàng):
void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
@ name: 文件/目錄 名
@ parent:父目錄
4、使用 file_operations 實(shí)現(xiàn) proc 文件讀寫 導(dǎo)向內(nèi)核信息
在調(diào)用 proc_create() 創(chuàng)建文件項(xiàng)時(shí), 提供了一個(gè) file_operations結(jié)構(gòu)體, 實(shí)現(xiàn)里面的read, write方法即可實(shí)現(xiàn)proc 文件讀寫,demo 程序如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/stat.h>
#include <linux/proc_fs.h>
MODULE_LICENSE("GPL");
#define LOG_TAG "my_test1: "
static char my_buf[256];
//====================================================================================
static ssize_t my_proc_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
{
int len = strlen(my_buf);
pr_info(LOG_TAG "enter %s()\n", __func__);
if( 0 == *pos ) {
strncpy(buf, my_buf, sizeof(my_buf));
*pos += len;
return len;
} else
return 0;
}
static ssize_t my_proc_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
int len = size < sizeof(my_buf) ? size : sizeof(my_buf);
pr_info(LOG_TAG "enter %s()\n", __func__);
if( 0 == *pos) {
memset(my_buf, '\0', sizeof(my_buf));
len = copy_from_user(my_buf, buf, len);
*pos += len;
my_buf[len - 1] = '\0';
return size;
}else
return 0;
}
static struct file_operations my_file_ops = {
.owner = THIS_MODULE,
.read = my_proc_read,
.write = my_proc_write,
};
//====================================================================================
static int __init my_module_init(void)
{
struct proc_dir_entry * my_proc_node = NULL;
pr_info(LOG_TAG "enter %s()\n", __func__);
my_proc_node = proc_create("my_test1", S_IRUGO | S_IWUGO, NULL, &my_file_ops);
if( NULL == my_proc_node ) {
pr_err(LOG_TAG "creat /proc/my_test1 failed\n");
remove_proc_entry("my_test1", NULL);
return -1;
}
pr_info(LOG_TAG "creat /proc/my_test1 success\n");
return 0;
}
static void __exit my_module_exit(void)
{
pr_info(LOG_TAG "enter %s()\n", __func__);
pr_info(LOG_TAG "remove /proc/my_test1\n");
remove_proc_entry("my_test1", NULL);
}
module_init(my_module_init);
module_exit(my_module_exit);
5、使用 seq_file 實(shí)現(xiàn) proc 文件的讀取
seq_file只是在普通的文件read中加入了內(nèi)核緩沖的功能,從而實(shí)現(xiàn)順序多次遍歷,讀取大數(shù)據(jù)量的簡(jiǎn)單接口。內(nèi)核使用 seq_file 結(jié)構(gòu)體來(lái)描述seq_file:
/* 序列文件結(jié)構(gòu)體 */
struct seq_file {
char buf; / 緩沖區(qū)指針 /
size_t size; / 緩沖區(qū)大小 /
size_t from; / 開(kāi)始位置 /
size_t count; / 計(jì)數(shù)器 /
loff_t index; / 索引 /
loff_t read_pos; / 讀取位置 /
u64 version; / 版本號(hào) /
struct mutex lock; / 互斥鎖 */
const struct seq_operations op; / 序列操作函數(shù)集指針 /
int poll_event; / poll() 事件 */
#ifdef CONFIG_USER_NS
struct user_namespace user_ns; / 用戶命名空間 */
#endifvoid private; / 私有數(shù)據(jù)指針 */
};
seq_file一般只提供只讀接口,在使用seq_read時(shí),主要靠下述四個(gè)操作來(lái)完成內(nèi)核自定義緩沖區(qū)的遍歷的輸出操作,其中pos作為遍歷的iterator,在seq_read函數(shù)中被多次使用,用以定位當(dāng)前從內(nèi)核自定義鏈表(不止是鏈表, 還可以是哈希表, 數(shù)組, 紅黑樹)中讀取的當(dāng)前位置,當(dāng)多次讀取時(shí),pos非常重要,且pos總是遵循從0,1,2…end+1遍歷的次序,其即必須作為遍歷內(nèi)核自定義鏈表的下標(biāo),也可以作為返回內(nèi)容的標(biāo)識(shí)。但是我在使用中僅僅將其作為返回內(nèi)容的標(biāo)示,并沒(méi)有將其作為遍歷鏈表的下標(biāo),從而導(dǎo)致返回?cái)?shù)據(jù)量大時(shí)造成莫名奇妙的錯(cuò)誤,注意:start返回的void*v如果非0,被show輸出后,在作為參數(shù)傳遞給next函數(shù),next可以對(duì)其修改,也可以忽略;當(dāng)next或者start返回NULL時(shí),在seq_open中控制路徑到達(dá)seq_end。
struct seq_operations {
void * (*start) (struct seq_file *m, loff_t *pos);
void (*stop) (struct seq_file *m, void *v);
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
};
在讀取 proc file 時(shí):文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-793349.html
- 如果只有一條記錄, 調(diào)用過(guò)程是:
start->show->stop,
start->stop. - 如果有多條記錄并且能通過(guò)緩沖區(qū)一次傳第完, 調(diào)用過(guò)程是,繼續(xù)
start->show->next->show->next-> … ->nex->show->stop,
start->stop . - 如果有多條記錄, 比且不能一次通過(guò)緩沖區(qū)傳送完成, 調(diào)用過(guò)程是:
start->show->next->show->…->show->stop,
start->show->next->show->…->show->stop, … , start->stop.
seq_file 的緩沖區(qū)通常為1K, 但是會(huì)動(dòng)態(tài)增長(zhǎng)以便能容納至少一條記錄(當(dāng)單條記錄的大小大于1頁(yè)的時(shí)候,這個(gè)就很有用), 通常, 應(yīng)該在start中進(jìn)行必要的加鎖, 在stop中進(jìn)行必要的解鎖一邊避免竟態(tài)。
當(dāng)使用seq_read時(shí), 需要實(shí)現(xiàn)seq_operations, 并且將file和seq_file關(guān)聯(lián)起來(lái)(通常在open操作中進(jìn)行), 同時(shí), seq_file也提供了游離的 seq_lseek, seq_release用于支持llseek和release操作。
使用seq_file 的demo如下:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-793349.html
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/stat.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#define LOG_TAG "my_test2: "
MODULE_LICENSE("GPL");
static char my_buf[][32] = { {"i am the 0th record"}, //buf[0]
{"i am the 1th record"}, //buf[1]
{"i am the 2th record"}, //buf[2]
{"i am the 3th record"}, //buf[3]
{"i am the 4th record"}, //buf[4]
};
//==========================================================================
static void* my_seq_start (struct seq_file *m, loff_t *pos)
{
pr_info(LOG_TAG "enter %s()\n", __func__);
if( *pos < 0 || *pos > 4 /*my_buf[][32] index*/) {
pr_err(LOG_TAG "invalid pos %ld\n", (long)*pos);
return NULL;
}else
return my_buf[*pos];
}
static void my_seq_stop (struct seq_file *m, void *v)
{
pr_info(LOG_TAG "enter %s()\n", __func__);
pr_info(LOG_TAG "do nothing\n");
}
static void* my_seq_next (struct seq_file *m, void *v, loff_t *pos)
{
pr_info(LOG_TAG "enter %s()\n", __func__);
if( ++(*pos) < 0 || *pos > 4 /*my_buf[][32] index*/) {
pr_info(LOG_TAG "end\n");
return NULL;
}else
return my_buf[*pos];
}
static int my_seq_show (struct seq_file *m, void *v)
{
seq_printf(m, "%s\n", (char*)v);
return 0;
}
static struct seq_operations my_seq_ops = {
.start = my_seq_start,
.stop = my_seq_stop,
.next = my_seq_next,
.show = my_seq_show,
};
//==========================================================================
static int my_proc_open(struct inode * inode , struct file * file)
{
return seq_open(file, &my_seq_ops );
}
static struct file_operations my_file_ops = {
.owner = THIS_MODULE,
.open = my_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
//==========================================================================
static int __init my_module_init(void)
{
struct proc_dir_entry * my_proc_node = NULL;
pr_info(LOG_TAG "enter %s()\n", __func__);
my_proc_node = proc_create("my_test2", S_IRUGO, NULL, &my_file_ops);
if( NULL == my_proc_node ) {
pr_err(LOG_TAG "creat /proc/my_test2 failed\n");
remove_proc_entry("my_test2", NULL);
return -1;
}
pr_info(LOG_TAG "creat /proc/my_test2 success\n");
return 0;
}
static void __exit my_module_exit(void)
{
pr_info(LOG_TAG "enter %s()\n", __func__);
pr_info(LOG_TAG "remove /proc/my_test2\n");
remove_proc_entry("my_test2", NULL);
}
module_init(my_module_init);
module_exit(my_module_exit);
到了這里,關(guān)于開(kāi)發(fā)中proc文件系統(tǒng)的簡(jiǎn)單使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!