kset的定义在前文已有描述,我们再回顾一下:
struct kset {
/*与子kobject的entry成员组成链表*/
struct list_head list;
/*自旋锁*/
spinlock_t list_lock;
/*kobject*/
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
kset的创建函数为kset_create_and_add,详细如下:
/**
* kset_create_and_add - create a struct kset dynamically and add it to sysfs
*
* @name: the name for the kset
* @uevent_ops: a struct kset_uevent_ops for the kset
* @parent_kobj: the parent kobject of this kset, if any.
*
* This function creates a kset structure dynamically and registers it
* with sysfs. When you are finished with this structure, call
* kset_unregister() and the structure will be dynamically freed when it
* is no longer being used.
*
* If the kset was not able to be created, NULL will be returned.
*/
struct kset *kset_create_and_add(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int error;
/*创建kset对象*/
kset = kset_create(name, uevent_ops, parent_kobj);
if (!kset)
return NULL;
/*注册kset*/
error = kset_register(kset);
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
它调用了kset_create和kset_register函数。
下面看kset_create的实现:
/**
* kset_create - create a struct kset dynamically
*
* @name: the name for the kset
* @uevent_ops: a struct kset_uevent_ops for the kset
* @parent_kobj: the parent kobject of this kset, if any.
*
* This function creates a kset structure dynamically. This structure can
* then be registered with the system and show up in sysfs with a call to
* kset_register(). When you are finished with this structure, if
* kset_register() has been called, call kset_unregister() and the
* structure will be dynamically freed when it is no longer being used.
*
* If the kset was not able to be created, NULL will be returned.
*/
static struct kset *kset_create(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int retval;
/*申请空间*/
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
if (!kset)
return NULL;
/*设置kset的kobject名称*/
retval = kobject_set_name(&kset->kobj, name);
if (retval) {
kfree(kset);
return NULL;
}
kset->uevent_ops = uevent_ops;
/*设置kobject的parent*/
kset->kobj.parent = parent_kobj;
/*
* The kobject of this kset will have a type of kset_ktype and belong to
* no kset itself. That way we can properly free it when it is
* finished being used.
*/
/*设置kobject的ktype,为系统定义好的ktype*/
kset->kobj.ktype = &kset_ktype;
/*设置kobject的kset为NULL*/
kset->kobj.kset = NULL;
return kset;
}
kset_create函数主要对ket的kobj成员进行初始化和设置。按面向对象来说,kset可以视为kobject的子类:
1)调用kobject_set_name函数设置kobject的名称
2)设置kobject的parent为传入的形参parent_kobj
3)设置kobject的ktype为系统定义好的ktype变量
4)设置kobject的所属kset为NULL,意思是kobject所属的kset就是kset本身,因为kset结构体包含了kobject成员。
kset_register的实现如下:
/**
* kset_register - initialize and add a kset.
* @k: kset.
*/
int kset_register(struct kset *k)
{
int err;
if (!k)
return -EINVAL;
/*初始化kset的kobject,和list链表*/
kset_init(k);
/*初始化kobject,创建对应的sys目录*/
err = kobject_add_internal(&k->kobj);
if (err)
return err;
kobject_uevent(&k->kobj, KOBJ_ADD);
return 0;
}
kset_register的关键内容:
1)调用kset_init函数,它的实现如下:
/**
* kset_init - initialize a kset for use
* @k: kset
*/
void kset_init(struct kset *k)
{
/*初始化kobject*/
kobject_init_internal(&k->kobj);
/*初始化以list成员为头结点的链表,它和子kobject的entry成员组成链表*/
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
可以看到,kset_init调用了kobject_init_internal来初始化kobject,kobject_init_internal在【kobject创建流程】中我们已有描述。
1)调用kobject_add_internal初始化kobject,此函数前文已有描述,主要创建kobject的sys目录。
2)需要注意的是,删除kset的时候,必须调用kset_unregister函数释放相应的空间。
#include
#include
#include
#include
#include
#include
#include
#include
/*kset变量*/
static struct kset *m_kset;
/**********************************************************/
/*模块加载函数*/
static int __init kset_module_init(void)
{
m_kset = kset_create_and_add("kset_demo1", NULL, NULL);
if (!m_kset) {
goto out;
}
printk("%s success.\n", __FUNCTION__);
return 0;
out:
printk("%s failed!\n", __FUNCTION__);
return -1;
}
/*模块退出函数*/
static void __exit kset_module_exit(void)
{
//删除set
kset_unregister(m_kset);
printk("%s\n", __FUNCTION__);
}
module_init(kset_module_init);
module_exit(kset_module_exit);
MODULE_AUTHOR("tonny");
MODULE_DESCRIPTION("kset demo");
MODULE_LICENSE("GPL");
编译并运行:
# insmod kset_demo1.ko
# dmesg
[1056355.652305] kset_module_init success.
# ls /sys/
block bus class dev devices firmware fs hypervisor kernel kset_demo1 module power
# rmmod kset_demo1.ko
# dmesg
[1056355.652305] kset_module_init success.
[1056382.292335] kset_module_exit
可以看到,加载kset_demo1.ko后,在/sys目录下多了一个kset_demo1目录。
#include
#include
#include
#include
#include
#include
#include
#include
/*kset变量*/
static struct kset *m_kset;
/*kobject变量*/
static struct kobject m_kobj;
/*
struct attribute {
const char *name;
mode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
*/
/*struct attribute变量*/
static struct attribute m_attr = {
.name = "name",
.mode = S_IRWXUGO,
};
/*attribute数组*/
static struct attribute *m_attrs[] = {
&m_attr,
NULL,
};
/**********************************************************/
//sysfs_ops
/*
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
*/
/*sysfs_ops的show函数实现*/
static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
ssize_t count = 0;
printk("%s\n", __FUNCTION__);
count = sprintf(buf, "%s\n", kobject_name(kobj) );
return count;
}
/*sysfs_ops的store函数实现*/
static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
printk("%s\n", __FUNCTION__);
return 0;
}
/*struct sysfs_ops变量*/
static struct sysfs_ops m_sys_ops = {
.show = kobj_attr_show,
.store = kobj_attr_store,
};
/**********************************************************/
//kobj_type
/*kobj_type的release函数实现*/
void kobj_release(struct kobject *kobj)
{
printk("%s\n", __FUNCTION__);
}
static struct kobj_type m_ktype = {
.release = kobj_release,
.sysfs_ops = &m_sys_ops,
.default_attrs = m_attrs,
};
/**********************************************************/
/*模块加载函数*/
static int __init kobj_init(void)
{
int error = 0;
//创建kset
m_kset = kset_create_and_add("kset_demo2", NULL, NULL);
if(!m_kset){
goto out;
}
//创建kobject,并把它的父kobject指向kset的kobject成员
error = kobject_init_and_add(&m_kobj, &m_ktype, &m_kset->kobj, "kobj_demo1");
if(error){
//初始化失败后必须调用kobject_put清理相关内容
goto out1;
}
printk("%s success.\n", __FUNCTION__);
return 0;
out1:
//使引用计数减1并调用kobj_type的release函数
kobject_put(&m_kobj);
out:
printk("%s failed!\n", __FUNCTION__);
return error;
}
static void __exit kobj_exit(void)
{
//删除kobject
kobject_del(&m_kobj);
//使引用计数减1并调用kobj_type的release函数
kobject_put(&m_kobj);
//删除kset
kset_unregister(m_kset);
printk("%s\n", __FUNCTION__);
}
module_init(kobj_init);
module_exit(kobj_exit);
MODULE_AUTHOR("tonny");
MODULE_DESCRIPTION("kset demo");
MODULE_LICENSE("GPL");
FILE=kset_demo2
obj-m:=$(FILE).o
KERNELBUILD :=/lib/modules/$(shell uname -r)/build
default:
make -C $(KERNELBUILD) M=$(shell pwd) modules
echo insmod/rmmod ./$(FILE).ko to load or uninstall
clean:
rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions
insmod kset_demo2.ko
# dmesg
[2081793.060586] kobj_init success.
# ls /sys/kset_demo2/
kobj_demo1
# cat /sys/kset_demo2/kobj_demo1/name
kobj_demo1
# rmmod kset_demo2.ko
# dmesg
[2081793.060586] kobj_init success.
[2081822.043931] kobj_attr_show
[2081838.532606] kobj_release
[2081838.532616] kobj_exit
sysfs的目录层次图:
我们再来回顾/sys的目录层次,