PF_NETLINK应用实例NETLINK_KOBJECT_UEVENT具体实现--udev实现原理

2023-11-07

相对于linux来说,udev还是一个新事物。然而,尽管它03年才出现,尽管它很低调(J),但它无疑已经成为linux下不可或缺的组件了。udev是什么?它是如何实现的?最近研究Linux设备管理时,花了一些时间去研究udev的实现。 
   
  udev是什么?u 是指user space,dev是指device,udev是用户空间的设备驱动程序吗?最初我也这样认为,调试内核空间的程序要比调试用户空间的程序复杂得多,内核空间的程序的BUG所引起的后果也严重得多,device driver是内核空间中所占比较最大的代码,如果把这些device driver中硬件无关的代码,从内核空间移动到用户空间,自然是一个不错的想法。 
   
  但我的想法并不正确,udev的文档是这样说的, 
  1. dynamic replacement for /dev。作为devfs的替代者,传统的devfs不能动态分配major和minor的值,而major和minor非常有限,很快就会用完了。 udev能够像DHCP动态分配IP地址一样去动态分配major和minor。 
   
  2. device naming。提供设备命名持久化的机制。传统设备命名方式不具直观性,像/dev/hda1这样的名字肯定没有boot_disk这样的名字直观。udev能够像DNS解析域名一样去给设备指定一个有意义的名称。 
   
  3. API to access info about current system devices 。提供了一组易用的API去操作sysfs,避免重复实现同样的代码,这没有什么好说的。 
   
  我们知道,用户空间的程序与设备通信的方法,主要有以下几种方式:
  1. 通过ioperm获取操作IO端口的权限,然后用inb/inw/ inl/ outb/outw/outl等函数,避开设备驱动程序,直接去操作IO端口。(没有用过) 
  2. 用ioctl函数去操作/dev目录下对应的设备,这是设备驱动程序提供的接口。像键盘、鼠标和触摸屏等输入设备一般都是这样做的。 
  3. 用write/read/mmap去操作/dev目录下对应的设备,这也是设备驱动程序提供的接口。像framebuffer等都是这样做的。 
   
  上面的方法在大多数情况下,都可以正常工作,但是对于热插拨(hotplug)的设备,比如像U盘,就有点困难了,因为你不知道:什么时候设备插上了,什么时候设备拔掉了。这就是所谓的hotplug问题了。 
   
  处理hotplug传统的方法是,在内核中执行一个称为hotplug的程序,相关参数通过环境变量传递过来,再由hotplug通知其它关注 hotplug事件的应用程序。这样做不但效率低下,而且感觉也不那么优雅。新的方法是采用NETLINK实现的,这是一种特殊类型的socket,专门用于内核空间与用户空间的异步通信。下面的这个简单的例子,可以监听来自内核hotplug的事件。

  
  
#include < stdio.h > #include < stdlib.h > #include < string .h > #include < ctype.h > #include < sys / un.h > #include < sys / ioctl.h > #include < sys / socket.h > #include < linux / types.h > #include < linux / netlink.h > #include < errno.h > #include < unistd.h > #include < arpa / inet.h > #include < netinet / in .h > #define UEVENT_BUFFER_SIZE 2048 static int init_hotplug_sock() { const int buffersize = 1024 ; int ret; struct sockaddr_nl snl; bzero( & snl, sizeof ( struct sockaddr_nl)); snl.nl_family = AF_NETLINK; snl.nl_pid = getpid(); snl.nl_groups = 1 ; int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if (s == - 1 ) { perror( " socket " ); return - 1 ; } setsockopt(s, SOL_SOCKET, SO_RCVBUF, & buffersize, sizeof (buffersize)); ret = bind(s, ( struct sockaddr * ) & snl, sizeof ( struct sockaddr_nl)); if (ret < 0 ) { perror( " bind " ); close(s); return - 1 ; } return s; } int main( int argc, char * argv[]) { int hotplug_sock = init_hotplug_sock(); while ( 1 ) { /* Netlink message buffer */ char buf[UEVENT_BUFFER_SIZE * 2 ] = { 0 }; recv(hotplug_sock, & buf, sizeof (buf), 0 ); printf( " %s\n " , buf); /* USB 设备的插拔会出现字符信息,通过比较不同的信息确定特定设备的插拔,在这添加比较代码 */ } return 0 ; }

   
  编译: 
  gcc -g hotplug.c -o hotplug_monitor 
   
  运行后插/拔U盘,可以看到:

  
  
  add@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1   add@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / usbdev2.2_ep00   add@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0   add@ / class / scsi_host / host2   add@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / usbdev2.2_ep81   add@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / usbdev2.2_ep02   add@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / usbdev2.2_ep83   add@ / class / usb_device / usbdev2. 2   add@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / host2 / target2: 0 : 0 / 2 : 0 : 0 : 0   add@ / class / scsi_disk / 2 : 0 : 0 : 0   add@ / block / sda   add@ / block / sda / sda1   add@ / class / scsi_device / 2 : 0 : 0 : 0   add@ / class / scsi_generic / sg0   remove@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / usbdev2.2_ep81   remove@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / usbdev2.2_ep02   remove@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / usbdev2.2_ep83   remove@ / class / scsi_generic / sg0   remove@ / class / scsi_device / 2 : 0 : 0 : 0   remove@ / class / scsi_disk / 2 : 0 : 0 : 0   remove@ / block / sda / sda1   remove@ / block / sda   remove@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0 / host2 / target2: 0 : 0 / 2 : 0 : 0 : 0   remove@ / class / scsi_host / host2   remove@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / 2 - 1 : 1.0   remove@ / class / usb_device / usbdev2. 2   remove@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1 / usbdev2.2_ep00   remove@ / devices / pci0000: 00 / 0000 : 00 :1d. 1 / usb2 / 2 - 1

  udev的主体部分在udevd.c文件中,它主要监控来自4个文件描述符的事件/消息,并做出处理: 
  1. 来自客户端的控制消息。这通常由udevcontrol命令通过地址为/org/kernel/udev/udevd的本地socket,向udevd发送的控制消息。其中消息类型有: 
  l UDEVD_CTRL_STOP_EXEC_QUEUE 停止处理消息队列。 
  l UDEVD_CTRL_START_EXEC_QUEUE 开始处理消息队列。 
  l UDEVD_CTRL_SET_LOG_LEVEL 设置LOG的级别。 
  l UDEVD_CTRL_SET_MAX_CHILDS 设置最大子进程数限制。好像没有用。 
  l UDEVD_CTRL_SET_MAX_CHILDS_RUNNING 设置最大运行子进程数限制(遍历proc目录下所有进程,根据session的值判断)。 
  l UDEVD_CTRL_RELOAD_RULES 重新加载配置文件。 
  2. 来自内核的hotplug事件。如果有事件来源于hotplug,它读取该事件,创建一个udevd_uevent_msg对象,记录当前的消息序列号,设置消息的状态为EVENT_QUEUED,然后并放入running_list和exec_list两个队列中,稍后再进行处理。 
  3. 来自signal handler中的事件。signal handler是异步执行的,即使有signal产生,主进程的select并不会唤醒,为了唤醒主进程的select,它建立了一个管道,在 signal handler中,向该管道写入长度为1个子节的数据,这样就可以唤醒主进程的select了。 
  4. 来自配置文件变化的事件。udev通过文件系统inotify功能,监控其配置文件目录/etc/udev/rules.d,一旦该目录中文件有变化,它就重新加载配置文件。 
   
  其中最主要的事件,当然是来自内核的hotplug事件,如何处理这些事件是udev的关键。udev本身并不知道如何处理这些事件,也没有必要知道,因为它只实现机制,而不实现策略。事件的处理是由配置文件决定的,这些配置文件即所谓的rule。 
   
  关于rule的编写方法可以参考《writing_udev_rules》,udev_rules.c实现了对规则的解析。 
   
  在规则中,可以让外部应用程序处理某个事件,这有两种方式,一种是直接执行命令,通常是让modprobe去加载驱动程序,或者让mount去加载分区。另外一种是通过本地socket发送消息给某个应用程序。 
   
  在udevd.c:udev_event_process函数中,我们可以看到,如果RUN参数以”socket:”开头则认为是发到socket,否则认为是执行指定的程序。 
   
  下面的规则是执行指定程序: 
  60-pcmcia.rules: RUN+="/sbin/modprobe pcmcia" 
   
  下面的规则是通过socket发送消息: 
  90-hal.rules:RUN+="socket:/org/freedesktop/hal/udev_event"


