一.关于Udev

u即user space,dev是device,通过它的名字,我们就可以简单了解到,它是一个和用户态相关的驱动设备管理机制。udev是一个针对2.6内核的文件系统。提供一种基于用户空间的动态设备节点管理和命名的解决方案。用于取代落后的devfs

udev与硬件平台无关,属于用户空间的进程,是一个后台程序,它脱离驱动层的关联,而建立在操作系统之上,只要修改配置文件使之生效,无需重启操 作系统,它需要sysfs的支持,当底层设备发生插拔的时候,底层驱动通过netlink发送事件(uevent)给udev后台程序,udev监听这些 事件,并在上层做相应的设备节点的创建,命名,权限控制等。

它有以下优点:

1.动态管理:当设备添加/删除时,udev的守护进程侦听到来自内核的uevent,以此添加或者删除/dev下的设备文件,所以,udev只为 已经连接的设备产生设备文件,而不会在/dev/下产生大量虚无的设备文件.在发生热插拔时,设备的变化的相关信息会输出到内核的/sys(sysfs文 件系统),udev利用sysfs的信息来进行相应的设备节点的管理

2.自定义命名规则:通过规则文件,udev在/dev/下为所有的设备定义了内核设备名称,比如/dev/sda,/dev/hda,/dev /fd(这些都是驱动层定义的设备名)等等。由于udev是在用户空间运行,Linux用户可以自己定义规则文件,产生标识性强的设备文件,比如/dev /boot_disk,/dev/root_disk,/dev/color_printer等等

3.设定设备的权限和所有者/组。同样在规则文件中,可以自己定义设备相关的权限和所有者/组

工作流程:

二.uevent的交互

如之前提到过的,udev必须要有sysfs的支持,sysfs是一个建立在内存基础上的文件系统,它把连接在系统上的设备和总线组织成一个分级的文件,它们可以由用户空间获取,向用户空间导出内核数据结构以及它们的属性,它建立在内核对象kobject的基础上。

在内核空间,当系统启动加载驱动或设备发生热插拔的时候,驱动自身需要做相应的硬件探测方面的工作,探测到设备后,会去加载相应的设备驱动,在 sysfs下创建添加内核对象,会调用到kobject_add()来完成该内核对象的添加注册,再调用kobject_uevent()来通知系统,该 对象已经添加进来了。kobject_uevent()函数是uevent的关键函数,它将通过netlink socket把对象相应的信息,属性等发 给上层用户空间。

int device_add(struct device *dev)

{

struct device *parent = NULL;

struct class_interface *class_intf;

int error = -EINVAL;

dev = get_device(dev);

if (!dev)

goto done;

.......

/* first, register with generic layer. */

error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev));

if (error)

goto Error;

.......

kobject_uevent(&dev->kobj, KOBJ_ADD);

bus_attach_device(dev);

if (parent)

klist_add_tail(&dev->knode_parent, &parent->klist_children);

.......

attrError:

kobject_uevent(&dev->kobj, KOBJ_REMOVE);

kobject_del(&dev->kobj);

Error:

cleanup_device_parent(dev);

if (parent)

put_device(parent);

goto done;

}

上面的代码段为我们常见的添加注册设备时的会调用到的接口,device_add()函数,删除了一些无关代码,可以看出,是先调用了 kobject_add()创建添加该内核对象,然后调用kobject_uevent()来通知系统uevent的变化,这里的action是 KOBJ_ADD,相对应还有

enum kobject_action {

KOBJ_ADD,

KOBJ_REMOVE,

KOBJ_CHANGE,

KOBJ_MOVE,

KOBJ_ONLINE,

KOBJ_OFFLINE,

KOBJ_MAX

};

在kobject_uevent()里面采用的就是Linux中比较经典的内核空间和用户空间的一种通信机制netlink socket,这个不 是udev的重点,我也不做过多的解释,总之相信它能让内核空间和用户空间进行通信就行了。在udev也会有相应的socket来接受底层的消息。如下为 参照udev源码写的一个简单的uevent消息侦听程序:

#define UEVENT_BUFFER_SIZE      2048

