/proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux 内核空间和用户空间之间进行通信。在/proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段,但是与普通文件不同的是,这些虚拟文件的内容都是动态创建的。
要在 /proc 文件系统中创建一个虚拟文件,请使用 create_proc_entry
函数。这个函数可以接收一个文件名、一组权限和这个文件在 /proc 文件系统中出现的位置。create_proc_entry
的返回值是一个 proc_dir_entry
指针(或者为 NULL,说明在 create
时发生了错误)。然后就可以使用这个返回的指针来配置这个虚拟文件的其他参数,例如在对该文件执行读操作时应该调用的函数。create_proc_entry
的原型和 proc_dir_entry
结构中的一部分如清单 1 所示。
struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode, struct proc_dir_entry *parent ); struct proc_dir_entry { const char *name; // virtual file name mode_t mode; // mode permissions uid_t uid; // File's user id gid_t gid; // File's group id struct inode_operations *proc_iops; // Inode operations functions struct file_operations *proc_fops; // File operations functions struct proc_dir_entry *parent; // Parent directory ... read_proc_t *read_proc; // /proc read function write_proc_t *write_proc; // /proc write function void *data; // Pointer to private data atomic_t count; // use count ... }; void remove_proc_entry( const char *name, struct proc_dir_entry *parent ); |
稍后我们就可以看到如何使用 read_proc
和 write_proc
命令来插入对这个虚拟文件进行读写的函数。
要从 /proc 中删除一个文件,可以使用 remove_proc_entry
函数。要使用这个函数,我们需要提供文件名字符串,以及这个文件在 /proc 文件系统中的位置(parent)。这个函数原型如清单 7 所示。
parent 参数可以为 NULL(表示 /proc 根目录),也可以是很多其他值,这取决于我们希望将这个文件放到什么地方。表 1 列出了可以使用的其他一些父 proc_dir_entry
,以及它们在这个文件系统中的位置。
proc_dir_entry | 在文件系统中的位置 |
---|---|
proc_root_fs | /proc |
proc_net | /proc/net |
proc_bus | /proc/bus |
proc_root_driver | /proc/driver |
我们可以使用 write_proc
函数向 /proc 中写入一项。这个函数的原型如下:
int mod_write( struct file *filp, const char __user *buff, unsigned long len, void *data ); |
filp
参数实际上是一个打开文件结构(我们可以忽略这个参数)。
buff
参数是传递给您的字符串数据。缓冲区地址实际上是一个用户空间的缓冲区,因此我们不能直接读取它。
len
参数定义了在
buff
中有多少数据要被写入。
data
参数是一个指向私有数据的指针(参见 清单 7)。在这个模块中,我们声明了一个这种类型的函数来处理到达的数据。
我们可以使用 read_proc
函数从一个 /proc 项中读取数据(从内核空间到用户空间)。这个函数的原型如下:
int mod_read( char *page, char **start, off_t off, int count, int *eof, void *data ); |
page
参数是这些数据写入到的位置,其中 count
定义了可以写入的最大字符数。在返回多页数据(通常一页是 4KB)时,我们需要使用 start
和 off
参数。当所有数据全部写入之后,就需要设置 eof
(文件结束参数)。与 write
类似,data
表示的也是私有数据。此处提供的 page
缓冲区在内核空间中。因此,我们可以直接写入,而不用调用 copy_to_user
。