http://www.cnblogs.com/hoys/archive/2011/04/09/2010759.html


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PF_NETLINK应用实例NETLINK_KOBJECT_UEVENT具体实现--udev实现原理 的相关文章

  • 在Fedora16中安装Qt

    首先 在http www trolltech com download上下载linux下的qt源文件 我下载时最新版是 qt everywhere opensource src 4 7 4 tar gz 将该文件放到某个目录下 进行解压缩
  • Centos 7安装mysql

    1 安装前清理工作 1 1 1 清理原有的mysql数据库 使用以下命令查找出安装的mysql软件包和依赖包 rpm pa grep mysql 显示结果如下 mysql80 community release el7 1 noarch m
  • 【内核驱动】Linux概述

    00 目录 文章目录 00 目录 01 Unix简介 02 Linux简介 03 Linux发展史 04 单内核与微内核区别 05 Linux内核 06 Linux内核组成 07 Linux官方网站 08 附录 01 Unix简介 UNIX
  • linux内核对于指令异常的处理

    1 处理流程 以arm64来介绍一下流程 如果在用户层发生指令异常时 首先进入入口el0 undef arch arm64 kernel entry s el0 undef Undefined instruction enable inte
  • gethostbyname() -- 用域名或主机名获取IP地址

    http hi baidu com zengzhaonong item 87d9d296d0824cbb82d29570 include
  • 杂项知识

    挂载 img 文件 mount t proc o loop initrd 2 6 23 1 42 fc8 img mnt img mount t debugfs o loop initrd 2 6 23 1 42 fc8 img mnt i
  • 鼠标点击页面出现富强自由等文字JS特效

    在其他博客看到一款JS特效 感觉很不错 所有网上收集过来分享给大家 效果参考本网站 添加点击特效 点击页面会显示 富强 民主 文明 和谐 自由 平等 公正 法治 爱国 敬业 诚信 友善 把以下代码添加到当前主题的head php或foote
  • 中标麒麟QT中qDebug无输出问题解决办法

    一 系统环境 中标麒麟V5 qt creator 4 3 1 qt5 qtbase 5 6 2 二 问题 代码中qDebug 函数无输出 但qInfo 和qWarning 有输出 创建一个test工程 使用qDebug 打印信息 但是没有任
  • 【xenclient】 使用小结 -- ubuntu的千百bug

    说道多系统 不能不提下ubuntu 以前redhat似乎是linux的领头羊 但在桌面领域 跟windows还是差得太远 在linux最弱的桌面特性上 ubuntu算是第一个以桌面特效全面超越windows的系统了 因此我的系统 除了保留做
  • 七种Linux设备驱动模型之——Device

    前言 Linux将所有的设备统一抽象为struct device结构 同时将所有的驱动统一抽象为struct device driver结构 这样设计之后就方便驱动开发工程师编写驱动 只需要将具体的设备包含struct device结构 具
  • 使用truss、strace或ltrace诊断软件的"疑难杂症"

    作者 李凯斌 2005 01 18 11 03 24 来自 IBM DW中国 进程无法启动 软件运行速度突然变慢 程序的 Segment Fault 等等都是让每个Unix系统用户头痛的问题 本文通过三个实际案例演示如何使用truss st
  • 音视频大牛雷霄骅

    https blog csdn net leixiaohua1020 https www zhihu com question 49211380 https www bilibili com video av9927626 share so
  • Linux的目录切换和用户管理

    切换目录 在使用linux系统的时候 会用cd来切换目录 cd 切换到根目录 cd 切换到主目录 cd 切换到之前工作目录 cd 虽然很方便但只能保存一次目录 pushd命令使用目录堆栈可以把多个目录存放起来 配套使用pushd popd
  • 第九章 tcp拥塞控制--基于Linux3.10

    下载地址 http download csdn net detail shichaog 8620701 Linux提供丰富的拥塞控制算法 这些算法包括Vegas Reno HSCTP High Speed TCP Westwood BIC
  • spark_hadoop集群搭建自动化脚本

    bin bash 脚本使用说明 1 使用脚本前需要弄好服务器的基础环境 2 在hadoop的每个节点需要手动创建如下目录 data hdfs tmp 3 修改下面的配置参数 4 脚本执行完备后需要收到格式化namenode
  • int $0x80系统调用的idea

    1 基础知识 用户态和内核态 一般现代CPU都有几种不同的指令执行级别 Linux总共划分为4个指令执行级别 内核运行在0级别上 1 2级别默认不运行 用户程序运行在3级别上 在内核指令执行级别上 代码可以执行特权指令 访问任意的物理地址
  • 主线程退出后,子线程会不会退出

    额 好吧 这是个标题党 其实所有的线程都是平级的 根本不存在主线程和子线程 下文所述为了方便 将在main函数中的线程看做主线程 其它线程看成子线程 特此说明 先考虑以下代码 include
  • begin to drop messages due to rate-limiting

    对于syslog保存的日志会有很多重要信息 但是一旦打印的日志数量超过设置的阈值 就会丢掉 imuxsock pid 48 begin to drop messages due to rate limiting 这是在调试时不愿看到的 可以
  • linux内核-软中断与Bottom Half

    中断服务一般都是在将中断请求关闭的条件下执行的 以避免嵌套而使控制复杂化 可是 如果关中断的时间持续太长就可能因为CPU不能及时响应其他的中断请求而使中断 请求 丢失 为此 内核允许在将具体的中断服务程序挂入中断请求队列时将SA INTER
  • gcc搜索动态链接库的路径优先级排序

    GCC运行时 Linux动态链接库的搜索路径按优先级排序为 1 编译目标代码时 Wl rpath 指定的动态库搜索路径 当指定多个动态库搜索路径时 路径之间用冒号 分隔 2 环境变量 LD LIBRARY PATH 指定的动态库搜索路径 3