static int init_hotplug_sock(void)

{

struct sockaddr_nl snl;

const int buffersize = 16 * 1024 * 1024;

int retval;

memset(&snl, 0x00, sizeof(struct sockaddr_nl));

snl.nl_family = AF_NETLINK;

snl.nl_pid = getpid();

snl.nl_groups = 1;

int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);

if (hotplug_sock == -1) {

printf("error getting socket: %s", strerror(errno));

return -1;

}

/* set receive buffersize */

setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));

retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));

if (retval < 0) {

printf("bind failed: %s", strerror(errno));

close(hotplug_sock);

hotplug_sock = -1;

return -1;

}

return hotplug_sock;

}

int main(int argc, char* argv[])

{

int hotplug_sock       = init_hotplug_sock();

while(1)

{

//printf("sunqidong debug\n");

char buf[UEVENT_BUFFER_SIZE*2] = {0};

recv(hotplug_sock, &buf, sizeof(buf), 0);

printf("%s\n", buf);

}

return 0;

}

这也是一个后台服务程序,循环的执行接受底层的消息过来,当发生U盘的插拔时,会产生如下的log:

[root@localhost test]# ./hotplug

add@/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1

add@/class/usb_endpoint/usbdev1.5_ep00

add@/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0

add@/class/scsi_host/host6

add@/class/usb_endpoint/usbdev1.5_ep81

add@/class/usb_endpoint/usbdev1.5_ep02

add@/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host6/target6:0:0/6:0:0:0

add@/class/scsi_disk/6:0:0:0

add@/block/sdb

add@/block/sdb/sdb1

add@/block/sdb/sdb2

add@/block/sdb/sdb5

add@/block/sdb/sdb6

add@/block/sdb/sdb7

add@/block/sdb/sdb8

add@/class/scsi_device/6:0:0:0

add@/class/scsi_generic/sg2

add@/class/bsg/6:0:0:0

remove@/class/usb_endpoint/usbdev1.5_ep81

remove@/class/usb_endpoint/usbdev1.5_ep02

remove@/class/bsg/6:0:0:0

remove@/class/scsi_generic/sg2

remove@/class/scsi_device/6:0:0:0

remove@/class/scsi_disk/6:0:0:0

remove@/block/sdb/sdb8

remove@/block/sdb/sdb7

remove@/block/sdb/sdb6

remove@/block/sdb/sdb5

remove@/block/sdb/sdb2

remove@/block/sdb/sdb1

remove@/block/sdb

remove@/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/host6/target6:0:0/6:0:0:0

remove@/class/scsi_host/host6

remove@/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0

remove@/class/usb_endpoint/usbdev1.5_ep00

remove@/devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1

三.udev的规则文件     规则文件是udev中最重要的部分,默认是存放在/etc/udev/rules.d/下。所有的规则文件都必须以".rules"为后缀名。下面是一个简单的规则文件例子说明

KERNEL=="sdb8" ,  NAME="mydisk",MODE="0660"

KERNEL是匹配键,NAME和MODE是赋值键。"=="这是判断语句,"="是赋值语句,这条规则的意思是,如果有一个设备的内核设备名称为sdb8(我移动硬盘内的一个分区),则该条件生效,执行后面的赋值:在/dev/下产生名为mydisk的设备文件,并把该设备文件的权限设为0660.

通过这条简单的规则,应该就可以对规则文件有了个基本的了解。每个规则文件被分成一个或多个匹配和赋值部分。匹配部分用匹配专用的关键字来表示,相应的赋值部分用赋值专用的字来表示。

1.常见的匹配关键字: ACTION(用于匹配行为add/remove),KERNEL(内核中定义的设备名),BUS(用于匹配总 线类型),SYSFS(用于匹配从sysfs得到的信息,比如lable,vendor,USB序列号等),SUBSYSTEM(匹配子系统名)等

2.常见的赋值关键字:

NAME(创建的设备文件名),SYMLINK(符号创建链接名),OWNER(设置设备的所有者),GROUP(设置设备的组),IMPORT(调用外部程序),MODE(权限位)

