一、sysfs简介
1.sysfs就是利用VFS的接口去读写kobject的层次结构,建立起来的文件系统。其更新与删除是那些xxx_register()/unregister()做的事
情。从sysfs中读写就相当于从kobject层提取数据。每当新增一个kobject结构时,就会在sysfs中增加一个目录。kobject对应的是文件
夹,attribute对应的是该文件夹下的文件。它是一个简单的文件系统,不涉及任何硬件驱动。sysfs来源于设备的层次结构,读sysfs文件就是动态地从设备树中寻找相关节点提取信息,然后返回给用户。sysfs是用户
与内核的接口,也是用户与设备的接口,通过读写sysfs文件来查看和改变内核的配置。
2.设备模型支持功能如下:
    1)电源管理和系统关机。
    2)与用户空间通信。将控制接口通过文件的形式暴露给用户空间
    3)支持热插拔。
    4)设备分类。比如找USB鼠标直接去/sys/class/input/里面去找即可,而不用关心它是接在哪个USB控制器的那个hub的哪个端口上。
    5)对象的生命周期。比如U盘拔掉以后,全局设备树和sysfs里面得相应的去掉。
3.sysfs文件用户读show()被调用,用户写store()被调用。
4.sfsfs是一个虚拟的文件系统,没有存储介质,掉电丢失。
mount -t vfat /dev/sda2 /mnt :有存储介质
mount -t sysfs sysfs /sys :没有存储介质
5.fs/sysfs目录下bin.c file.c dir.c symlink.c 分别代表了在sysfs文件系统中当文件类型为二进制文件,普通文件,目录,符号链接时各自的file_operations的实现。

二、sysfs用户空间测试

/sys/bus/usb/drivers_autoprobe:
在bus_register() --> add_probe_files() --> bus_create_file()
属性:S_IWUSR|S_IRUGO
每次向总线注册设备/驱动时,都会通过klist_drivers/klist_devices去匹配驱动/设备,
但是也可以通过bus_register()中创建的这个文件在用户空间使能或禁止这种自动匹配!其实它改的就是:
直接只更改struct bus_type bus->p->drivers_autoprobe的值。

1./sys/bus/usb/drivers_probe:
在bus_register() --> add_probe_files() --> bus_create_file()
属性:S_IWUSR
store(): store_drivers_probe(),如果dev->driver为NULL,下面操作就会重新触发设备匹配驱动
# echo 2-1:1.0 > /sys/bus/usb/drivers_probe
# echo 2-2.1:1.0 > /sys/bus/usb/drivers_probe

插上U盘:
# echo 0 > /sys/bus/usb/drivers_autoprobe
# ls /sys/bus/usb/devices/ 对出 1-2
# echo 1-2 > /sys/bus/usb/drivers_probe 然后多出1-2:1.0
# echo 1-2:1.0 > /sys/bus/usb/drivers_probe 然后/dev/sdb1就产生了!

2./sys/bus/usb/uevent
在bus_register() --> bus_create_file()
属性:S_IWUSR
store(): bus_uevent_store(),
bus和drivers目录下有uevent文件,而devices目录下没有.
可以输入kobject_actions中的字符,由于向用户空间广播事件
# echo add > /sys/bus/usb/uevent
# echo bind > /sys/bus/usb/uevent
# echo online > /sys/bus/usb/uevent

/sys/bus/usb/drivers和devices目录:
在bus_register() --> kset_create_and_add("devices")/kset_create_and_add("drivers")

3.U盘设备文件操作为例:
1)设备和驱动的绑定
/sys/bus/usb/drivers/usb-storage/unbind
函数:unbind_store 属性S_IWUSR,找到设备,然后释放其驱动
echo 1-2:1.0 > /sys/bus/usb/drivers/usb-storage/unbind 然后U盘的设备文件/dev/sdb1就消失了

/sys/bus/usb/drivers/usb-storage/bind
函数:bind_store 属性S_IWUSR,找到设备,然后重新执行match操作
echo 1-2:1.0 > /sys/bus/usb/drivers/usb-storage/bind U盘的设备文件/dev/sdb1重新出现并且挂载了

2)使用动态id_table可以使id动态地增减,增加了灵活性
/sys/bus/usb/drivers/usb-storage/new_id
属性:S_IWUSR | S_IRUGO
函数:
new_id_show :仅仅是打印动态id的厂商设备接口类信息
new_id_store :命令行参数获取:sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct, &bInterfaceClass, &refVendor, &refProduct);
也可以只指定idVendor和idProduct,新创建的动态id挂载usb_driver.dynids链表上,然后调用driver_attach()匹配驱动
# echo 0951 01666 3 4 5 > /sys/bus/usb/drivers/usb-storage/new_id
# echo 0951 01666 > /sys/bus/usb/drivers/usb-storage/new_id
# cat /sys/bus/usb/drivers/usb-storage/new_id

/sys/bus/usb/drivers/usb-storage/remove_id
属性:S_IWUSR | S_IRUGO
函数:
remove_id_show :直接调用的是new_id_show,仅仅打印出可以remove的动态id
remove_id_store :就是直接将此id从usb_driver->dynids.list删除
# echo 0951 01666 > /sys/bus/usb/drivers/usb-storage/remove_id
# cat /sys/bus/usb/drivers/usb-storage/remove_id

三、设备的底层模型

1.kobject

struct kobject {
const char *name; /*恒指向设备名称的指针*/
struct list_head entry; /*使用它挂接在kset中*/
struct kobject *parent; /*指向父对象(可能是kset.kobj)*/
struct kset *kset; /*所属的kset,device_init()中指向为全局devices_kset*/
struct kobj_type *ktype; /*指向其对象类型描述符的指针*/
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref; /*对象的引用计数,通过kobject_get()/kobject_put()访问*/
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:;
unsigned int state_in_sysfs:;
unsigned int state_add_uevent_sent:;
unsigned int state_remove_uevent_sent:;
unsigned int uevent_suppress:;
};

entry, parent, kset用来构成树状的结构的指针。相关函数有kobj_add() kobj_put()等

2.kset

struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
} __randomize_layout;

一个kset里面的所有kobject组成一个双向循环链表,list是链表头。相同类型(kobj_type)的kobject集合在一起组成kset.
相关函数有kset_get() kset_put()等。

3.kobj_type

struct kobj_type {
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops; /*里面有show store*/
struct attribute **default_attrs; /*属性以文件的形式存储在sysfs中,文件名就是.name,*/
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};

attribute以文件的形式输出到sysfs的目录中,文件名就是name.kobject是连接attribute与sysfs的桥梁。文件读写对应于
kobj_type中的sysfs_ops,里面有show()和store()

kobject:
kobject_set_name(): 为kobj对象进行命名时里面的'/'将会被替换为'!'
kobject_del(): 会调用sysfs_remove_dir(kobj),删除一个目录也会先删除其所有的子目录或文件
kobject_add(): 会增加父目录各级kobject的引用计数,在其parent指向的目录下创建文件节点,并启动该类型内核对现的hotplug函数
kobject_add(): 会将kogj的引用计数减1,减为0后就会调用kobject_release()释放该对象。

kset:
kset_register(): 中调用了kobject_uevent(&k->kobj, KOBJ_ADD);
kset_unregister(): 只调用kobject_del(&k->kobj);kobject_put(&k->kobj);

struct device:
device_register()将一个device对象插入设备模型中,并在/sys/devices下创建一个对应的目录。
device_unregister()完成相反操作,注销设备。get_device()/put_device()分别增加减少引用计数。
它通常嵌入到其它结构体中使用

device_register() --> device_add() --> kobject_uevent(&dev->kobj, KOBJ_ADD);