随机推荐

  • 常用Linux的ssh远程终端连接工具

    1 putty 说明 putty是最简单的SSH工具 无需安装 支持多系统版本 下载后就可以直接使用 优点 1 免费 2 免安装 缺点 1 不支持标签模式 2 默认设置不友好 很多功能都需要额外配置才行 例如自动登录功能 3 不能传输文件
  • SCP 命令

    svn 删除所有的 svn文件 find name svn type d exec rm fr linux之cp scp命令 scp命令详解 2011 03 09 17 27 22 分类 Linux 标签 linux cp scp comm
  • 管理学经典定理汇粹

    一 素养 蓝斯登原则 在你往上爬的时候 一定要保持梯子的整洁 否则你下来时可能会滑倒 提出者 美国管理学家蓝斯登 点评 进退有度 才不至进退维谷 宠辱皆忘 方可以宠辱不惊 卢维斯定理 谦虚不是把自己想得很糟 而是完全不想自己 提出者 美国心
  • SVN下最高效打基线方法

    作者 张克强 作者微博 张克强 敏捷307 2014 7 6 方法一来自于我的一条微博 组织级scm建一个名为controlled的目录 当项目某文档通过评审后 组织级scm从项目目录下找到那文档 复制到controlled目录下 请 sc
  • 通过命令行运行java文件(jar、class),以及生成一个简单的jar包

    最近在开发中涉及到了java文件的运行 踩了一些坑 简单记录一下 jar文件 在装有java的计算机中 要直接运行jar文件 可以用命令 java jar jarpath 若要指定运行类名 则用 java cp jarpath classn
  • PointNet家族

    点云数据的特性和挑战 1 点云具有不规则性 顺序不相关性 置换排序不变性对深度学习具有很大的挑战 Irregular unordered permutation invariance 2 刚性变换 scale transorfmation
  • 开源库生态与供应链论坛

    ChinaOSC 2022开源库生态与供应链技术论坛将于8月21日在陕西省西安高新国际会议中心召开 开源软件供应链管理是软件项目持续维护过程中的关键任务 本论坛邀请来自学术界和开源社区的专家分享开源三方库和供应链管理有关的学术研究成果和社区
  • SQL中的PowerDesigner逐步深入提问,你能掌握多少?

    你提到了有PowerDesigner操作经验 请解释一下PowerDesigner是什么 以及它在数据库设计和开发中的作用是什么 标准回答 PowerDesigner是一种数据库建模和设计工具 它用于创建数据库模型 设计表结构 定义关系和生
  • Python入门教程完整版(懂中文就能学会)

    今天给大家带来了干货 Python入门教程完整版 完整版啊 完整版 言归正传 小编该给大家介绍一下这套教程了 希望每个小伙伴都沉迷学习 无法自拔 本套教程学习时间15天 1 3天内容 为Linux基础命令 4 13天内容 为Python基础
  • Oauth2授权模式访问之客户端模式(client_credentials)访问

    Oauth3授权模式访问之客户端模式 client credentials 访问 使用POSTMAN获取token url上填写http localhost 8080 oauth token grant type client creden
  • confidence weighted learning

    这个算法原作者意思是在NLP中面对高维向量和数据稀疏时效果会不错 算法保持了当前预测向量w的均值和方差 并做优化 代码实现如下 cw learning algorithm def get phi confidence parameter p
  • 从数仓到数据中台,谈技术选型最优解

    本文根据颜博老师在 Deeplus直播第218期 线上分享演讲内容整理而成 文末有获取本期PPT 回放的途径 不要错过 颜博 马蜂窝数仓研发总监 现任马蜂窝数据仓库团队负责人 曾供职于京东 IBM 亚信等公司 数据行业老兵一名 历经传统数据
  • 2023年的C基础笔记

    头介绍 include
  • 《汇编语言(第四版)》---王爽 第一章 基础知识 详细笔记 ~后续章节笔记,课后检测,实验代码持续更新中

    汇编语言 第四版 王爽 第一章基础知识 汇编语言是直接在硬件之上工作的汇编语言 1 1 机器语言 机器语言就是机器指令的集合 机器指令展开来讲就是一台计算机可以正确执行的命令 早期的程序员进行纸带打孔 电子计算机的机器指令是一列二进制数字
  • 查看系统中支持CUDA的设备数量和属性---deviceQuery示例

    在你安装了CUDA显卡驱动之后 需要检测是否安装正确 或者需要查看系统中支持CUDA的设备数量和属性 可以通过SDK中的deviceQuery示例来查看 工程目录位置 C ProgramData NVIDIA Corporation CUD
  • 谈谈数据的增量更新

    谈谈数据的增量更新 在数据同步的过程中 必然会遇到数据增量更新的需求 但如果没有一个有效的数据增量更新的设计与机制 可能每次上游数据更新时 你都需要将全量的数据同步一遍 即使只有1 的数据发生了更新 全量数据同步在数据首次同步的时候是需要的
  • source insight3.5 unable to create the project directory file

    在开始 gt 解除锁定的工程就可以了
  • 基于Docker快速搭建Hadoop集群和Flink运行环境

    前言 搭建集群 环境升级 配置Hadoop 配置Flink 打包镜像 启动集群 前言 本文主要讲 基于Docker在本地快速搭建一个Hadoop 2 7 2集群和Flink 1 11 2运行环境 用于日常Flink任务运行测试 前任栽树 后
  • Socks5代理IP在跨境电商与游戏中的应用

    随着互联网的迅猛发展 网络已经成为人们日常生活不可或缺的一部分 在这个数字化时代 跨境电商和网络游戏产业蓬勃发展 但伴随而来的是网络安全的威胁与挑战 本文将介绍Socks5代理IP技术 探讨它在网络安全 跨境电商以及游戏中的关键作用 以确保
  • PF_NETLINK应用实例NETLINK_KOBJECT_UEVENT具体实现--udev实现原理

    相对于linux来说 udev还是一个新事物 然而 尽管它03年才出现 尽管它很低调 J 但它无疑已经成为linux下不可或缺的组件了 udev是什么 它是如何实现的 最近研究Linux设备管理时 花了一些时间去研究udev的实现 udev