Linux Device Model (kobject, kset, and Subsystem) (2), kobjectkset
1. kobject Structure
In the Linux kernel, kobject is the basis of the Linux device model. A kobject corresponds to a directory in sysfs. From the object-oriented perspective, kobject can be considered as the base class of all Device objects, because the C language does not have the object-oriented syntax, therefore, we usually embed kobject into other structs to implement similar functions. Other structs here can be considered as the derived class of kobject. Kobject provides many useful functions for Linux device models, such as reference counting, interface abstraction, and parent-child relationship. In essence, the reference count is implemented using kref.
In addition, the Linux device model has an important data structure kset. Kset itself is also a kobject, so it is also represented as a directory in sysfs, But it differs from kobject in that kset can be seen as a container, if you compare it to the container class in C ++, such as list. Kset can be used as a container. It is embedded with a bidirectional linked list structure, struct list_head.
Description of kobject in Kernel
View plaincopy
Structkobject {
Constchar * name;
Structlist_headentry;
Structkobject * parent;
Structkset * kset;
Structkobj_type * ktype;
Structsysfs_dirent * sd;
Structkrefkref;
Unsignedintstate_initialized: 1;
Unsignedintstate_in_sysfs: 1;
Unsignedintstate_add_uevent_sent: 1;
Unsignedintstate_remove_uevent_sent: 1;
Unsignedintuevent_suppress: 1;
};
The devices in the kernel are organized in a tree. In this organizational structure, the upper-layer nodes can be regarded as the parent nodes of the lower-layer nodes, the relationship between the parent directory and the sub-directory is reflected in sysfs. In the kernel, It is kobject that helps us implement this parent-child relationship. In the definition of kobject, name indicates the name of kobject in sysfs; pointer parent is used to point to the parent object of kobject; Kref should be familiar to everyone, and kobject uses it to implement reference counting; the Kset pointer is used to point to the kset to which the kobject belongs. The usage of the kset is described in detail below. For the ktype, if it is just as intended, it should be used to describe the type information of the kobject. Ktype is defined as follows:
View plaincopy
Structkobj_type {
Void (* release) (structkobject * kobj );
Conststructsysfs_ops * sysfs_ops;
Structattribute ** default_attrs;
}; Function pointer release is used by kref. When the reference count is 0, the function pointed to by this pointer will be called to release the memory. What is the use of sysfs_ops and attribute? As mentioned above, a kobject corresponds to a directory in sysfs, and the files in the directory are implemented by sysfs_ops and attribute. attribute defines the attributes of kobject, corresponds to a file in sysfs, and sysfs_ops is used to define the method for reading and writing this file. Attribute in Ktype is the default attribute, and more flexible means can be used. This article focuses on default attribute.
View plaincopy
# Include
# Include
# Include
# Include
Structmy_kobj {// embedded structure of kobject
Intval;
Structkobjectkobj;
};
Structmy_kobj * obj1, * obj2;
Structkobj_typemy_type;
Structattributename_attr = {
. Name = "name", // file name
. Mode = 0444, // specify the object access permission
};
Structattributeval_attr = {
. Name = "val", // file name
. Mode = 0666, // specify the object access permission
};
Structattribute * my_attrs [] = {
& Name_attr,
& Val_attr,
NULL,
};
/*
The name variable in the structure structattribute is used to specify the file name, and the mode variable is used to specify the file access permission.
It should be noted that the last entry of the array my_attrs must be NULL, otherwise it will cause the kernel oops.
*/
Ssize_tmy_show (structkobject * kobj, structattribute * attr, char * buffer)
{
Structmy_kobj * obj = container_of (kobj, structmy_kobj, kobj );
Ssize_tcount = 0;
If (strcmp (attr-> name, "name") = 0 ){
Count = sprintf (buffer, "% s \ n", kobject_name (kobj ));
} Elseif (strcmp (attr-> name, "val") = 0 ){
Count = sprintf (buffer, "% d \ n", obj-> val );
}
Returncount;
}
Ssize_tmy_store (structkobject * kobj, structattribute * attr, constchar * buffer, size_tsize)
{
Structmy_kobj * obj = container_of (kobj, structmy_kobj, kobj );
If (strcmp (attr-> name, "val") = 0 ){
Sscanf (buffer, "% d", & obj-> val );
}
Returnsize;
}
Structsysfs_opsmy_sysfsops = {
. Show = my_show,
. Store = my_store,
};
Voidobj_release (structkobject * kobj)
{
Structmy_kobj * obj = container_of (kobj, structmy_kobj, kobj );
Printk (KERN_INFO "obj_release % s \ n", kobject_name (& obj-> kobj ));
Kfree (obj );
}
Staticint _ initmykobj_init (void)
{
Printk (KERN_INFO "mykobj_init \ n ");
Obj1 = kzarloc (sizeof (structmy_kobj), GFP_KERNEL); // allocate obj1 and obj2 and assign values
If (! Obj1 ){
Return-ENOMEM;
}
Obj1-> val = 1;
Obj2 = kzarloc (sizeof (structmy_kobj), GFP_KERNEL );
If (! Obj2 ){
Kfree (obj1 );
Return-ENOMEM;
}
Obj2-> val = 2;
My_type.release = obj_release;
My_type.default_attrs = my_attrs;
My_type.sysfs_ops = & my_sysfsops;
Kobject_init_and_add (& obj1-> kobj, & my_type, NULL, "mykobj1");/* function to initialize kobject and add it to the architecture of the device model */
Kobject_init_and_add (& obj2-> kobj, & my_type, & obj1-> kobj, "mykobj2 ");
/*
Kobject_init is used to initialize the kobject structure, and kobject_add is used to add kobj to the device model.
In practice, we first initialize and add obj1. In the call parameter, parent is assigned NULL, indicating that obj1 has no parent object and is reflected in sysfs,
The Directory of my_kobj1 will appear under/sys, and the parent object of obj2 will be set to obj1, so the directory of my_kobj2 will appear under/sys/my_kobj1.
As mentioned above, kobject also provides the reference counting function. Although it uses kref in essence, it also provides other interfaces for users to use.
After the kobject_init_and_add and kobject_init functions are called, the reference count of kobj is initialized to 1,
Therefore, remember to use kobject_put to release the reference count when module_exit.
*/
Return0;
}
Staticvoid _ exitmykobj_exit (void)
{
Printk (KERN_INFO "mykobj_exit \ n ");
Kobject_del (& obj2-> kobj);/* First Sub-object, last parent object */
Kobject_put (& obj2-> kobj );
Kobject_del (& obj1-> kobj );
Kobject_put (& obj1-> kobj );
Return;
}
/*
Kobject_del is used to remove kobject from the tree of the device model and delete the corresponding directories in sysfs.
It should be noted that the release sequence should be the first sub-object and the last parent object.
Because the kobject_init_and_add and kobject_add functions call kobject_get to increase the reference count of the parent object,
Therefore, kobject_del needs to call kobject_put to reduce the reference count of the parent object. In this example, If you first release obj1 through kobject_put,
Then kobject_del (& obj2-> kobj) will see a memory error.
*/
Module_init (mykobj_init );
Module_exit (mykobj_exit );
MODULE_LICENSE ("GPL ");