备注:内核版本:5.4
一、重要结构体
device.h (msm-5.4\include\linux)
struct attribute {
const char *name;
umode_t mode;
...
};
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);
};
struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *, struct attribute *, int);
umode_t (*is_bin_visible)(struct kobject *, struct bin_attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
struct driver_attribute { // 驱动属性文件
struct attribute attr;
ssize_t (*show)(struct device_driver *driver, char *buf);
ssize_t (*store)(struct device_driver *driver, const char *buf,
size_t count);
};
1. 驱动开发中我们通常使用
static DEVICE_ATTR_RW(xxx);
static DEVICE_ATTR_RO(xxx);
static DEVICE_ATTR_WO(xxx);
//如drm_sysfs.c (msm-5.4/drivers/gpu/drm)
static DEVICE_ATTR_RW(status);
static DEVICE_ATTR_RO(enabled);
static DEVICE_ATTR_RO(dpms);
static DEVICE_ATTR_RO(modes);
static struct attribute *connector_dev_attrs[] = {
&dev_attr_status.attr,
&dev_attr_enabled.attr,
&dev_attr_dpms.attr,
&dev_attr_modes.attr,
NULL
};
2. 宏展开
#define DEVICE_ATTR_RW(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
//sysfs.h (msm-5.4\include\linux)
#define __ATTR_RO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \
.show = _name##_show, \
}
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
#define __ATTR(_name, _mode, _show, _store) { \
.attr = {.name = __stringify(_name), \
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
.show = _show, \
.store = _store, \
}
static device_attribute dev_attr_status = {
.attr = {
.name = "status",
.mode = 0644
},
.show = status_show,
.store = status_store,
}
二、kernel API
struct device *device_create_with_groups(struct class *class,
struct device *parent, dev_t devt,
void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...) //函数创建设备和一堆属性文件
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp)//函数创建一堆属性文件
extern int device_create_file(struct device *device,
const struct device_attribute *entry);//函数创建单个文件
extern void device_remove_file(struct device *dev,
const struct device_attribute *attr);//函数删除单个文件
struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent,
const char *name) // 通过sysfs属性文件名字获取struct kernfs_node
void sysfs_notify_dirent(struct kernfs_node *kn) //用上面函数获取到的struct kernfs_node去唤醒在读写属性文件(sysfs节点)时因调用select()或poll()而阻塞的用户进程
void sysfs_notify(struct kobject *kobj, const char *dir,
const char *attr) //用于用来唤醒在读写属性文件(sysfs节点)时因调用select()或poll()而阻塞的用户进程
注意:sysfs 属性文件poll()或者select()的时候 fd.events 只能包含 POLLPRI | POLLERR,不然会阻塞不住
API使用举例
kernel 举例
sde_crtc.c (msm-5.4/techpack/display/msm/sde)
1、通过 int device_create_with_groups(struct kobject *kobj, const struct attribute_group *grp)创建一堆属性文件
static DEVICE_ATTR_RO(vsync_event);
static DEVICE_ATTR_RO(measured_fps);
static DEVICE_ATTR_RW(fps_periodicity_ms);
static struct attribute *sde_crtc_dev_attrs[] = {
&dev_attr_vsync_event.attr,
&dev_attr_measured_fps.attr,
&dev_attr_fps_periodicity_ms.attr,
NULL
};
static const struct attribute_group sde_crtc_attr_group = {
.attrs = sde_crtc_dev_attrs,
};
static const struct attribute_group *sde_crtc_attr_groups[] = {
&sde_crtc_attr_group,
NULL,
};
int sde_crtc_post_init(struct drm_device *dev, struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc;
int rc = 0;
...
sde_crtc = to_sde_crtc(crtc);
sde_crtc->sysfs_dev = device_create_with_groups(
dev->primary->kdev->class, dev->primary->kdev, 0, crtc,
sde_crtc_attr_groups, "sde-crtc-%d", crtc->index); // 创建设备和一堆属性文件,下面分析device_create_with_groups函数创建设备和属性文件的函数调用过程
分析函数调用
struct device *device_create_with_groups(struct class *class,
struct device *parent, dev_t devt,
void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...)
|-->device_create_groups_vargs(class, parent, devt, drvdata, groups, fmt, vargs);
|-->dev->groups = groups;
|-->device_add(dev);
|-->device_add_attrs(dev);
|-->device_add_groups(dev, dev->groups);
|-->sysfs_create_groups(&dev->kobj, groups); 熟悉的api
|-->internal_create_groups(kobj, 0, groups);
|-->internal_create_group(kobj, update, groups[i]);
|-->kernfs_create_dir_ns(kobj->sd, grp->name, S_IRWXU | S_IRUGO | S_IXUGO, uid, gid, kobj, NULL);
|-->create_files(kn, kobj, uid, gid, grp, update);
如手机sysfs文件系统中呈现:
venus:/sys/class/drm/sde-crtc-0 # ls -l
total 0
lrwxrwxrwx 1 root root 0 2020-10-20 19:06 device -> ../../card0
-rw-r--r-- 1 root root 4096 2020-10-20 19:06 fps_periodicity_ms ######
-r--r--r-- 1 root root 4096 2020-10-20 19:06 measured_fps ######
drwxr-xr-x 2 root root 0 2020-10-20 19:06 power
lrwxrwxrwx 1 root root 0 2020-10-20 19:06 subsystem -> ../../../../../../../class/drm
-rw-r--r-- 1 root root 4096 2020-10-20 19:06 uevent
-r--r--r-- 1 root root 4096 2020-10-20 19:06 vsync_event ######
....
2、通过sysfs_get_dirent api 获取属性文件的struct kernfs_node
sde_crtc->vsync_event_sf = sysfs_get_dirent(
sde_crtc->sysfs_dev->kobj.sd, "vsync_event");
sde_crtc->retire_frame_event_sf = sysfs_get_dirent(
sde_crtc->sysfs_dev->kobj.sd, "retire_frame_event");
3、当属性文件内容变化的时候通知唤醒
static void sde_crtc_vblank_cb(void *data)
{
struct drm_crtc *crtc = (struct drm_crtc *)data;
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
/* keep statistics on vblank callback - with auto reset via debugfs */
if (ktime_compare(sde_crtc->vblank_cb_time, ktime_set(0, 0)) == 0)
sde_crtc->vblank_cb_time = ktime_get();
else
sde_crtc->vblank_cb_count++;
sde_crtc->vblank_last_cb_time = ktime_get();
sysfs_notify_dirent(sde_crtc->vsync_event_sf); #######
drm_crtc_handle_vblank(crtc);
DRM_DEBUG_VBL("crtc%d\n", crtc->base.id);
SDE_EVT32_VERBOSE(DRMID(crtc));
}
2 应用举例
上层应用程序通过poll()或者select()sysfs属性文件的简单使用例子
int fd = open("/sys/class/drm/sde-crtc-0/vsync_event", O_RDONLY);
struct pollfd test_poll;
test_poll.fd = fd;
test_poll.events = POLLERR | POLLPRI;
for(;;) {
ret = poll(&test_poll, 1, -1);
if (ret <= 0) {
printf("poll error\n");
continue;
} else {
if (test_poll.revents & POLLPRI) {
if(read(fd, buf, 64)) {
...
} else {
...
}
} else {
...
}
}
}
三、API分析
struct device *device_create_with_groups(struct class *class,
struct device *parent, dev_t devt,
void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...)
|-->device_create_groups_vargs(class, parent, devt, drvdata, groups, fmt, vargs);
|-->dev->groups = groups;
|-->device_add(dev);
|-->device_add_attrs(dev);
|-->device_add_groups(dev, dev->groups);
|-->sysfs_create_groups(&dev->kobj, groups); 熟悉的api
|-->internal_create_groups(kobj, 0, groups);
|-->internal_create_group(kobj, update, groups[i]);
|-->kernfs_create_dir_ns(kobj->sd, grp->name, S_IRWXU | S_IRUGO | S_IXUGO, uid, gid, kobj, NULL);
|-->create_files(kn, kobj, uid, gid, grp, update);
|--> sysfs_add_file_mode_ns(parent, *attr, false, mode, uid, gid, NULL);
sysfs_create_file(struct kobject *kobj, const struct attribute *attr)
|--> sysfs_create_file_ns(kobj, attr, NULL);
|--> sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, uid, gid, ns);
创建属性文件的内部最后都是调用sysfs_add_file_mode_ns()函数
int sysfs_add_file_mode_ns(struct kernfs_node *parent,
const struct attribute *attr, bool is_bin,
umode_t mode, kuid_t uid, kgid_t gid, const void *ns)
{
struct lock_class_key *key = NULL;
const struct kernfs_ops *ops;
struct kernfs_node *kn;
loff_t size;
if (!is_bin) {
struct kobject *kobj = parent->priv;
const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops;
/* every kobject with an attribute needs a ktype assigned */
if (WARN(!sysfs_ops, KERN_ERR
"missing sysfs attribute operations for kobject: %s\n",
kobject_name(kobj)))
return -EINVAL;
if (sysfs_ops->show && sysfs_ops->store) {
if (mode & SYSFS_PREALLOC)
ops = &sysfs_prealloc_kfops_rw;
else
ops = &sysfs_file_kfops_rw; ############## 记住挂上来的结构体 struct kernfs_ops *ops = &sysfs_file_kfops_rw
} else if (sysfs_ops->show) {
if (mode & SYSFS_PREALLOC)
ops = &sysfs_prealloc_kfops_ro;
else
ops = &sysfs_file_kfops_ro; ############## 记住挂上来的结构体 struct kernfs_ops *ops = &sysfs_file_kfops_ro
} else if (sysfs_ops->store) {
if (mode & SYSFS_PREALLOC)
ops = &sysfs_prealloc_kfops_wo;
else
ops = &sysfs_file_kfops_wo; ############## 记住挂上来的结构体 struct kernfs_ops *ops = &sysfs_file_kfops_wo
} else
ops = &sysfs_file_kfops_empty;
size = PAGE_SIZE;
} else {
struct bin_attribute *battr = (void *)attr;
if (battr->mmap)
ops = &sysfs_bin_kfops_mmap;
else if (battr->read && battr->write)
ops = &sysfs_bin_kfops_rw;
else if (battr->read)
ops = &sysfs_bin_kfops_ro;
else if (battr->write)
ops = &sysfs_bin_kfops_wo;
else
ops = &sysfs_file_kfops_empty;
size = battr->size;
}
#ifdef CONFIG_DEBUG_LOCK_ALLOC
if (!attr->ignore_lockdep)
key = attr->key ?: (struct lock_class_key *)&attr->skey;
#endif
kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
size, ops, (void *)attr, ns, key);
if (IS_ERR(kn)) {
if (PTR_ERR(kn) == -EEXIST)
sysfs_warn_dup(parent, attr->name);
return PTR_ERR(kn);
}
return 0;
}
---------------------
static const struct kernfs_ops sysfs_file_kfops_ro = {
.seq_show = sysfs_kf_seq_show,
};
static const struct kernfs_ops sysfs_file_kfops_wo = {
.write = sysfs_kf_write,
};
static const struct kernfs_ops sysfs_file_kfops_rw = {
.seq_show = sysfs_kf_seq_show,
.write = sysfs_kf_write,
};
---------------------
注意:上面的ops 是struct kernfs_ops *ops,不是struct file_operations,
大家都知道vfs_open、vfs_poll、vfs_read、vfs_write 等调用,最终都是调用到驱动的struct file_operations中挂载的函数
so,下面分析一下sysfs属性文件的struct file_operations 是怎么挂上来的
四、sysfs的mount
init 进程mount sysfs文件系统
miui-r-venus-dev/system/core/init/main.cpp
int main(int argc, char** argv)
|-->FirstStageMain(argc, argv);
|-->CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
kernel 注册sysfs文件系统
start_kernel(void) // main.c
|-->vfs_caches_init();
|--> mnt_init(); // namespace.c
|-->kernfs_init();
|-->sysfs_init(); // 我们重点看这个 #########
|-->init_rootfs(); // 创建rootfs文件系统
|-->init_mount_tree(); // mount rootfs文件系统
int __init sysfs_init(void)
{
int err;
sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,NULL);
sysfs_root_kn = sysfs_root->kn;
err = register_filesystem(&sysfs_fs_type);
return 0;
}
static struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.init_fs_context = sysfs_init_fs_context, ########## 在这个函数中将fc->ops = &sysfs_fs_context_ops; 挂载下面的fs_context_operations操作函数集
.kill_sb = sysfs_kill_sb,
.fs_flags = FS_USERNS_MOUNT,
};
static const struct fs_context_operations sysfs_fs_context_ops = {
.free = sysfs_fs_context_free,
.get_tree = sysfs_get_tree, ##########
};
mount sysfs文件系统
当init 进程mount sysfs的时候,驱动层会调用ksys_mount()
mount("sysfs", "/sys", "sysfs", 0, NULL);
// namespace.c (msm-5.4/fs)
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
char __user *, type, unsigned long, flags, void __user *, data)
{
return ksys_mount(dev_name, dir_name, type, flags, data);
}
ksys_mount(dev_name, dir_name, type, flags, data);
|-->do_mount(kernel_dev, dir_name, kernel_type, flags, options);
|-->do_new_mount(&path, type_page, sb_flags, mnt_flags, dev_name, data_page);
|--> type = get_fs_type(fstype); // 如struct file_system_type sysfs_fs_type
|--> fc = fs_context_for_mount(type, sb_flags);
|--> alloc_fs_context(fs_type, NULL, sb_flags, 0, FS_CONTEXT_FOR_MOUNT);
|--> init_fs_context = fc->fs_type->init_fs_context;
|--> ret = init_fs_context(fc); // .init_fs_context = sysfs_init_fs_context,
在这个函数中将fc->ops = &sysfs_fs_context_ops;
|--> fc->ops = &sysfs_fs_context_ops; // 挂载fs_context_operations操作函数集
|-->err = vfs_get_tree(fc);
|--> error = fc->ops->get_tree(fc); // .get_tree = sysfs_get_tree, ######## 3.1小结 后面重点分析
|-->err = do_new_mount_fc(fc, path, mnt_flags);
|--> mnt = vfs_create_mount(fc);
|--> error = do_add_mount(real_mount(mnt), mountpoint, mnt_flags);
3.1小结
static int sysfs_get_tree(struct fs_context *fc)
{
struct kernfs_fs_context *kfc = fc->fs_private;
int ret;
ret = kernfs_get_tree(fc); ######## 3.2小结 下面分析
if (ret)
return ret;
if (kfc->new_sb_created)
fc->root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE;
return 0;
}
3.2小结
kernfs_get_tree(struct fs_context *fc)
|--> kernfs_fill_super(sb, kfc);
|--> inode = kernfs_get_inode(sb, info->root->kn);
|--> kernfs_init_inode(kn, inode);
static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode)
{
kernfs_get(kn);
inode->i_private = kn;
inode->i_mapping->a_ops = &kernfs_aops;
inode->i_op = &kernfs_iops;
inode->i_generation = kn->id.generation;
set_default_inode_attr(inode, kn->mode);
kernfs_refresh_inode(kn, inode);
/* initialize inode according to type */
switch (kernfs_type(kn)) {
case KERNFS_DIR:
inode->i_op = &kernfs_dir_iops;
inode->i_fop = &kernfs_dir_fops;
if (kn->flags & KERNFS_EMPTY_DIR)
make_empty_dir_inode(inode);
break;
case KERNFS_FILE:
inode->i_size = kn->attr.size;
inode->i_fop = &kernfs_file_fops; ########### 终于找到sysfs 文件的struct file_operations操作函数集
break;
case KERNFS_LINK:
inode->i_op = &kernfs_symlink_iops;
break;
default:
BUG();
}
unlock_new_inode(inode);
}
const struct file_operations kernfs_file_fops = {
.read = kernfs_fop_read, #######
.write = kernfs_fop_write, #######
.llseek = generic_file_llseek,
.mmap = kernfs_fop_mmap,
.open = kernfs_fop_open, #######
.release = kernfs_fop_release,
.poll = kernfs_fop_poll, #######
.fsync = noop_fsync,
};
五、应用程序read sysfs属性文件是如何调用到属性文件的show函数的
因为应用程序调用sysfs属性文件的read函数,所以肯定要调用到struct file_operations kernfs_file_fops中的.read = kernfs_fop_read,
先看看kernfs_fop_read函数
static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct kernfs_open_file *of = kernfs_of(file);
if (of->kn->flags & KERNFS_HAS_SEQ_SHOW)
return seq_read(file, user_buf, count, ppos); 1.1 上面分析没有注意KERNFS_HAS_SEQ_SHOW,所有seq_read和kernfs_file_direct_read 分别在下面分析
else
return kernfs_file_direct_read(of, user_buf, count, ppos); 1.2 下面分析
}
1.1分析seq_read
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
|-->m->buf = seq_buf_alloc(m->size = PAGE_SIZE); / 这个地方需要很注意,sysfs属性文件拷贝数据到用户空间,一次只能拷贝一个PAGE_SIZE
|-->p = m->op->start(m, &m->index); // op是 struct seq_operations *op; 这个是怎么挂上来的呢?????????? 猜测是open函数大家sysfs 属性文件节点的时候
|-->err = m->op->show(m, p); // 需要找到这个show函数是哪个????
还记得上面4、sysfs的mount中分析的结果吗:
const struct file_operations kernfs_file_fops = {
.read = kernfs_fop_read,
.write = kernfs_fop_write,
.llseek = generic_file_llseek,
.mmap = kernfs_fop_mmap,
.open = kernfs_fop_open,
.release = kernfs_fop_release,
.poll = kernfs_fop_poll,
.fsync = noop_fsync,
};
sysfs 的struct file_operations是 kernfs_file_fops,所有open的时候会调用.open = kernfs_fop_open,看一下kernfs_fop_open函数
static int kernfs_fop_open(struct inode *inode, struct file *file)
{
if (ops->seq_show) ### 这个有定义吗??ops是 struct kernfs_ops *ops;
error = seq_open(file, &kernfs_seq_ops);
还记得上面3、API分析中sysfs_add_file_mode_ns函数挂载上来的const struct kernfs_ops *ops吗?
截取关键部分:
int sysfs_add_file_mode_ns(struct kernfs_node *parent,
const struct attribute *attr, bool is_bin,
umode_t mode, kuid_t uid, kgid_t gid, const void *ns)
{
...
if (sysfs_ops->show && sysfs_ops->store) {
ops = &sysfs_file_kfops_rw;
} else if (sysfs_ops->show) {
ops = &sysfs_file_kfops_ro;
} else if (sysfs_ops->store) {
ops = &sysfs_file_kfops_wo;
------------
static const struct kernfs_ops sysfs_file_kfops_rw = {
.seq_show = sysfs_kf_seq_show,
.write = sysfs_kf_write,
};
static const struct kernfs_ops sysfs_file_kfops_ro = {
.seq_show = sysfs_kf_seq_show,
};
-------------
也就是sysfs文件只要有read权限就会有seq_show,所有会调用到seq_open(file, &kernfs_seq_ops),将kernfs_seq_ops挂载上来
static const struct seq_operations kernfs_seq_ops = {
.start = kernfs_seq_start,
.next = kernfs_seq_next,
.stop = kernfs_seq_stop,
.show = kernfs_seq_show,
};
所以,上面:
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
|-->p = m->op->start(m, &m->index); // .start = kernfs_seq_start,
|-->err = m->op->show(m, p); // .show = kernfs_seq_show,
static int kernfs_seq_show(struct seq_file *sf, void *v)
{
struct kernfs_open_file *of = sf->private;
of->event = atomic_read(&of->kn->attr.open->event);
return of->kn->attr.ops->seq_show(sf, v); // sysfs_kf_seq_show
}
static int sysfs_kf_seq_show(struct seq_file *sf, void *v)
{
...
const struct sysfs_ops *ops = sysfs_file_ops(of->kn); // 这个函数在1.1小结已经分析
if (ops->show) {
count = ops->show(kobj, of->kn->priv, buf);看下面2、下面会重点分析sysfs_ops是如何挂上的
...
}
static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn)
{
struct kobject *kobj = kn->parent->priv;
if (kn->flags & KERNFS_LOCKDEP)
lockdep_assert_held(kn);
return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; //获取sysfs_ops, 大多数的设备都是dev_sysfs_ops, 在device_initialize中设定
}
#######################################
1.2 分析kernfs_file_direct_read
static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
char __user *user_buf, size_t count,
loff_t *ppos)
{
ssize_t len = min_t(size_t, count, PAGE_SIZE);
buf = kmalloc(len, GFP_KERNEL); // 这个地方需要很注意,sysfs属性文件拷贝数据到用户空间,一次只能拷贝一个PAGE_SIZE
ops = kernfs_ops(of->kn);
if (ops->read)
len = ops->read(of, buf, len, *ppos); //上面3、API分析 中的分析sysfs_add_file_mode_ns 现在派上用场
----------------
if (sysfs_ops->show && sysfs_ops->store) {
if (mode & SYSFS_PREALLOC)
ops = &sysfs_prealloc_kfops_rw;
else
ops = &sysfs_file_kfops_rw;
----------------
220static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
221 .read = sysfs_kf_read,
222 .write = sysfs_kf_write,
223 .prealloc = true,
224};
static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
size_t count, loff_t pos)
{
const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
struct kobject *kobj = of->kn->parent->priv;
ssize_t len;
/*
* If buf != of->prealloc_buf, we don't know how
* large it is, so cannot safely pass it to ->show
*/
if (WARN_ON_ONCE(buf != of->prealloc_buf))
return 0;
len = ops->show(kobj, of->kn->priv, buf);
if (len < 0)
return len;
if (pos) {
if (len <= pos)
return 0;
len -= pos;
memmove(buf, buf + pos, len);
}
return min_t(ssize_t, count, len);
}
下面分析sysfs_ops是如何挂上的
int device_register(struct device *dev)
{
device_initialize(dev); // 调用 kobject_init(&dev->kobj, &device_ktype);
return device_add(dev);
}
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
...
}
static struct kobj_type device_ktype = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops, ########## 属性文件的sysfs_ops 操作函数集就是这样挂上来的, 2.1小结, 继续分析
.namespace = device_namespace,
.get_ownership = device_get_ownership,
};
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
kobject_init_internal(kobj);
kobj->ktype = ktype; ####### kobj->ktype = &device_ktype 记住这个
return;
..
}
2.1小结
static const struct sysfs_ops dev_sysfs_ops = {
.show = dev_attr_show,
.store = dev_attr_store,
};
static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct device_attribute *dev_attr = to_dev_attr(attr);
struct device *dev = kobj_to_dev(kobj);
ssize_t ret = -EIO;
if (dev_attr->show)
ret = dev_attr->show(dev, dev_attr, buf); ##### 总于,调用到了我们static DEVICE_ATTR_RW(status)定义的show函数,store函数类似,就不分析了
return ret;
}
六、验证上面的分析
最简单的方法,在属性文件的show和store函数中打印dump_stack()
如drm_sysfs.c (msm-5.4/drivers/gpu/drm)
static DEVICE_ATTR_RW(status);
static ssize_t status_store(struct device *device,struct device_attribute *attr,const char *buf, size_t count)
static ssize_t status_show(struct device *device, struct device_attribute *attr, char *buf)
分别打印dump_stack()看一下函数调用栈
cat /sys/class/drm/card0-DSI-1/status
[ 89.689473] Call trace:
[ 89.689494] dump_backtrace.cfi_jt+0x0/0x4
[ 89.689508] show_stack+0x18/0x24
[ 89.689522] dump_stack+0xe0/0x160
[ 89.689538] status_show+0x1c/0x70
[ 89.689561] dev_attr_show+0x48/0xa8
[ 89.689577] sysfs_kf_seq_show+0xb8/0x14c
[ 89.689585] kernfs_seq_show+0x48/0x84
[ 89.689607] seq_read+0x1c8/0x5b8
[ 89.689614] kernfs_fop_read+0x64/0x1cc
[ 89.689630] __vfs_read+0x60/0x204
[ 89.689636] vfs_read+0xbc/0x15c
[ 89.689643] ksys_read+0x78/0xe4
[ 89.689649] __arm64_sys_read+0x1c/0x28
[ 89.689661] el0_svc_common+0xb8/0x1a8
[ 89.689666] el0_svc_handler+0x74/0x98
[ 89.689674] el0_svc+0x8/0xc
echo on > /sys/class/drm/card0-DSI-1/status
[ 121.242235] Call trace:
[ 121.242263] dump_backtrace.cfi_jt+0x0/0x4
[ 121.242283] show_stack+0x18/0x24
[ 121.242302] dump_stack+0xe0/0x160
[ 121.242324] status_store+0x2c/0x180
[ 121.242344] dev_attr_store+0x34/0x80
[ 121.242363] sysfs_kf_write+0x60/0xb8
[ 121.242374] kernfs_fop_write+0x124/0x1b8
[ 121.242397] __vfs_write+0x60/0x20c
[ 121.242409] vfs_write+0xe4/0x1a8
[ 121.242422] ksys_write+0x78/0xe4
[ 121.242434] __arm64_sys_write+0x1c/0x28
[ 121.242449] el0_svc_common+0xb8/0x1a8
[ 121.242460] el0_svc_handler+0x74/0x98
[ 121.242478] el0_svc+0x8/0xc
dump_stack验证结果符合代码分析