2010年1月3日星期日

浅谈hotplug, udev, hal, d-bus

转自:http://blog.csdn.net/Tomsen00/archive/2009/11/26/4879217.aspx
App
↑ App等候设备处理信息并挂载设备
D-Bus
↑ 过滤处理内容后送给D-Bus
HAL 它是一个位于操作系统和驱动程序之上,运行在用户空间中的服务程序
↑ 把硬件相关内容送到HAL
udev
↑ kernel2.6发现设备变化反映到sysfs, 并通过hotplug机制通知udev
Linux Kernel2.6 自动调用驱动模块

1. 自动挂载磁盘分区的操作从底层来说,是要内核支持的,2.6 内核的sysfs 虚拟文件系统就提供了这一支持,这个文件系统 (/sys/) 通常用于反应系统硬件信息,总线上的设备变化、网络设备的变化等事件在这里都能反应出来,这个文件系统的变化配合上内核的 hotplug 机制就可以掌握硬件改动相关的信息.
说到内核的 hotplug 机制,简单地说就是在硬件发生变化的时候去通知某一用户态程序,缺省是 /sbin/hotplug,不过现在它已经被 udev 取代了,收到信息之后,udev 会根据 sysfs 的变化调用一些脚本来处理这个事件,这里的处理是指某个用户空间的动作,而不是加载驱动,加载驱动是内核自己的事情,在 udev 反应过来之前就完成了.

2. 下面轮到我们著名的硬件抽象层(HAL)

HAL是Hardware Abstraction Layer的首字母缩写。我最早是在Winnt 3.5的帮助中知道这个名词的,对帮助文档中的说法我比较认同,所以一直对它抱有好感。不过Windows下的HAL和Linux下的HAL两者所指并非相同之物:

Windows下的HAL:位于操作系统的最底层,直接操作物理硬件,隔离与硬件相关的信息,为上层的操作系统和设备驱动程序提供一个统一的接口,起到对硬件的抽象作用。有了HAL,编写驱动程序就容易多了,因为HAL的接口不但使用简单,而且具有更好的可移植性(没用过)。

Linux 下的HAL:至于对硬件的抽象,Linux内核早就有类似机制,只不过没有专门的名称罢了。而Linux的HAL指的并非这个,它不是位于操作系统的最底层,直接操作硬件,相反,它位于操作系统和驱动程序之上,是一个运行在用户空间中服务程序。

我们知道,Linux和所有的Unix一样,习惯用文件来抽象设备,任何设备都是一个文件,比如/dev/mouse是鼠标的设备文件。这种方法看起来不错,每个设备都有统一的形式,但使用并不那么容易,设备文件名没有什么规范,从简单的一个文件名,你无法得知它是什么设备,具有有什么特性。

结果形成这样的尴尬:有了设备和设备驱动程序,却不知道如何使用它。这些乱七八糟的设备文件,让设备的管理和应用程序的开发都变得很麻烦,所以有必要提供一个硬件抽象层,来为上层应用程序提供一个统一的接口,Linux的HAL就这样应运而生了。

但HAL并不提供诸如拍照和刻录等之类的功能,相反它只是告诉应用程序,系统中有哪些设备可用,以及这些设备的类型、特性和能力等。主要说来,它提供以下几项功能:

1. 获取指定类型的设备列表。

2. 获取/更改设备的属性值。

3. 获取设备具有的能力描述。

4. 设备插入/拔除时,通知相关应用程序。

5. 设备属性或能力变化时,通知相关应用程序。

udev创建dev下的文件结点,加载驱动程序,让设备处于可用状态。而HAL则告诉应用程序,现在有哪些设备可用,这些设备的类型、特性和能力,让应用程序知道如何使用它们。

设备的属性管理是HAL最重要任务之一,有的设备属性来源于实际的硬件,有的来源于设备信息文件(/usr/share/hal/fdi/),有的来源其它配置信息(如/usr/share/hwdata/)。设备属性的都有标准的定义,这些属性定义是HAL的SPEC的主要内容之一

3. udev & HAL

