本文转载自:http://blog.csdn.net/skyflying2012/article/details/9364555

一.关于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简介

    一.关于Udev u即user space,dev是device,通过它的名字,我们就可以简单了解到,它是一个和用户态相关的驱动设备管理机制.udev是一个针对2.6内核的文件系统.提供一种基于用户空 ...

  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. 5.29clone项目地址

  2. Net.Json 常用例子

    #JsonConvert 例子 内容主要都是官方的例子,加上一些中文注释而已. 主要方便自己查询,分享一份出来. 参考文档: https://www.newtonsoft.com/json/help/ ...

  3. Boost-QT兼容问题:#define FUSION_HASH #

    使用原始的MSVC10+QT48很长时间,需要把PCL升级到新的版本,不再使用自行编译的PCL1.7.2版本. 在使用MSVC2012的时候,使用MSVC12-的PCL1.8.0版本,出现了一个不大不 ...

  4. 【sqli-labs】 less21 Cookie Injection- Error Based- complex - string ( 基于错误的复杂的字符型Cookie注入)

    这个和less20是一样的,唯一的不同在于添加了括号和使用了base64对cookie进行了编码(因为使用了base64_decode解码函数) admin被编码成了YWRtaW4=但是执行的SQL语 ...

  5. vue-awesome-swiper组件的使用

    一.轮播图组件是这样安装的 npm i --save-dev vue-awesome-swiper main.js里面 import 'swiper/dist/css/swiper.css' impo ...

  6. vue-router在同一个路由下切换,取不到变化的路由参数

    最近用vue写项目的时候碰到一个问题,在同一个页面下跳转,路由地址不变,路由参数有变化,一开始只是在data里取路由的参数,发现根本取不到变化的路由参数. 例如:订单列表也跳转详情页,跳转方法如下 & ...

  7. KVM之virsh管理虚拟机内存

    调整内存 virsh setmem 命令帮助: [root@ubuntu ~]# virsh setmem --help NAME setmem - change memory allocation ...

  8. 用doxygen风格注释代码生成文档

    目录 用doxygen风格注释代码生成文档 1. 说明 2. 具体操作 2.1 生成头部注释 2.2 安装doxygen 2.3 工程配置 3. 总结 用doxygen风格注释代码生成文档 1. 说明 ...

  9. spotlight on mysql 监控

    . 安装 下载地址:https://pan.baidu.com/s/1qYi3lec 官网地址——https://www.quest.com/common/registration.aspx?requ ...

  10. S-HR薪酬项目与核算表的关系