sysfs--kset, kobj, kobj_type

博客围绕Linux内核sysfs文件系统展开,介绍了kobject、kobj_type属性和kset。kobject用于组织拓扑关系,sysfs中一个目录对应一个;kobj_type属性是内核与用户空间信息交互方法;kset是多个kobject的集合,用于组织sysfs目录结构。
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以及其属性部分不变。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ma浩然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值