四.xx项目上自动挂载usb存储设备的应用

在xx项目上,我们需要自动挂载usb存储设备,并且要支持常见的几种文件系统,fat32,ntfs,exfat等,其中fat32等fat系列,Linux下早就有支持,ntfs和exfat目前的内核自身还没支持,我们有关于这两个文件系统的内核模块文件tntfs,ko和texfat.ko,加载进去过后就能让我们的内核识别这两种文件系统,实现手动加载这两种格式的存储设备。但如果要支持自动加载还有问题,需要去修改相应的规则文件。

在加载的时候,不同的格式的文件系统,加载的参数是不一样的,如exfat为

mount -t texfat /dev/sda /mnt/udisk

而ntfs为

mount -t tntfs /dev/sda /mnt/udisk

并且针对不同的格式,还有些其他挂载选项参数不一样,所以对不同的格式需要区别对待。

在规则文件里面是通过blkid -o udev命令来获取文件系统的信息的,判断出该盘是哪种格式,再去执行不同的挂载命令。

如下是blkid -o udev读出来的文件系统格式信息

ID_FS_UUID=2EE054B8E054884B

ID_FS_UUID_ENC=2EE054B8E054884B

ID_FS_LABEL=disk3

ID_FS_LABEL_ENC=disk3

ID_FS_TYPE=ntfs

ID_FS_LABEL=DISK4

ID_FS_LABEL_ENC=DISK4

ID_FS_UUID=B8CF-FF22

ID_FS_UUID_ENC=B8CF-FF22

ID_FS_TYPE=vfat

ID_FS_UUID=3606-1B2C

ID_FS_UUID_ENC=3606-1B2C

ID_FS_TYPE=exfat

ID_FS_LABEL=Disk5

ID_FS_LABEL_ENC=Disk5

可以看到上面的几个赋值项,在规则文件里面就会去读这些值。做相应的判断,实现不同文件系统的区别对待挂载

如下为规则文件的一部分

KERNEL!="sd[a-z][0-9]", GOTO="media_by_label_auto_mount_end"

# Import FS infos

IMPORT{program}="/sbin/blkid -o udev -p %N"

ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}"

ENV{ID_FS_LABEL}=="", ENV{dir_name}="usb-%k"

#vfat,fat

ACTION=="add",ENV{ID_FS_TYPE}=="vfat|fat",RUN+="/bin/mkdir -p /mnt/udisk/%E{dir_name}",ENV{mount_options}="$env{mount_options},gid=100,umask=000",RUN+="/bin/mount -o $env{mount_options},iocharset=utf8 /dev/%k /mnt/udisk/%E{dir_name}"

#ntfs

ACTION=="add",ENV{ID_FS_TYPE}=="ntfs",RUN+="/bin/mkdir -p /mnt/udisk/%E{dir_name}",ENV{mount_options}="$env{mount_options},gid=100,umask=000",RUN+="/bin/mount -t tntfs -o $env{mount_options},iostreaming /dev/%k /mnt/udisk/%E{dir_name}"

#exfat

ACTION=="add",ENV{ID_FS_TYPE}=="exfat",RUN+="/bin/mkdir -p /mnt/udisk/%E{dir_name}",RUN+="/bin/mount -t texfat -o rw /dev/%k /mnt/udisk/%E{dir_name}"

关于blkid,在我们目前的文件系统里面,blkid是不支持exfat格式的,通过命令查看磁盘的信息,根本找不到exfat格式的磁盘。所以之前在做自动挂载的时候没法实现挂exfat,后来在网上找了个util-linux-ng2.18源码包,里面包含了blkid的源码。修改编译,编译出一个新的blkid文件,使其可以在我们的系统上运行,能够识别出exfat文件

