Linux热插拔及mdev机制

1、创建设备类,是为了让mdev知道根据这些信息来创建设备节点,根据/sys来创建,所以从devfs开始,根文件系统就引入了一个/sys目录,/sys/dev下面都是内核加载的驱动的主从设备号
 
2、class的初始化过程(在/sys/下创建class目录):
start_kernel() -> rest_init() -> kernel_init() -> do_basic_setup() -> driver_init() -> classes_init()
 
3、所谓的uevent机制,就是由内核来启动一个用户进程
 
4、uevent通知机制:kobject_uevent() -> kobject_uevent_env()
    11.1、得到kset->uevent_ops,通过filter判断kset中的内核对象状态改变是否需要通知到用户层,返回0就不通知
    11.2、如果内核对象状态变化需要通知用户层,分配环境变量空间env,并设置环境变量
    11.3、内核来启动一个用户空间的程序,一般默认为这个属性文件(/proc/sys/kernel/hotplug)指定的进程,如:/sbin/mdev
 
5、在x86系统下,用户空间一般会有udevd这个守护进程一直监听kobject_uevent通过netlink广播的uevent数据包,来获取内核的各种变化,可通过命令查看:ps -aux |grep udevd
 
6、调用通知用户过程:
设备端:device_add() -> kobject_uevent(&dev->kobj, KOBJ_ADD);
驱动端:driver_register() -> bus_add_driver() -> kobject_uevent(&priv->kobj, KOBJ_ADD);
 
设备端卸载:
device_del() -> bus_remove_device() -> bus_put() -> kset_put() -> kobject_put() ->  -> kobject_release() -> kobject_cleanup() -> kobject_uevent(kobj, KOBJ_REMOVE);
device_del() -> put_device() -> kobject_put() ......
 
驱动端卸载:
driver_unregister() -> bus_remove_driver() -> kobject_put() ......
driver_unregister() -> bus_remove_driver() -> bus_put() -> kset_put() -> kobject_put() ......
 
7、当内核对象kset改变时,内核会采用内核对象通知机制(kobject_uevent),通知用户层,那么用户程序必须指定一个进程给/proc/sys/kernel/hotplug,比如/sbin/mdev
 
8、咱们也可以替换/sbin/mdev来观察现象,但被替换的应用程序由于没有任何描述符可用,所以需要自己打开标准输入输出,如:
    fd = open("/dev/console",O_RDWR);
    fd = open("/dev/console",O_RDWR);
替换方法:echo /mnt/t > /proc/sys/kernel/hotplug
 
9、可以通过热插拔usb设备来观察现象,也可以通过自己写一个驱动程序,在驱动中调用kobject_uevent()向用户发送消息,但自己来实现向用户空间发送改变的状态,通过属性文件操作实现,那么佣有属性文件的kobject必须要隶属于一个kset,即要有subsystem。
应用程序测试代码(参考busybox中的mdev完成),如下:

#include      // FILE
#include      // O_RDWR
#include    // getenv()


// debug:
//        echo /mnt/t > /proc/sys/kernel/hotplug
//        hotplug operation



int main(int argc, char *argv[])
{
   int i;
   int fd;
   char *env[6];
   char *pname[] = {"ACTION","DEVNAME","DEVPATH","SUBSYSTEM","FIRMWARE","SEQNUM"};

   fd = open("/dev/console",O_RDWR);
   fd = open("/dev/console",O_RDWR);

   printf("\n");
   for(i=0;i<</span>argc;i++)
       printf("argv[%d] = %s\n",i,argv[i]);
   printf("\n");
   
   env[0] = getenv("ACTION");
   env[1] = getenv("DEVNAME");
   env[2] = getenv("DEVPATH");
   env[3] = getenv("SUBSYSTEM");
   env[4] = getenv("FIRMWARE");
   env[5] = getenv("SEQNUM");

   for(i=0;i<</span>6;i++)
       if(env[i] != NULL)
           printf("%s = %s\n",pname[i],env[i]);
       
   close(0);
   close(1);
   return 0;    
}

10、udev和mdev都有着相似的功能,即完成设备文件的动态创建,但实现机制略有不同,有时候也说成mdev是udev的嵌入式简化版
 
11、两者使是用uevent 机制处理热插拔问题的用户空间程序,uevent 是“user event”的简称,是一种内核向用户空间发送信息的方式
 
12、udev 是基于netlink 机制的,它在系统启动时运行了一个daemon (守护进程)程序udevd,通过监听内核发送的uevent 来执行相应的热拔插动作
 
13、mdev 是基于uevent_helper 机制的,它在系统启动时修改了内核中的uevnet_helper 变量(通过写/proc/sys/kernel/hotplug),这样内核产生uevent 时会调用uevent_helper 所指的用户级程序,也就是mdev,来执行相应的热拔插动作,uevent_helper 的初始值在内核编译时可配置:
   -> Device Drivers                           
     -> Generic Driver Options
        (/proc/sys/kernel/hotplug) path to uevent helper  

14、udev 使用的netlink 机制在有大量uevent 的场合效率高,适合用在PC 机上;而mdev 使用的uevent_helper 机制实现简单,适合用在嵌入式系统中
将可移动设备连入系统时,系统的后台中会依次发生如下事件: l 内核检测到新硬件插入,然后分别通知hotplug和udev。前者用来装入相应的内核模块(如usb-storage),而后者用来在/dev中创建相应的设备节点(如/dev/sda1)。 l udev创建了相应的设备节点之后,会将这一消息通知hal的守护程序(hald)。当然udev还得保证新创建的设备节点可以被普通用户访问。 l hotplug装入了相应的内核模块之后,会把这一消息通知给hald。 l hald在受到hotplug和udev发出的消息之后,认为新硬件已经正式被系统认可了。此时它会通过一系列精心编写的规则文件(就是传说中的xxx-policy.fdi),把发现新硬件的消息通过dbus发送出去,同时还会调用update-fstab或fstab-sync来更新/etc/fstab,为相应的设备节点创建适合的挂载点。 l 卷管理器会监听dbus中发现新硬件的消息。根据所插入的硬件(区分U盘和数码相机等)不同,卷管理器会先将相应的设备节点挂载到hald创建的挂载点上,然后再打开不同的应用程序。 当然,如果是在CDROM中插入光盘,过程可能比较简单。因为CDROM本身就是一个固定的硬件,无需hotplug和udev的协助: l hald会自己监视CDROM,并且将光盘托架开合的消息通过dbus发出去。 l 卷管理器负责检查CDROM中的盘片内容,进行挂载,并调用合适的应用程序。 要注意,hald的工作是从上游得到硬件就绪的消息,然后将这个消息转发到dbus中。尽管它会调用程序来更新fstab,但实际上它自己并不执行挂载的工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值