《Linux设备节点创建》内核kobject上报uevent过滤规则

2024-03-15 14:32

本文主要是介绍《Linux设备节点创建》内核kobject上报uevent过滤规则,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

说明:本文基于Android2.3和Linux2.6,其余版本仅供参考。

Android2.3及Linux2.6.29内核模拟器版本编译与调试

阅读本文前请阅读:Linux总线、设备、驱动与设备节点创建、用户测试程序 

一、netlink监听程序

testnet.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <asm/types.h>
//该头文件需要放在netlink.h前面防止编译出现__kernel_sa_family未定义
#include <sys/socket.h>  
#include <linux/netlink.h>void MonitorNetlinkUevent()
{int sockfd;struct sockaddr_nl sa;int len;char buf[4096];struct iovec iov;struct msghdr msg;int i;memset(&sa,0,sizeof(sa));sa.nl_family=AF_NETLINK;sa.nl_groups=NETLINK_KOBJECT_UEVENT;sa.nl_pid = 0;//getpid(); both is okmemset(&msg,0,sizeof(msg));iov.iov_base=(void *)buf;iov.iov_len=sizeof(buf);msg.msg_name=(void *)&sa;msg.msg_namelen=sizeof(sa);msg.msg_iov=&iov;msg.msg_iovlen=1;sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);if(sockfd==-1)printf("socket creating failed:%s\n",strerror(errno));if(bind(sockfd,(struct sockaddr *)&sa,sizeof(sa))==-1)printf("bind error:%s\n",strerror(errno));while(1){memset(buf,0,sizeof(buf));len=recvmsg(sockfd,&msg,0);if(len<0){}//printf("receive error\n");else if(len<32||len>sizeof(buf))printf("invalid message");for(i=0;i<len;i++)if(*(buf+i)=='\0')buf[i]='\n';printf("received %d bytes\n%s\n",len,buf);}
}int main(int argc,char **argv)
{MonitorNetlinkUevent();return 0;
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)LOCAL_SRC_FILES:= \testnet.cLOCAL_SHARED_LIBRARIES := \libutils LOCAL_MODULE:= testnetLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE)

二、如下是添加打印后的信息(Android用户空间udev为ueventd,属于init的一个软连接)

1.总线驱动

root@android:/data/tank # insmod testbus.ko 

//内核模块加载成功,会上报netlink                                  
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'testbus' (bf02d1c8): kobject_uevent_env
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast
//总线注册上报netlink
TK---testlddbus.c----->>>>ldd_bus_init
TK--------->>>>>>bus.c>>>>>>bus_register,,,bus->name is ldd
TK-------_>>>>kobject.c>>>>>>>kset_register
TK-------_>>>>kobject.c>>>>>>>kset_register>>>kobject_uevent
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'ldd' (cfcdb1c8): kobject_uevent_env
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast
//设备注册由于没有分配主设备号,不上报netlink
TK-------_>>>>>>>>core.c>>>>>device_register
TK-------_>>>>>>>>core.c>>>>>device_add
TK-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
TK-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0x0
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->class is 0x0
kobject: 'ldd0' (bf02d074): kobject_uevent_env
kobject: 'ldd0' (bf02d074): kobject_uevent_env: filter function caused the event to drop!
//用户空间ueventd的处理,2个uevent事件
init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 4
init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0
received 83 bytes
add@/module/testbus
ACTION=add
DEVPATH=/module/testbus
SUBSYSTEM=module
SEQNUM=649received 66 bytes
add@/bus/ldd
ACTION=add
DEVPATH=/bus/ldd
SUBSYSTEM=bus
SEQNUM=650
说明:

drivers/base/bus.c

int bus_register(struct bus_type *bus){retval = kset_register(&priv->subsys);/*lib/kobject.cint kset_register(struct kset *k){kobject_uevent(&k->kobj, KOBJ_ADD);}*/retval = bus_create_file(bus, &bus_attr_uevent);priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj);priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
}

2.插入设备

root@android:/data/tank # insmod testdev.ko 

//内核模块加载会上报netlink                          
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'testdev' (bf0334e0): kobject_uevent_env
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast
//没有主设备号,不会上报netlink
TK---testdev.c----->>>>mini_init
TK-------_>>>>>>>>core.c>>>>>device_register
TK-------_>>>>>>>>core.c>>>>>device_add
TK-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'mini' (bf0333dc): kobject_uevent_env
TK-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0xbf001130
TK---testlddbus.c----->>>>ldd_uevent
TK-------_>>>>>>drivers/base/core.c>>dev_uevent>>retval is -12
kobject: 'mini' (bf0333dc): kobject_uevent_env: uevent() returned -12  
//用户空间ueventd的处理,1个uevent事件
init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 4
init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0
received 83 bytes
add@/module/testdev
ACTION=add
DEVPATH=/module/testdev
SUBSYSTEM=module
SEQNUM=651
3.设备驱动

root@android:/data/tank # insmod testdriver.ko  

//内核模块成功加载,会上报netlink                              
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'testdriver' (bf039c34): kobject_uevent_env
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast
//类注册会上报netlink(class_creat)
TK---testdriver.c----->>>>driver_init
Tk--------->>>>>driver.c>>>>>>driver_register
TK---------_>>>>>bus.c>>>>>>>bus_add_driver
TK---testbus.c----->>>>ldd_match
TK---testbus.c----->>>>ldd_match
TK---testlddbus.c----->>>>ldd_drv_probe
TK----testdriver.c------>>>>driver_probe mini
TK-------_>>>>kobject.c>>>>>>>kset_register
TK-------_>>>>kobject.c>>>>>>>kset_register>>>kobject_uevent
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'mymodule' (cfee5b68): kobject_uevent_env
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast
//有主设备号时设备注册上报netlink
TK-------->>>>>core.c>>>>device_create
TK-------_>>>>>>>>core.c>>>>>device_register
TK-------_>>>>>>>>core.c>>>>>device_add
TK-------_>>>>>>>>core.c>>>>>device_add>>>>>kobject_uevent
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'mymod0' (caa4e724): kobject_uevent_env
TK-------_>>>>>>drivers/base/core.c>>dev_uevent_filter>>ktype is 0xc032137c,&device_ktype is 0xc032137c
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->uevent_suppress is 0
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->bus is 0x0
TK-------->>>>drivers/base/core.c>>dev_uevent_filter>>dev->class is 0xcaade760
TK-------_>>>>>>drivers/base/core.c>>dev_uevent>>retval is 0
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast
//驱动注册都会上报netlink
TK---------_>>>>>bus.c>>>>>>>bus_add_driver>>>>kobject_uevent
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env
kobject: 'mini' (c8aa48c0): kobject_uevent_env
TK------->>>>>>kobject_uevent.c>>>>>kobject_uevent_env>>>>netlink_broadcast
//用户空间ueventd的处理,4个uevent事件
init: TK-------_>>>>>uevent.c>>>>>>ueventd_main>>>>ufd.fd is 4
init: TK-------_>>>>>>device.c.>>>>>>handle_device_fd
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is 248,uevent->minor is 0
init: TK------_>>>>>>>>>make_devices
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>uevent->major is -1,uevent->minor is -1
init: TK------------>>>>device.c>>>>>>handle_device_event>>>>>>uevent->major and minor < 0
received 89 bytes
add@/module/testdriver
ACTION=add
DEVPATH=/module/testdriver
SUBSYSTEM=module
SEQNUM=652received 82 bytes
add@/class/mymodule
ACTION=add
DEVPATH=/class/mymodule
SUBSYSTEM=class
SEQNUM=653received 137 bytes
add@/devices/virtual/mymodule/mymod0
ACTION=add
DEVPATH=/devices/virtual/mymodule/mymod0
SUBSYSTEM=mymodule
MAJOR=248
MINOR=0
SEQNUM=654received 96 bytes
add@/bus/ldd/drivers/mini
ACTION=add
DEVPATH=/bus/ldd/drivers/mini
SUBSYSTEM=drivers
SEQNUM=655
说明:

drivers/base/driver.c  

int driver_register(struct device_driver *drv){ret = bus_add_driver(drv);/*drivers/base/bus.cint bus_add_driver(struct device_driver *drv){kobject_uevent(&priv->kobj, KOBJ_ADD);}*/
}
include/linux/device.h
#define class_create(owner, name)		\
({						\static struct lock_class_key __key;	\__class_create(owner, name, &__key);	\/*drivers/base/class.cretval = __class_register(cls, key);int __class_register(struct class *cls, struct lock_class_key *key){error = kset_register(&cp->subsys);}lib/kobject.cint kset_register(struct kset *k){kobject_uevent(&k->kobj, KOBJ_ADD);}*/ 
})

drivers/base/core.c

struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...){dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);/*struct device *device_create_vargs(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt,va_list args){retval = device_register(dev);}int device_register(struct device *dev){return device_add(dev);}int device_add(struct device *dev){error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev));if (MAJOR(dev->devt)) {  //有设备号才会上报uevent事件!!error = device_create_file(dev, &devt_attr);if (error)  goto ueventattrError;error = device_create_sys_dev_entry(dev);if (error) goto devtattrError;}kobject_uevent(&dev->kobj, KOBJ_ADD);}*/
}
总结:

bus_register,driver_register,class_create,device_create以及内核模块加载有uevent通过netlink上报,

device_register的uevent会根据是否有设备号来决定是否上报事件

三、最后分析下内核kobject_uevent函数:

对于uevent通过netlink的事件上报,其实还是kobject这个类起作用。

1.看总线注册给Linux内核总线模型的情况,即bus_register

先回忆下内核启动时总线模型初始化:

drivers/base/bus.c

int __init buses_init(void)
{bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
}
static struct kset_uevent_ops bus_uevent_ops = {.filter = bus_uevent_filter,
};

具体过滤规则可以看代码;我想说的是Linux内核总线模型的过滤函数很简单、没有特别限制,这样在我们注册一个新的总线(bus_register)时、都会上报uevent事件。

2.看设备注册给Linux内核设备模型的情况,即device_register

先会议下内核启动时设备模型初始化:

drivers/base/core.c

int __init devices_init(void)
{devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
}
static struct kset_uevent_ops device_uevent_ops = {.filter =	dev_uevent_filter,.name =		dev_uevent_name,.uevent =	dev_uevent,
}

具体过滤规则可以看代码;我想说的是Linux内核设备模型的过滤函数和是否uevent上报函数比较复杂,其中过滤函数功能是:如果新注册到设备模型的设备不属于总线、不会上报uevent,如果新注册设备没有主次设备号也不会上报uevent;只有上述两个同时满足时,才会上报。

lib/kobject_uevent.c

int kobject_uevent(struct kobject *kobj, enum kobject_action action){return kobject_uevent_env(kobj, action, NULL);
}
EXPORT_SYMBOL_GPL(kobject_uevent);
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[]){struct kobject *top_kobj;struct kset *kset;struct kset_uevent_ops *uevent_ops;top_kobj = kobj;while (!top_kobj->kset && top_kobj->parent)top_kobj = top_kobj->parent;kset = top_kobj->kset;uevent_ops = kset->uevent_ops;if (uevent_ops && uevent_ops->filter) //kset的过滤规则,详细看drivers/base/core.c的dev_uevent_filter函数if (!uevent_ops->filter(kset, kobj)) {/*drivers/base/core.cint __init devices_init(void){devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);}static struct kset_uevent_ops device_uevent_ops = {.filter =	dev_uevent_filter,//上处uevent_ops->filter(kset, kobj)就是这个.name =		dev_uevent_name,.uevent =	dev_uevent,//下边uevent_ops->uevent(kset, kobj, env)就是这个};*/pr_debug("kobject: '%s' (%p): %s: filter function ""caused the event to drop!\n",kobject_name(kobj), kobj, __func__); //change by tank from pr_debug to printkreturn 0;}if (uevent_ops && uevent_ops->uevent) {//无设备号的设备注册不会被上报!详细看drivers/base/core.c的dev_uevent函数retval = uevent_ops->uevent(kset, kobj, env);if (retval) {pr_debug("kobject: '%s' (%p): %s: uevent() returned ""%d\n", kobject_name(kobj), kobj,__func__, retval); //change by tank from pr_debug to printkgoto exit;}}retval = netlink_broadcast_filtered(uevent_sock, skb, 0, 1, GFP_KERNEL,kobj_bcast_filter, kobj);  //netlink上报事件
}
net/netlink/af_netlink.c
int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 pid,u32 group, gfp_t allocation,int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data),void *filter_data){}

这篇关于《Linux设备节点创建》内核kobject上报uevent过滤规则的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/812283

相关文章

Nginx路由匹配规则及优先级详解

《Nginx路由匹配规则及优先级详解》Nginx作为一个高性能的Web服务器和反向代理服务器,广泛用于负载均衡、请求转发等场景,在配置Nginx时,路由匹配规则是非常重要的概念,本文将详细介绍Ngin... 目录引言一、 Nginx的路由匹配规则概述二、 Nginx的路由匹配规则类型2.1 精确匹配(=)2

ubuntu16.04如何部署dify? 在Linux上安装部署Dify的技巧

《ubuntu16.04如何部署dify?在Linux上安装部署Dify的技巧》随着云计算和容器技术的快速发展,Docker已经成为现代软件开发和部署的重要工具之一,Dify作为一款优秀的云原生应用... Dify 是一个基于 docker 的工作流管理工具,旨在简化机器学习和数据科学领域的多步骤工作流。它

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I

Linux系统调试之ltrace工具使用与调试过程

《Linux系统调试之ltrace工具使用与调试过程》:本文主要介绍Linux系统调试之ltrace工具使用与调试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、ltrace 定义与作用二、ltrace 工作原理1. 劫持进程的 PLT/GOT 表2. 重定

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Java 如何创建和使用ExecutorService

《Java如何创建和使用ExecutorService》ExecutorService是Java中用来管理和执行多线程任务的一种高级工具,可以有效地管理线程的生命周期和任务的执行过程,特别是在需要处... 目录一、什么是ExecutorService?二、ExecutorService的核心功能三、如何创建

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构