updates uevent and make fmt

This commit is contained in:
val213
2024-10-11 23:56:12 +08:00
parent 40d9375b6b
commit 4e4ce68e03
8 changed files with 800 additions and 612 deletions

View File

@ -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;

View File

@ -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

View File

@ -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())
}