linuxproc文件系统.docx
《linuxproc文件系统.docx》由会员分享,可在线阅读,更多相关《linuxproc文件系统.docx(12页珍藏版)》请在冰豆网上搜索。
![linuxproc文件系统.docx](https://file1.bdocx.com/fileroot1/2022-12/9/c24dc0f8-75c5-4103-951b-fb5c21c1bf1c/c24dc0f8-75c5-4103-951b-fb5c21c1bf1c1.gif)
linuxproc文件系统
Linux内核提供了一种通过/proc文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。
本文只讨论基于intelx86架构的Linux/proc文件系统。
/proc文件系统是一种内核和内核模块用来向进程(process)发送信息的机制(所以叫做/proc)。
这个伪文件系统让你可以和内核内部数据结构进行交互,获取有关进程的有用信息,在运行中(onthefly)改变设置(通过改变内核参数)。
与其他文件系统不同,/proc存在于内存之中而不是硬盘上。
/proc由内核控制,没有承载/proc的设备。
因为/proc主要存放由内核控制的状态信息,所以大部分这些信息的逻辑位置位于内核控制的内存。
对/proc进行一次'ls-l'可以看到大部分文件都是0字节大的;不过察看这些文件的时候,确实可以看到一些信息。
这怎么可能?
这是因为/proc文件系统和其他常规的文件系统一样把自己注册到虚拟文件系统层(VFS)了。
然而,直到当VFS调用它,请求文件、目录的i-node的时候,/proc文件系统才根据内核中的信息建立相应的文件和目录。
加载proc文件系统
如果系统中还没有加载proc文件系统,可以通过如下命令加载proc文件系统:
mount-tprocproc/proc
上述命令将成功加载你的proc文件系统。
更多细节请阅读mount命令的manpage。
察看/proc的文件
/proc的文件可以用于访问有关内核的状态、计算机的属性、正在运行的进程的状态等信息。
大部分/proc中的文件和目录提供系统物理环境最新的信息。
尽管/proc中的文件是虚拟的,但它们仍可以使用任何文件编辑器或像'more','less'或'cat'这样的程序来查看。
当编辑程序试图打开一个虚拟文件时,这个文件就通过内核中的信息被凭空地(onthefly)创建了。
这是一些我从我的系统中得到的一些有趣结果
$ls-l/proc/cpuinfo
-r--r--r--1rootroot0Dec2511:
01/proc/cpuinfo
$file/proc/cpuinfo
/proc/cpuinfo:
empty
$cat/proc/cpuinfo
processor:
0
vendor_id:
GenuineIntel
cpufamily:
6
model:
8
….
bogomips:
1992.29
注意:
这里ls,file两个命令看到的cpuinfo的大小是0,但是cat可以可以看到内容.
得到有用的系统/内核信息
proc文件系统可以被用于收集有用的关于系统和运行中的内核的信息。
下面是一些重要的文件:
*/proc/cpuinfo-CPU的信息(型号,家族,缓存大小等)
*/proc/meminfo-物理内存、交换空间等的信息
*/proc/mounts-已加载的文件系统的列表
*/proc/devices-可用设备的列表
*/proc/filesystems-被支持的文件系统
*/proc/modules-已加载的模块
*/proc/version-内核版本
*/proc/cmdline-系统启动时输入的内核命令行参数
*/proc/XXX–XXX是指以数字编号的目录,有不少这样的目录,每一个目录表示一个进程(即线程组)
*/proc/sys–可以修改的系统信息
*/proc/swaps-要获知swap空间的使用情况
*/proc/uptime-获取系统的正常运行时间
*/proc/fs/nfsd/exports-列出由NFS共享的文件系统
*/proc/kmsg–该文件被作为内核日志信息源,它可以被作为一个系统信息调用的接口使用。
*/proc/kcore–该文件提供了以内核文件格式形式访问系统物理内存,并且可以被gdb用于检查任意内核数据结构的当前状态。
如果装了源码,那么可以通过查看/usr/src/linux/Documentation/filesystems/proc.txt文件来获取更多的信息。
有关运行中的进程的信息
/proc文件系统可以用于获取运行中的进程的信息。
在/proc中有一些文件名为数字的子目录。
每个目录对应一个进程id(PID)。
这样,每一个运行中的进程/proc中都有一个用它的PID命名的目录。
这些子目录中包含可以提供有关进程的状态和环境的重要细节信息的文件。
下面是一些文件(实在太多,只列一部分):
1.文件"cmdline"包含启动进程时调用的命令行。
2."envir"进程的环境变两。
3."status"是进程的状态信息,包括启动进程的用户的用户ID(UID)和组ID(GID),父进程ID(PPID),还有进程当前的状态,比如"Sleelping"和"Running"。
4.”cwd”是指向进程当前工作目录的符号链接
5."exe"指向运行的进程的可执行程序
5."root"指向被这个进程看作是根目录的目录(通常是"/")。
6."fd"包含指向进程使用的文件描述符的链接。
7."cpu"仅在运行SMP内核时出现,里面是按CPU划分的进程时间。
/proc/self是一个有趣的子目录,它使得程序可以方便地使用/proc查找本进程地信息。
/proc/self是一个链接到/proc中访问/proc的进程所对应的PID的目录的符号链接。
通过/proc与内核交互
上面讨论的大部分/proc的文件是只读的。
而实际上/proc文件系统通过/proc中可读写的文件提供了对内核的交互机制。
写这些文件可以改变内核的状态,因而要慎重改动这些文件。
/proc/sys目录存放所有可读写的文件的目录,可以被用于改变内核行为(linux有专门的api做读取这个目录的文件)。
/proc/sys/kernel:
这个目录包含反通用内核行为的信息.可修改已改变配置.
/proc/sys/kernel/{domainname,hostname}:
存放着机器/网络的域名和主机名。
这些文件可以用于修改这些名字。
通过修改/proc文件系统中的文件,我们可以修改主机名.
/proc/sys/net:
这个目录中的文件可以用于修改机器/网络的网络属性。
比如,简单修改一个文件,你可以在网络上瘾藏匿的计算机。
$echo1>/proc/sys/net/ipv4/icmp_echo_ignore_all
这将在网络上瘾藏你的机器,因为它不响应icmp_echo。
主机将不会响应其他主机发出的ping查询。
要改回缺省设置,只要
$echo0>/proc/sys/net/ipv4/icmp_echo_ignore_all
VFS与procfs的对照表
注意:
proc仅存在于内存中
VFS类型
Procfs相应类型
备注
superblock
无.proc只要使用VFS的superblock就可以表示其信息了.没有自己的superblock表示
proc的superblock动态分配得到.
Superblockoperation
相应的super_operations为proc_sops.其值在备注栏显示
.alloc_inode=proc_alloc_inode,
.destroy_inode=proc_destroy_inode,
.read_inode=proc_read_inode,
.drop_inode=generic_delete_inode,
.delete_inode=proc_delete_inode,
.statfs=simple_statfs,
.remount_fs=proc_remount,
inode
proc_inode.这个类型内嵌了inode.
proc有相应的cache实例proc_inode_cachep来分配proc_inode实例.
Inodeoperation
不同文件的inode,其操作不一样
file
无
Fileoperation
不同文件其操作不一样
dentry
无
Dentryoperaion
不同文件其操作不一样
注:
procfs使用proc_dir_entry表示每一个inode(即proc_inode)实例,proc_dir_entry包含了proc中的文件所需要的信息.每一个procfs中的文件都有一个inode,也都有一个proc_dir_entry实例,该实例的首地址存放在相应的inode的u.generic_ip成员中
procfile–inode—proc_inode—proc_dir_entry
procfs使用全局变量proc_fs_type表示其文件系统类型.其定义如下:
staticstructfile_system_typeproc_fs_type={
.name="proc",
.get_sb=proc_get_sb,
.kill_sb=kill_anon_super,
};
通过调用register_filesystem(proc_fs_type)向内核注册procfs文件系统类型.
procfs定义了全局的指向vfsmount实例的指针proc_mnt.它通过调用kern_mount(proc_fs_type)进行初始化,并且proc_mnt有一个成员包含了procfs超级块的信息(proc_mnt.mnt_sb).此外,proc_mnt也包含了两个dentry实例.proc_mnt.mnt_root,proc_mnt.mnt_mountpoint.
procfs使用了全局的vfsmount实例proc_mnt,以方便VFS对proc进行管理.
把procfs加载后,目录/proc对应的dentry是动态分配的,对应的inode是动态分配的,对应的proc_dir_entry是proc_root.(参考下文)
对proc文件的管理
前面我们提过,相对于其他逻辑文件系统的具体文件组织形式(比如ext2文件系统的inode),proc文件系统也有自己的组织结构,那就是proc_dir_entry结构,所有属于proc文件系统的文件,都对应一个proc_dir_entry结构,并且在VFS需要读取proc文件的时候,把这个结构和VFS的inode建立链接(即由inode->u.generic_ip指向该prc_dir_entry结构)。
因此,proc文件系统实现了一套对proc_dir_entry结构的管理,下面我们就此进行一个分析。
proc_dir_entry结构
proc_dir_entry描述proc中文件的信息.实例对应一个proc中的文件.
proc_dir_entry实例放在inode->u.generic_ip成员中.proc文件系统本质就是一堆proc_dir_entry实例.
proc_dir_entry定义如下:
unsignedshortlow_ino;
proc_dir_entry实例的ID,除了根结点,其他的节点号都是在创建proc_dir_entry的时候,由make_inode_number()动态创建的
unsignedshortnamelen;
constchar*name;
proc文件的名字,以及其长度
mode_tmode;
proc文件的模式由两部分用位或运算组成,第一部分是文件的类型,可以参考include/linux/stat.h中的定义,比如,S_IFREG表示普通文件,而S_IFDIR表示目录文件。
第二部分是该文件的权限,同样可以参考include/linux/stat.h中的定义,比如,S_IRUSR表示该文件能够被拥有者读,S_IROTH表示该文件可以被其他人读取。
但真正的权限检查,我们可以放到后面提到的inode_operations结构中。
nlink_tnlink;
uid_tuid;
gid_tgid;
unsignedlongsize;
使用“ls”命令时,所显示出的文件大小
structinode_operations*proc_iops;
proc中的inode的操作(即proc下inode的操作).值得注意的是proc中不同的类型的文件其inode操作是不一样的
structfile_operations*proc_fops;
Proc中file的操作.注意不同类型的文件支持的文件操作不一样
get_info_t*get_info
当用户向proc文件读取的数据小于一个页面大小时,可以使用这个函数向用户返回数据
structmodule*owner
定义procfs的模块
structproc_dir_entry*next,*parent,*subdir;
使用这些指针,把所有的proc_dir_entry构成树
void*data;
特殊用途的字段.如果文件是链接文件,那么这个字段指向目标文件的文件名
read_proc_t*read_proc;
write_proc_t*write_proc;
对于proc中普通的文件,我们只要用这两个函数来实现或者写操作.而不用为其专门定义inode操作.
atomic_tcount
使用计数.一个proc_dir_entry结构的count减为零时,会释放该实例
intdeleted;
当我们调用remove_proc_entry函数要删除一个proc_dir_entry时,如果发现该结构还在使用,就会设置该标志并且退
kdev_trdev;
如果该proc文件是设备文件,那么设置这个成员
创建proc文件create_proc_entry
proc中使用create_proc_entry来创建一个文件.其函数原型为:
structproc_dir_entry*create_proc_entry(constchar*name,mode_tmode,structproc_dir_entry*parent)
该函数的执行流程如下:
1.检查参数的合法性(eg:
父节点的存在性)
2.分配proc_dir_entry实例的空间(ent),然后做必要的初始化.比如,初始化文件名,如果该文件是目录,那么把ent->proc_fops=&proc_dir_operations,ent->proc_iops=&proc_dir_inode_operations
3.调用proc_register把ent加入proc文件系统(即proc文件树)中
4.返回ent
proc_register函数
这个函数把一个proc文件加入到proc文件树中,其函数原型如下:
staticintproc_register(structproc_dir_entry*parent,structproc_dir_entry*ent)
其主要的流程如下:
1.使用make_inode_number()函数动态的到一个节点号,并且设置low_ino.注意只是获得inode编号,并不会真的创建inode.该inode的创建会推迟到proc_lookup中.
2.将这个proc_dir_entry结构链接到它的父节点上
3.根据文件类型(普通文件,目录,symbolic)的不同,设置不同的缺省操作函数集。
删除proc文件remove_proc_entry
这个函数用来删除一个proc文件.注意如果该文件正被使用那么只是设置deleted标志,该函数的原型:
voidremove_proc_entry(constchar*name,structproc_dir_entry*parent)
其中name是待删的proc文件.parent是该文件的父目录.
其执行流程如下:
1.确定其父目录.如果parent有效,则执行2,否则(parent==NULL)尝试从name分析出parent,如果分析失败则函数返回失败,否则执行2.
2.在parent中找出待删的文件对应的proc_dir_enty实例ent.
3.把ent从proc文件树中删除,并更新树的状态
4.如果该文件被使用则设置deleted标识(在其后的恰当时候会被释放),否则调用free_proc_entry
其他proc文件操作函数
structproc_dir_entry*proc_mkdir(constchar*name,structproc_dir_entry*parent)
这个函数用来在proc文件系统中创建一个子目录,根据它的参数,我们就可以看出它的功能。
在这个函数里,将动态分配一个proc_dir_entry结构以及它的名字,然后,设置目录文件的缺省操作(proc_iops以及proc_fops)以及nlink值,最后,调用proc_register函数将其注册。
structproc_dir_entry*proc_mknod(constchar*name,mode_tmode,structproc_dir_entry*parent,kdev_trdev)
用来在proc文件系统中建立一个设备文件,因此,在创建proc_dir_entry结构后,没有设置缺省操作,而是使用ent->rdev=rdev指定了设备。
最后,调用proc_register函数将其注册。
structproc_dir_entry*proc_symlink(constchar*name,structproc_dir_entry*parent,constchar*dest)函数,该函数创建了一个链接文件,使用ent->mode=S_IFLNK|S_IRUGO|S_IWUGO|S_IXUGO来标志,它和其他文件的建立很相似,只是,它将链接的目标文件名放在了ent->data域中。
最后,它同样调用proc_register函数将该结构注册。
structproc_dir_entry*create_proc_read_entry(constchar*name,mode_tmode,structproc_dir_entry*base,read_proc_t*read_proc,void*data)
创建只读的proc文件,并且设置其对应的proc_dir_entry中的read_proc成员.
voidcreate_seq_entry(char*name,mode_tmode,structfile_operations*f)
在/proc目录下创建一个文件,其文件操作函数由f指定
内核还定义了很多其他的创建proc文件的方式,请参考源代码.
对proc文件操作的分析
对于proc中的普通文件,目录,链接的默认操作为:
注:
需要看看下面各个全局函数表的各个成员是如何实现的.
proc文件类型
Inode默认操作
(proc_dir_entry.proc_iops)
它也记录在inode上
类型:
structinode_operations
File默认操作
(proc_dir_entry.proc_fops)
它也记录在inode上
类型:
structfile_operations
dentry默认操作.它记录在相应的structfile实例上
注意下面是proc定义的全局变量
普通文件
proc_file_inode_operations
proc_file_operations
proc_dentry_operations
proc_dir_inode_operations
proc_dir_operations;
proc_dentry_operations
链接
proc_link_inode_operations
NULL
proc_dentry_operations
注意:
Proc_dir_entry中有两个函数指read_proc,write_proc.
对于proc中普通的文件,我们只要用这两个函数来实现或者写操作.而不用为其专门定义inode操作或者file操作.不同类型的文件,这两个操作也不一样.
下面的讨论针对proc下各个类型的文件来说明.如果必要会指定相应的proc_dir_entry实例(通常是静态的).如果没有说明是采用上面的默认值.注意,这里只列出一部分
/proc
(proc_root)
proc_root_inode_operations
proc_root_operations
/proc/meminfo
注:
read_proc为meminfo_read_proc,其它默认
/proc/modules
proc_modules_operations
/proc/TGID
(它其实是一个线程组)
proc_tgid_base_inode_operations
proc_tgid_base_operations
pid_base_dentry_operations
注:
/proc/tgid目录下的文件的dentry操作均为pid_dentry_operations
/proc/TGID/environ
/proc/TGID/task/PID/environ
proc_info_file_operations;read_proc=proc_pid_environ
注意:
/proc/TGID下还有很多文件,其操作也大不相同.这里只是列举了一些.另外/proc/tgid/task/pid目录下的文件的操作大部分与/proc/TGID目录下的操作一样
/proc/TGID/task
proc_task_inode_operations
proc_task_operations
/proc/TGID/fd
/proc/TGID/task/PID/fd
proc_fd_inode_operations
proc_fd_operations
/proc/TGID/task/PID
proc_tid_base_inode_operations
proc_tid_base_operations
pid_base_dentry_operations
/proc/self
proc_self_inode_operations
假设有一个线程组,其TGID为32182,