新闻资讯
Group news
青岛广盛源肥业有限公司    您的位置: 首页  >  新闻资讯  >  正文

Linux设备模型:sysfs

2019年10月11日 文章来源:网络整理 热度:55℃ 作者:刘英

sysfs是一个基于RAM的文件系统,它和Kobject一起,可以将Kernel的数据结构导出到用户空间,以文件目录结构的形式,提供对这些数据结构(以及数据结构的属性)的访问支持。

sysfs具备文件系统的所有属性,而本文主要侧重其设备模型的特性,因此不会涉及过多的文件系统实现细节,而只介绍sysfs在Linux设备模型中的作用和使用方法。具体包括:

sysfs和Kobject的关系

attribute的概念

sysfs的文件系统操作接口

2. sysfs和Kobject的关系

在"Linux设备模型_Kobject”文章中,有提到过,每一个Kobject,都会对应sysfs中的一个目录。因此在将Kobject添加到Kernel时,create_dir接口会调用sysfs文件系统的创建目录接口,创建和Kobject对应的目录,相关的代码如下:

1: /* lib/kobject.c, line 47 */

2: static int create_dir(struct kobject *kobj)

3: {

4:     int error = 0;

5:     error = sysfs_create_dir(kobj);

6:     if (!error) {

7:         error = populate_dir(kobj);

8:     if (error)

9:         sysfs_remove_dir(kobj);

10:     }

11:     return error;

12: }

13:

14: /* fs/sysfs/dir.c, line 736 */

15: **

16: * sysfs_create_dir - create a directory for an object.

17: * @kobj: object we're creaTIng directory for.

18: */

19: int sysfs_create_dir(struct kobject * kobj)

20: {

21:     enum kobj_ns_type type;

22:     struct sysfs_dirent *parent_sd, *sd;

23:     const void *ns = NULL;

24:     int error = 0;

25:     ...

26: }

3. attribute

3.1 attribute的功能概述

在sysfs中,为什么会有attribute的概念呢?其实它是对应kobject而言的,指的是kobject的“属性”。我们知道,

sysfs中的目录描述了kobject,而kobject是特定数据类型变量(如struct device)的体现。因此kobject的属性,就是这些变量的属性。它可以是任何东西,名称、一个内部变量、一个字符串等等。而attribute,在sysfs文件系统中是以文件的形式提供的,即:kobject的所有属性,都在它对应的sysfs目录下以文件的形式呈现。这些文件一般是可读、写的,而kernel中定义了这些属性的模块,会根据用户空间的读写操作,记录和返回这些attribute的值。

总结一下:所谓的atTIbute,就是内核空间和用户空间进行信息交互的一种方法。例如某个driver定义了一个变量,却希望用户空间程序可以修改该变量,以控制driver的运行行为,那么就可以将该变量以sysfs attribute的形式开放出来。

Linux内核中,attribute分为普通的attribute和二进制attribute,如下:

1: /* include/linux/sysfs.h, line 26 */

2: struct attribute {

3:     const char *name;

4:     umode_t mode;

5: #ifdef CONFIG_DEBUG_LOCK_ALLOC

6:     bool ignore_lockdep:1;

7:     struct lock_class_key *key;

8:     struct lock_class_key skey;

9: #endif

10: };

11:

12: /* include/linux/sysfs.h, line 100 */

13: struct bin_attribute {

14:     struct attribute attr;

15:     size_t size;

16:     void *private;

17:     ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,

18:                     char *, loff_t, size_t);

19:     ssize_t (*write)(struct file *,struct kobject *, struct bin_attribute *,

20:                     char *, loff_t, size_t);

21:     int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,

22:                     struct vm_area_struct *vma);

23: };

struct attribute为普通的attribute,使用该attribute生成的sysfs文件,只能用字符串的形式读写(后面会说为什么)。而struct bin_attribute在struct attribute的基础上,增加了read、write等函数,因此它所生成的sysfs文件可以用任何方式读写。

说完基本概念,我们要问两个问题:

Kernel怎么把attribute变成sysfs中的文件呢?

用户空间对sysfs的文件进行的读写操作,怎么传递给Kernel呢?

下面来看看这个过程。

3.2 atTIbute文件的创建

在linux内核中,atTIbute文件的创建是由fs/sysfs/file.c中sysfs_create_file接口完成的,该接口的实现没有什么特殊之处,大多是文件系统相关的操作,和设备模型没有太多的关系,这里先略过不提。

3.3 attibute文件的read和write

看到3.1章节struct attribute的原型时,也许我们会犯嘀咕,该结构很简单啊,name表示文件名称,mode表示文件模式,其它的字段都是内核用于debug Kernel Lock的,那文件操作的接口在哪里呢?

不着急,我们去fs/sysfs目录下看看sysfs相关的代码逻辑。

所有的文件系统,都会定义一个struct file_operations变量,用于描述本文件系统的操作接口,sysfs也不例外:

1: /* fs/sysfs/file.c, line 472 */

2: const struct file_operations sysfs_file_operations = {

3:     .read = sysfs_read_file,

4:     .write = sysfs_write_file,

5:     .llseek = generic_file_llseek,

6:     .open = sysfs_open_file,

7:     .release = sysfs_release,

8:     .poll = sysfs_poll,

9: };

attribute文件的read操作,会由VFS转到sysfs_file_operations的read(也就是sysfs_read_file)接口上,让我们大概看一下该接口的处理逻辑。

1: /* fs/sysfs/file.c, line 127 */

2: static ssize_t

3: sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)

4: {

5:     struct sysfs_buffer * buffer = file->private_data;

6:     ssize_t retval = 0;

7:

8:     mutex_lock(&buffer->mutex);

9:     if (buffer->needs_read_fill || *ppos == 0) {

10:        retval = fill_read_buffer(file->f_path.dentry,buffer);

11:        if (retval)

12:            goto out;

13:    }

14: ...

15: }

16: /* fs/sysfs/file.c, line 67 */

17: static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)

18: {

19:    struct sysfs_dirent *attr_sd = dentry->d_fsdata;

20:    struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;

21:    const struct sysfs_ops * ops = buffer->ops;

22:    ...

23:    count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);

24:    ...

25: }

上一篇:嵌入式linux,一个发烧友不能错过的东西!


下一篇:Linux内核,必要了解的编译知识

友情链接
Links