新的Linux内核使用udev代替了hotplug作为热拔插管理, 虽然有udevd管理热拔插,但有时候我们还是需要在应用程序中检测热拔插事件以便快速地处理,比如在读写SD卡的时候拔下SD卡,那么需要立即检测出该情况,然后结束读写线程,防止VFS崩溃。Netlink是面向数据包的服务,为内核与用户层搭建了一个高速通道,是udev实现的基础。该工作方式是异步的,用户空间程序不必使用轮询等技术来检测热拔插事件。

    内核中使用uevent事件通知用户空间,uevent首先在内核中调用netlink_kernel_create()函数创建一个socket套接字,该函数原型在netlink.h有定义,其类型是表示往用户空间发送消息的NETLINK_KOBJECT_UEVENT,groups=1,由于uevent只往用户空间发送消息而不接受,因此其输入回调函数input和cb_mutex都设置为NULL。
#include
struct sock *netlink_kernel_create(struct net *net,int unit,unsigned int groups,
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex,

struct module *module);

ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT,
1, NULL, NULL, THIS_MODULE);

当有事件发生的时候,调用 kobject_uevent()函数,实际上最终是调用
netlink_broadcast_filtered(uevent_sock, skb , 0, 1, GFP_KERNEL , 
kobj_bcast_filter, kobj);

完成广播任务。
用户空间程序只需要创建一个socket描述符,将描述符绑定到接收地址,就可以实现热拔插事件的监听了。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <sys/types.h>
  6. #include <asm/types.h>
  7. //该头文件需要放在netlink.h前面防止编译出现__kernel_sa_family未定义
  8. #include <sys/socket.h>
  9. #include <linux/netlink.h>
  10. void MonitorNetlinkUevent()
  11. {
  12. int sockfd;
  13. struct sockaddr_nl sa;
  14. int len;
  15. char buf[4096];
  16. struct iovec iov;
  17. struct msghdr msg;
  18. int i;
  19. memset(&sa,0,sizeof(sa));
  20. sa.nl_family=AF_NETLINK;
  21. sa.nl_groups=NETLINK_KOBJECT_UEVENT;
  22. sa.nl_pid = 0;//getpid(); both is ok
  23. memset(&msg,0,sizeof(msg));
  24. iov.iov_base=(void *)buf;
  25. iov.iov_len=sizeof(buf);
  26. msg.msg_name=(void *)&sa;
  27. msg.msg_namelen=sizeof(sa);
  28. msg.msg_iov=&iov;
  29. msg.msg_iovlen=1;
  30. sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);
  31. if(sockfd==-1)
  32. printf("socket creating failed:%s\n",strerror(errno));
  33. if(bind(sockfd,(struct sockaddr *)&sa,sizeof(sa))==-1)
  34. printf("bind error:%s\n",strerror(errno));
  35. len=recvmsg(sockfd,&msg,0);
  36. if(len<0)
  37. printf("receive error\n");
  38. else if(len<32||len>sizeof(buf))
  39. printf("invalid message");
  40. for(i=0;i<len;i++)
  41. if(*(buf+i)=='\0')
  42. buf[i]='\n';
  43. printf("received %d bytes\n%s\n",len,buf);
  44. }
  45. int main(int argc,char **argv)
  46. {
  47. MonitorNetlinkUevent();
  48. return 0;
  49. }

创建socket描述符的时候指定协议族为AF_NETLINK或者PF_NETLINK,套接字type选择SOCK_RAW或者SOCK_DGRAM,Netlink协议并不区分这两种类型,第三个参数协议填充NETLINK_KOBJECT_UEVENT表示接收内核uevent信息。接着就绑定该文件描述
符到sockadd_nl,注意该结构体nl_groups是接收掩码,取~0是将接收所有来自内核的消息,我们接收热拔插只需要填NETLINK_KOBJECT_UEVENT即可。接下来调用recvmsg开始接收内核消息,recvmsg函数需要我们填充message报头,包括指定接收缓存等工作。该函数会阻塞直到有热拔插事件产生。
运行程序,然后我插入一个U盘,得到下面的结果:
$ ./netlink 
received 289 bytes
add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1
SUBSYSTEM=usb
MAJOR=189
MINOR=8
DEVNAME=bus/usb/001/009
DEVTYPE=usb_device
DEVICE=/proc/bus/usb/001/009
PRODUCT=781/5530/100
TYPE=0/0/0
BUSNUM=001
DEVNUM=009
SEQNUM=2306

运行程序,拔掉U盘
$ ./netlink 
received 294 bytes
remove@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/host10/target10:0:0/10:0:0:0/bsg/10:0:0:0
ACTION=remove
DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0/host10/target10:0:0/10:0:0:0/bsg/10:0:0:0
SUBSYSTEM=bsg
MAJOR=253
MINOR=2
DEVNAME=bsg/10:0:0:0
SEQNUM=2345

