什么是proc
linux 操作系統(tǒng)把虛擬地址分為用戶空間和內核空間,內核空間可以通過procfs把內核的數(shù)據(jù)呈現(xiàn)給用戶空間,用戶空間也可以把數(shù)據(jù)寫入到內核從而更改內核的行為,這在驅動中很常見,最終目的就是app就能通過讀寫procfs的文件和內核交互。
procfs是基于內存的文件系統(tǒng),意味著掉電就會丟失,因此只能更改運行的行為和查看運行時的狀態(tài),一般都是用來查看動態(tài)的數(shù)據(jù),大多數(shù)是只讀的,當然這個可以設置。
procfs存在于系統(tǒng)中/proc目錄中,可以通過mount 查看
mount
...
proc on /proc type proc (rw,relatime)
...
常見proc文件
/proc/devices
已經(jīng)注冊了的字符設備和塊設備的住設備號/proc/iomem
系統(tǒng)能感知到的物理地址和總線設備地址,會包含外設的地址/proc/ioports
I/O空間的地址,ARM中沒有IO空間,因此是X86架構使用/proc/interrupts
已經(jīng)注冊了的中斷的信息/proc/softirqs
已經(jīng)注冊了的softirq/proc/swaps
當前有效的swaps/proc/kallsyms
運行時的內核的符號,包括已經(jīng)加載驅動的符號/proc/partitions
當前已經(jīng)連接的塊設備和它們的分區(qū)/proc/partitions
當前內核可以識別的文件系統(tǒng)/proc/cpuinfo
cpu信息
創(chuàng)建proc目錄
使用這個API來創(chuàng)建一個proc目錄:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
- name :在創(chuàng)建目錄的名字
- parent:在哪個目錄下創(chuàng)建目錄,如果傳入NULL,則在/proc下創(chuàng)建
返回一個表示你要創(chuàng)建的目錄的對象proc_dir_entry ,一個proc_dir_entry 表示一個proc目錄或者一個proc文件。
創(chuàng)建一個proc文件
使用這個API來創(chuàng)建一個文件:
static inline struct proc_dir_entry *
proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent,
const struct proc_ops *proc_ops)
- name 要創(chuàng)建文件的名字
- mode :此文件的默認權限
- parent : 要在哪個目錄下創(chuàng)建文件,如果為NULL ,則在/proc下創(chuàng)建
- proc_ops :此文件的操作集合
struct proc_ops類似于設備驅動中的文件操作集合,也就是open /read那些,在這里面實現(xiàn)讀取,控制邏輯。
完整demo
#include < linux/kernel.h >
#include < linux/init.h >
#include < linux/module.h >
#include< linux/proc_fs.h >
static struct proc_dir_entry *parent;
static char etx_array[100] = "justice hello\\n";
static int len =1;
static int open_proc(struct inode *inode, struct file *file)
{
pr_info("proc file opend.....\\t");
return 0;
}
static int release_proc(struct inode *inode, struct file *file)
{
pr_info("proc file released.....\\n");
return 0;
}
static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset)
{
pr_info("proc file read.....\\n");
printk("offset (%d),length (%d)\\n",*offset,length );
if(*offset >= 100)
{
pr_info("file end!\\n");
return 0;
}
if(length > 100 - *offset)
length = 100 - *offset;
*offset += length;
if(copy_to_user(buffer,etx_array,100) )
{
pr_err("Data Send : Err!\\n");
}
pr_info("read end\\n");
return length;
}
static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off)
{
pr_info("proc file wrote.....\\n");
memset(etx_array, 0, 100);
if( copy_from_user(etx_array,buff,len) )
{
pr_err("Data Write : Err!\\n");
}
return len;
}
const struct proc_ops proc_ops = {
.proc_open = open_proc,
.proc_read = read_proc,
.proc_write = write_proc,
.proc_release = release_proc,
};
static int __init procfs_init(void)
{
parent = proc_mkdir("procfs-test", NULL);
if( parent == NULL )
{
pr_info("Error creating proc entry");
return -EINVAL;
}
proc_create("lzy", 0666, parent, &proc_ops);
return 0;
}
static void __exit procfs_exit(void)
{
proc_remove(parent);
}
module_init(procfs_init);
module_exit(procfs_exit);