root@ubuntu:/sys# ll
total 4
dr-xr-xr-x 13 root root 0 1月 25 19:43 ./
drwxr-xr-x 26 root root 4096 11月 9 2021 ../
drwxr-xr-x 2 root root 0 1月 25 19:43 block/
drwxr-xr-x 36 root root 0 1月 25 19:43 bus/
drwxr-xr-x 59 root root 0 1月 25 19:43 class/
drwxr-xr-x 4 root root 0 1月 25 19:43 dev/
drwxr-xr-x 13 root root 0 1月 25 19:43 devices/
drwxr-xr-x 5 root root 0 1月 25 19:43 firmware/
drwxr-xr-x 8 root root 0 1月 25 19:43 fs/
drwxr-xr-x 2 root root 0 1月 25 19:43 hypervisor/
drwxr-xr-x 10 root root 0 1月 25 19:43 kernel/
drwxr-xr-x 142 root root 0 1月 25 19:43 module/
drwxr-xr-x 2 root root 0 1月 25 19:43 power/
root@ubuntu:/sys#
root@ubuntu:/sys#
内核sysfs文件系统使用kobject将上述目录中的各个对象链接起来,并组成一个分层的结构体系。内核为sysfs文件目录内的每个目录都创建一个kobject结构。
一 内核对象 kobject
1 kobject代表内核对象,结构体本身不单独使用,而是嵌套在其他高层结构中,用于组织成拓扑关系。
2 sysfs文件系统中一个目录对应一个kobject
//内核对象
struct kobject {
//为该koject 的name,相当于sysfs内的目录名称。
const char *name;
//为一个链接结构,用于将其他kobject结构链接起来
struct list_head entry;
//指向该kobject的父kobject,即相当于该kobejct的父目录。
struct kobject *parent;
//相同类型的kobject集合,指向该kobject归属于哪个kset
struct kset *kset;
//指向该对象类型,里面包含了对该对象的一些操作以及默认属性。
struct kobj_type *ktype;
//syfs目录节点
struct kernfs_node *sd; /* sysfs directory entry */
//kobject计数,当该计数为0时,该kobject将会释放
struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
使用:实现在sys的根目录内创建一个testKOBJ目录,与block、dev等目录平行:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
static struct kobject * testKobj = NULL;
static int __init sysfs_test_init(void)
{
testKobj = kobject_create_and_add("testKobj", NULL);
if (!testKobj)
{
printk(KERN_INFO "create kbject failed\n");
return 1;
}
return 0;
}
static void __exit sysfs_test_exit(void)
{
kobject_put(testKobj);
}
module_init(sysfs_test_init);
module_exit(sysfs_test_exit);
MODULE_AUTHOR("hrma");
MODULE_LICENSE("GPL");
makefile如下
ifneq ($(KERNELRELEASE),)
obj-m:=test_kobject.o
else
KERDIR := /lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
make -C $(KERDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.symvers *.cmd *.cmd.o modules.* *.mod.c
运行结果如下在sys根目录下生成testKobj目录
二 kobj_type 属性
//kobject的属性
struct kobj_type {
//释放kobject对象的接口,有点类似面向对象中的析构
void (*release)(struct kobject *kobj);
//操作kobject的方法集,一般包含show和restore两个功能。
const struct sysfs_ops *sysfs_ops;
//一般在每个sysfs目录内都会存在一些该目录的属性,使应用程序可以与内核进行交互。
struct attribute **default_attrs; /* use default_groups instead */
const struct attribute_group **default_groups;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
//操作kobject的方法集,一般包含show和restore两个功能。
struct sysfs_ops { /* kobject操作函数集 */
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
所谓的attribute就是内核空间和用户空间进行信息交互的一种方法,例如某个driver定义了一个变量,却希望用户空间程序可以修改该变量,以控制driver的行为,那么可以将该变量以sysfs attribute的形式开放出来
struct attribute {
const char *name;
umode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
其用法一般需要结合sysfs_ops,用户对该属性的读写操作
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
在linux内核内部提供一个默认的 kobj_type,如果一个驱动没有特殊要求,可以不设置,使用默认dynamic_kobj_ktype
static void dynamic_kobj_release(struct kobject *kobj)
{
pr_debug("kobject: (%p): %s\n", kobj, __func__);
kfree(kobj);
}
static struct kobj_type dynamic_kobj_ktype = {
.release = dynamic_kobj_release,
.sysfs_ops = &kobj_sysfs_ops,
};
const struct sysfs_ops kobj_sysfs_ops = {
.show = kobj_attr_show,
.store = kobj_attr_store,
};
/* default kobject attribute operations */
static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct kobj_attribute *kattr;
ssize_t ret = -EIO;
kattr = container_of(attr, struct kobj_attribute, attr);
if (kattr->show)
ret = kattr->show(kobj, kattr, buf);
return ret;
}
static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct kobj_attribute *kattr;
ssize_t ret = -EIO;
kattr = container_of(attr, struct kobj_attribute, attr);
if (kattr->store)
ret = kattr->store(kobj, kattr, buf, count);
return ret;
}
关系:
struct kobject
//kobject的属性
struct kobj_type *ktype;
//释放kobject对象
.release = dynamic_kobj_release,
//kobject操作函数集
.sysfs_ops = &kobj_sysfs_ops,-------------------------------------------+
|
const struct sysfs_ops kobj_sysfs_ops = {
.show = kobj_attr_show,
.store = kobj_attr_store,
};
使用:对test目录内提供:
release(),释放kobject对象
sysfs_ops, kobject操作函数集
两个属性,属性名称分别为name_attri和para_attri,以及属性的操作函数
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
static struct kobject * testKobj = NULL;
static ssize_t test_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
{
...
}
static ssize_t test_attr_store(struct kobject *kobj, struct attribute * attr, const char *buf, size_t len)
{
...
}
static const struct sysfs_ops test_sysfs_ops ={
.show = test_attr_show,
.store = test_attr_store,
};
static void test_kset_release(struct kobject *kobj)
{
printk(KERN_INFO "test kset relsase\n");
kfree(kobj);
}
static ssize_t sysfs_test_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf,"sysfs_test_show\n");
}
static ssize_t sysfs_test_store(struct kobject *kobj, struct kobj_attribute * attr, const char * buf, size_t count)
{
printk(KERN_INFO "sysfs_test_store recv: %s\n", buf);
return count;
}
//属性
static struct kobj_attribute testName =
__ATTR(name_attri, 0664,sysfs_test_show,sysfs_test_store);
//属性
static struct kobj_attribute testPara =
__ATTR(para_attri, 0664,sysfs_test_show,sysfs_test_store);
static struct attribute *test_sys_groups[] = {
&testName.attr,
&testPara.attr,
NULL,
};
ATTRIBUTE_GROUPS(test_sys);
//kobject的属性以及操作集
static struct kobj_type test_ktype = {
//kobject操作集
.sysfs_ops = &test_sysfs_ops,
//释放
.release = test_kset_release,
//kobject属性组
.default_groups = test_sys_groups,
};
static int __init kset_test_init(void)
{
testKobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
if(!testKobj)
{
printk(KERN_INFO "create and add kset kobject failed\n");
return 1;
}
/*
初始化kobject的属性组 并添加到 sysfs
*/
if (kobject_init_and_add(testKobj, &test_ktype, NULL,"test"))
{
kfree(testKobj);
return 1;
}
return 0;
}
static void __exit kset_test_exit(void)
{
kobject_put(testKobj);
}
module_init(kset_test_init);
module_exit(kset_test_exit);
MODULE_AUTHOR("hrma");
MODULE_LICENSE("GPL");
则有如下两个属性:
cd /sys/test;ls
name_attri
para_attri
三 kset
kset是包含多个kobject的集合,即 为相同类型的kobject集合,为kobject更高一级的组织形式
struct kset {
//用于链接kset中所有kobject的链表 头部
struct list_head list;
spinlock_t list_lock;
//为内嵌的kobject,其kset本身也可以认为是一个kobject,可以使用该字段链接到更上一层的结构,用于构建更复杂的拓扑结构
struct kobject kobj;
//事件操作集合
const struct kset_uevent_ops *uevent_ops;
} __randomize_layout;
如果需要在sysfs的目录中包含多个子目录,那需要将它定义成一个kset。sysfs中的设备组织结构很大程度上根据kset组织的,/sys/bus目录就是一个kset对象,在Linux设备模型中,注册设备或驱动时就将kobject添加到对应的kset中。
使用:
1:创建一个kset
2: 创建一个kobject,将该kobject指向该kset
3:将kobject添加到sysfs,此时不需要指定parent,可以根据设置的kset 自动按照所属的kset层级进行添加
kset部分就这些,kobject以及其属性部分不变。
博客围绕Linux内核sysfs文件系统展开,介绍了kobject、kobj_type属性和kset。kobject用于组织拓扑关系,sysfs中一个目录对应一个;kobj_type属性是内核与用户空间信息交互方法;kset是多个kobject的集合,用于组织sysfs目录结构。
1394

被折叠的 条评论
为什么被折叠?