程序正确地接收到了U盘热拔插事件,通过该信息用户程序可以在第一时间得到事件通知。事实上热拔插的时候产生的消息可不止一条呢,可以在revmsg的时候用一个循环接收更多的消息。

转自: http://blog.chinaunix.net/uid-24943863-id-3223000.html

Netlink实现热拔插监控相关推荐

  1. ctk编译linux,CTK插件框架学习5-插件间通信(Netlink实现热拔插监控)

    本章来写一个插件,插件功能为通过NETLINK读取linux系统中的hotplug信息,比如usb.SD卡.磁盘等设备的插拔事件产生的信息,将读到的信息通过插件间通信的方式发出. 1. eventad ...

  2. U盘的热拔插/自动挂载跟linux2.6 kernel、 udev、 hal、 dbus 、gnome-mount 、thunar的关系...

    U盘的热拔插/自动挂载跟linux2.6 kernel. udev. hal. dbus .gnome-mount .thunar的关系 博客分类: System About Linux配置管理网络应 ...

  3. Hadoop节点热拔插

    一. Hadoop节点热拔插 在Hadoop集群中经常会进行增添节点操作,即实现节点的热拔插.在这些操作中不希望对集群进行重启. 2.在集群中添加节点: a. 把新节点IP或者主机名字加入到主节点的s ...

  4. HDMI热拔插电路举例说明

    HDMI_PLUG 最近设计关于HDMI的接口设计,在热拔插上纠结了很久,现在总结下. 如图 我们HDMI接口的18脚为外部输入电压5V,而19脚是我们的检测脚,该脚在内部是有一个500k的电阻接到地 ...

  5. Weston中HDMI热拔插检测

    Weston中的检测 drm_backend_create在创建时,会创建一个循环获取热拔插事件. b->udev_drm_source =wl_event_loop_add_fd(loop,u ...

  6. 嵌入式linux pcie网卡配置,[嵌入式linux]PCIe 热拔插(rescan)

    linux下可通过/sys/bus/pci/devices/0000\:[bus number]\:[device number].[function number]/ 目录下的节点进行热拔插操作. ...

  7. 【Orangepi Zero2 全志H616】语音刷抖音 / 手机连接Linux热拔插相关

    目录 一.手机连接Linux步骤 二.adb控制指令 三.基于Linux串口实现语音刷抖音 1.语音模块控制详情 2.代码实现 一.手机连接Linux步骤 1.把手机接入开发板 2.安装adb工具,在 ...

  8. 韦东山二期驱动视频-热拔插驱动——RK3399自制linux系统不支持HDMI热拔插问题分析

    背景: 公司的板子,对于HDMI的显示器热拔插不支持,只能在插入HDMI时启动才能输出,而当开机之后,再插入HDMI显示器则无输出,不知道原因. 推测如下: 1.设备树的引脚配置有误,导致插入HDMI ...

  9. [热拔插] 轻量级Winform插件式框架

    写在前面的话 对于大神,Winform这种"古董玩具",实在没太多"技术性"可言了,然而『好用才是王道』,本文不以技术为卖点,纯属经验之谈,欢迎交流拍砖 朴素版 ...

最新文章

  1. 植物微生物组培养与重组技术:从描述性研究走向功能性研究
  2. python中类方法与实例方法的区别-python中类方法、类实例方法、静态方法的使用与区别...
  3. 《P5R》的反派设计有什么可取之处?
  4. 7-192 素因子分解 (20 分)
  5. 2021年6月20日 是第111个父亲节,祝福所有的父亲节日快乐
  6. Security+ 学习笔记29 虚拟化
  7. vue登录如何存储cookie_vue登录模块,登录状态应该存在哪里,怎么防止手动改cookie、localStorage?...
  8. ghost 开发主题
  9. 动手刷LeetCode-转换罗马字符
  10. notifier_chain 内核通知链的学习与使用
  11. VMware Workstation 15 Player 社区版安装教程
  12. 工业制造行业B2B电商平台解决方案
  13. Windows 7 Boot Updater 如何使用
  14. 贝叶斯法则,先验概率,后验概率,最大后验概率
  15. 智慧文娱,阿里巴巴文娱技术探索之路
  16. 嵌入式Linux根文件系统制作
  17. C语言程序设计--学生信息管理系统
  18. 一个简单的http server,处理get和post请求,Python实现
  19. 【科研经验】刚读博士想退学?如何避免博士毕业不了?
  20. 中国大学生计算机设计大赛

热门文章

  1. 项目经理怎么运用思维导图
  2. windows环境下封装条件wait和signal
  3. java 获取当前时间月加1 ,年加1
  4. 一个return引发的血案 - 自己动手实现allocator
  5. javascript:重新加载js文件
  6. Prism4文档翻译(第四章 第二部分)
  7. 表单身份验证(受保护的目录)
  8. 利用系统滴答时间计算实际程序运行时间
  9. 获得北大新材料学院夏令营offer的艰险历程(附面试答辩PPT)
  10. 数据结构与算法必备的 50 个代码实现