procfs和sysfs

本文探讨了proc和sys文件系统在Linux中作为数据暴露接口的区别,涉及目录结构、特点、实现方式以及在不同场景下的应用。proc侧重于内核交互,sys更接近设备驱动,展示了proc_demo和sys_demo实例以说明两者操作方式的不同。
摘要由CSDN通过智能技术生成

背景

前段时间进行XXXX方案移植过程中,该方案中使用的是sys文件系统向上层暴露数据,而本周进行XXXX方案移植时,采用的则是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 <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
 
/* 定义一个proc_dir_entry结构体类型变量*/
struct proc_dir_entry *proc_node = NULL;
/* 定义一个全局数据,用来保存用户空间返回的数据 */
static char hello_data[20] = {};
 
/* 如果使用cat此节点,则传入的count为4K,直到读取的数据大小为4K,也就是直到此函数返回0
   当此函数返回0时,读取到的内容是不显示的。
 */
static ssize_t hello_proc_read(struct file *fp, char __user *user_buf, size_t count, loff_t *ppos)
{
	int ret = 0;
	/* 首先清空用户空间的user_buf地址的内容,有可能显示杂乱信息 */
    if (clear_user(user_buf, count)) {
        printk(KERN_ERR "clear error\n");
        return -EIO;
    }
	/* 从hello_data数组中读取数据到用户空间user_buf,读取的长度应该是字符串的大小 */
	ret = simple_read_from_buffer(user_buf, count, ppos, hello_data, strlen(hello_data));
    return ret;
}
 
/*
  用户空间使用echo往此节点写入数据,只有要写入的数据写完之后,也就是返回count是,此函数此不会被调用
*/
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;
}
 
/* 定义一个file_operations结构体变量 */				      
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_create()函数创建"hello_proc"文件 */
    /* 
    	"hello_proc":节点名称 
    	0:权限
    	NULL:父节点
    	hello_proc_fops:操作
    */
    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文件系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值