四、设备模型的上层容器: bus、device、device_driver

1.总线bus是处理器与设备之间的通道。在设备模型中所有设备都是通过总线进行连接。即使设备没有在一根物理的总线上,也会设置
一个内部虚拟的平台总线来维持总线、设备、驱动的三角关系。
2.struct bus_type:每个bus_type对象都对应于/sys/bus目录下的一个子目录。使用bus_register()向系统中注册总线
3.device_register()将一个新的device对象插入设备模型中,并在/sys/devices/下创建对应的目录

五、代码阅读总结

1.file_operations dentry_operations inode_operations super_operations 实现一个文件系统需要实现这4个函数集合
file_operations:是对每一个具体的文件进行的读写操作
dentry_operations inode_operations 是对文件的属性进行更改,如更改名字,建立或删除操作。
2..对于不同的文件系统,open()系统调用调用到的是不同的file_operations.open()
3.进程通过目录项和索引节点描述文件
4.文件包含两方面的信息,存储的数据本身和有关该文件的组织和管理信息。每个文件都有一个dentry(目录项)和inode(索引节点,物理意义上的文件)。
dentry记录着文件名和上级目录信息等,形成树状结构。inode里面存放该文件的组织和管理信息。dentry和inode是一对多的关系,
因为可能一个文件有好几个文件名。
5.文件可分为:磁盘文件,设备文件,特殊文件
6.要打开/home/hello.c,先找到‘/’,读入其内容,找到名为'home'的文件的索引节点号,打开'/home'这个文件,找到名为‘hello.c’这个
文件的索引节点号,最后就得到‘/home/hello.c’了。
7.使用glibc进行读写的系统调用次数可能和读写调用的次数不一样!又封装了一下。
8.不管是bus还是设备添加到系统后都会调用kobject_uevent(&dev->kobj, KOBJ_ADD);
9.struct bus_type中有很多与struct driver重复的函数指针,这些函数在注册的时候只要bus的存在就使用bus的,bus的不存在才会使用
driver的,若两者都存在某些函数还会报警告!
10.module_add_driver(drv->owner, drv): usbstorge: /sys/bus/usb/drivers/usb-storage下创建到/sys/module的连接
11.创建sysfs文件:driver_create_file() --> sysfs_create_file(&drv->p->kobj, &attr->attr);
12.注册的bus和注册的驱动指向的bus可以是不是一个的,driver的bus用来为driver提供一些函数,好像driver并产生设备模型并没有涉及到bus
13.设备驱动绑定
bus_add_driver
如果 drv->probe_type == PROBE_PREFER_ASYNCHRONOUS, 则进行异步匹配
否则同步匹配,调用driver_attach()
bus_for_each_dev()
如果bus->match存在(usb_storage的是存在的),则调用bus的然后返回。如果不存在,调用really_probe
driver_bound()将设备加到驱动的链表中
kobject_uevent(&dev->kobj, KOBJ_BIND); 发送bind的事件,但是udevadm监听不到是因为没有在rules.d里面加吗?

