proc
文件系统,是一个处于内存中的文件系统,它用于显示当前进程的状态信息,如:进程处于的状态,文件打开描述符,ps
程序就是基于此设计出来的。另外,它还可以用于显示当前系统运行的状态如CPU
信息,内存信息,中断信息,网络流量等等。通过它可以配置当前系统所运行的一些参数,一般来说,一个文件只有一个数值,这些值的含义可能如下(Linux 2.6.24版):
1.限制缓存的大小
2.开启或关闭某些功能
3.某些内核参数
但是在/proc/sysfs/文件夹下面的文件却不是由proc接口来实现,它采用的是sysctl机制,procfs支持两种类型的API供内核模块使用:
1.标准的procfs
API:只要处理的数据量很小时就可以使用,很小的数据量通常限制在一页大小(i386中为4096个字节)
2.seq_file
API:seq_file用于处理读请求,它可以支持多于一页大小的读请求,提供了链表来进行遍历,将所有的元素发送至用户空间。
数据结构定义
proc中的每个文件定义如下:
- struct proc_dir_entry{
-
-
//与普通文件系统类似
-
-
unsigned int low_ino;//索引号
-
-
unsigned short namelen;//文件名长度
-
-
const char* name;//具体文件名
-
-
mode_t mode;//权限及文件类型
-
-
nlink_t nlink;//来自子文件夹以及符号链接的数量
-
-
uid_t uid;//用户id
-
-
gid_t gid;//组id,这两个域值一般置为0,代表为root用户所有
-
-
loff_t size;//文件大小,由于proc都是动态产生,长度很难知道,一般为0
-
-
const struct inode_operations *proc_iops;//暴露给vfs的操作接口
-
-
const struct file_operations *proc_fops;
-
-
//subdir指向第一个子文件夹
-
-
struct proc_dir_entry *next,*parent,*subdir;//文件的组织情况
-
-
void *data;
-
-
//向内核进行读写的函数指针,需要用户实现
-
-
//原型:typedef int (read_proc_t)(char*page,char**start,off_t off,int count,int eof,void* data)
-
-
read_proc_t *read_proc;
-
-
//原型:typedef int (write_proc_t)(struct file*file,const char __user *buffer,,off_t off,unsigned long //count,void* data)
-
-
write_proc_t *write_proc;
-
-
atomic_t count;//该文件被内核模块使用的计数
-
-
int pde_users;
-
-
spinlock_t pde_unload_lock;
-
-
struct completion *pde_unload_completion;
-
-
struct list_head pde_openers;
-
-
}
上面的__user表明该字段来自用户空间,需要通过copy_from_user进行复制,而read,write中的data参数则来自proc_dir_entry中的data域,说明proc中注册的read/write可以被多个proc
entry进行调用。
proc的索引节点结构体既要连接到VFS文件下,又要保持属于自己proc的数据,所以索引节点的定义就包含了下面两个部分。
proc的索引节点定义如下:
- struct proc_inode{
-
-
struct pid *pid;//与进程文件夹相关联的进程
-
-
int fd;//进程中的/proc//fd文件的文件描述符
-
-
union proc_op op;//用于访问文件的函数指针
-
-
struct proc_dir_entry *pde;//与文件表项相关的proc_dir_entry
-
-
struct inode vfs_inode;
-
-
}
-
-
union proc_op{
-
-
int (*proc_get_link)(struct inode*,struct dentry**,struct vfsmount* *);
-
-
int (*proc_read)(struct task_struct *task,char*page);
-
-
}
proc
初始化
在proc文件系统使用之前,需要进行挂载,在挂载期间,内核需要创建,初始化许多类型的文件夹(网络,设备等等),由于与内核,体系结构相关,初始化就存在一些#ifdef的编译选项,它也是通过模块来进行安装进入内核中,代码如下:
- fs/proc/root.c
-
-
void __init proc_root_init(void)
-
-
{
-
-
//创建一个proc_inode对象的slab缓存,以加快创建,销毁proc内存节点速度
-
-
int err = proc_init_inodecache();
-
-
if(err)
-
-
return;
-
-
//将文件系统注册
-
-
err = register_filesystem(&proc_fs_type);
-
-
if(err) return;
-
-
//注册文件系统之后,就进行挂载,它返回一个vfsmount的实例,保持在全局变量proc_mnt中
-
-
//kern_mount_data实际调用函数do_kern_mount
-
-
proc_mnt = kern_mount_data(&proc_fs_type,&init_pid_ns);
-
-
err = PTR_ERR(proc_mt);
-
-
if(IS_ERR(proc_mnt)){
-
-
unregister_filesystem(&proc_fs_type);
-
-
return;
-
-
}
-
-
//下面就是产生/proc中的各种文件夹
-
-
proc_misc_init();
-
-
proc_net_init();
-
-
proc_root_fs = proc_mkdir(“fs”,NULL);
-
-
proc_root_driver = proc_mkdir(“driver”,NULL);
-
-
proc_mkdir(“fs/nfsd”,NULL);
-
-
proc_bus = proc_mkdir(“bus”,NULL);
-
-
//这个机制有些特别system control mechanism,当一个新的sysctl定义,pro_sys_root就会产生新///的文件
-
-
proc_sys_init();
-
-
}
proc_misc_init生成/proc
main文件夹中的各种文件,它通过特定的程序来读取内核数据结构,这些程序主要如下:
loadavg(loadavg_read_proc):读取系统负载的信息
uptime(uptime_read_proc):
meminfo(meminfo_read_proc):读取内存方面的信息
version(version_read_proc):内核版本信息
….......
对上面的信息进行建立每一个文件,上面的每一个都是只读的,通过调用create_proc_read_entry()
函数实现,其中注册了get_info调用的函数指针。
如meminfo_read_proc函数
- static int version_read_proc(char*page,char**start,off_t off,int count,int *eof,void *data)
-
-
{
-
-
int len;
-
-
//转换为指定的格式,写入用户空间
-
-
len = sprintf(page,PAGE_SIZE,linux_proc_banner,utsname()->sysname,utsname()->release
-
-
,utsname()->version);
-
-
//返回写入的数据长度,主要是判断数据是否在一页中
-
-
return proc_calc_metries(page,start,off,count,eof,len);
-
-
}
其中的linux_proc_banner
定义如下:- const char linux_banner[]= “%s version %s ”
-
-
“ (” LINUX_COMPILE_BY “@” LINUX_COMPILE_HOST “)”
-
-
“ (” LINUX_COMPILER “) %s\n”;
proc_misc_init
返回后,就是系统的不同模块夹进行初始化各自文件夹,每个模块的proc_dir_entry
的子目录都设置为全局变量。
阅读(744) | 评论(0) | 转发(0) |