Udev详解

Udev详解

udev
linux用户空间设备管理(Linux userspace device management),在kernel 2.6.13后被使用,动态提供了在系统中实际存在的设备节点。
udev与不同的发布版本有很强的依赖性。一个系统如果没有安装正确的udev版本,有可能造成无法启动或者工作不正常。udev的开发团队也不推荐使用新版本替代系统当前版本的udev.
随着udev发布的工具和规则文件可以改变为己用,不是公共的API。不要直接从外部程序调用/lib/udev目录下的私有工具,因为在下一个发布版本中有可能不存在这个私有工具。获取udev相关信息只通过udevadm和libudev。在/lib/udev和/dev/.udev目录下的所有Tools和rules都是私有的,可能在不同版本中不同。
udev要求:
  支持sysfs, procfs, signalfd, inotify,unix domain sockets, networking and hotplug的Linux kernel。
需要配置kernel的以下选项:
   CONFIG_HOTPLUG=y
      CONFIG_UEVENT_HELPER_PATH=""
      CONFIG_NET=y
      CONFIG_UNIX=y
      CONFIG_SYSFS=y
      CONFIG_SYSFS_DEPRECATED*=n
      CONFIG_PROC_FS=y
      CONFIG_INOTIFY_USER=y
      CONFIG_SIGNALFD=y 
 可选项:
   CONFIG_TMPFS=y
      CONFIG_TMPFS_POSIX_ACL=y (user ACLs for device nodes)
      CONFIG_BLK_DEV_BSG=y (SCSI devices)
 如果CONFIG_SYSFS_DEPRECATED*=y则udev将不可用。
 kernel配置中禁用掉/sbin/hotplug,如果未禁用,将导致系统不稳定,因为kernel并行创建了许多进程,会出现内存溢出。
 需要将proc文件系统挂到/proc,将sysfs挂载到/sys,因为udev会需要这些目录。

udev在系统启动时,将devtmpfs挂载到/dev目录下,udev管理kernel创建的设备节点的权限和所有权,udev会创建附加的软链接。udev也可以使用tmpfs文件系统,像/dev/null, /dev/console, /dev/kmsg这样的静态结点,需要在udev开始时创建。
 udev守护进程通过内核的方式来开始处理设备事件,启动过程中,kernel将为所有udev配置的所有已存在的设备发送事件,通常是通过以下命令:
   /sbin/udevadm trigger --type=subsystems
      /sbin/udevadm trigger --type=devices
  重启udev守护进程不需要已存在设备的规则。
  规则改变后会自动识别,不需要重启守护进程或者发送信号。
 
基于kernel的发送设备文件创建/移除的事件,udev在/dev目录下创建/移除结点。
所有的kernel事件与一组指定的规则相匹配,这些规则与事件处理函数和kernel模块有关。所有的设备结点都需要主设备号、从设备号。udev还可以创建所有权限,以及软连接来指向结点,和事件处理函数。


为什么使用udev


在此之前的设备文件管理方法(静态文件和devfs)有几个缺点:


*不确定的设备映射。特别是那些动态设备,比如USB设备,设备文件到实际设备的映射并不可靠和确定。举一个例子:如果你有两个USB打印机。一个可能称 为/dev/usb/lp0,另外一个便是/dev/usb/lp1。但是到底哪个是哪个并不清楚,lp0,lp1和实际的设备没有一一对应的关系,因为 他可能因为发现设备的顺序,打印机本身关闭等原因而导致这种映射并不确定。理想的方式应该是:两个打印机应该采用基于他们的序列号或者其他标识信息的唯一 设备文件来映射。但是静态文件和devfs都无法做到这点。


*没有足够的主/辅设备号。我们知道,每一个设备文件是有两个8位的数字:一个是主设备号 ,另外一个是辅设备号来分配的。这两个8位的数字加上设备类型(块设备或者字符设备)来唯一标识一个设备。不幸的是,关联这些身边的的数字并不足够。


*/dev目录下文件太多。一个系统采用静态设备文件关联的方式,那么这个目录下的文件必然是足够多。而同时你又不知道在你的系统上到底有那些设备文件是激活的。


*命名不够灵活。尽管devfs解决了以前的一些问题,但是它自身又带来了一些问题。其中一个就是命名不够灵活;你别想非常简单的就能修改设备文件的名字。缺省的devfs命令机制本身也很奇怪,他需要修改大量的配置文件和程序。;


*内核内存使用,devfs特有的另外一个问题是,作为内核驱动模块,devfs需要消耗大量的内存,特别当系统上有大量的设备时(比如上面我们提到的系统一个上有好几千磁盘时)


udev的目标是想解决上面提到的这些问题,他通采用用户空间(user-space)工具来管理/dev/目录树,他和文件系统分开。知道如何改变缺省配置能让你之大如何定制自己的系统,比如创建设备字符连接,改变设备文件属组,权限等。

 

