sysfs设备节点创建分析
sysfs是一种基于ram的文件系统,它提供了一种用于向用户空间展现内核空间里的对象、属性和链接。
1、使用流程
1.1、使用DEVICE_ATTR设置设备属性。
DEVICE_ATTR的定义如下
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
@_name:名称,也就是将在sys fs中生成的文件名称。
@_mode:上述文件的访问权限,与普通文件相同,UGO的格式。
@_show:显示函数,cat该文件时,此函数被调用。
@_store:写函数,echo内容到该文件时,此函数被调用。
#define __ATTR(_name, _mode, _show, _store) {
\
.attr = {
.name = __stringify(_name), \
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
.show = _show, \
.store = _store, \
}
例如:
static DEVICE_ATTR(register, S_IWUSR | S_IRUGO, reg_show, reg_store);
将上式展开为
struct device_attribute dev_attr_register =
{
.attr = {
.name = __stringify(register),
.mode = VERIFY_OCTAL_PERMISSIONS(S_IWUSR | S_IRUGO) },
.show = reg_show,
.store = reg_store,
}
device_attribute 的定义为
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
1.2、创建属性文件
1.2.1 如果只需要创建一个属性文件
直接使用sysfs_create_file创建即可。
static inline int __must_check sysfs_create_file(struct kobject *kobj,
const struct attribute *attr)
{
return sysfs_create_file_ns(kobj, attr, NULL);
}
1.2.2 如果需要创建多个属性文件
例如
static DEVICE_ATTR(register,
S_IWUSR | S_IRUGO,
reg_show, _reg_store);
static DEVICE_ATTR(hw_en,
S_IWUSR | S_IRUGO,
hwen_show, hwen_store);
static DEVICE_ATTR(blink,
S_IWUSR | S_IRUGO,
blink_show, blink_store);
如果要创建register、hw_en和blink三个属性文件,则需要使用属性组创建。
首先定义属性数组。
static struct attribute *led_attributes[] = {
&dev_attr_register.attr,
&dev_attr_hw_en.attr,
&dev_attr_blink.attr,
NULL
};
然后定义属性组
static struct attribute_group led_attribute_group = {
.attrs = led_attributes
};
最后使用sysfs_create_group创建多个属性
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp)
{
return internal_create_group(kobj, 0, grp);
}
这样就可以在sys路径下创建出相应的属性文件。
2、创建过程分析
2.1 创建一个属性文件
由第一节可知创建一个属性文件的起始函数为
int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
const void *ns)
{
kuid_t uid;
kgid_t gid;
if (WARN_ON(!kobj || !kobj->sd || !attr))
return -EINVAL;
kobject_get_ownership(kobj, &uid, &gid);
return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode,
uid, gid, ns);
}
这里会用到sysfs_add_file_mode_ns。而创建多个属性文件同样会用到这个函数。
2.2 创建多个属性文件
由1.2.2可知创建多个属性文件的起始入口为
// fs\sysfs\group.c
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp)
{
return internal_create_group(kobj, 0, grp);
}
// fs\sysfs\group.c
static int internal_create_group(struct kobject *kobj, int update,
const struct attribute_group *grp)
{
struct kernfs_node *kn;
kuid_t uid;
kgid_t gid;
int error;
if (WARN_ON(!kobj || (!update && !kobj->sd)))
return -EINVAL;
/* Updates may happen before the object has been instantiated */
if (unlikely(update && !kobj->sd))
return -EINVAL;
if (!grp->attrs && !grp->bin_attrs) {
WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n",
kobj->name, grp->name ?