sysfs文件系统
sysfs,全称为System Filesystem,是一个由Linux内核实现的虚拟文件系统。它扮演着一个桥梁的角色,将内核中的设备和驱动程序信息以文件的形式呈现给用户空间。与/proc文件系统相似,sysfs专注于展示设备和驱动程序的细节,而/proc则主要反映进程信息。
在sysfs中,信息被组织成层次化的文件系统结构。每个设备或内核对象在文件系统中都有其对应的表示,通常是以文件或目录的形式存在。这些文件不仅存储了设备的属性和状态信息,而且很多文件还允许用户通过读写操作来对设备进行配置或控制。
sysfs默认挂载在文件系统的/sys路径下。通过这个虚拟文件系统,用户空间的应用程序能够以一种直观和动态的方式访问和管理系统设备,无需进行复杂的内核空间交互。这种设计提供了一种高效且用户友好的接口,使得设备管理变得更加简单和灵活。
kernel Object
在Linux内核架构中,kobject扮演着一个核心角色,它是一个用于抽象化内核对象的框架。kobject不仅构成了内核中各种子系统的基础构件,而且能够代表设备、驱动程序、总线等多样化的内核实体。
kobject架构提供了一种灵活且统一的模型,用以维护和管理内核对象。每个Kobject实例都拥有一个独一无二的标识符和指向其上层Kobject的链接,这样的设计允许它们形成一个有序的层级网络。更进一步,Kobject可以附加多种属性,这些属性反映了对象的特征或状态,并且可以通过sysfs这一虚拟文件系统对外公布,使得用户空间程序能够访问和操作这些属性。
Sysfs作为Kobject信息呈现的媒介,将内核内部的设备和驱动程序等对象的状态和信息以文件的形式展现给用户空间。每当内核中新增设备或驱动程序时,相应的Kobject实例也会被动态创建,并通过Sysfs将这些信息映射到用户空间可访问的路径下。
在Linux内核的源码树中,struct kobject这一数据结构在"linux/kobject.h"头文件里定义。它经常作为其他结构体的成员出现,使得这些结构体所代表的内核对象能够整合进Kobject的管理体系中。通过这种方式,内核开发者可以轻松地为各种内核对象实现统一的管理和访问接口。
structkobject{ constchar*name; structlist_headentry; structkobject*parent; structkset*kset; structkobj_type*ktype; structkernfs_node*sd;/*sysfsdirectoryentry*/ structkrefkref; ... };
其中:- kref:提供kobject的引用技术。- ktype:kobject关联的类型。- kset:指向同一类kobject集合的指针。- sd:当前kobject在/sys下的目录条目。
sysfs使用方式
Linux内核中使用sysfs的步骤比较简单:(1)在sys路径下创建目录;(2)创建sysfs文件。下面将详细展开这两步涉及的内核API。
在sys下创建目录
structkobject*kobject_create_and_add(constchar*name,structkobject*parent);
Linux内核预定义了几个常用的parent参数:- kernel_kobj:在/sys/kernel下创建目录;- firmware_kobj:在/sys/firmware下创建目录;- fs_kobj:在/sys/fs下创建目录。- 如果parent取值为NULL,则在/sys下面创建目录。
相应地,如果需要删除对应的sysfs目录,可以用:
voidkobject_put(structkobject*kobj);
创建sysfs文件
sysfs文件可以通过sysfs属性来创建,它定义在头文件"sysfs.h"中:
structkobj_attribute{ structattributeattr; ssize_t(*show)(structkobject*kobj,structkobj_attribute*attr,char*buf); ssize_t(*store)(structkobject*kobj,structkobj_attribute*attr,constchar*buf,size_tcount); };
attr表示将要创建的文件(属性),而show和store分别表示对应的sysfs文件在读和写操作时的回调函数。
struct kobj_attribute可以通过__ATTR宏来创建:
__ATTR(name,permission,show_ptr,store_ptr);
准备好attr之后,可以通过sysfs_create_file来创建出sysfs文件:
intsysfs_create_file(structkobject*kobj,conststructattribute*attr);
如果需要删除对应的sysfs文件,可以用:
voidsysfs_remove_file(structkobject*kobj,conststructattribute*attr);
sysfs创建设备节点
前面描述了如何创建一个基本的sysfs,接下载描述的是如何创建设备节点的sysfs。
实际创建设备节点的sysf跟基本的sysfs是一样的,只是结构体换了一个名字。它使用DEVICE_ATTR宏,可以定义一个struct device_attribute设备属性,使用sysfs_create_file便可以在设备目录下创建具有show和store方法的节点。
DEVICE_ATTR宏定义
DEVICE_ATTR宏定义如下:
#defineDEVICE_ATTR(_name,_mode,_show,_store) structdevice_attributedev_attr_##_name=__ATTR(_name,_mode,_show,_store)
__ATTR宏定义,宏定义在include/linux/sysfs.h文件中,如下:
#define__ATTR(_name,_mode,_show,_store){ .attr={.name=__stringify(_name), .mode=VERIFY_OCTAL_PERMISSIONS(_mode)}, .show=_show, .store=_store, }
struct device_attribute结构体,该结构体的定义在include /linux/device.h,其定义如下:
structdevice_attribute{ structattributeattr; ssize_t(*show)(structdevice*dev,structdevice_attribute*attr, char*buf); ssize_t(*store)(structdevice*dev,structdevice_attribute*attr, constchar*buf,size_tcount); };
struct attribute结构体, 该结构体的定义在include /linux/device.h,其定义如下:
structattribute{ constchar*name; umode_tmode; #ifdefCONFIG_DEBUG_LOCK_ALLOC boolignore_lockdep:1; structlock_class_key*key; structlock_class_keyskey; #endif };
DEVICE_ATTR宏定义等价说明
我们顶一个文件的范式如下
DEVICE_ATTR(_name,_mode,_show,_store)
等价于:
structdevice_attributedev_attr_##_name={ .attr={.name=__stringify(_name), .mode=VERIFY_OCTAL_PERMISSIONS(_mode)}, .show=_show, .store=_store, }
show函数的详细描述:
ssize_t(*show)(structdevice*dev,structdevice_attribute*attr,char*buf);
参数说明:
入参buf是需要我们填充的string即我们cat属性节点时要显示的内容;-函数的返回值是我们填充buf的长度,且长度应当小于一个页面的大小(4096字节);
其他参数一般不用关心。
实例说明,当我们使用cat命令的时候,将调用该函数
staticssize_tshow_youyeetoo_device(structdevice*dev, structdevice_attribute*attr,char*buf) { returnsprintf(buf,"%sn",mybuf); }
store函数的详细描述:
ssize_t(*store)(structdevice*dev,structdevice_attribute*attr,constchar*buf,size_tcount);
参数说明:
入参buf是用户传入的字符串,即echo到属性节点的内容;
入参count是buf中字符串的长度。
函数的返回值通常返回count即可。
其他参数一般不用关心。
实例说明,当我们使用echo命令的时候,将调用该函数:
staticssize_tstore_youyeetoo_device(structdevice*dev, structdevice_attribute*attr, constchar*buf,size_tcount) { sprintf(mybuf,"%s",buf); returncount; }
mode的权限定义,在kernel/include/uapi/linux/stat.h中:
#defineS_IRWXU00700//用户可读写和执行 #defineS_IRUSR00400//用户可读 #defineS_IWUSR00200//用户可写 #defineS_IXUSR00100//用户可执行 #defineS_IRWXG00070//用户组可读写和执行 #defineS_IRGRP00040//用户组可读 #defineS_IWGRP00020//用户组可写 #defineS_IXGRP00010//用户组可执行 #defineS_IRWXO00007//其他可读写和执行 #defineS_IROTH00004//其他可读 #defineS_IWOTH00002//其他可写 #defineS_IXOTH00001//其他可执行
至此,我们已经定义好了.show和.store函数,那么就可以使用DEVICE_ATTR了。
staticDEVICE_ATTR(youyeetoo_device,S_IWUSR|S_IRUSR,show_youyeetoo_device,store_youyeetoo_device);
device attribute添加到sysfs
上面描述的是sysfs的读写接口的定义方式,他还需要注册到sysfs中。才会在对应驱动中显示我们的文件,其中:
注册函数:sysfs_create_file();
注销函数:sysfs_remove_file();
样例代码代码:
注册样例:
sysfs_create_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr);
注销样例:
sysfs_remove_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr);
sysfs样例测试
完整的测试代码,在sysfs的驱动节点里面生成一个youyeetoo文件,文件支持读写功能。
#include #include #include #include #include staticintmajor; staticstructclass*youyeetoo_class; structdevice*youyeetoo_dev; staticcharyouyeetoo_buff[100]="youyeetoo"; staticssize_tshow_youyeetoo_device(structdevice*dev, structdevice_attribute*attr,char*buf) { returnsprintf(buf,"%sn",youyeetoo_buff); } staticssize_tstore_youyeetoo_device(structdevice*dev, structdevice_attribute*attr, constchar*buf,size_tcount) { sprintf(youyeetoo_buff,"%s",buf); returncount; } staticDEVICE_ATTR(youyeetoo,S_IWUSR|S_IRUSR,show_youyeetoo_device,store_youyeetoo_device); structfile_operationsyouyeetoo_ops={ .owner=THIS_MODULE, }; staticintyouyeetoo_init(void) { major=register_chrdev(0,"youyeetoo",&youyeetoo_ops); youyeetoo_class=class_create(THIS_MODULE,"youyeetoo"); youyeetoo_dev=device_create(youyeetoo_class,0,MKDEV(major,0),NULL,"youyeetoo"); if(sysfs_create_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr)) {//在mytest_device设备目录下创建一个sys_device_file属性文件 return-1; } return0; } staticvoidyouyeetoo_exit(void) { device_destroy(youyeetoo_class,MKDEV(major,0)); class_destroy(youyeetoo_class); unregister_chrdev(major,"youyeetoo"); sysfs_remove_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr); } module_init(youyeetoo_init); module_exit(youyeetoo_exit); MODULE_AUTHOR("youyeetoo"); MODULE_LICENSE("GPL");
将上面驱动编译烧录之后,就可以sysfs下看到我们创建的文件:
测试我们创建的sysfs
审核编辑 黄宇
-
Linux
+关注
关注
87文章
11342浏览量
210319 -
Sysfs
+关注
关注
0文章
15浏览量
6250
发布评论请先 登录
相关推荐
评论