udev的配置文件
一般放在/etc/udev/和/lib/udev/。udev的主配置文件是/etc/udev/udev.conf,里面主要设置
udev_root和udev_log。udev_root指定放置设备结点的位置,默认是/dev。udev_log保存记录优先级,有效的值为err, info和debug或者syslog优先级支持的数字。
udev的规则文件
一般存放在/lib/udev/rules.d/和/etc/udev/rules.d/,前者存放默认的规则,后者存放自定义的规则。还有一个存放临时规则的目录/run/udev/rules.d/。这些规则汇总后按字母排序。但是/etc/udev/rules.d/下面的同名规则优先于/lib/udev/rules.d/默认的规则。
规则文件必须以.rules会后缀,否则被忽略。
规则文件支持:==,!=,=,+=,:=,*,?,[]。分别表示相等,不等,赋值,添加入列,终极赋值(后面的无效),[]配置之中某一个,[0-9]表示0到9中的一个。
关键字:ACTION,DEVPATH,KERNEL,NAME,SYMLINK,SYBSYSTEM,DRIVER,ATTR{filename},KERNELS,SYBSYSTEMS,DRIVERS,ATTRS{filename},TAGS,ENV{key},TAG,TEST{octal mod mask},PROGRAM,RESULT。
ACTION:事件活动名称;常用ACTION=="add"或者ACTION=="remove"表示添加或移除。
DEVPATH:事件设备路径;比如/dev
KERNEL:事件设备名称;如:sd[a-z][0-9]
NAME:结点或者网络接口名;设置一次,可全局使用。
SYBSYSTEM:事件设备子系统;比如:usb,sound,net
DRIVER:事件设备驱动名,比如:usb
ATTR{filename}:匹配事件设备的sysfs属性值。
PROGRAM:执行匹配的程序,返回0,为真。
ENV{key}:环境变量
RESULT:返回最后PROGRAM调用的字串。
RUN:为指定的设备添加PROGRAM列表。
LABEL:常和GOTO使用。
BUS:总线的名字,比如IDE,USB
OPTIONS:特殊选项;last_rule为这类设备规则执行;ignore_device 忽略当前规则; ignore_remove 忽略接下来的并移走请求,all_partitions 为所有的磁盘分区创建设备文件。
更多参数请man udev.

libudev参考手册:
libudev主要由以下六部分组成:
{
   udev 
   udev_list
   udev_device
   udev_monitor
   udev_enumerate
   udev_queue
}


udev结构体:主要保存从配置文件读取的默认值。

struct udev {
 int refcount;
 void (*log_fn)(struct udev *udev,
         int priority, const char *file, int line, const char *fn,
         const char *format, va_list args);
 void *userdata;
 char *sys_path;
 char *dev_path;
 char *rules_path;
 char *run_config_path;
 char *run_path;
 struct udev_list_node properties_list;
 int log_priority;
};
udev_list_entry结构体:设备链表入口
struct udev_list_entry {
 struct udev_list_node node;
 struct udev *udev;
 struct udev_list_node *list;
 char *name;
 char *value;
 int num;
};
udev_device结构体:udev设备链表
struct udev_device {
 struct udev *udev;
 struct udev_device *parent_device;
 char *syspath;
 const char *devpath;
 char *sysname;
 const char *sysnum;
 char *devnode;
 mode_t devnode_mode;
 char *subsystem;
 char *devtype;
 char *driver;
 char *action;
 char *devpath_old;
 char *knodename;
 char *id_filename;
 char **envp;
 char *monitor_buf;
 size_t monitor_buf_len;
 struct udev_list_node devlinks_list;
 struct udev_list_node properties_list;
 struct udev_list_node sysattr_value_list;
 struct udev_list_node sysattr_list;
 struct udev_list_node tags_list;
 unsigned long long int seqnum;
 unsigned long long int usec_initialized;
 int timeout;
 int devlink_priority;
 int refcount;
 dev_t devnum;
 int ifindex;
 int watch_handle;
 int maj, min;
 bool parent_set;
 bool subsystem_set;
 bool devtype_set;
 bool devlinks_uptodate;
 bool envp_uptodate;
 bool tags_uptodate;
 bool driver_set;
 bool info_loaded;
 bool db_loaded;
 bool uevent_loaded;
 bool is_initialized;
 bool sysattr_list_read;
 bool db_persist;
};
udev_monitor结构体:udev设备事件源
struct udev_monitor {
 struct udev *udev;
 int refcount;
 int sock;
 struct sockaddr_nl snl;
 struct sockaddr_nl snl_trusted_sender;
 struct sockaddr_nl snl_destination;
 struct sockaddr_un sun;
 socklen_t addrlen;
 struct udev_list_node filter_subsystem_list;
 struct udev_list_node filter_tag_list;
 bool bound;
};
udev_enumerate结构体:查找和排序sys设备
struct udev_enumerate {
 struct udev *udev;
 int refcount;
 struct udev_list_node sysattr_match_list;
 struct udev_list_node sysattr_nomatch_list;
 struct udev_list_node subsystem_match_list;
 struct udev_list_node subsystem_nomatch_list;
 struct udev_list_node sysname_match_list;
 struct udev_list_node properties_match_list;
 struct udev_list_node tags_match_list;
 struct udev_device *parent_match;
 struct udev_list_node devices_list;
 struct syspath *devices;
 unsigned int devices_cur;
 unsigned int devices_max;
 bool devices_uptodate:1;
 bool match_is_initialized;
};
udev_queue结构体:存取当前活动事件
struct udev_queue {
 struct udev *udev;
 int refcount;
 struct udev_list_node queue_list;
 struct udev_list_node failed_list;
};


udev代码的一般编译选项:
./configure \
    --prefix=/usr \
    --sysconfdir=/etc \
    --sbindir=/sbin \
    --libdir=/usr/lib64 \
    --with-rootlibdir=/lib64 \
    --libexecdir=/lib/udev
   

更多资料可以参阅:
 http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
 http://www.kernel.org/pub/linux/utils/kernel/hotplug/gudev/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值