sysfs文件系统学习--sysfs的更多相关文章

  1. proc文件系统、sysfs文件系统、kobject操作

    Proc文件系统是提供一个接口给用户,让用户可以查看系统运行的一些状态信息,让用户修改内核的一些参数,比方说printk的打印级别就可以通过proc去修改 Sysfs文件系统, Sysfs is a ...

  2. Linux设备模型——设备驱动模型和sysfs文件系统解读

    本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的.在分析过程中,本文将以platform总线和spi主控制器的 ...

  3. sysfs文件系统的建立【转】

    http://blog.csdn.net/dndxhej/article/details/7434615 对sysfs和设备模型有了解的都会知道sysfs实际是为了将设备模型导出到用户空间的一个内存文 ...

  4. [中英对照]The sysfs Filesystem | sysfs文件系统

    The sysfs Filesystem | sysfs文件系统 Abstract | 摘要 sysfs is a feature of the Linux 2.6 kernel that allow ...

  5. 概述sysfs文件系统【转】

    转自:http://blog.csdn.net/npy_lp/article/details/78933292 内核源码:linux-2.6.38.8.tar.bz2 目标平台:ARM体系结构 sys ...

  6. Sysfs文件系统与Linux设备模型

    转:http://www.360doc.com/content/11/1218/16/1299815_173168170.shtml sysfs把连接在系统上的设备和总线组织成为一个分级的目录及文件, ...

  7. sysfs文件系统

    3 sysfs文件系统 sysfs是一个基于内存的文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用.该文件系统的目录层次结构严格按照内核的数据结构组织.除了二进制文件外(只有特殊场合才使用 ...

  8. Linux 内核sysfs 文件系统符号连接

    sysfs 文件系统有通常的树结构, 反映它代表的 kobjects 的层次组织. 但是内核中对象 间的关系常常比那个更加复杂. 例如, 一个 sysfs 子树 (/sys/devices )代表所有 ...

  9. Documentation/filesystems/sysfs.txt 文档翻译--sysfs

    sysfs - 用于导出内核对象的文件系统. 1.sysfs是一个基于ram的文件系统,最初基于ramfs. 它提供了一种方法,可以将内核数据结构,它们的属性以及它们之间的链接导出到用户空间.sysf ...

随机推荐

  1. hdu5021 树状数组+二分

    这 题 说 的 是 给 了 一 个 K—NN    每次查询离loc 最近的k个数 然后将这k个数的权值加起来除以k 赋值给 loc 这个位置上的 权值  我说说 我的做法 假如 查询的是loc 这个 ...

  2. SQL: 拼接列

    1. 因工作需要,需把两列(id,created_by)拼接成一列,结果很有意思,前5个值都是null. 2.解决方法:null加减乘除任何值都等于null,所以使用isnull函数先处理下列的值再拼 ...

  3. 20145204 《Java程序设计》第7周学习总结

    20145204 <Java程序设计>第7周学习总结 教材学习内容总结 时间 GMT.UT.TAI 格林威治标准时间(GMT)的正午是太阳抵达天空最高点之时,因为地球公转轨道为椭圆且速度不 ...

  4. Block作为参数时的使用

    Block作为参数使用,常见于各框架之中,比如在封装一个类时,当做什么事情由外界去决定,什么时候调用由自己的类决定时,这时候就需要将block作为参数使用. 下面我们模仿AFNetworking的ma ...

  5. ExtJS发送POST请求 参数格式为JSON

    背景 这要从我比较懒说起.技术框架ExtJS + resteasy,默认请求方式是ajax get,这后台方法就要写很多@QueryParam来获取参数.我比较喜欢前台用ajax post请求,后台方 ...

  6. js 判断浏览器类型及版本

    1.思路: 能力检测 + 字符串检索 2.例子 IE    Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)      ActiveXObject函 ...

  7. activemq、rabbitmq、kafka原理和比较

    一.activemq 虽然是java写的消息队列,但是提供Java, C, C++, C#, Ruby, Perl, Python, PHP各种客户端,所以语言上是没什么问题的.配置和使用,基本上是j ...

  8. JavaScript变量: 变量命名原则

    变量的命名相对而言没有太多的技术含量,今天整理有关于变量命名相关的原则,主要是想告诉大家,虽然命名没有技术含量,但对于个人编码,或者说一个团队的再次开发及阅读是相当有用的.良好的书写规范可以让你的Ja ...

  9. hdu2149巴什博弈输出

    一眼就能看出来的巴什博弈,只是要输出第一步取的值,如果m>n+1,输出m%(n+1),否则输出m到n,因为这是第一步 #include<map> #include<set> ...

  10. vue 点击按钮 input框架获取焦点的方法

    在按钮事件里加上这一段this.$nextTick(() =>{ this.$refs.input.focus()})