前段时间进行卡托检测方案移植过程中,该方案中使用的是sys文件系统向上层暴露数据,而本周进行boottime方案移植时,采用的则是proc文件系统。同样是向上层暴露数据,且都叫“文件系统”,这两者之间有什么区别和联系呢?
目录结构首先各自查看一下两类文件系统的目录结构
/proc目录下的部分文件
/proc/cmdline 启动时传递给kernel的参数信息(就是bootargs信息) /proc/cpuinfo cpu的信息 /proc/crypto 内核使用的所有已安装的加密密码及细节 /proc/devices 已经加载的设备并分类 /proc/dma 已注册使用的ISA DMA频道列表 /proc/execdomains Linux 内核当前支持的execution domains /proc/fb 帧缓冲设备列表,包括数量和控制它的驱动 /proc/filesystems 内核当前支持的文件系统类型 /proc/interrupts x86架构中的每个IRQ中断数 /proc/iomem 每个物理设备当前在系统内存中的映射 /proc/ioports 一个设备的输入输出所使用的注册端口范围 /proc/kcore 代表系统的物理内存,存储为核心文件格式,里边显示的是字节数,等于RAM大小加上4kb /proc/kmsg 记录内核生成的信息,可以通过/sbin/klogd或/bin/dmesg来处理 /proc/loadavg 根据过去一段时间内CPU和IO的状态得出的负载状态,与uptime命令有关 /proc/locks 内核锁住的文件列表 /proc/mdstat 多硬盘,RAID配置信息(md=multiple disks) /proc/meminfo RAM使用的相关信息 /proc/misc 其他的主要设备(设备号为10)上注册的驱动 /proc/modules 所有加载到内核的模块列表 /proc/mounts 系统中使用的所有挂载 /proc/partitions 分区中的块分配信息 /proc/pci 系统中的PCI设备列表 /proc/slabinfo 系统中所有活动的 slab 缓存信息 /proc/stat 所有的CPU活动信息 /proc/uptime 系统已经运行了多久 /proc/swaps 交换空间的使用情况 /proc/version Linux内核版本和gcc版本 /proc/bus 系统总线(Bus)信息,例如pci/usb等 /proc/driver 驱动信息 /proc/fs 文件系统信息 /proc/ide ide设备信息 /proc/irq 中断请求设备信息 /proc/net 网卡设备信息 /proc/scsi scsi设备信息 /proc/tty tty设备信息 /proc/net/dev 显示网络适配器及统计信息 /proc/vmstat 虚拟内存统计信息 /proc/vmcore 内核panic时的内存映像 /proc/diskstats 取得磁盘信息 /proc/schedstat kernel调度器的统计信息 /proc/zoneinfo 显示内存空间的统计信息,对分析虚拟内存行为很有用
/sys目录下的文件结构
/sys/devices 包含所有被发现的注册在各种总线上的各种物理设备。 /sys/dev 包含block(块设备)和char(字符设备)两个文件夹,下面均是以主次设备号(major:minor)命名的链接文件,连接到/sys/devices目录下 /sys/class 该目录下包含所有注册在kernel里面的设备类型,每个设备类型表达具有一种功能的设备。每个设备类型子目录下是具体设备的符号链接,这些链接指向/sys/devices/...下的具体设备。 /sys/block (从linux2.6.26版本开始已经移到了/sys/class/block) /sys/bus 按总线类型分类设备 /sys/module 该目录包含所有被载入Kernel的模块 /sys/fs 该目录用来描述系统中所有的文件系统 /sys/kernel 该目录下存放的是内核中所有可调整的参数 /sys/firmware 系统加载固件机制的对用户空间的接口 /sys/power 该目录下有几个属性文件可以用于控制整个机器的电源状态,如向其中写入控制命令让机器关机/重启等demo
proc文件系统和sys文件系统最终直观效果都是提供给上层接口,然后上层可以使用cat/echo命令往相应节点读/写数据,但是实现方式却有略微不同,以下以两个例子进行演示。
proc_demo
// proc.c #include#include #include #include #include #include #include #include #include struct proc_dir_entry *proc_node = NULL; static char hello_data[20] = {}; static ssize_t hello_proc_read(struct file *fp, char __user *user_buf, size_t count, loff_t *ppos) { int ret = 0; if (clear_user(user_buf, count)) { printk(KERN_ERR "clear errorn"); return -EIO; } ret = simple_read_from_buffer(user_buf, count, ppos, hello_data, strlen(hello_data)); return ret; } static ssize_t hello_proc_write(struct file *fp, const char __user *user_buf, size_t count, loff_t *ppos) { int ret; printk("hello_proc_write:count is %d.n",count); memset(hello_data,0,sizeof(hello_data)); ret = simple_write_to_buffer(hello_data, sizeof(hello_data),ppos,user_buf,count); printk("hello_proc_write:ret is %d.n",ret); printk("hello_proc_write:user_buf is %s",hello_data); return count; } static const struct file_operations hello_proc_fops = { .owner = THIS_MODULE, .read = hello_proc_read, //使用cat时的回调函数 .write = hello_proc_write, //使用echo时的回调函数 }; static int __init proc_test_init(void) { proc_node = proc_create("hello_proc", 0,NULL,&hello_proc_fops); return 0; } static void __exit proc_test_exit(void) { if(proc_node) remove_proc_entry("hello_proc", NULL); } module_init(proc_test_init); module_exit(proc_test_exit); MODULE_LICENSE("GPL"); MODULE_DEscriptION("proc filesystem test");
Makefile
KVERS = $(shell uname -r) obj-m += proc.o build:kernel_modules kernel_modules: make -C /lib/modules/$(KVERS)/build M=$(CURDIR)
执行make kernel_modules指令,然后输入insmod proc.ko,即可在/proc路径下看到hello_proc节点。
尝试使用echo指令和cat指令操作该节点,可以看到内核日志和执行效果为:
以上就是proc文件系统的读写操作demo。
sysfs的操作则略有不同,是通过xxx_show/xxx_store函数实现cat/echo功能。以卡托检测部分代码为例。
sys_demo
总结个人理解:
proc文件系统历史最久远,最初是用来跟内核交互的唯一方式,和系统本身数据联系紧密,如获取cpu/mem/进程等数据,如/proc/cpuinfo、/proc/meminfo等。而sysfs和设备驱动联系更加紧密,通过分析目录结构,相比于 proc 文件系统,使用 sysfs导出内核数据的方式更为统一,并且组织的方式更好。
两种文件系统的实现方式略有不同,proc文件系统创建节点时,需要显式的制定创建文件权限,若编写代码时出现错误,权限设置有误,则可能对系统安全性或稳定性造成影响,而sys文件系统设计时,一个属性文件只做一件事,sysfs属性文件一般只有一个值,直接读取或写入。
编写驱动程序时,应优先使用sysfs文件系统。



