对于sysfs中的每个目录,内核中都会存在一个对应的kobject。
每个kobject都输出一个或多个属性,他们在kobject的sysfs目录中表现为文件,其内容由内核生成,这些内容揭示了kobject和sysfs在底层是如何交互的。
只要调用kobject_add(),就能在sysfs中显示kobject.
一、创建sysfs入口需要注意一下几点:
1.kobject在sysfs中的入口始终都是一个目录,因此调用kobject_add()将在sysfs中创建一个目录。通常这个目录包含一个或多个属性(attr)。
2,分配给kobject的名字就是sysfs中的目录名。该文件名不能包含反斜杠,并强烈建议不要使用空格。
3.sysfs入口在目录中的位置对应于kobject的parent指针。如果调用kobject_add()的时候,parent=null,那么它将被嵌入到新kobject的kset中的kobject,这样sysfs分层结构通常与kset创建的内部结构相匹配。
二、默认属性:
当创建kobject的时候,都会给每个kobject一系列默认属性。这些属性保存在kobj_type结构中。
struct kobj_type {
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops; //提供了实现这些属性的方法。
struct attribute **default_attrs; //默认属性,保存了属性列表,用于创建该类型的每一个kobject。
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};
default_attrs指向一个包含attribute结构数组的指针:
struct attribute {
const char *name; //属性名字,在kobject的sysfs目录中显示.
struct module *owner; //指向模块的指针,该模块负责实现这些属性。
mode_t mode; //用作属性的保护位。
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
default_attrs链表中的最后一个元素必须用0填充。
default_attrs数组只是说明了都有哪些属性,但是并没有告诉sysfs如何真正实现这些属性,所以,这个任务就交给了kobj_type->sysfs_ops成员。这个结构定义在include/linux/sysfs.h中
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
a. 当用户控件读取一个属性时,内核会用指向kobject的指针和属性结构来调用show方法。
b. 当拥有对属性的写权限时,可以调用store函数。
三、非默认属性
如果希望在kobject的sysfs目录中添加新的属性,可以填写一个attribute结构,并把它传递给下面的函数:
/**
* sysfs_create_file - create an attribute file for an object.
* @kobj: object we're creating for.
* @attr: attribute descriptor.
*/
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
{
BUG_ON(!kobj || !kobj->sd || !attr);
return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
}
int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
{
int err = 0;
int i;
for (i = 0; ptr[i] && !err; i++)
err = sysfs_create_file(kobj, ptr[i]);
if (err)
while (--i >= 0)
sysfs_remove_file(kobj, ptr[i]);
return err;
}
调用下面的函数删除一个属性:
/**
* sysfs_remove_file - remove an object attribute.
* @kobj: object we're acting for.
* @attr: attribute descriptor.
*
* Hash the attribute name and kill the victim.
*/
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
{
sysfs_hash_and_remove(kobj->sd, NULL, attr->name);
}
void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr)
{
int i;
for (i = 0; ptr[i]; i++)
sysfs_remove_file(kobj, ptr[i]);
}
四、二进制属性
如果系统中需要load firmware时,会使用二进制sysfs属性将firmware传递给内核。
bin_attribute结构定义如下:
struct bin_attribute {
struct attribute attr; //定义了名字,所有者,二进制属性的权限
size_t size; //制定了二进制属性的最大长度。
void *private;
ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *, //加载过程中调用read/write函数
char *, loff_t, size_t);
ssize_t (*write)(struct file *,struct kobject *, struct bin_attribute *,
char *, loff_t, size_t);
int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
struct vm_area_struct *vma);
};
下面的调用创建和删除二进制属性:sysfs_create_bin_file()/sysfs_remove_bin_file().
/**
* sysfs_create_bin_file - create binary file for object.
* @kobj: object.
* @attr: attribute descriptor.
*/
int sysfs_create_bin_file(struct kobject *kobj,
const struct bin_attribute *attr)
{
BUG_ON(!kobj || !kobj->sd || !attr);
return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
}
/**
* sysfs_remove_bin_file - remove binary file for object.
* @kobj: object.
* @attr: attribute descriptor.
*/
void sysfs_remove_bin_file(struct kobject *kobj,
const struct bin_attribute *attr)
{
sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name);
}
五、符号链接
sysfs文件系统具有树形结构,以反映kobject之间的组织层次关系。
这种关系可以通过建立符号链接实现:sysfs_create_link()/ sysfs_remove_link():
/**
* sysfs_create_link - create symlink between two objects.
* @kobj: object whose directory we're creating the link in.
* @target: object we're pointing to.
* @name: name of the symlink.
*/
int sysfs_create_link(struct kobject *kobj, struct kobject *target,
const char *name)
{
return sysfs_do_create_link(kobj, target, name, 1);
}
/**
* sysfs_delete_link - remove symlink in object's directory.
* @kobj: object we're acting for.
* @targ: object we're pointing to.
* @name: name of the symlink to remove.
*
* Unlike sysfs_remove_link sysfs_delete_link has enough information
* to successfully delete symlinks in tagged directories.
*/
void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
const char *name)
{
const void *ns = NULL;
spin_lock(&sysfs_assoc_lock);
if (targ->sd && sysfs_ns_type(kobj->sd))
ns = targ->sd->s_ns;
spin_unlock(&sysfs_assoc_lock);
sysfs_hash_and_remove(kobj->sd, ns, name);
}
/**
* sysfs_remove_link - remove symlink in object's directory.
* @kobj: object we're acting for.
* @name: name of the symlink to remove.
*/
void sysfs_remove_link(struct kobject * kobj, const char * name)
{
struct sysfs_dirent *parent_sd = NULL;
if (!kobj)
parent_sd = &sysfs_root;
else
parent_sd = kobj->sd;
sysfs_hash_and_remove(parent_sd, NULL, name);
}