linux下udev简介的更多相关文章

  1. linux下udev简介【转】

    本文转载自:http://blog.csdn.net/skyflying2012/article/details/9364555 一.关于Udev u即user space,dev是device,通过 ...

  2. Linux下UDP简介及程序设计

    一.UDP简介 UDP(User Datagram Protocol),用户数据报协议,是OSI参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务.UDP提供了无连接通信,且不对传 ...

  3. linux下udev和mdev的使用

    linux下设备文件系统有devfs.udev和mdev这三种. 一.devfs devfs是由Linux 2.4内核引入的,引入时被许多工程师给予了高度评价,它的出现使得设备驱动程序能自主地管理自己 ...

  4. linux下目录简介——/sys

    Linux下/sys目录介绍    1. 概述 ramdisk 文件系统基于磁盘模拟技术,实际文件系统是ex2 ex3等.sysfs是一种基于ram文件系统和proc一样.Sysfs文件系统是一个类似 ...

  5. LINUX下 Udev详解

    如果你使用Linux比较长时间了,那你就知道,在对待设备文件这块,Linux改变了几次策略.在Linux早期,设备文件仅仅是是一些带有适当的属性集的普通文件,它由mknod命令创建,文件存放在/dev ...

  6. linux下udev

    如果你使用Linux比较长时间了,那你就知道,在对待设备文件这块,Linux改变了几次策略.在Linux早期,设备文件仅仅是是一些带有适当的属性集的普通文件,它由mknod命令创建,文件存放在/dev ...

  7. linux下目录简介——/SElinux

    一.前言 安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统. SELinux 主要由美国 ...

  8. linux下目录简介——/proc

    1. /proc目录Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文 ...

  9. Linux下内存映射文件的用法简介

    由于项目需要,所以学习了一下Linux下内存映射文件的用法,在这里共享一下自己的收获,希望大家提出宝贵意见,进行交流. 简介: 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区 ...

随机推荐

  1. Android Studio 1.1.0 切换主题和绑定 代码提示 快捷键

    这篇文章用于给刚从eclipse 转用 Android Studio 1.1.0的同学看的. 所以经常会更新的. 至于为什么要转Android Studio 1.1.0呢,就自己想吧.没有人强逼的. ...

  2. 关于casperjs的wait方法的执行顺序

    var casper = require('casper').create({ viewportSize:{ width:1920, height:1080 } }); var url1 = 'htt ...

  3. STL之string类详解

    通过在网站上的资料搜集,得到了很多关于string类用法的文档,通过对这些资料的整理和加入一些自己的代码,就得出了一份比较完整的关于string类函数有哪些和怎样用的文档了!下面先罗列出string类 ...

  4. 【内核】嵌入式linux内核的五个子系统

    Perface Linux内核主要由进程调度(SCHED).内存管理(MM).虚拟文件系统(VFS).网络接口(NET)和进程间通信(IPC)5个子系统组成,如图1所示. 图1 Linux内核的组成部 ...

  5. 开发openfire 消息拦截器插件PacketInterceptor

    开发消息拦截器的步骤跟开发简单插件步骤一样,要开发消息拦截器插件,首先继承PacketInterceptor包拦截类,然后在initializelPlugin()方法中注册拦截器,就可以实现inter ...

  6. Android线程通信

    摘要 andriod提供了 Handler 和 Looper 来满足线程间的通信.例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑定在主线程的Handler来传 ...

  7. NewStyleClass学习笔记[一]

    from : https://www.python.org/doc/newstyle/ New-style Classes Unfortunately(遗憾,不幸的), new-style class ...

  8. JAVA-JSP内置对象之response对象实现页面自动跳转

    相关资料:<21天学通Java Web开发> response对象 实现页面自动跳转1.可以通过response对象的addHeader()方法添加一个标题为Refresh的标头,并指定页 ...

  9. asp.net基于StateServer的二级域名共享session

    备注:亲自试验有效,如果网友有通过下面的教程未实现session共享的,欢迎留言说明你遇到的问题.必有回复. 最近为实现的二级域名共享session纠结好久.网上的很多实现的方法试了都不行,查了很久才 ...

  10. Web基础 HTML CSS JS JQuery AJAX

    1. Web基础 网页的骨骼HTML 什么是HTML超文本标记语言:Hyper Text Markup Language 这都不重要,重要的是:HTML是Web网页的基本组成部分HTML中定义的元素, ...