(1).实线箭头为主动调用,虚线箭头为事件上报。
(2).udev通过NetLink注册内核的设备事件,当有设备插入/拔除时,udev就会收到通知,它会从事件中所带参数和sysfs中的信息,加载适当的驱动程序,创建dev下的结点,让设备处于可用的状态。
(3).udev只是一个框架,它的行为完全受它的规则所控制,这些规则存放在目录/etc/udev/rules.d/中,其中90-hal.rules是用来让udev把设备插入/拔除的事件通过socket socket:/org/freedesktop/hal/udev_event转发给HAL的。
(4).HAL挂在socket:/org/freedesktop/hal/udev_event上等待事件,有事件发生时就调用函数 hald_udev_data处理,它先从事件中取出主要参数,创建一个hotplug_event对象,把它放入事件队列中,然后调用 hotplug_event_process_queue处理事件。
(5).函数hotplug_event_begin负责具体事件的处理,它把全部事件分为四类,并分别处理hotplug_event_begin_sysfs 处理普通设备事件,hotplug_event_begin_acpi处理ACPI事件,hotplug_event_begin_apm处理APM事件,hotplug_event_begin_pmu处理PMU事件。要注意的是,后三者的事件源并非源于udev,而是在device_reprobe 时触发的 (osspec_device_reprobe/hotplug_reprobe_tree /hotplug_reprobe_generate_add_events/acpi_generate_add_hotplug_event)。
(6).函数hotplug_event_begin_sysfs中,如果是插入设备,则创建一个设备对象,设置设备的属性,调用相关callouts,然后放入设备列表中,并触发signal让dbus通知相关应用程序。如果是拔除设备,则调用相关callouts,然后从设备列表中删除,并触发signal让 dbus通知相关应用程序。
(7).应用程序可以主动调用HAL提供的DBUS接口函数,这些函数在libhal.h中有定义。应用程序也可以注册HAL的signal,当设备变化时,HAL通过DBUS上报事件给应用程序。
(8).callout是HAL一种扩展方式,它在设备插入/拔除时执行。可以在设备信息文件中(/usr/share/hal目录)指定。
(9).addon也是HAL一种扩展方式,它与callout的不同之处在于addon往往是事件的触发者,而不是事件的消费者。HAL的事件源主要源于 udev,而udev源于kernel的hotplug,然而有的设备如电源设备、磁盘设备和特殊按键等,它们并不产生hotplug事件。HAL就得不到通知,怎么办呢,addon就是用于支持新事件源的扩展方式。比如addon-acpi从/proc/acpi/event或者 /var/run/acpid.socket收到事件,然后转发成HAL事件。addon-storage检测光盘或磁盘的状态,并设置设备的属性。 addon-keyboard检测一些特殊按键,并触发相应事件。
access-check/ci-tracker/ck-tracker负责权限的检查,里面提到的PolicyKit/ConsoleKit不是太熟悉,有时间再看看。
简单的说,HAL就是一个设备数据库,它管理当前系统中所有的设备,你可以以多种灵活的方式去查询这些设备,可以获取指定设备的特性,可以注册设备变化事件。

4. 那 hal 怎么发出通知呢? 这是利用一个新兴的系统内用户空间消息总线系统 -- dbus 来完成的,hal 会通过 dbus 上的一条消息总线把新加入的块设备和相关的挂载提示信息,比如加载选项 sync, iocharset 之类的信息发送到总线上来,只等待一个终结者来接受并处理这些信息了.

5. 这个终结者对于 gnome 来说就是 gnome-volume-manager (名字太长了,下面简称 gvm),它从 dbus 上探听消息,当发现有设备挂载提示的时候就会尝试把设备挂载上来。缺省的,还会打开一个 nautilus 浏览窗口来浏览新挂载上的分区的内容。
嗯,最后一个问题就是怎么挂了,众所周知,如果块设备在 /etc/fstab 里没有描述存在的话,挂载就比较麻烦:

  • 本来如果有 fstab 中的 user 属性的话,普通用户可以挂载,但 现在没有,普通用户没法挂
  • 如果 sudo 授权的话,用户可能获得挂载其他分区的过大权限,危及 系统安全。

pmount 就是这个工具链上的最后一环,它可以代表用户 (运行 gvm 的用户) 来挂载一个属于他的可移动存储设备,即使 fstab 里没有这个设备存在,缺省的挂载位置是 /media/ 下,和 块设备同名,比如 /dev/sda1 挂载到 /media/sda1/ 目录。

嗯, 综上,设备的自动挂载就完成了,呵呵,希望一大堆的关键词没把大家搞晕,回顾一下: kernel 发现设备变化反应到 sysfs 上并通过 hotplug 机制通知udev, udev 把硬件相关内容送给 hal,hal 过滤、处理之后发送信息到 dbus 上,在 dbus 上等候的 gvm 收到消息后用 pmount 把设备挂上,这样,设备的自动挂载就完成.

PS:HAL的相关文件:

首先是硬件信息文件fdi的路径会有:

/usr/share/hal/fdi 通常是由系统程序安装包提供的文件。

/etc/hal/fdi 这里是用户或者管理员修改fdi的位置。

这两个路径下各自存在information policy preprobe等3个目录,用来存放不同用途的fdi文件。后面再解释。

其次是HAL的一些Callout和Addon,他们位于 /usr/lib/hal/scripts 及 /usr/lib/hal/ 下面

再有一些与HAL本身相关的配置文件等:

/etc/init.d/hal hal的启动脚本

/etc/udev/rules.d/95-hal.rules HAL在UDEV中的规则

/etc/dbus-1/system.d/hal.conf HAL的一些常用的Interface在DBUS中的权限设置。

相关程序

/usr/bin/lshal

/usr/bin/hal-device

/usr/bin/hal-get-property

/usr/bin/hal-set-property

/usr/bin/hal-find-by-capability

/usr/bin/hal-find-by-property

/usr/bin/hal-disable-polling

/usr/bin/hal-is-caller-locked-out

/usr/bin/hal-lock

/usr/sbin

/usr/sbin/hald

没有评论: