mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 12:16:31 +00:00
updates uevent and make fmt
This commit is contained in:
@ -333,11 +333,9 @@ impl KObjectManager {
|
||||
length -= cur;
|
||||
let parent_name = parent.name();
|
||||
let name = parent_name.as_bytes();
|
||||
for i in 0..cur {
|
||||
path[length + i] = name[i];
|
||||
}
|
||||
path[length..(cur + length)].copy_from_slice(&name[..cur]);
|
||||
length -= 1;
|
||||
path[length] = '/' as u8;
|
||||
path[length] = b'/';
|
||||
if let Some(weak_parent) = parent.parent() {
|
||||
if let Some(upgraded_parent) = weak_parent.upgrade() {
|
||||
parent = upgraded_parent;
|
||||
|
@ -10,10 +10,10 @@ use crate::libs::rwlock::RwLock;
|
||||
use crate::net::socket::netlink::af_netlink::netlink_has_listeners;
|
||||
use crate::net::socket::netlink::af_netlink::NetlinkSocket;
|
||||
use crate::net::socket::netlink::af_netlink::{netlink_broadcast, NetlinkSock};
|
||||
use crate::net::socket::netlink::netlink::{
|
||||
use crate::net::socket::netlink::skbuff::SkBuff;
|
||||
use crate::net::socket::netlink::{
|
||||
netlink_kernel_create, NetlinkKernelCfg, NETLINK_KOBJECT_UEVENT, NL_CFG_F_NONROOT_RECV,
|
||||
};
|
||||
use crate::net::socket::netlink::skbuff::SkBuff;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::LinkedList;
|
||||
use alloc::string::{String, ToString};
|
||||
@ -86,46 +86,26 @@ fn uevent_net_exit() {
|
||||
// /* This lock protects uevent_seqnum and uevent_sock_list */
|
||||
// static DEFINE_MUTEX(uevent_sock_mutex);
|
||||
|
||||
// to be adjust
|
||||
pub const BUFFERSIZE: usize = 666;
|
||||
|
||||
/*
|
||||
kobject_uevent_env,以envp为环境变量,上报一个指定action的uevent。环境变量的作用是为执行用户空间程序指定运行环境。具体动作如下:
|
||||
|
||||
查找kobj本身或者其parent是否从属于某个kset,如果不是,则报错返回(注2:由此可以说明,如果一个kobject没有加入kset,是不允许上报uevent的)
|
||||
查看kobj->uevent_suppress是否设置,如果设置,则忽略所有的uevent上报并返回(注3:由此可知,可以通过Kobject的uevent_suppress标志,管控Kobject的uevent的上报)
|
||||
如果所属的kset有kset->filter函数,则调用该函数,过滤此次上报(注4:这佐证了3.2小节有关filter接口的说明,kset可以通过filter接口过滤不希望上报的event,从而达到整体的管理效果)
|
||||
判断所属的kset是否有合法的名称(称作subsystem,和前期的内核版本有区别),否则不允许上报uevent
|
||||
分配一个用于此次上报的、存储环境变量的buffer(结果保存在env指针中),并获得该Kobject在sysfs中路径信息(用户空间软件需要依据该路径信息在sysfs中访问它)
|
||||
调用add_uevent_var接口(下面会介绍),将Action、路径信息、subsystem等信息,添加到env指针中
|
||||
如果传入的envp不空,则解析传入的环境变量中,同样调用add_uevent_var接口,添加到env指针中
|
||||
如果所属的kset存在kset->uevent接口,调用该接口,添加kset统一的环境变量到env指针
|
||||
根据ACTION的类型,设置kobj->state_add_uevent_sent和kobj->state_remove_uevent_sent变量,以记录正确的状态
|
||||
调用add_uevent_var接口,添加格式为"SEQNUM=%llu”的序列号
|
||||
如果定义了"CONFIG_NET”,则使用netlink发送该uevent
|
||||
以uevent_helper、subsystem以及添加了标准环境变量(HOME=/,PATH=/sbin:/bin:/usr/sbin:/usr/bin)的env指针为参数,调用kmod模块提供的call_usermodehelper函数,上报uevent。
|
||||
其中uevent_helper的内容是由内核配置项CONFIG_UEVENT_HELPER_PATH(位于./drivers/base/Kconfig)决定的(可参考lib/kobject_uevent.c, line 32),该配置项指定了一个用户空间程序(或者脚本),用于解析上报的uevent,例如"/sbin/hotplug”。
|
||||
call_usermodehelper的作用,就是fork一个进程,以uevent为参数,执行uevent_helper。
|
||||
|
||||
kobject_uevent,和kobject_uevent_env功能一样,只是没有指定任何的环境变量。
|
||||
|
||||
add_uevent_var,以格式化字符的形式(类似printf、printk等),将环境变量copy到env指针中。
|
||||
|
||||
kobject_action_type,将enum kobject_action类型的Action,转换为字符串
|
||||
*/
|
||||
|
||||
//kobject_uevent->kobject_uevent_env
|
||||
/// kobject_uevent,和kobject_uevent_env功能一样,只是没有指定任何的环境变量
|
||||
pub fn kobject_uevent(kobj: Arc<dyn KObject>, action: KobjectAction) -> Result<(), SystemError> {
|
||||
// kobject_uevent和kobject_uevent_env功能一样,只是没有指定任何的环境变量
|
||||
match kobject_uevent_env(kobj, action, None) {
|
||||
match kobject_uevent_env(kobj, action, Vec::new()) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// kobject_uevent_env,以envp为环境变量,上报一个指定action的uevent。环境变量的作用是为执行用户空间程序指定运行环境。
|
||||
pub fn kobject_uevent_env(
|
||||
kobj: Arc<dyn KObject>,
|
||||
action: KobjectAction,
|
||||
envp_ext: Option<Vec<String>>,
|
||||
envp_ext: Vec<String>,
|
||||
) -> Result<i32, SystemError> {
|
||||
log::info!("kobject_uevent_env: kobj: {:?}, action: {:?}", kobj, action);
|
||||
let mut state = KObjectState::empty();
|
||||
@ -247,15 +227,14 @@ pub fn kobject_uevent_env(
|
||||
};
|
||||
|
||||
/* keys passed in from the caller */
|
||||
if let Some(env_ext) = envp_ext {
|
||||
for var in env_ext {
|
||||
let retval = add_uevent_var(&mut env, "%s", &var).unwrap();
|
||||
if !retval.is_zero() {
|
||||
drop(devpath);
|
||||
drop(env);
|
||||
log::info!("add_uevent_var failed");
|
||||
return Ok(retval);
|
||||
}
|
||||
|
||||
for var in envp_ext {
|
||||
let retval = add_uevent_var(&mut env, "%s", &var).unwrap();
|
||||
if !retval.is_zero() {
|
||||
drop(devpath);
|
||||
drop(env);
|
||||
log::info!("add_uevent_var failed");
|
||||
return Ok(retval);
|
||||
}
|
||||
}
|
||||
if let Some(kset_ref) = kset.as_ref() {
|
||||
@ -335,6 +314,7 @@ pub fn kobject_uevent_env(
|
||||
return Ok(retval);
|
||||
}
|
||||
|
||||
/// 以格式化字符的形式,将环境变量copy到env指针中。
|
||||
pub fn add_uevent_var(
|
||||
env: &mut Box<KobjUeventEnv>,
|
||||
format: &str,
|
||||
@ -403,7 +383,6 @@ pub fn kobject_uevent_net_broadcast(
|
||||
action_string: &str,
|
||||
devpath: &str,
|
||||
) -> i32 {
|
||||
let mut ret = 0;
|
||||
// let net:Net = None;
|
||||
// let mut ops = kobj_ns_ops(kobj);
|
||||
|
||||
@ -428,7 +407,7 @@ pub fn kobject_uevent_net_broadcast(
|
||||
// if !net.is_none() {
|
||||
// ret = uevent_net_broadcast_tagged(net.unwrap(), env, action_string, devpath);
|
||||
// } else {
|
||||
ret = uevent_net_broadcast_untagged(env, action_string, devpath);
|
||||
let ret = uevent_net_broadcast_untagged(env, action_string, devpath);
|
||||
// }
|
||||
log::info!("kobject_uevent_net_broadcast finish. ret: {}", ret);
|
||||
ret
|
||||
|
@ -1,26 +1,7 @@
|
||||
// include/linux/kobject.h
|
||||
// lib/kobject_uevent.c
|
||||
|
||||
use crate::driver::base::uevent::kobject_uevent::kobject_uevent_env;
|
||||
use core::fmt::Write;
|
||||
/*
|
||||
UEVENT_HELPER_PATH_LEN
|
||||
UEVENT_NUM_ENVP
|
||||
_KOBJECT_H_
|
||||
|
||||
Variable
|
||||
|
||||
__randomize_layout
|
||||
|
||||
Enum
|
||||
|
||||
kobject_action
|
||||
|
||||
Struct
|
||||
|
||||
kobj_attribute
|
||||
kobj_type
|
||||
kobj_uevent_env
|
||||
kobject
|
||||
kset
|
||||
kset_uevent_ops
|
||||
|
||||
Function
|
||||
@ -32,56 +13,83 @@ Function
|
||||
to_kset
|
||||
*/
|
||||
use crate::driver::base::kobject::KObject;
|
||||
use alloc::string::String;
|
||||
use crate::driver::net::Iface;
|
||||
use crate::filesystem::sysfs::{Attribute, SysFSOpsSupport, SYSFS_ATTR_MODE_RW};
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use intertrait::cast::CastArc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::block::block_device::{BlockDevice, BlockDeviceOps};
|
||||
use super::char::CharDevice;
|
||||
use super::device::{Device, DeviceType};
|
||||
|
||||
pub mod kobject_uevent;
|
||||
|
||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c?fi=kobject_uevent#457
|
||||
// kobject_action
|
||||
#[derive(Debug)]
|
||||
pub enum KobjectAction {
|
||||
KOBJADD,
|
||||
KOBJREMOVE, //Kobject(或上层数据结构)的添加/移除事件
|
||||
KOBJCHANGE, //Kobject(或上层数据结构)的状态或者内容发生改变; 如果设备驱动需要上报的事件不再上面事件的范围内,或者是自定义的事件,可以使用该event,并携带相应的参数。
|
||||
KOBJMOVE, //Kobject(或上层数据结构)更改名称或者更改Parent(意味着在sysfs中更改了目录结构)
|
||||
KOBJREMOVE, // Kobject(或上层数据结构)的添加/移除事件
|
||||
KOBJCHANGE, // Kobject(或上层数据结构)的状态或者内容发生改变; 如果设备驱动需要上报的事件不再上面事件的范围内,或者是自定义的事件,可以使用该event,并携带相应的参数。
|
||||
KOBJMOVE, // Kobject(或上层数据结构)更改名称或者更改Parent(意味着在sysfs中更改了目录结构)
|
||||
KOBJONLINE,
|
||||
KOBJOFFLINE, //Kobject(或上层数据结构)的上线/下线事件,其实是是否使能
|
||||
KOBJOFFLINE, // Kobject(或上层数据结构)的上线/下线事件,其实是是否使能
|
||||
KOBJBIND,
|
||||
KOBJUNBIND,
|
||||
}
|
||||
|
||||
/*
|
||||
@parament:
|
||||
/// 解析一个字符串,以确定它代表的是哪个 kobject_action,并提取出随后的参数(如果有的话)
|
||||
fn kobject_action_type(buf: &[u8]) -> Result<(KobjectAction, Vec<String>), SystemError> {
|
||||
let mut action = KobjectAction::KOBJCHANGE;
|
||||
let mut action_args: Vec<String> = Vec::new();
|
||||
let mut count = buf.len();
|
||||
if count != 0 && (buf[count - 1] == b'\n' || buf[count - 1] == b'\0') {
|
||||
count -= 1;
|
||||
}
|
||||
if count == 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
envp,指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。
|
||||
let arg_start = buf.iter().position(|&c| c == b' ').unwrap_or(count);
|
||||
let count_first = arg_start;
|
||||
let args_start = arg_start + 1;
|
||||
|
||||
envp_idx,用于访问环境变量指针数组的index。
|
||||
// 匹配KobjectAction
|
||||
match &buf[..count_first] {
|
||||
b"add" => action = KobjectAction::KOBJADD,
|
||||
b"remove" => action = KobjectAction::KOBJREMOVE,
|
||||
b"change" => action = KobjectAction::KOBJCHANGE,
|
||||
b"move" => action = KobjectAction::KOBJMOVE,
|
||||
b"online" => action = KobjectAction::KOBJONLINE,
|
||||
b"offline" => action = KobjectAction::KOBJOFFLINE,
|
||||
b"bind" => action = KobjectAction::KOBJBIND,
|
||||
b"unbind" => action = KobjectAction::KOBJUNBIND,
|
||||
_ => return Err(SystemError::EINVAL),
|
||||
}
|
||||
|
||||
buf,保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。
|
||||
// 如果有参数,提取参数
|
||||
if count - args_start > 0 {
|
||||
action_args = buf[args_start..]
|
||||
.split(|&c| c == b' ')
|
||||
.map(|s| String::from_utf8_lossy(s).to_string())
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
buflen,访问buf的变量。
|
||||
|
||||
*/
|
||||
|
||||
//https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/kobject.h#31
|
||||
Ok((action, action_args))
|
||||
}
|
||||
|
||||
pub const UEVENT_NUM_ENVP: usize = 64;
|
||||
pub const UEVENT_BUFFER_SIZE: usize = 2048;
|
||||
pub const UEVENT_HELPER_PATH_LEN: usize = 256;
|
||||
|
||||
/// Represents the environment for handling kernel object uevents.
|
||||
/*
|
||||
envp,指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。
|
||||
|
||||
envp_idx,用于访问环境变量指针数组的index。
|
||||
|
||||
buf,保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。
|
||||
|
||||
buflen,访问buf的变量。
|
||||
|
||||
*/
|
||||
// 表示一个待发送的uevent
|
||||
/// 表示处理内核对象 uevents 的环境
|
||||
/// - envp,指针数组,用于保存每个环境变量的地址,最多可支持的环境变量数量为UEVENT_NUM_ENVP。
|
||||
/// - envp_idx,用于访问环境变量指针数组的index。
|
||||
/// - buf,保存环境变量的buffer,最大为UEVENT_BUFFER_SIZE。
|
||||
/// - buflen,访问buf的变量。
|
||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/kobject.h#31
|
||||
#[derive(Debug)]
|
||||
pub struct KobjUeventEnv {
|
||||
argv: Vec<String>,
|
||||
@ -100,3 +108,113 @@ pub struct KobjUeventEnv {
|
||||
uevent,当任何Kobject需要上报uevent时,它所属的kset可以通过该接口统一为这些event添加环境变量。因为很多时候上报uevent时的环境变量都是相同的,因此可以由kset统一处理,就不需要让每个Kobject独自添加了。
|
||||
|
||||
*/
|
||||
|
||||
/// 设备文件夹下的`uevent`文件的属性
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct UeventAttr;
|
||||
|
||||
impl Attribute for UeventAttr {
|
||||
fn name(&self) -> &str {
|
||||
"uevent"
|
||||
}
|
||||
|
||||
fn mode(&self) -> crate::filesystem::vfs::syscall::ModeType {
|
||||
SYSFS_ATTR_MODE_RW
|
||||
}
|
||||
|
||||
fn support(&self) -> crate::filesystem::sysfs::SysFSOpsSupport {
|
||||
SysFSOpsSupport::ATTR_SHOW | SysFSOpsSupport::ATTR_STORE
|
||||
}
|
||||
|
||||
/// 用户空间读取 uevent 文件,返回 uevent 信息
|
||||
fn show(&self, _kobj: Arc<dyn KObject>, _buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let device: Arc<dyn KObject> = _kobj
|
||||
.parent()
|
||||
.and_then(|x| x.upgrade())
|
||||
.ok_or(SystemError::ENODEV)?;
|
||||
let device = kobj2device(device).ok_or(SystemError::EINVAL)?;
|
||||
let device_type = device.dev_type();
|
||||
let mut uevent_content = String::new();
|
||||
match device_type {
|
||||
DeviceType::Block => {
|
||||
let block_device = device
|
||||
.cast::<dyn BlockDevice>()
|
||||
.ok()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let major = block_device.id_table().device_number().major().data();
|
||||
let minor = block_device.id_table().device_number().minor();
|
||||
let device_name = block_device.id_table().name();
|
||||
writeln!(&mut uevent_content, "MAJOR={:?}", major).unwrap();
|
||||
writeln!(&mut uevent_content, "MINOR={:?}", minor).unwrap();
|
||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
||||
writeln!(&mut uevent_content, "DEVTYPE=disk").unwrap();
|
||||
}
|
||||
DeviceType::Char => {
|
||||
let char_device = device
|
||||
.cast::<dyn CharDevice>()
|
||||
.ok()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let major = char_device.id_table().device_number().major().data();
|
||||
let minor = char_device.id_table().device_number().minor();
|
||||
let device_name = char_device.id_table().name();
|
||||
writeln!(&mut uevent_content, "MAJOR={}", major).unwrap();
|
||||
writeln!(&mut uevent_content, "MINOR={}", minor).unwrap();
|
||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
||||
writeln!(&mut uevent_content, "DEVTYPE=char").unwrap();
|
||||
}
|
||||
DeviceType::Net => {
|
||||
let net_device = device.cast::<dyn Iface>().ok().ok_or(SystemError::EINVAL)?;
|
||||
// let ifindex = net_device.ifindex().expect("Find ifindex error.\n");
|
||||
let device_name = net_device.iface_name();
|
||||
writeln!(&mut uevent_content, "INTERFACE={}", device_name).unwrap();
|
||||
// writeln!(&mut uevent_content, "IFINDEX={}", ifindex).unwrap();
|
||||
}
|
||||
_ => {
|
||||
// 处理其他设备类型
|
||||
let device_name = device.name();
|
||||
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
|
||||
writeln!(&mut uevent_content, "DEVTYPE={:?}", device_type).unwrap();
|
||||
}
|
||||
}
|
||||
sysfs_emit_str(_buf, &uevent_content)
|
||||
}
|
||||
/// 捕获来自用户空间对 uevent 文件的写操作,触发uevent事件
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
return kobject_synth_uevent(_buf, _kobj);
|
||||
}
|
||||
}
|
||||
|
||||
/// 将 kobject 转换为 device
|
||||
fn kobj2device(kobj: Arc<dyn KObject>) -> Option<Arc<dyn Device>> {
|
||||
kobj.cast::<dyn Device>().ok()
|
||||
}
|
||||
|
||||
/// 将设备的基本信息写入 uevent 文件
|
||||
fn sysfs_emit_str(buf: &mut [u8], content: &str) -> Result<usize, SystemError> {
|
||||
let bytes = content.as_bytes();
|
||||
if buf.len() < bytes.len() {
|
||||
return Err(SystemError::ENOMEM);
|
||||
}
|
||||
buf[..bytes.len()].copy_from_slice(bytes);
|
||||
Ok(bytes.len())
|
||||
}
|
||||
|
||||
/// 解析用户空间写入的 uevent 信息,触发 uevent 事件
|
||||
fn kobject_synth_uevent(buf: &[u8], kobj: Arc<dyn KObject>) -> Result<usize, SystemError> {
|
||||
let no_uuid_envp = vec!["SYNTH_UUID=0".to_string()];
|
||||
let (action, action_args) = kobject_action_type(buf)?;
|
||||
|
||||
let result = if action_args.is_empty() {
|
||||
kobject_uevent_env(kobj.clone(), action, no_uuid_envp)
|
||||
} else {
|
||||
kobject_uevent_env(kobj.clone(), action, action_args)
|
||||
};
|
||||
|
||||
if let Err(e) = result {
|
||||
let device = kobj2device(kobj).ok_or(SystemError::EINVAL)?;
|
||||
let devname = device.name();
|
||||
log::error!("synth uevent: {}: {:?}", devname, e);
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
Reference in New Issue
Block a user