From 5cbe962ff62b898001958d804aa1153608accdb8 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Tue, 19 Aug 2025 20:14:07 +0000 Subject: [PATCH 01/39] =?UTF-8?q?=E5=AE=8C=E6=88=90loop=5Fdevice=E7=9A=84?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=EF=BC=8C=E8=83=BD=E5=9C=A8/dev=E4=B8=8B?= =?UTF-8?q?=E7=9C=8B=E8=A7=818=E4=B8=AAloopdevice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 480 ++++++++++++++++++ kernel/src/driver/base/block/mod.rs | 2 +- .../src/driver/base/device/device_number.rs | 1 + kernel/src/filesystem/devfs/mod.rs | 2 + 4 files changed, 484 insertions(+), 1 deletion(-) create mode 100644 kernel/src/driver/base/block/loop_device.rs diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs new file mode 100644 index 000000000..e53c316fd --- /dev/null +++ b/kernel/src/driver/base/block/loop_device.rs @@ -0,0 +1,480 @@ +use crate::filesystem::devfs::LockedDevFSInode; +use crate::{ + driver::base::{ + block::{ + block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, + disk_info::Partition, + manager::{block_dev_manager, BlockDevMeta}, + }, + class::Class, + device::{ + bus::{bus_manager, Bus}, + device_number::{DeviceNumber, Major}, + driver::{Driver, DriverCommonData}, + DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + subsys::SubSysPrivate, + }, + filesystem::{ + devfs::{self, devfs_register, DevFS, DeviceINode}, + kernfs::KernFSInode, + vfs::{IndexNode, InodeId, Metadata}, + }, + init::initcall::INITCALL_POSTCORE, + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, +}; +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use bitmap::traits::BitMapOps; +use core::{ + any::Any, + fmt::{Debug, Formatter}, +}; +use log::error; +use system_error::SystemError; +use unified_init::macros::unified_init; +const LOOP_BASENAME: &str = "loop"; +//LoopDevice是一个虚拟的块设备,它将文件映射到块设备上. +pub struct LoopDevice { + inner: SpinLock, //加锁保护LoopDeviceInner + //有主设备次设备号 + block_dev_meta: BlockDevMeta, + dev_id: Arc, + locked_kobj_state: LockedKObjectState, //对Kobject状态的锁 + self_ref: Weak, //对自身的弱引用 + fs: RwLock>, //文件系统弱引用 + parent: RwLock>, +} +//Inner内数据会改变所以加锁 +pub struct LoopDeviceInner { + // 关联的文件节点 + pub file_inode: Option>, + // 文件大小 + pub file_size: usize, + // 设备名称 + pub device_number: DeviceNumber, + // 数据偏移量 + pub offset: usize, + // 数据大小限制 + pub size_limit: usize, + // 是否允许用户直接 I/O 操作 + pub user_direct_io: bool, + // 是否只读 + pub read_only: bool, + // 是否可见 + pub visible: bool, + // 使用弱引用避免循环引用 + pub self_ref: Weak, + pub kobject_common: KObjectCommonData, + pub device_common: DeviceCommonData, +} +impl Debug for LoopDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LoopDevice") + .field("devname", &self.block_dev_meta.devname) + .field("dev_id", &self.dev_id.id()) + .finish() + } +} +impl LoopDevice { + fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } + pub fn new_empty_loop_device( + devname: DevName, + dev_id: Arc, + minor: u32, + ) -> Option> { + // 创建一个空的 LoopDevice + let dev = Arc::new_cyclic(|self_ref| Self { + inner: SpinLock::new(LoopDeviceInner { + file_inode: None, // 默认的虚拟 inode + file_size: 0, + device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), // Loop 设备主设备号为 7 + offset: 0, + size_limit: 0, + user_direct_io: false, + read_only: false, + visible: true, + self_ref: self_ref.clone(), + kobject_common: KObjectCommonData::default(), + device_common: DeviceCommonData::default(), + }), + //只用重复8次,就会有从0-7八个次设备号 + block_dev_meta: BlockDevMeta::new(devname, Major::new(7)), // Loop 设备主设备号为 7 + dev_id, + locked_kobj_state: LockedKObjectState::default(), + self_ref: self_ref.clone(), + fs: RwLock::new(Weak::default()), + parent: RwLock::new(Weak::default()), + }); + + Some(dev) + } + + /// 设置 loop 设备关联的文件 + pub fn set_file(&self, file_inode: Arc) -> Result<(), SystemError> { + let mut inner = self.inner(); + // 获取文件大小 + let file_size = file_inode.metadata()?.size; + + inner.file_inode = Some(file_inode); + inner.file_size = file_size as usize; + + Ok(()) + } + + /// 获取文件大小 + pub fn file_size(&self) -> usize { + self.inner().file_size + } + + /// 设置只读模式 + pub fn set_read_only(&self, read_only: bool) { + self.inner().read_only = read_only; + } + + /// 检查是否为只读 + pub fn is_read_only(&self) -> bool { + self.inner().read_only + } +} + +impl KObject for LoopDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + LOOP_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing,不支持设置loop为别的名称 + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.locked_kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.locked_kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobj_state.write() = state; + } +} + +//对loopdevice进行抽象 +impl IndexNode for LoopDevice { + fn fs(&self) -> Arc { + todo!() + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn read_at( + &self, + _offset: usize, + _len: usize, + _buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn list(&self) -> Result, system_error::SystemError> { + Err(SystemError::ENOSYS) + } + fn metadata(&self) -> Result { + let file_metadata = match &self.inner().file_inode { + Some(inode) => inode.metadata()?, + None => { + return Err(SystemError::EPERM); + } + }; + let metadata = Metadata { + dev_id: 0, + inode_id: InodeId::new(0), // Loop 设备通常没有实际的 inode ID + size: self.inner().file_size as i64, + blk_size: LBA_SIZE as usize, + blocks: (self.inner().file_size + LBA_SIZE - 1) / LBA_SIZE as usize, // 计算块数 + atime: file_metadata.atime, + mtime: file_metadata.mtime, + ctime: file_metadata.ctime, + btime: file_metadata.btime, + file_type: crate::filesystem::vfs::FileType::BlockDevice, + mode: crate::filesystem::vfs::syscall::ModeType::from_bits_truncate(0o644), + nlinks: 1, + uid: 0, // 默认用户 ID + gid: 0, // 默认组 ID + raw_dev: self.inner().device_number, + }; + Ok(metadata.clone()) + } +} + +impl DeviceINode for LoopDevice { + fn set_fs(&self, fs: alloc::sync::Weak) { + *self.fs.write() = fs; + } + fn set_parent(&self, parent: Weak) { + *self.parent.write() = parent; + } +} + +impl Device for LoopDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Block + } + + fn id_table(&self) -> IdTable { + IdTable::new(LOOP_BASENAME.to_string(), None) + } + + fn bus(&self) -> Option> { + self.inner().device_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn class(&self) -> Option> { + let mut guard = self.inner(); + let r = guard.device_common.class.clone()?.upgrade(); + if r.is_none() { + guard.device_common.class = None; + } + return r; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn driver(&self) -> Option> { + let r = self.inner().device_common.driver.clone()?.upgrade(); + if r.is_none() { + self.inner().device_common.driver = None; + } + return r; + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn dev_parent(&self) -> Option> { + self.inner().device_common.get_parent_weak_or_clear() + } + + fn set_dev_parent(&self, parent: Option>) { + self.inner().device_common.parent = parent; + } +} + +impl BlockDevice for LoopDevice { + fn dev_name(&self) -> &DevName { + &self.block_dev_meta.devname + } + + fn blkdev_meta(&self) -> &BlockDevMeta { + &self.block_dev_meta + } + + fn disk_range(&self) -> GeneralBlockRange { + let inner = self.inner(); + let blocks = inner.file_size / LBA_SIZE; + drop(inner); + GeneralBlockRange::new(0, blocks).unwrap_or(GeneralBlockRange { + lba_start: 0, + lba_end: 0, + }) + } + fn read_at_sync( + &self, + lba_id_start: BlockId, + count: usize, + buf: &mut [u8], + ) -> Result { + let inner = self.inner(); + let offset = inner.offset + lba_id_start * LBA_SIZE; + let len = count * LBA_SIZE; + + // 通过文件 inode 读取数据 + // 使用一个空的 FilePrivateData 作为占位符 + use crate::filesystem::vfs::FilePrivateData; + use crate::libs::spinlock::SpinLock; + let data = SpinLock::new(FilePrivateData::Unused); + let data_guard = data.lock(); + + // 处理 Option 类型的 file_inode + match &inner.file_inode { + Some(inode) => { + // 计算实际的文件偏移量 + let file_offset = inner.offset + offset; + inode.read_at(file_offset, len, buf, data_guard) + } + None => { + // 如果没有关联的文件,返回错误 + Err(SystemError::ENODEV) + } + } + } + + fn write_at_sync( + &self, + lba_id_start: BlockId, + count: usize, + buf: &[u8], + ) -> Result { + let inner = self.inner(); + + // 检查是否只读 + if inner.read_only { + return Err(SystemError::EROFS); + } + + let offset = inner.offset + lba_id_start * LBA_SIZE; + let len = count * LBA_SIZE; + + // 通过文件 inode 写入数据 + // 使用一个空的 FilePrivateData 作为占位符 + use crate::filesystem::vfs::FilePrivateData; + use crate::libs::spinlock::SpinLock; + let data = SpinLock::new(FilePrivateData::Unused); + let data_guard = data.lock(); + + // 处理 Option 类型的 file_inode + match &inner.file_inode { + Some(inode) => { + // 计算实际的文件偏移量 + let file_offset = inner.offset + offset; + inode.write_at(file_offset, len, buf, data_guard) + } + None => { + // 如果没有关联的文件,返回错误 + Err(SystemError::ENODEV) + } + } + } + + fn sync(&self) -> Result<(), SystemError> { + // Loop 设备的同步操作 + Ok(()) + } + + fn blk_size_log2(&self) -> u8 { + 9 // 512 bytes = 2^9 + } + + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn device(&self) -> Arc { + self.self_ref.upgrade().unwrap() + } + + fn block_size(&self) -> usize { + LBA_SIZE + } + + fn partitions(&self) -> Vec> { + // Loop 设备通常不支持分区 + Vec::new() + } +} +//注册8个loop设备 +use crate::init::initcall::INITCALL_DEVICE; +#[unified_init(INITCALL_DEVICE)] +pub fn register_loop_devices() -> Result<(), SystemError> { + for minor in 0..8 { + let devname = DevName::new(format!("loop{}", minor), minor); + let dev_id = + DeviceId::new(None, Some(devname.name().to_string())).ok_or(SystemError::EINVAL)?; + if let Some(loop_dev) = + LoopDevice::new_empty_loop_device(devname.clone(), dev_id, minor as u32) + { + log::info!( + "Registering loop device: {}", + loop_dev.block_dev_meta.devname + ); + block_dev_manager().register(loop_dev.clone())?; + //devfs进行注册时[ ERROR ] (src/init/initcall.rs:22) Failed to call initializer register_loop_devices: EPERM + //devfs_register(&format!("loop{}", minor), loop_dev.clone())?; + } else { + error!("Failed to create loop device for minor {}", minor); + } + } + + Ok(()) +} diff --git a/kernel/src/driver/base/block/mod.rs b/kernel/src/driver/base/block/mod.rs index a34479836..179e611de 100644 --- a/kernel/src/driver/base/block/mod.rs +++ b/kernel/src/driver/base/block/mod.rs @@ -2,7 +2,7 @@ pub mod block_device; pub mod disk_info; pub mod gendisk; pub mod manager; - +pub mod loop_device; #[derive(Debug)] #[allow(dead_code)] pub enum SeekFrom { diff --git a/kernel/src/driver/base/device/device_number.rs b/kernel/src/driver/base/device/device_number.rs index cce7c09c2..b3dd13470 100644 --- a/kernel/src/driver/base/device/device_number.rs +++ b/kernel/src/driver/base/device/device_number.rs @@ -41,6 +41,7 @@ impl Major { pub const fn data(&self) -> u32 { self.0 } + pub const LOOP_MAJOR: Self = Self::new(7); } impl Hash for Major { diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index e77ea447e..6bd815ba8 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -193,6 +193,8 @@ impl DevFS { } else if name.starts_with("nvme") { // NVMe设备挂载在 /dev 下 dev_root_inode.add_dev(name, device.clone())?; + } else if name.starts_with("loop"){ + dev_root_inode.add_dev(name, device.clone())?; } else { dev_block_inode.add_dev(name, device.clone())?; device.set_parent(Arc::downgrade(&dev_block_inode)); From be65aaa1b6bd3115bfafa56862e058fedba10355 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 20 Aug 2025 06:59:45 +0000 Subject: [PATCH 02/39] =?UTF-8?q?fmt=20&=20=E5=88=A0=E9=99=A4loopdevice?= =?UTF-8?q?=E4=B8=AD=E7=9A=84devid=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index e53c316fd..747cb928b 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -47,7 +47,7 @@ pub struct LoopDevice { inner: SpinLock, //加锁保护LoopDeviceInner //有主设备次设备号 block_dev_meta: BlockDevMeta, - dev_id: Arc, + //dev_id: Arc, locked_kobj_state: LockedKObjectState, //对Kobject状态的锁 self_ref: Weak, //对自身的弱引用 fs: RwLock>, //文件系统弱引用 @@ -59,7 +59,7 @@ pub struct LoopDeviceInner { pub file_inode: Option>, // 文件大小 pub file_size: usize, - // 设备名称 + // 设备名称 Major和Minor pub device_number: DeviceNumber, // 数据偏移量 pub offset: usize, @@ -73,26 +73,25 @@ pub struct LoopDeviceInner { pub visible: bool, // 使用弱引用避免循环引用 pub self_ref: Weak, + // KObject的公共数据 pub kobject_common: KObjectCommonData, + // 设备的公共数据 pub device_common: DeviceCommonData, } impl Debug for LoopDevice { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("LoopDevice") .field("devname", &self.block_dev_meta.devname) - .field("dev_id", &self.dev_id.id()) .finish() } } impl LoopDevice { fn inner(&self) -> SpinLockGuard { + // 获取 LoopDeviceInner 的自旋锁 self.inner.lock() } - pub fn new_empty_loop_device( - devname: DevName, - dev_id: Arc, - minor: u32, - ) -> Option> { + //注册一个新的空loop设备占位 + pub fn new_empty_loop_device(devname: DevName, minor: u32) -> Option> { // 创建一个空的 LoopDevice let dev = Arc::new_cyclic(|self_ref| Self { inner: SpinLock::new(LoopDeviceInner { @@ -110,7 +109,6 @@ impl LoopDevice { }), //只用重复8次,就会有从0-7八个次设备号 block_dev_meta: BlockDevMeta::new(devname, Major::new(7)), // Loop 设备主设备号为 7 - dev_id, locked_kobj_state: LockedKObjectState::default(), self_ref: self_ref.clone(), fs: RwLock::new(Weak::default()), @@ -453,7 +451,6 @@ impl BlockDevice for LoopDevice { Vec::new() } } -//注册8个loop设备 use crate::init::initcall::INITCALL_DEVICE; #[unified_init(INITCALL_DEVICE)] pub fn register_loop_devices() -> Result<(), SystemError> { @@ -461,9 +458,7 @@ pub fn register_loop_devices() -> Result<(), SystemError> { let devname = DevName::new(format!("loop{}", minor), minor); let dev_id = DeviceId::new(None, Some(devname.name().to_string())).ok_or(SystemError::EINVAL)?; - if let Some(loop_dev) = - LoopDevice::new_empty_loop_device(devname.clone(), dev_id, minor as u32) - { + if let Some(loop_dev) = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) { log::info!( "Registering loop device: {}", loop_dev.block_dev_meta.devname From c9157f8ae44d386147dc7a9bed20614e0ff32701 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 20 Aug 2025 11:01:56 +0000 Subject: [PATCH 03/39] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86driver?= =?UTF-8?q?=E5=92=8Ccontrol=20device=E5=92=8Cmanager=EF=BC=8C=E5=B0=86?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E9=80=BB=E8=BE=91=E7=A7=BB=E5=8A=A8=E8=87=B3?= =?UTF-8?q?driver=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 168 ++++++++++++++++++-- 1 file changed, 157 insertions(+), 11 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 747cb928b..e9ee810dd 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -451,16 +451,50 @@ impl BlockDevice for LoopDevice { Vec::new() } } -use crate::init::initcall::INITCALL_DEVICE; -#[unified_init(INITCALL_DEVICE)] -pub fn register_loop_devices() -> Result<(), SystemError> { - for minor in 0..8 { - let devname = DevName::new(format!("loop{}", minor), minor); - let dev_id = - DeviceId::new(None, Some(devname.name().to_string())).ok_or(SystemError::EINVAL)?; - if let Some(loop_dev) = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) { - log::info!( - "Registering loop device: {}", + +/// Loop设备驱动 +/// 参考Virtio_blk驱动的实现 +#[derive(Debug)] +#[cast_to([sync] Driver)] +pub struct LoopDeviceDriver { + inner: SpinLock, + kobj_state: LockedKObjectState, +} +struct InnerLoopDeviceDriver{ + driver_common: DriverCommonData, + kobj_common: KObjectCommonData, +} +impl Debug for InnerLoopDeviceDriver { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("InnerLoopDeviceDriver") + .field("driver_common", &self.driver_common) + .field("kobj_common", &self.kobj_common) + .finish() + } +} +impl LoopDeviceDriver { + + pub fn new() -> Arc { + let inner = InnerLoopDeviceDriver{ + driver_common: DriverCommonData::default(), + kobj_common: KObjectCommonData::default(), + }; + Arc::new(Self { + inner: SpinLock::new(inner), + kobj_state: LockedKObjectState::default(), + }) + } + fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } + fn loop_init(&self) -> Result<(), SystemError> { + // 创建并初始化 LoopManager 单例 + // let loop_mgr = LOOP_MANAGER.call_once(|| LoopManager::new()); + for minor in 0..LoopManager::MAX_DEVICES { + let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor); + if let Some(loop_dev) = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) { + log::info!( + "Registering loop device: {}", loop_dev.block_dev_meta.devname ); block_dev_manager().register(loop_dev.clone())?; @@ -470,6 +504,118 @@ pub fn register_loop_devices() -> Result<(), SystemError> { error!("Failed to create loop device for minor {}", minor); } } + // // 创建并注册 /dev/loop-control + // let control_dev = Arc::new(LoopControlDevice::new()); // 假设的构造函数 + // block_dev_manager().register(control_dev.clone())?; + // devfs::devfs_register("loop-control", control_dev.clone())?; + // info!("LoopDeviceDriver and all devices initialized."); + Ok(()) + } +} +use crate::init::initcall::INITCALL_DEVICE; +#[unified_init(INITCALL_DEVICE)] +pub fn loop_init()-> Result<(), SystemError> { + // 获取 LoopDeviceDriver 的单例并调用初始化函数 + let driver = LoopDeviceDriver::new(); + driver.loop_init() +} + + +impl Driver for LoopDeviceDriver { + fn id_table(&self) -> Option { + Some(IdTable::new("loop".to_string(), None)) + } + + fn devices(&self) -> Vec> { + self.inner().driver_common.devices.clone() + } + + fn add_device(&self, device: Arc) { + self.inner().driver_common.push_device(device); + } + + fn delete_device(&self, device: &Arc) { + self.inner().driver_common.delete_device(device); + } + + fn bus(&self) -> Option> { + self.inner().driver_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().driver_common.bus = bus; + } +} + +impl KObject for LoopDeviceDriver { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobj_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobj_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobj_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobj_common.parent = parent; + } - Ok(()) + fn kset(&self) -> Option> { + self.inner().kobj_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobj_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobj_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobj_common.kobj_type = ktype; + } + + fn name(&self) -> String { + "loop".to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.kobj_state.write() = state; + } +} +pub struct LoopControlDevice { + locked_kobj_state: LockedKObjectState, + inner: SpinLock, +} + +pub struct LoopControlDeviceInner { + kobject_common: KObjectCommonData, + device_common: DeviceCommonData, +} +pub struct LoopManager { + devices: Vec>, } +impl LoopManager { + const MAX_DEVICES: usize =8; +} \ No newline at end of file From 0867f831bba2b87c9adfc35033b7606b3d5fe863 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Mon, 22 Sep 2025 07:51:25 +0000 Subject: [PATCH 04/39] =?UTF-8?q?-=20=E5=B0=86=E5=85=B7=E4=BD=93=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E9=80=BB=E8=BE=91=E7=A7=BB=E5=8A=A8=E5=88=B0loopdrive?= =?UTF-8?q?r=E4=B8=AD=EF=BC=8C=E7=94=B1loopmanager=E5=B0=81=E8=A3=85init?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=8C=E7=AE=A1=E7=90=86loopdevice?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=20=3D=20=E6=B7=BB=E5=8A=A0loopdevice?= =?UTF-8?q?=E7=9A=84=E5=9B=9B=E7=A7=8D=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 166 +++++++++++++++----- 1 file changed, 131 insertions(+), 35 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index e9ee810dd..6d236b80a 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -33,7 +33,6 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; -use bitmap::traits::BitMapOps; use core::{ any::Any, fmt::{Debug, Formatter}, @@ -55,18 +54,27 @@ pub struct LoopDevice { } //Inner内数据会改变所以加锁 pub struct LoopDeviceInner { + // 设备名称 Major和Minor + pub device_number: DeviceNumber, + //状态管理 + state: LoopState, + state_lock: SpinLock<()>, + //后端文件相关 // 关联的文件节点 pub file_inode: Option>, // 文件大小 pub file_size: usize, - // 设备名称 Major和Minor - pub device_number: DeviceNumber, // 数据偏移量 pub offset: usize, // 数据大小限制 pub size_limit: usize, + //文件名缓存 + pub file_name: u8, + // 是否允许用户直接 I/O 操作 pub user_direct_io: bool, + //标志位 + pub flags: u32, // 是否只读 pub read_only: bool, // 是否可见 @@ -77,6 +85,31 @@ pub struct LoopDeviceInner { pub kobject_common: KObjectCommonData, // 设备的公共数据 pub device_common: DeviceCommonData, + //工作管理 todo + //work_queue: Option>, +} +impl LoopDeviceInner{ + fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { + let _guard = self.state_lock.lock(); + + // 状态转换检查 + match (&self.state, &new_state) { + (LoopState::Unbound, LoopState::Bound) => {}, + (LoopState::Bound, LoopState::Unbound) => {}, + (LoopState::Bound, LoopState::Rundown) => {}, + (LoopState::Rundown, LoopState::Deleting) => {}, + _ => return Err(SystemError::EINVAL), + } + + self.state = new_state; + Ok(()) + } +} +pub enum LoopState { + Unbound, + Bound, + Rundown, + Deleting, } impl Debug for LoopDevice { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { @@ -106,6 +139,11 @@ impl LoopDevice { self_ref: self_ref.clone(), kobject_common: KObjectCommonData::default(), device_common: DeviceCommonData::default(), + file_name: 0, + flags: 0, + state: LoopState::Unbound, + state_lock: SpinLock::new(()), + //work_queue: None, }), //只用重复8次,就会有从0-7八个次设备号 block_dev_meta: BlockDevMeta::new(devname, Major::new(7)), // Loop 设备主设备号为 7 @@ -460,7 +498,7 @@ pub struct LoopDeviceDriver { inner: SpinLock, kobj_state: LockedKObjectState, } -struct InnerLoopDeviceDriver{ +struct InnerLoopDeviceDriver { driver_common: DriverCommonData, kobj_common: KObjectCommonData, } @@ -473,9 +511,8 @@ impl Debug for InnerLoopDeviceDriver { } } impl LoopDeviceDriver { - pub fn new() -> Arc { - let inner = InnerLoopDeviceDriver{ + let inner = InnerLoopDeviceDriver { driver_common: DriverCommonData::default(), kobj_common: KObjectCommonData::default(), }; @@ -487,14 +524,11 @@ impl LoopDeviceDriver { fn inner(&self) -> SpinLockGuard { self.inner.lock() } - fn loop_init(&self) -> Result<(), SystemError> { - // 创建并初始化 LoopManager 单例 - // let loop_mgr = LOOP_MANAGER.call_once(|| LoopManager::new()); - for minor in 0..LoopManager::MAX_DEVICES { - let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor); - if let Some(loop_dev) = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) { - log::info!( - "Registering loop device: {}", + fn new_loop_device(&self, minor: usize) -> Result<(), SystemError> { + let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor); + if let Some(loop_dev) = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) { + log::info!( + "Registering loop device: {}", loop_dev.block_dev_meta.devname ); block_dev_manager().register(loop_dev.clone())?; @@ -503,30 +537,34 @@ impl LoopDeviceDriver { } else { error!("Failed to create loop device for minor {}", minor); } - } - // // 创建并注册 /dev/loop-control - // let control_dev = Arc::new(LoopControlDevice::new()); // 假设的构造函数 - // block_dev_manager().register(control_dev.clone())?; - // devfs::devfs_register("loop-control", control_dev.clone())?; - // info!("LoopDeviceDriver and all devices initialized."); Ok(()) } + // pub fn new_loop_ctrl_device(&self)-> Result<(), SystemError>{ + // // 创建并注册 /dev/loop-control + // let control_dev = Arc::new(LoopControlDevice::new()); // 假设的构造函数 + // block_dev_manager().register(control_dev.clone())?; + // devfs::devfs_register("loop-control", control_dev.clone())?; + // log::info!("LoopDeviceDriver and all devices initialized."); + // Ok(()) + // } } use crate::init::initcall::INITCALL_DEVICE; #[unified_init(INITCALL_DEVICE)] -pub fn loop_init()-> Result<(), SystemError> { +pub fn loop_init() -> Result<(), SystemError> { + let loop_mgr = LoopManager::new(); // 获取 LoopDeviceDriver 的单例并调用初始化函数 let driver = LoopDeviceDriver::new(); - driver.loop_init() -} + loop_mgr.loop_init(driver)?; + Ok(()) +} impl Driver for LoopDeviceDriver { fn id_table(&self) -> Option { Some(IdTable::new("loop".to_string(), None)) } - fn devices(&self) -> Vec> { + fn devices(&self) -> Vec> { self.inner().driver_common.devices.clone() } @@ -604,18 +642,76 @@ impl KObject for LoopDeviceDriver { *self.kobj_state.write() = state; } } -pub struct LoopControlDevice { - locked_kobj_state: LockedKObjectState, - inner: SpinLock, -} -pub struct LoopControlDeviceInner { - kobject_common: KObjectCommonData, - device_common: DeviceCommonData, -} pub struct LoopManager { - devices: Vec>, + inner: SpinLock, +} +pub struct LoopManagerInner { + devices: [Option>; LoopManager::MAX_DEVICES], } impl LoopManager { - const MAX_DEVICES: usize =8; -} \ No newline at end of file + const MAX_DEVICES: usize = 8; + pub fn new() -> Self { + Self { + inner: SpinLock::new(LoopManagerInner { + devices: [const { None }; Self::MAX_DEVICES], + }), + } + } + fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } + //index: 次设备号 + pub fn register_device(&self, index: usize, device: Arc) { + if index < Self::MAX_DEVICES { + self.inner().devices[index] = Some(device); + } + } + + // 动态分配空闲的loop设备,与指定文件inode关联 + pub fn alloc_device( + &self, + file_inode: Arc, + ) -> Result, SystemError> { + let mut inner = self.inner(); + for (i, device) in inner.devices.iter_mut().enumerate() { + if device.is_none() { + let devname = DevName::new(format!("{}{}", LOOP_BASENAME, i), i as usize); + let loop_device = LoopDevice::new_empty_loop_device(devname, i as u32) + .ok_or(SystemError::ENOMEM)?; + loop_device.set_file(file_inode.clone())?; + *device = Some(loop_device.clone()); + return Ok(loop_device); + } + } + Err(SystemError::ENOSPC) + } + pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { + + //注册loop_control设备 + // let loop_ctl=Arc::new(LoopControlDevice::new()); + // DevFS::register_device("loop-control",loop_ctl.clone())?; + + // 注册 loop 设备 + for minor in 0..Self::MAX_DEVICES { + driver.new_loop_device(minor)?; + } + log::info!("Loop devices initialized"); + + //添加到loop_manager中 + + log::info!("LoopDeviceDriver and all devices initialized."); + Ok(()) + } + // pub fn loop_add(&self) + + // pub fn loop_control_remove + // pub loop_control_get_free(&self) -> Result { + // let inner = self.inner(); + // for (i, device) in inner.devices.iter().enumerate() { + // if device.is_none() { + // return Ok(i); + // } + // } + // Err(SystemError::ENOSPC) +} From d8eb2e7f73068b4258e559746dcb9ffa880df1c8 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Fri, 26 Sep 2025 07:19:47 +0000 Subject: [PATCH 05/39] =?UTF-8?q?=E6=B3=A8=E5=86=8Cloop-control=E8=AE=BE?= =?UTF-8?q?=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 285 ++++++++++++++++++-- kernel/src/filesystem/devfs/mod.rs | 5 +- 2 files changed, 261 insertions(+), 29 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 6d236b80a..bfb97be33 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -10,6 +10,7 @@ use crate::{ device::{ bus::{bus_manager, Bus}, device_number::{DeviceNumber, Major}, + device_register, driver::{Driver, DriverCommonData}, DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable, }, @@ -88,19 +89,19 @@ pub struct LoopDeviceInner { //工作管理 todo //work_queue: Option>, } -impl LoopDeviceInner{ +impl LoopDeviceInner { fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { let _guard = self.state_lock.lock(); - + // 状态转换检查 match (&self.state, &new_state) { - (LoopState::Unbound, LoopState::Bound) => {}, - (LoopState::Bound, LoopState::Unbound) => {}, - (LoopState::Bound, LoopState::Rundown) => {}, - (LoopState::Rundown, LoopState::Deleting) => {}, + (LoopState::Unbound, LoopState::Bound) => {} + (LoopState::Bound, LoopState::Unbound) => {} + (LoopState::Bound, LoopState::Rundown) => {} + (LoopState::Rundown, LoopState::Deleting) => {} _ => return Err(SystemError::EINVAL), } - + self.state = new_state; Ok(()) } @@ -168,17 +169,17 @@ impl LoopDevice { Ok(()) } - /// 获取文件大小 + // 获取文件大小 pub fn file_size(&self) -> usize { self.inner().file_size } - /// 设置只读模式 + // 设置只读模式 pub fn set_read_only(&self, read_only: bool) { self.inner().read_only = read_only; } - /// 检查是否为只读 + // 检查是否为只读 pub fn is_read_only(&self) -> bool { self.inner().read_only } @@ -650,7 +651,8 @@ pub struct LoopManagerInner { devices: [Option>; LoopManager::MAX_DEVICES], } impl LoopManager { - const MAX_DEVICES: usize = 8; + const MAX_DEVICES: usize = 256; // 支持的最大 loop 设备数量 + const MAX_INIT_DEVICES: usize = 8; //初始化loop设备数量 pub fn new() -> Self { Self { inner: SpinLock::new(LoopManagerInner { @@ -664,7 +666,8 @@ impl LoopManager { //index: 次设备号 pub fn register_device(&self, index: usize, device: Arc) { if index < Self::MAX_DEVICES { - self.inner().devices[index] = Some(device); + let mut inner = self.inner(); + inner.devices[index] = Some(device); } } @@ -686,14 +689,18 @@ impl LoopManager { } Err(SystemError::ENOSPC) } + pub fn deallocate_device(&self, device: &Arc) -> Result<(), SystemError> { + todo!() + } pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { - //注册loop_control设备 - // let loop_ctl=Arc::new(LoopControlDevice::new()); - // DevFS::register_device("loop-control",loop_ctl.clone())?; - + let loop_ctl = LoopControlDevice::new(); + device_register(loop_ctl.clone())?; + log::info!("Loop control device registered."); + devfs_register("loop-control", loop_ctl.clone())?; + log::info!("Loop control device initialized."); // 注册 loop 设备 - for minor in 0..Self::MAX_DEVICES { + for minor in 0..Self::MAX_INIT_DEVICES { driver.new_loop_device(minor)?; } log::info!("Loop devices initialized"); @@ -703,15 +710,237 @@ impl LoopManager { log::info!("LoopDeviceDriver and all devices initialized."); Ok(()) } - // pub fn loop_add(&self) - - // pub fn loop_control_remove - // pub loop_control_get_free(&self) -> Result { - // let inner = self.inner(); - // for (i, device) in inner.devices.iter().enumerate() { - // if device.is_none() { - // return Ok(i); - // } - // } - // Err(SystemError::ENOSPC) +} +//一个字符设备,作为一个抽象接口控制loop设备的创建,绑定和删除 +/* +设备分配和查找 +设备绑定和解绑 +设备状态查询和配置(配置设备参数,如偏移量、大小限制等) +*/ + +pub struct LoopControlDevice { + inner: SpinLock, + locked_kobj_state: LockedKObjectState, +} +struct LoopControlDeviceInner { + // 设备的公共数据 + pub device_common: DeviceCommonData, + // KObject的公共数据 + pub kobject_common: KObjectCommonData, + + parent: RwLock>, + device_inode_fs: RwLock>>, + devfs_metadata: Metadata, +} +impl LoopControlDevice { + pub fn new() -> Arc { + Arc::new(Self { + inner: SpinLock::new(LoopControlDeviceInner { + kobject_common: KObjectCommonData::default(), + device_common: DeviceCommonData::default(), + parent: RwLock::new(Weak::default()), + device_inode_fs: RwLock::new(None), + devfs_metadata: Metadata::default(), + }), + locked_kobj_state: LockedKObjectState::default(), + }) + } + pub fn inner(&self) -> SpinLockGuard { + self.inner.lock() + } +} +impl DeviceINode for LoopControlDevice { + fn set_fs(&self, fs: alloc::sync::Weak) { + *self.inner().device_inode_fs.write() = Some(fs); + } + fn set_parent(&self, parent: Weak) { + *self.inner().parent.write() = parent; + } +} +impl Debug for LoopControlDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LoopControlDevice").finish() + } +} +impl IndexNode for LoopControlDevice { + fn metadata(&self) -> Result { + use crate::filesystem::vfs::{syscall::ModeType, FileType, InodeId}; + use crate::time::PosixTimeSpec; + + let metadata = Metadata { + dev_id: 0, + inode_id: InodeId::new(0), // Loop control 设备的 inode ID + size: 0, // 字符设备大小通常为0 + blk_size: 0, // 字符设备不使用块大小 + blocks: 0, // 字符设备不使用块数 + atime: PosixTimeSpec::default(), + mtime: PosixTimeSpec::default(), + ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), + file_type: FileType::CharDevice, // 字符设备类型 + mode: ModeType::from_bits_truncate(0o600), // 读写权限,仅owner可访问 + nlinks: 1, + uid: 0, // root用户 + gid: 0, // root组 + raw_dev: DeviceNumber::new(Major::new(10), 237), // loop-control设备号通常是(10, 237) + }; + Ok(metadata) + } + fn fs(&self) -> Arc { + todo!() + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn read_at( + &self, + _offset: usize, + _len: usize, + _buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn list(&self) -> Result, system_error::SystemError> { + Err(SystemError::ENOSYS) + } + // fn metadata(&self) -> Result { + // Metadata + // } +} +impl Device for LoopControlDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Char + } + + fn id_table(&self) -> IdTable { + IdTable::new(LOOP_BASENAME.to_string(), None) + } + + fn bus(&self) -> Option> { + self.inner().device_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn class(&self) -> Option> { + let mut guard = self.inner(); + let r = guard.device_common.class.clone()?.upgrade(); + if r.is_none() { + guard.device_common.class = None; + } + return r; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn driver(&self) -> Option> { + let r = self.inner().device_common.driver.clone()?.upgrade(); + if r.is_none() { + self.inner().device_common.driver = None; + } + return r; + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn dev_parent(&self) -> Option> { + self.inner().device_common.get_parent_weak_or_clear() + } + + fn set_dev_parent(&self, parent: Option>) { + self.inner().device_common.parent = parent; + } +} +impl KObject for LoopControlDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + "loop-control".to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.locked_kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.locked_kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobj_state.write() = state; + } } diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index 6bd815ba8..7c6394c1f 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -157,6 +157,9 @@ impl DevFS { } else if name == "ptmx" { // ptmx设备 dev_root_inode.add_dev(name, device.clone())?; + } else if name == "loop-control" { + // loop-control设备 + dev_root_inode.add_dev(name, device.clone())?; } else { // 在 /dev/char 下创建设备节点 dev_char_inode.add_dev(name, device.clone())?; @@ -193,7 +196,7 @@ impl DevFS { } else if name.starts_with("nvme") { // NVMe设备挂载在 /dev 下 dev_root_inode.add_dev(name, device.clone())?; - } else if name.starts_with("loop"){ + } else if name.starts_with("loop") { dev_root_inode.add_dev(name, device.clone())?; } else { dev_block_inode.add_dev(name, device.clone())?; From 521d819a3325e6dc58dbe9ca1cb5ffb84c67bcab Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Mon, 29 Sep 2025 08:36:01 +0000 Subject: [PATCH 06/39] =?UTF-8?q?=E5=A4=8D=E7=94=A8linux=E4=B8=AD=E5=85=B3?= =?UTF-8?q?=E4=BA=8Eloop=E7=9A=84ioctl=E9=AD=94=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 48 ++++++++++++++++++--- kernel/src/driver/base/block/mod.rs | 2 +- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index bfb97be33..73ce6b475 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -1,4 +1,5 @@ use crate::filesystem::devfs::LockedDevFSInode; +use crate::filesystem::vfs::FilePrivateData; use crate::{ driver::base::{ block::{ @@ -42,6 +43,36 @@ use log::error; use system_error::SystemError; use unified_init::macros::unified_init; const LOOP_BASENAME: &str = "loop"; +// loop device 加密类型 +pub const LO_CRYPT_NONE: u32 = 0; +pub const LO_CRYPT_XOR: u32 = 1; +pub const LO_CRYPT_DES: u32 = 2; +pub const LO_CRYPT_FISH2: u32 = 3; // Twofish encryption +pub const LO_CRYPT_BLOW: u32 = 4; +pub const LO_CRYPT_CAST128: u32 = 5; +pub const LO_CRYPT_IDEA: u32 = 6; +pub const LO_CRYPT_DUMMY: u32 = 9; +pub const LO_CRYPT_SKIPJACK: u32 = 10; +pub const LO_CRYPT_CRYPTOAPI: u32 = 18; +pub const MAX_LO_CRYPT: u32 = 20; + +// IOCTL 命令 - 使用 0x4C ('L') +pub const LOOP_SET_FD: u32 = 0x4C00; +pub const LOOP_CLR_FD: u32 = 0x4C01; +pub const LOOP_SET_STATUS: u32 = 0x4C02; +pub const LOOP_GET_STATUS: u32 = 0x4C03; +pub const LOOP_SET_STATUS64: u32 = 0x4C04; +pub const LOOP_GET_STATUS64: u32 = 0x4C05; +pub const LOOP_CHANGE_FD: u32 = 0x4C06; +pub const LOOP_SET_CAPACITY: u32 = 0x4C07; +pub const LOOP_SET_DIRECT_IO: u32 = 0x4C08; +pub const LOOP_SET_BLOCK_SIZE: u32 = 0x4C09; +pub const LOOP_CONFIGURE: u32 = 0x4C0A; + +// /dev/loop-control 接口 +pub const LOOP_CTL_ADD: u32 = 0x4C80; +pub const LOOP_CTL_REMOVE: u32 = 0x4C81; +pub const LOOP_CTL_GET_FREE: u32 = 0x4C82; //LoopDevice是一个虚拟的块设备,它将文件映射到块设备上. pub struct LoopDevice { inner: SpinLock, //加锁保护LoopDeviceInner @@ -285,8 +316,8 @@ impl IndexNode for LoopDevice { dev_id: 0, inode_id: InodeId::new(0), // Loop 设备通常没有实际的 inode ID size: self.inner().file_size as i64, - blk_size: LBA_SIZE as usize, - blocks: (self.inner().file_size + LBA_SIZE - 1) / LBA_SIZE as usize, // 计算块数 + blk_size: LBA_SIZE, + blocks: (self.inner().file_size + LBA_SIZE - 1) / LBA_SIZE, // 计算块数 atime: file_metadata.atime, mtime: file_metadata.mtime, ctime: file_metadata.ctime, @@ -549,6 +580,7 @@ impl LoopDeviceDriver { // Ok(()) // } } +//初始化函数,注册1个loopcontrol设备和8个loop设备备用 use crate::init::initcall::INITCALL_DEVICE; #[unified_init(INITCALL_DEVICE)] pub fn loop_init() -> Result<(), SystemError> { @@ -556,7 +588,6 @@ pub fn loop_init() -> Result<(), SystemError> { // 获取 LoopDeviceDriver 的单例并调用初始化函数 let driver = LoopDeviceDriver::new(); loop_mgr.loop_init(driver)?; - Ok(()) } @@ -679,7 +710,7 @@ impl LoopManager { let mut inner = self.inner(); for (i, device) in inner.devices.iter_mut().enumerate() { if device.is_none() { - let devname = DevName::new(format!("{}{}", LOOP_BASENAME, i), i as usize); + let devname = DevName::new(format!("{}{}", LOOP_BASENAME, i), i); let loop_device = LoopDevice::new_empty_loop_device(devname, i as u32) .ok_or(SystemError::ENOMEM)?; loop_device.set_file(file_inode.clone())?; @@ -793,7 +824,14 @@ impl IndexNode for LoopControlDevice { fn as_any_ref(&self) -> &dyn core::any::Any { self } - + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { + todo!() + } fn read_at( &self, _offset: usize, diff --git a/kernel/src/driver/base/block/mod.rs b/kernel/src/driver/base/block/mod.rs index 179e611de..8b7a38db4 100644 --- a/kernel/src/driver/base/block/mod.rs +++ b/kernel/src/driver/base/block/mod.rs @@ -1,8 +1,8 @@ pub mod block_device; pub mod disk_info; pub mod gendisk; -pub mod manager; pub mod loop_device; +pub mod manager; #[derive(Debug)] #[allow(dead_code)] pub enum SeekFrom { From 327d16662a8d67ba8f86c0baa35cc6083ea46d9f Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 9 Oct 2025 09:43:19 +0000 Subject: [PATCH 07/39] =?UTF-8?q?-=20=E5=BE=80loop=5Fcontrol=5Fdevice?= =?UTF-8?q?=E4=B8=AD=E5=8A=A0=E5=85=A5loopmanager=E7=9A=84arc=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=20-=20=E6=B7=BB=E5=8A=A0loop=5Fadd=E5=92=8Cloop=5Frem?= =?UTF-8?q?ove=E5=87=BD=E6=95=B0=20-=20=E6=B7=BB=E5=8A=A0loop=5Fcontrol=5F?= =?UTF-8?q?ioctl=E7=9A=84loop=E6=96=87=E4=BB=B6=E7=A7=81=E6=9C=89=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=EF=BC=8C=E5=8F=91=E7=8E=B0data=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E4=BB=A3=E6=9B=BF=20-=20=E5=BE=85=E5=AE=8C=E6=88=90loop=5Fctl?= =?UTF-8?q?=E7=9A=84read=20=E5=92=8Cwrite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 157 +++++++++++++++++--- kernel/src/filesystem/vfs/file.rs | 3 +- 2 files changed, 140 insertions(+), 20 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 73ce6b475..6a9cae10d 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -84,6 +84,11 @@ pub struct LoopDevice { fs: RwLock>, //文件系统弱引用 parent: RwLock>, } +#[derive(Debug, Clone)] +pub struct LoopPrivateData { + //索引号 + pub parms: u32, +} //Inner内数据会改变所以加锁 pub struct LoopDeviceInner { // 设备名称 Major和Minor @@ -184,7 +189,6 @@ impl LoopDevice { fs: RwLock::new(Weak::default()), parent: RwLock::new(Weak::default()), }); - Some(dev) } @@ -564,13 +568,12 @@ impl LoopDeviceDriver { loop_dev.block_dev_meta.devname ); block_dev_manager().register(loop_dev.clone())?; - //devfs进行注册时[ ERROR ] (src/init/initcall.rs:22) Failed to call initializer register_loop_devices: EPERM - //devfs_register(&format!("loop{}", minor), loop_dev.clone())?; } else { error!("Failed to create loop device for minor {}", minor); } Ok(()) } + // pub fn new_loop_ctrl_device(&self)-> Result<(), SystemError>{ // // 创建并注册 /dev/loop-control // let control_dev = Arc::new(LoopControlDevice::new()); // 假设的构造函数 @@ -584,9 +587,15 @@ impl LoopDeviceDriver { use crate::init::initcall::INITCALL_DEVICE; #[unified_init(INITCALL_DEVICE)] pub fn loop_init() -> Result<(), SystemError> { - let loop_mgr = LoopManager::new(); + let loop_mgr = Arc::new(LoopManager::new()); // 获取 LoopDeviceDriver 的单例并调用初始化函数 let driver = LoopDeviceDriver::new(); + let loop_ctl = LoopControlDevice::new(loop_mgr.clone()); + //注册loop_control设备 + device_register(loop_ctl.clone())?; + log::info!("Loop control device registered."); + devfs_register("loop-control", loop_ctl.clone())?; + log::info!("Loop control device initialized."); loop_mgr.loop_init(driver)?; Ok(()) } @@ -680,6 +689,7 @@ pub struct LoopManager { } pub struct LoopManagerInner { devices: [Option>; LoopManager::MAX_DEVICES], + next_free_minor: u32, } impl LoopManager { const MAX_DEVICES: usize = 256; // 支持的最大 loop 设备数量 @@ -688,6 +698,7 @@ impl LoopManager { Self { inner: SpinLock::new(LoopManagerInner { devices: [const { None }; Self::MAX_DEVICES], + next_free_minor: 0, }), } } @@ -701,7 +712,76 @@ impl LoopManager { inner.devices[index] = Some(device); } } - + /* + 请求队列,工作队列未实现 + */ + pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { + let mut inner_guard = self.inner(); + let minor_to_use: u32 = match requested_minor { + Some(req_minor) => { + if req_minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + if inner_guard.devices[req_minor as usize].is_some() { + return Err(SystemError::EEXIST); + } + req_minor + } + None => { + let mut found_minor_candidate = None; + let start_minor = inner_guard.next_free_minor; + let mut current_search_minor = start_minor; + + for _ in 0..Self::MAX_DEVICES { + if inner_guard.devices[current_search_minor as usize].is_none() { + found_minor_candidate = Some(current_search_minor); + // 更新 next_free_minor 以便下次从这里开始查找 + inner_guard.next_free_minor = + (current_search_minor + 1) % (Self::MAX_DEVICES as u32); + break; + } + current_search_minor = (current_search_minor + 1) % (Self::MAX_DEVICES as u32); + if current_search_minor == start_minor { + // 遍历了一圈,没有找到空闲的 + break; + } + } + + found_minor_candidate.ok_or(SystemError::ENOSPC)? + } + }; + let devname = DevName::new( + format!("{}{}", LOOP_BASENAME, minor_to_use), + minor_to_use as usize, + ); + let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor_to_use) + .ok_or(SystemError::ENOMEM)?; + log::info!("Registing loop device: {}", loop_dev.block_dev_meta.devname); + block_dev_manager().register(loop_dev.clone())?; + inner_guard.devices[minor_to_use as usize] = Some(loop_dev.clone()); + log::info!("Loop device loop{} added successfully.", minor_to_use); + Ok(loop_dev) + } + pub fn find_device_by_minor(&self, minor: u32) -> Option> { + let inner = self.inner(); + if minor < Self::MAX_DEVICES as u32 { + inner.devices[minor as usize].clone() + } else { + None + } + } + // pub fn loop_remove(&self ,minor:u32)-> Result<(),SystemError>{ + // let mut inner_guard=self.inner(); + // if minor >=Self::MAX_DEVICES as u32{ + // return Err(SystemError::EINVAL); + // } + // if let Some(loop_dev)=inner_guard.devices[minor as usize ].take(){ + // //loop_dev.clear_file()?; + // //loop_dev.inner().set_stable(LoopState::Deleting)?; + + // block_dev_manager().unregister(loop_dev.dev_name())?; + // } + // } // 动态分配空闲的loop设备,与指定文件inode关联 pub fn alloc_device( &self, @@ -724,12 +804,6 @@ impl LoopManager { todo!() } pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { - //注册loop_control设备 - let loop_ctl = LoopControlDevice::new(); - device_register(loop_ctl.clone())?; - log::info!("Loop control device registered."); - devfs_register("loop-control", loop_ctl.clone())?; - log::info!("Loop control device initialized."); // 注册 loop 设备 for minor in 0..Self::MAX_INIT_DEVICES { driver.new_loop_device(minor)?; @@ -738,7 +812,7 @@ impl LoopManager { //添加到loop_manager中 - log::info!("LoopDeviceDriver and all devices initialized."); + log::info!("Loop devices initialized."); Ok(()) } } @@ -752,6 +826,7 @@ impl LoopManager { pub struct LoopControlDevice { inner: SpinLock, locked_kobj_state: LockedKObjectState, + loop_mgr: Arc, } struct LoopControlDeviceInner { // 设备的公共数据 @@ -764,7 +839,11 @@ struct LoopControlDeviceInner { devfs_metadata: Metadata, } impl LoopControlDevice { - pub fn new() -> Arc { + pub fn loop_add(&self, index: u32) -> Result, SystemError> { + //let loop_dri= LoopDeviceDriver::new(); + self.loop_mgr.loop_add(Some(index)) + } + pub fn new(loop_mgr: Arc) -> Arc { Arc::new(Self { inner: SpinLock::new(LoopControlDeviceInner { kobject_common: KObjectCommonData::default(), @@ -774,6 +853,7 @@ impl LoopControlDevice { devfs_metadata: Metadata::default(), }), locked_kobj_state: LockedKObjectState::default(), + loop_mgr, }) } pub fn inner(&self) -> SpinLockGuard { @@ -820,17 +900,56 @@ impl IndexNode for LoopControlDevice { fn fs(&self) -> Arc { todo!() } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } fn ioctl( &self, cmd: u32, data: usize, - _private_data: &FilePrivateData, + private_data: &FilePrivateData, ) -> Result { - todo!() + match cmd { + LOOP_CTL_ADD => { + let requested_index = data as u32; + match self.loop_mgr.loop_add(Some(requested_index)) { + Ok(loop_dev) => Ok(loop_dev.inner().device_number.minor() as usize), + Err(e) => Err(e), + } + } + + LOOP_CTL_REMOVE => { + let minor_to_remove = data as u32; + // self.loop_mgr.loop_remove(minor_to_remove)?; + Ok(0) + } + LOOP_CTL_GET_FREE => { + let mut inner_guard = self.loop_mgr.inner(); + let start_minor = inner_guard.next_free_minor; + let mut found_minor = None; + for _ in 0..LoopManager::MAX_DEVICES { + let current_minor = inner_guard.next_free_minor; + //轮询找到一个空闲的loop设备好 + inner_guard.next_free_minor = + (inner_guard.next_free_minor + 1) % LoopManager::MAX_DEVICES as u32; + if inner_guard.devices[current_minor as usize].is_none() { + found_minor = Some(current_minor); + break; + } + if inner_guard.next_free_minor == start_minor { + //没找到 + break; + } + } + drop(inner_guard); + match found_minor { + Some(minor) => Ok(minor as usize), + None => Err(SystemError::ENOSPC), + } + } + _ => Err(SystemError::ENOSYS), + } + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self } fn read_at( &self, diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 86f2d3559..01063b5c3 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -7,7 +7,7 @@ use system_error::SystemError; use super::{FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; use crate::{ driver::{ - base::{block::SeekFrom, device::DevicePrivateData}, + base::{block::loop_device::LoopPrivateData, block::SeekFrom, device::DevicePrivateData}, tty::tty_device::TtyFilePrivateData, }, filesystem::{ @@ -34,6 +34,7 @@ pub enum FilePrivateData { Tty(TtyFilePrivateData), /// epoll私有信息 EPoll(EPollPrivateData), + Loop(LoopPrivateData), /// 不需要文件私有信息 Unused, } From e7363e3d885fe4268b721ed5f67e83ce7b22bad5 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 15 Oct 2025 06:47:57 +0000 Subject: [PATCH 08/39] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=8D=E5=AF=B9?= =?UTF-8?q?=E5=9B=9E=E7=8E=AF=E8=B7=AF=E7=94=B1=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 99 ++++++++++++--------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 6a9cae10d..b2d2a09b1 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -9,22 +9,20 @@ use crate::{ }, class::Class, device::{ - bus::{bus_manager, Bus}, + bus:: Bus, device_number::{DeviceNumber, Major}, - device_register, + device_register,device_unregister, driver::{Driver, DriverCommonData}, - DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable, + DevName, Device, DeviceCommonData,DeviceType, IdTable, }, kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, kset::KSet, - subsys::SubSysPrivate, }, filesystem::{ - devfs::{self, devfs_register, DevFS, DeviceINode}, + devfs::{devfs_register, DevFS, DeviceINode}, kernfs::KernFSInode, vfs::{IndexNode, InodeId, Metadata}, }, - init::initcall::INITCALL_POSTCORE, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, spinlock::{SpinLock, SpinLockGuard}, @@ -43,31 +41,31 @@ use log::error; use system_error::SystemError; use unified_init::macros::unified_init; const LOOP_BASENAME: &str = "loop"; -// loop device 加密类型 -pub const LO_CRYPT_NONE: u32 = 0; -pub const LO_CRYPT_XOR: u32 = 1; -pub const LO_CRYPT_DES: u32 = 2; -pub const LO_CRYPT_FISH2: u32 = 3; // Twofish encryption -pub const LO_CRYPT_BLOW: u32 = 4; -pub const LO_CRYPT_CAST128: u32 = 5; -pub const LO_CRYPT_IDEA: u32 = 6; -pub const LO_CRYPT_DUMMY: u32 = 9; -pub const LO_CRYPT_SKIPJACK: u32 = 10; -pub const LO_CRYPT_CRYPTOAPI: u32 = 18; -pub const MAX_LO_CRYPT: u32 = 20; - -// IOCTL 命令 - 使用 0x4C ('L') -pub const LOOP_SET_FD: u32 = 0x4C00; -pub const LOOP_CLR_FD: u32 = 0x4C01; -pub const LOOP_SET_STATUS: u32 = 0x4C02; -pub const LOOP_GET_STATUS: u32 = 0x4C03; -pub const LOOP_SET_STATUS64: u32 = 0x4C04; -pub const LOOP_GET_STATUS64: u32 = 0x4C05; -pub const LOOP_CHANGE_FD: u32 = 0x4C06; -pub const LOOP_SET_CAPACITY: u32 = 0x4C07; -pub const LOOP_SET_DIRECT_IO: u32 = 0x4C08; -pub const LOOP_SET_BLOCK_SIZE: u32 = 0x4C09; -pub const LOOP_CONFIGURE: u32 = 0x4C0A; +// // loop device 加密类型 +// pub const LO_CRYPT_NONE: u32 = 0; +// pub const LO_CRYPT_XOR: u32 = 1; +// pub const LO_CRYPT_DES: u32 = 2; +// pub const LO_CRYPT_FISH2: u32 = 3; // Twofish encryption +// pub const LO_CRYPT_BLOW: u32 = 4; +// pub const LO_CRYPT_CAST128: u32 = 5; +// pub const LO_CRYPT_IDEA: u32 = 6; +// pub const LO_CRYPT_DUMMY: u32 = 9; +// pub const LO_CRYPT_SKIPJACK: u32 = 10; +// pub const LO_CRYPT_CRYPTOAPI: u32 = 18; +// pub const MAX_LO_CRYPT: u32 = 20; + +// // IOCTL 命令 - 使用 0x4C ('L') +// pub const LOOP_SET_FD: u32 = 0x4C00; +// pub const LOOP_CLR_FD: u32 = 0x4C01; +// pub const LOOP_SET_STATUS: u32 = 0x4C02; +// pub const LOOP_GET_STATUS: u32 = 0x4C03; +// pub const LOOP_SET_STATUS64: u32 = 0x4C04; +// pub const LOOP_GET_STATUS64: u32 = 0x4C05; +// pub const LOOP_CHANGE_FD: u32 = 0x4C06; +// pub const LOOP_SET_CAPACITY: u32 = 0x4C07; +// pub const LOOP_SET_DIRECT_IO: u32 = 0x4C08; +// pub const LOOP_SET_BLOCK_SIZE: u32 = 0x4C09; +// pub const LOOP_CONFIGURE: u32 = 0x4C0A; // /dev/loop-control 接口 pub const LOOP_CTL_ADD: u32 = 0x4C80; @@ -573,15 +571,6 @@ impl LoopDeviceDriver { } Ok(()) } - - // pub fn new_loop_ctrl_device(&self)-> Result<(), SystemError>{ - // // 创建并注册 /dev/loop-control - // let control_dev = Arc::new(LoopControlDevice::new()); // 假设的构造函数 - // block_dev_manager().register(control_dev.clone())?; - // devfs::devfs_register("loop-control", control_dev.clone())?; - // log::info!("LoopDeviceDriver and all devices initialized."); - // Ok(()) - // } } //初始化函数,注册1个loopcontrol设备和8个loop设备备用 use crate::init::initcall::INITCALL_DEVICE; @@ -801,7 +790,35 @@ impl LoopManager { Err(SystemError::ENOSPC) } pub fn deallocate_device(&self, device: &Arc) -> Result<(), SystemError> { - todo!() + /* + 重置状态unbound + */ + let mut inner_guard =device.inner(); + inner_guard.set_state(LoopState::Unbound)?; + inner_guard.file_inode=None; + inner_guard.file_size-0; + inner_guard.offset=0; + inner_guard.size_limit = 0; + inner_guard.read_only = false; + inner_guard.user_direct_io = false; + inner_guard.flags = 0; + inner_guard.file_name = 0; + drop(inner_guard); + let minor = device.inner().device_number.minor() as usize; + let mut loop_mgr_inner = self.inner(); // Lock the LoopManager + if minor < LoopManager::MAX_DEVICES { + if let Some(removed_device) = loop_mgr_inner.devices[minor].take() { + log::info!("Deallocated loop device loop{} from manager.", minor); + // Unregister from block device manager + device_unregister(removed_device.clone()); + } else { + log::warn!("Attempted to deallocate loop device loop{} but it was not found in manager.", minor); + } + } else { + return Err(SystemError::EINVAL); // Minor out of bounds + } + + Ok(()) // Indicate success } pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { // 注册 loop 设备 From a1f2a304467fbe1a3dc1e2eafe933e8cd0be96a5 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 30 Oct 2025 06:54:23 +0000 Subject: [PATCH 09/39] add test --- kernel/src/driver/base/block/loop_device.rs | 13 +- user/apps/c_unitest/test_loop.c | 159 ++++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 user/apps/c_unitest/test_loop.c diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index b2d2a09b1..4a43b5f52 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -21,7 +21,7 @@ use crate::{ filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, kernfs::KernFSInode, - vfs::{IndexNode, InodeId, Metadata}, + vfs::{IndexNode, InodeId, Metadata,file::FileMode}, }, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, @@ -891,6 +891,16 @@ impl Debug for LoopControlDevice { } } impl IndexNode for LoopControlDevice { + fn open( + &self, + _data: SpinLockGuard, + _mode: &FileMode, + ) -> Result<(), SystemError> { + + + // 若文件系统没有实现此方法,则返回“不支持” + return Ok(()); + } fn metadata(&self) -> Result { use crate::filesystem::vfs::{syscall::ModeType, FileType, InodeId}; use crate::time::PosixTimeSpec; @@ -925,6 +935,7 @@ impl IndexNode for LoopControlDevice { ) -> Result { match cmd { LOOP_CTL_ADD => { + log::info!("Starting LOOP_CTL_ADD ioctl"); let requested_index = data as u32; match self.loop_mgr.loop_add(Some(requested_index)) { Ok(loop_dev) => Ok(loop_dev.inner().device_number.minor() as usize), diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c new file mode 100644 index 000000000..b6a29ea15 --- /dev/null +++ b/user/apps/c_unitest/test_loop.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include +#include // For fstat +// magic +#define LOOP_CTL_ADD 0x4C80 +#define LOOP_CTL_REMOVE 0x4C81 +#define LOOP_CTL_GET_FREE 0x4C82 +//调用open和ioctl()接口实现通信 +#define LOOP_DEVICE_CONTROL "/dev/loop-control" +#define TEST_FILE_NAME "test_image.img" +#define TEST_FILE_SIZE (1024 * 1024) // 1MB for the test image + +void create_test_file() { + printf("Creating test file: %s with size %d bytes\n", TEST_FILE_NAME, TEST_FILE_SIZE); + int fd = open(TEST_FILE_NAME, O_CREAT | O_TRUNC | O_RDWR, 0644); + if (fd < 0) { + perror("Failed to create test file"); + exit(EXIT_FAILURE); + } + // Write some data to make it a non-empty file + char zero_block[512] = {0}; + for (int i = 0; i < TEST_FILE_SIZE / 512; ++i) { + if (write(fd, zero_block, 512) != 512) { + perror("Failed to write to test file"); + close(fd); + exit(EXIT_FAILURE); + } + } + printf("Test file created successfully.\n"); + close(fd); +} + +int main() { + int control_fd; + int loop_minor; + char loop_dev_path[64]; + int loop_fd; + char write_buf[512] = "Hello Loop Device!"; + char read_buf[512]; + + create_test_file(); // Create a file to back a loop device + + // 1. Open the loop-control device + printf("Opening loop control device: %s\n", LOOP_DEVICE_CONTROL); + control_fd = open(LOOP_DEVICE_CONTROL, O_RDWR); + if (control_fd < 0) { + perror("Failed to open loop control device. Make sure your kernel module is loaded and /dev/loop-control exists."); + exit(EXIT_FAILURE); + } + printf("Loop control device opened successfully (fd=%d).\n", control_fd); + + // 2. Get a free loop device minor number + printf("Requesting a free loop device minor...\n"); + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &loop_minor) < 0) { + perror("Failed to get free loop device minor"); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("Got free loop minor: %d\n", loop_minor); + + // 3. Add a new loop device using the minor number + // Note: The `LOOP_CTL_ADD` in your Rust code takes the minor as `data: usize`. + // We'll pass `loop_minor` directly. Your Rust code then creates an empty device. + printf("Adding loop device loop%d...\n", loop_minor); + int returned_minor = ioctl(control_fd, LOOP_CTL_ADD, loop_minor); + if (returned_minor < 0) { + perror("Failed to add loop device"); + close(control_fd); + exit(EXIT_FAILURE); + } + if (returned_minor != loop_minor) { + fprintf(stderr, "Warning: LOOP_CTL_ADD returned minor %d, expected %d\n", returned_minor, loop_minor); + } + printf("Loop device loop%d added (kernel returned minor: %d).\n", loop_minor, returned_minor); + + // In a real system, you would now open the test_image.img and associate it with the loop device. + // Your Rust code `set_file` is internal. For user-space, you'd typically use another ioctl on /dev/loopX + // to bind a file descriptor to it. Let's simulate opening the block device. + + // 4. Try to open the newly created loop block device + sprintf(loop_dev_path, "/dev/loop%d", loop_minor); + printf("Attempting to open block device: %s\n", loop_dev_path); + loop_fd = open(loop_dev_path, O_RDWR); + if (loop_fd < 0) { + perror("Failed to open loop block device. This might mean the block device node wasn't created/registered correctly, or permissions."); + fprintf(stderr, "Make sure /dev/loop%d exists as a block device.\n", loop_minor); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("Loop block device %s opened successfully (fd=%d).\n", loop_dev_path, loop_fd); + + // 5. Test read/write operations on the loop block device + // NOTE: For these to work, your Rust LoopDevice needs to be bound to `TEST_FILE_NAME` + // This binding mechanism is not exposed via an IOCTL in your current Rust code. + // In a full implementation, you would have an IOCTL like LOOP_SET_FD to pass the file descriptor of `TEST_FILE_NAME` + // to the kernel loop device. For this test, we'll assume the kernel somehow handles this or mock it. + + // For now, let's assume the kernel has a way to bind a file to the loop device, + // and we are simply interacting with the block device /dev/loopX. + + printf("Writing to loop device %s...\n", loop_dev_path); + if (lseek(loop_fd, 0, SEEK_SET) < 0) { + perror("lseek failed before write"); + close(loop_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + if (write(loop_fd, write_buf, sizeof(write_buf)) != sizeof(write_buf)) { + perror("Failed to write to loop device"); + close(loop_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("Successfully wrote '%s' to loop device.\n", write_buf); + + printf("Reading from loop device %s...\n", loop_dev_path); + memset(read_buf, 0, sizeof(read_buf)); + if (lseek(loop_fd, 0, SEEK_SET) < 0) { + perror("lseek failed before read"); + close(loop_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + if (read(loop_fd, read_buf, sizeof(read_buf)) != sizeof(read_buf)) { + perror("Failed to read from loop device"); + close(loop_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("Successfully read '%s' from loop device.\n", read_buf); + + if (strcmp(write_buf, read_buf) == 0) { + printf("Read/write test PASSED.\n"); + } else { + printf("Read/write test FAILED: Mismatch in data.\n"); + } + + // 6. Remove the loop device + printf("Removing loop device loop%d...\n", loop_minor); + if (ioctl(control_fd, LOOP_CTL_REMOVE, loop_minor) < 0) { + perror("Failed to remove loop device"); + close(loop_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("Loop device loop%d removed successfully.\n", loop_minor); + + // Clean up + close(loop_fd); + close(control_fd); + unlink(TEST_FILE_NAME); + printf("All tests completed. Cleaned up.\n"); + + return 0; +} \ No newline at end of file From 89c7fb1fbd81d73e06fe37016c628cca405810cc Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Fri, 31 Oct 2025 12:08:47 +0000 Subject: [PATCH 10/39] =?UTF-8?q?merge=20=E4=B8=BB=E7=BA=BF=EF=BC=8C?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=89=88=E6=9C=AC=E5=8F=B7=E5=92=8C=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E9=93=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build-scripts/Makefile | 4 ++-- config/app-blocklist.toml | 3 +++ tools/Makefile | 2 +- tools/nix-dev-shell/flake.nix | 2 +- user/apps/clear/Makefile | 2 +- user/apps/r_unitest/Makefile | 2 +- user/apps/riscv_init/riscv_rust_init/Makefile | 2 +- user/apps/syscall_ebpf/Makefile | 2 +- user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml | 2 +- user/apps/test_tokio/Makefile | 2 +- user/apps/test_tracepoint/Makefile | 2 +- user/apps/user-manage/Makefile | 2 +- 12 files changed, 15 insertions(+), 12 deletions(-) diff --git a/build-scripts/Makefile b/build-scripts/Makefile index 9cafbd7d4..4ca896678 100644 --- a/build-scripts/Makefile +++ b/build-scripts/Makefile @@ -1,9 +1,9 @@ all: - @cargo +nightly-2024-11-05 build --release -p gen_kallsyms + @cargo +nightly-2025-08-10 build --release -p gen_kallsyms fmt: cargo fmt --all $(FMT_CHECK) clean: @cargo clean check: - @cargo +nightly-2024-11-05 check --workspace $(CARGO_ZBUILD) --message-format=json + @cargo +nightly-2025-08-10 check --workspace $(CARGO_ZBUILD) --message-format=json .PHONY: fmt \ No newline at end of file diff --git a/config/app-blocklist.toml b/config/app-blocklist.toml index 19be09579..2545212ca 100644 --- a/config/app-blocklist.toml +++ b/config/app-blocklist.toml @@ -65,3 +65,6 @@ log_skipped = true [[blocked_apps]] name = "gvisor syscall tests" reason = "由于文件较大,因此屏蔽。如果要允许系统调用测试,则把这几行取消注释即可" +[[blocked_apps]] +name = "NovaShell" +reason = "工具链版本有问题,应为nightly-2025-8-10" diff --git a/tools/Makefile b/tools/Makefile index 94ff2833a..0f424ec5c 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -6,4 +6,4 @@ clean: @cargo clean check: - @cargo +nightly-2024-11-05 check --workspace --message-format=json + @cargo +nightly-2025-08-10 check --workspace --message-format=json diff --git a/tools/nix-dev-shell/flake.nix b/tools/nix-dev-shell/flake.nix index b0daf84d9..19c6dbe47 100644 --- a/tools/nix-dev-shell/flake.nix +++ b/tools/nix-dev-shell/flake.nix @@ -12,7 +12,7 @@ let pkgs = nixpkgs.legacyPackages.${system}; rustVer = fenix.packages.${system}.fromToolchainName { - name = "nightly-2024-11-05"; + name = "nightly-2025-08-10"; sha256 = "sha256-muM2tfsMpo2gsFsofhwHutPWgiPjjuwfBUvYCrwomAY="; }; # 组合工具链并提取二进制路径 diff --git a/user/apps/clear/Makefile b/user/apps/clear/Makefile index 261eba3d6..4d6141ad8 100644 --- a/user/apps/clear/Makefile +++ b/user/apps/clear/Makefile @@ -1,4 +1,4 @@ -TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" +TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu" # RUSTFLAGS+="-C target-feature=+crt-static -C link-arg=-no-pie" ifdef DADK_CURRENT_BUILD_DIR diff --git a/user/apps/r_unitest/Makefile b/user/apps/r_unitest/Makefile index c40848ded..24f63c4bf 100644 --- a/user/apps/r_unitest/Makefile +++ b/user/apps/r_unitest/Makefile @@ -1,4 +1,4 @@ -TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" +TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu" RUSTFLAGS+="" ifdef DADK_CURRENT_BUILD_DIR diff --git a/user/apps/riscv_init/riscv_rust_init/Makefile b/user/apps/riscv_init/riscv_rust_init/Makefile index 7efb0f910..95908bde6 100644 --- a/user/apps/riscv_init/riscv_rust_init/Makefile +++ b/user/apps/riscv_init/riscv_rust_init/Makefile @@ -1,6 +1,6 @@ # The toolchain we use. # You can get it by running DragonOS' `tools/bootstrap.sh` -TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" +TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu" ifeq ($(ARCH), riscv64) RUSTFLAGS+="-C target-feature=+crt-static" diff --git a/user/apps/syscall_ebpf/Makefile b/user/apps/syscall_ebpf/Makefile index c8dadc36e..e00144106 100644 --- a/user/apps/syscall_ebpf/Makefile +++ b/user/apps/syscall_ebpf/Makefile @@ -1,4 +1,4 @@ -TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" +TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu" RUSTFLAGS+="" ifdef DADK_CURRENT_BUILD_DIR diff --git a/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml b/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml index 5d44daf0c..d08612814 100644 --- a/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml +++ b/user/apps/syscall_ebpf/syscall_ebpf-ebpf/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-11-05" +channel = "nightly-2025-08-10" components = ["rust-src"] diff --git a/user/apps/test_tokio/Makefile b/user/apps/test_tokio/Makefile index c98fd919e..ca67624fd 100644 --- a/user/apps/test_tokio/Makefile +++ b/user/apps/test_tokio/Makefile @@ -1,4 +1,4 @@ -TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" +TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu" RUSTFLAGS+="" ifdef DADK_CURRENT_BUILD_DIR diff --git a/user/apps/test_tracepoint/Makefile b/user/apps/test_tracepoint/Makefile index 27b551411..20e9d5fb8 100644 --- a/user/apps/test_tracepoint/Makefile +++ b/user/apps/test_tracepoint/Makefile @@ -1,4 +1,4 @@ -TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" +TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu" RUSTFLAGS+="" ifdef DADK_CURRENT_BUILD_DIR diff --git a/user/apps/user-manage/Makefile b/user/apps/user-manage/Makefile index b1691ea47..9be165dd2 100644 --- a/user/apps/user-manage/Makefile +++ b/user/apps/user-manage/Makefile @@ -1,6 +1,6 @@ # The toolchain we use. # You can get it by running DragonOS' `tools/bootstrap.sh` -TOOLCHAIN="+nightly-2024-11-05-x86_64-unknown-linux-gnu" +TOOLCHAIN="+nightly-2025-08-10-x86_64-unknown-linux-gnu" RUSTFLAGS+="" ifdef DADK_CURRENT_BUILD_DIR From 9ef8d3ca2f65495a021b7daa6bb85a4173390ae1 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sat, 1 Nov 2025 06:18:05 +0000 Subject: [PATCH 11/39] fmt --- kernel/src/driver/base/block/loop_device.rs | 57 +++++++++++---------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 4a43b5f52..d93bc28f5 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -9,11 +9,11 @@ use crate::{ }, class::Class, device::{ - bus:: Bus, + bus::Bus, device_number::{DeviceNumber, Major}, - device_register,device_unregister, + device_register, device_unregister, driver::{Driver, DriverCommonData}, - DevName, Device, DeviceCommonData,DeviceType, IdTable, + DevName, Device, DeviceCommonData, DeviceType, IdTable, }, kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, kset::KSet, @@ -21,7 +21,7 @@ use crate::{ filesystem::{ devfs::{devfs_register, DevFS, DeviceINode}, kernfs::KernFSInode, - vfs::{IndexNode, InodeId, Metadata,file::FileMode}, + vfs::{file::FileMode, IndexNode, InodeId, Metadata}, }, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, @@ -793,32 +793,35 @@ impl LoopManager { /* 重置状态unbound */ - let mut inner_guard =device.inner(); + let mut inner_guard = device.inner(); inner_guard.set_state(LoopState::Unbound)?; - inner_guard.file_inode=None; - inner_guard.file_size-0; - inner_guard.offset=0; - inner_guard.size_limit = 0; - inner_guard.read_only = false; - inner_guard.user_direct_io = false; - inner_guard.flags = 0; - inner_guard.file_name = 0; - drop(inner_guard); - let minor = device.inner().device_number.minor() as usize; - let mut loop_mgr_inner = self.inner(); // Lock the LoopManager - if minor < LoopManager::MAX_DEVICES { - if let Some(removed_device) = loop_mgr_inner.devices[minor].take() { - log::info!("Deallocated loop device loop{} from manager.", minor); - // Unregister from block device manager - device_unregister(removed_device.clone()); + inner_guard.file_inode = None; + inner_guard.file_size - 0; + inner_guard.offset = 0; + inner_guard.size_limit = 0; + inner_guard.read_only = false; + inner_guard.user_direct_io = false; + inner_guard.flags = 0; + inner_guard.file_name = 0; + drop(inner_guard); + let minor = device.inner().device_number.minor() as usize; + let mut loop_mgr_inner = self.inner(); // Lock the LoopManager + if minor < LoopManager::MAX_DEVICES { + if let Some(removed_device) = loop_mgr_inner.devices[minor].take() { + log::info!("Deallocated loop device loop{} from manager.", minor); + // Unregister from block device manager + device_unregister(removed_device.clone()); + } else { + log::warn!( + "Attempted to deallocate loop device loop{} but it was not found in manager.", + minor + ); + } } else { - log::warn!("Attempted to deallocate loop device loop{} but it was not found in manager.", minor); + return Err(SystemError::EINVAL); // Minor out of bounds } - } else { - return Err(SystemError::EINVAL); // Minor out of bounds - } - Ok(()) // Indicate success + Ok(()) // Indicate success } pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { // 注册 loop 设备 @@ -896,8 +899,6 @@ impl IndexNode for LoopControlDevice { _data: SpinLockGuard, _mode: &FileMode, ) -> Result<(), SystemError> { - - // 若文件系统没有实现此方法,则返回“不支持” return Ok(()); } From 786c435ad9a23318333f2ff6a82fbd43205a9d69 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sun, 2 Nov 2025 14:45:29 +0000 Subject: [PATCH 12/39] fix : function loop_add() --- kernel/src/driver/base/block/loop_device.rs | 126 +++++++++++++++----- user/apps/c_unitest/test_loop.c | 5 +- 2 files changed, 102 insertions(+), 29 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index d93bc28f5..9ddb8ef7d 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -558,18 +558,22 @@ impl LoopDeviceDriver { fn inner(&self) -> SpinLockGuard { self.inner.lock() } - fn new_loop_device(&self, minor: usize) -> Result<(), SystemError> { + fn new_loop_device(&self, minor: usize) -> Result, SystemError> { let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor); - if let Some(loop_dev) = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) { - log::info!( - "Registering loop device: {}", - loop_dev.block_dev_meta.devname - ); - block_dev_manager().register(loop_dev.clone())?; - } else { - error!("Failed to create loop device for minor {}", minor); - } - Ok(()) + let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) + .ok_or_else(|| { + error!("Failed to create loop device for minor {}", minor); + SystemError::ENOMEM // 如果创建失败,返回具体的错误 + })?; + log::info!( + "Registering loop device: {}", + loop_dev.block_dev_meta.devname + ); + // 先注册到块设备管理器,让它可用 + block_dev_manager().register(loop_dev.clone())?; + + // 返回创建的设备,让 LoopManager 能够存储它 + Ok(loop_dev) } } //初始化函数,注册1个loopcontrol设备和8个loop设备备用 @@ -704,51 +708,112 @@ impl LoopManager { /* 请求队列,工作队列未实现 */ - pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { - let mut inner_guard = self.inner(); + + /* + loop_a思路 + 1.检查请求的次设备号是否有效且未被占用-》直接返回当前设备 + 2.如果未指定次设备号,遍历设备数组寻找第一个未被占用的次设备号 + 3.如果都不行,创建LoopDevice实例,注册到块设备管理器 + */ + pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { + // 锁定 LoopManager,获取可变访问权限 + let mut inner_manager_guard = self.inner(); + log::info!("Adding loop device with requested minor: {:?}", requested_minor); let minor_to_use: u32 = match requested_minor { + // ====================================================== + // 1. 指定次设备号 (Some) 逻辑 + // ====================================================== Some(req_minor) => { if req_minor >= Self::MAX_DEVICES as u32 { + // 检查次设备号是否超出最大限制 return Err(SystemError::EINVAL); } - if inner_guard.devices[req_minor as usize].is_some() { - return Err(SystemError::EEXIST); + + // 检查设备数组中该位置是否有设备 (Option>) + if let Some(existing_dev) = &inner_manager_guard.devices[req_minor as usize] { + let inner_dev_guard = existing_dev.inner(); + // 如果设备已存在且处于 Bound 状态,则不能复用,返回 EEXIST。 + if matches!(inner_dev_guard.state, LoopState::Bound) { + return Err(SystemError::EEXIST); // 设备已绑定,不可用 + } + + // 如果设备已存在但处于 Unbound 或 Dead 状态,则复用该次设备号 + req_minor + } else { + // 设备数组中该位置为空 (None),直接使用该次设备号创建新设备 + req_minor } - req_minor } + + // ====================================================== + // 2. 未指定次设备号 (None) 逻辑:查找第一个可用的次设备号 + // ====================================================== None => { - let mut found_minor_candidate = None; - let start_minor = inner_guard.next_free_minor; + let start_minor = inner_manager_guard.next_free_minor; let mut current_search_minor = start_minor; + let mut found_minor_candidate = None; + // 遍历整个设备数组寻找空闲次设备号 for _ in 0..Self::MAX_DEVICES { - if inner_guard.devices[current_search_minor as usize].is_none() { + let index = current_search_minor as usize; + + if let Some(dev) = &inner_manager_guard.devices[index] { + let inner_dev_guard = dev.inner(); + + // 找到一个已存在但处于 Unbound 状态的设备,可以选择复用 + if matches!(inner_dev_guard.state, LoopState::Unbound) { + found_minor_candidate = Some(current_search_minor); + break; + } + // 如果是 Bound 状态,则跳过继续查找下一个 + } else { + // 找到一个数组中为 None 的位置(完全空闲) found_minor_candidate = Some(current_search_minor); - // 更新 next_free_minor 以便下次从这里开始查找 - inner_guard.next_free_minor = - (current_search_minor + 1) % (Self::MAX_DEVICES as u32); break; } + + // 循环到下一个次设备号 current_search_minor = (current_search_minor + 1) % (Self::MAX_DEVICES as u32); + + // 检查是否已经循环回起点 if current_search_minor == start_minor { - // 遍历了一圈,没有找到空闲的 - break; + break; // 遍历了一圈,没有找到空闲的,退出循环 } } + // 更新 next_free_minor,以便下次查找时从找到的次设备号的下一个开始 + if let Some(minor) = found_minor_candidate { + inner_manager_guard.next_free_minor = (minor + 1) % (Self::MAX_DEVICES as u32); + } + + // 如果找到,则使用;否则返回 ENOSPC (没有空间/资源) found_minor_candidate.ok_or(SystemError::ENOSPC)? } }; + + // ====================================================== + // 3. 创建和注册 LoopDevice + // ====================================================== + let devname = DevName::new( format!("{}{}", LOOP_BASENAME, minor_to_use), minor_to_use as usize, ); + + // 创建新的 LoopDevice 实例 let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor_to_use) .ok_or(SystemError::ENOMEM)?; + + // 注册到块设备管理器 log::info!("Registing loop device: {}", loop_dev.block_dev_meta.devname); block_dev_manager().register(loop_dev.clone())?; - inner_guard.devices[minor_to_use as usize] = Some(loop_dev.clone()); + + // 将新设备存入 Manager 的设备数组 + inner_manager_guard.devices[minor_to_use as usize] = Some(loop_dev.clone()); + log::info!("Loop device loop{} added successfully.", minor_to_use); + + // 返回新创建的 LoopDevice Ok(loop_dev) } pub fn find_device_by_minor(&self, minor: u32) -> Option> { @@ -824,9 +889,11 @@ impl LoopManager { Ok(()) // Indicate success } pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { + let mut inner =self.inner(); // 注册 loop 设备 for minor in 0..Self::MAX_INIT_DEVICES { - driver.new_loop_device(minor)?; + let loop_dev =driver.new_loop_device(minor)?; + inner.devices[minor]=Some(loop_dev); } log::info!("Loop devices initialized"); @@ -939,11 +1006,14 @@ impl IndexNode for LoopControlDevice { log::info!("Starting LOOP_CTL_ADD ioctl"); let requested_index = data as u32; match self.loop_mgr.loop_add(Some(requested_index)) { - Ok(loop_dev) => Ok(loop_dev.inner().device_number.minor() as usize), + + Ok(loop_dev) => + { log::info!("LOOP_CTL_ADD ioctl succeeded, allocated loop device loop{}", loop_dev.inner().device_number.minor()); + Ok(loop_dev.inner().device_number.minor() as usize) + } Err(e) => Err(e), } } - LOOP_CTL_REMOVE => { let minor_to_remove = data as u32; // self.loop_mgr.loop_remove(minor_to_remove)?; diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index b6a29ea15..a83e389eb 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -13,7 +13,7 @@ #define LOOP_DEVICE_CONTROL "/dev/loop-control" #define TEST_FILE_NAME "test_image.img" #define TEST_FILE_SIZE (1024 * 1024) // 1MB for the test image - +//创建测试文件 void create_test_file() { printf("Creating test file: %s with size %d bytes\n", TEST_FILE_NAME, TEST_FILE_SIZE); int fd = open(TEST_FILE_NAME, O_CREAT | O_TRUNC | O_RDWR, 0644); @@ -69,10 +69,13 @@ int main() { int returned_minor = ioctl(control_fd, LOOP_CTL_ADD, loop_minor); if (returned_minor < 0) { perror("Failed to add loop device"); + printf("returned_minor: %d\n", returned_minor); close(control_fd); exit(EXIT_FAILURE); } if (returned_minor != loop_minor) { + + fprintf(stderr, "Warning: LOOP_CTL_ADD returned minor %d, expected %d\n", returned_minor, loop_minor); } printf("Loop device loop%d added (kernel returned minor: %d).\n", loop_minor, returned_minor); From 29c767946f9bb3bd3c73ef35ccdda25f349eee07 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sun, 2 Nov 2025 16:12:41 +0000 Subject: [PATCH 13/39] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0read=5Fasync?= =?UTF-8?q?=EF=BC=8Cwrite=5Fasync=20-=20=E4=BF=AE=E6=94=B9gendisk=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E9=BB=98=E8=AE=A4=E8=A1=8C=E4=B8=BA=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E5=BE=97read=E5=92=8Cwrite=E8=83=BD=E4=BC=A0=E9=80=92=E5=88=B0?= =?UTF-8?q?loop=5Fdevice=E4=B8=AD=20-=20=E5=AE=8C=E6=88=90loop=5Fdevice?= =?UTF-8?q?=E7=9A=84=E6=AD=A3=E7=A1=AE=E6=8C=82=E8=BD=BD=E5=92=8C=E5=86=99?= =?UTF-8?q?=E5=85=A5=E6=95=B0=E6=8D=AE=E7=9A=84=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/gendisk/mod.rs | 64 ++- kernel/src/driver/base/block/loop_device.rs | 491 ++++++++++++-------- user/apps/c_unitest/test_loop.c | 51 +- 3 files changed, 396 insertions(+), 210 deletions(-) diff --git a/kernel/src/driver/base/block/gendisk/mod.rs b/kernel/src/driver/base/block/gendisk/mod.rs index e96f2cb4c..a9e969579 100644 --- a/kernel/src/driver/base/block/gendisk/mod.rs +++ b/kernel/src/driver/base/block/gendisk/mod.rs @@ -1,4 +1,5 @@ use core::{ + convert::TryFrom, ops::{Deref, DerefMut}, sync::atomic::{AtomicU32, Ordering}, }; @@ -19,7 +20,10 @@ use crate::{ libs::{rwlock::RwLock, spinlock::SpinLockGuard}, }; -use super::block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}; +use super::{ + block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, + loop_device::LoopDevice, +}; const MINORS_PER_DISK: u32 = 256; @@ -221,22 +225,34 @@ impl IndexNode for GenDisk { fn read_at( &self, - _offset: usize, - _len: usize, - _buf: &mut [u8], + offset: usize, + len: usize, + buf: &mut [u8], _data: SpinLockGuard, ) -> Result { - Err(SystemError::EPERM) + if len == 0 { + return Ok(0); + } + if len > buf.len() { + return Err(SystemError::ENOBUFS); + } + self.read_at_bytes(&mut buf[..len], offset) } fn write_at( &self, - _offset: usize, - _len: usize, - _buf: &[u8], + offset: usize, + len: usize, + buf: &[u8], _data: SpinLockGuard, ) -> Result { - Err(SystemError::EPERM) + if len == 0 { + return Ok(0); + } + if len > buf.len() { + return Err(SystemError::E2BIG); + } + self.write_at_bytes(&buf[..len], offset) } fn list(&self) -> Result, system_error::SystemError> { @@ -244,7 +260,19 @@ impl IndexNode for GenDisk { } fn metadata(&self) -> Result { - Ok(self.metadata.clone()) + let mut meta = self.metadata.clone(); + let bdev = self.block_device(); + let range = bdev.disk_range(); + let blocks = range.lba_end.saturating_sub(range.lba_start); + let size_in_bytes = blocks.saturating_mul(LBA_SIZE); + + meta.size = match i64::try_from(size_in_bytes) { + Ok(val) => val, + Err(_) => i64::MAX, + }; + meta.blocks = blocks; + meta.blk_size = LBA_SIZE; + Ok(meta) } fn dname(&self) -> Result { @@ -273,6 +301,22 @@ impl IndexNode for GenDisk { ) -> Result<(), SystemError> { Ok(()) } + + fn ioctl( + &self, + cmd: u32, + data: usize, + private_data: &crate::filesystem::vfs::FilePrivateData, + ) -> Result { + let bdev = self.block_device(); + if let Some(loop_dev) = + BlockDevice::as_any_ref(&*bdev).downcast_ref::() + { + loop_dev.ioctl(cmd, data, private_data) + } else { + Err(SystemError::ENOSYS) + } + } } impl DeviceINode for GenDisk { diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 9ddb8ef7d..dc114f481 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -1,5 +1,3 @@ -use crate::filesystem::devfs::LockedDevFSInode; -use crate::filesystem::vfs::FilePrivateData; use crate::{ driver::base::{ block::{ @@ -19,14 +17,17 @@ use crate::{ kset::KSet, }, filesystem::{ - devfs::{devfs_register, DevFS, DeviceINode}, + devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, kernfs::KernFSInode, - vfs::{file::FileMode, IndexNode, InodeId, Metadata}, + vfs::{ + file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata, + }, }, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, spinlock::{SpinLock, SpinLockGuard}, }, + process::ProcessManager, }; use alloc::{ string::{String, ToString}, @@ -55,8 +56,8 @@ const LOOP_BASENAME: &str = "loop"; // pub const MAX_LO_CRYPT: u32 = 20; // // IOCTL 命令 - 使用 0x4C ('L') -// pub const LOOP_SET_FD: u32 = 0x4C00; -// pub const LOOP_CLR_FD: u32 = 0x4C01; +pub const LOOP_SET_FD: u32 = 0x4C00; +pub const LOOP_CLR_FD: u32 = 0x4C01; // pub const LOOP_SET_STATUS: u32 = 0x4C02; // pub const LOOP_GET_STATUS: u32 = 0x4C03; // pub const LOOP_SET_STATUS64: u32 = 0x4C04; @@ -140,6 +141,7 @@ impl LoopDeviceInner { Ok(()) } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum LoopState { Unbound, Bound, @@ -192,12 +194,17 @@ impl LoopDevice { /// 设置 loop 设备关联的文件 pub fn set_file(&self, file_inode: Arc) -> Result<(), SystemError> { - let mut inner = self.inner(); - // 获取文件大小 - let file_size = file_inode.metadata()?.size; + let metadata = file_inode.metadata()?; + if metadata.size < 0 { + return Err(SystemError::EINVAL); + } + let file_size = metadata.size as usize; + let mut inner = self.inner(); inner.file_inode = Some(file_inode); - inner.file_size = file_size as usize; + inner.file_size = file_size; + inner.size_limit = file_size; + inner.offset = 0; Ok(()) } @@ -216,6 +223,61 @@ impl LoopDevice { pub fn is_read_only(&self) -> bool { self.inner().read_only } + + pub fn is_bound(&self) -> bool { + matches!(self.inner().state, LoopState::Bound) + } + + pub fn bind_file( + &self, + file_inode: Arc, + read_only: bool, + ) -> Result<(), SystemError> { + { + let inner = self.inner(); + if matches!(inner.state, LoopState::Bound) { + return Err(SystemError::EBUSY); + } + } + + self.set_file(file_inode.clone())?; + + let metadata = file_inode.metadata()?; + if metadata.size < 0 { + return Err(SystemError::EINVAL); + } + let file_size = metadata.size as usize; + + let mut inner = self.inner(); + inner.set_state(LoopState::Bound)?; + inner.read_only = read_only; + inner.size_limit = file_size; + inner.flags = 0; + inner.user_direct_io = false; + inner.visible = true; + // file_name目前仅作为占位字段 + inner.file_name = 0; + Ok(()) + } + + pub fn clear_file(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + match inner.state { + LoopState::Bound | LoopState::Rundown => inner.set_state(LoopState::Unbound)?, + LoopState::Unbound => {} + LoopState::Deleting => return Err(SystemError::EBUSY), + } + + inner.file_inode = None; + inner.file_size = 0; + inner.size_limit = 0; + inner.offset = 0; + inner.read_only = false; + inner.user_direct_io = false; + inner.flags = 0; + inner.file_name = 0; + Ok(()) + } } impl KObject for LoopDevice { @@ -286,22 +348,28 @@ impl IndexNode for LoopDevice { fn read_at( &self, - _offset: usize, - _len: usize, - _buf: &mut [u8], + offset: usize, + len: usize, + buf: &mut [u8], _data: SpinLockGuard, ) -> Result { - Err(SystemError::ENOSYS) + if len > buf.len() { + return Err(SystemError::ENOBUFS); + } + BlockDevice::read_at_bytes(self, offset, len, buf) } fn write_at( &self, - _offset: usize, - _len: usize, - _buf: &[u8], + offset: usize, + len: usize, + buf: &[u8], _data: SpinLockGuard, ) -> Result { - Err(SystemError::ENOSYS) + if len > buf.len() { + return Err(SystemError::E2BIG); + } + BlockDevice::write_at_bytes(self, offset, len, &buf[..len]) } fn list(&self) -> Result, system_error::SystemError> { @@ -333,6 +401,42 @@ impl IndexNode for LoopDevice { }; Ok(metadata.clone()) } + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { + match cmd { + LOOP_SET_FD => { + let file_fd = data as i32; + let fd_table = ProcessManager::current_pcb().fd_table(); + let file = { + let guard = fd_table.read(); + guard.get_file_by_fd(file_fd) + } + .ok_or(SystemError::EBADF)?; + + let mode = file.mode(); + let read_only = !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); + + let inode = file.inode(); + let metadata = inode.metadata()?; + match metadata.file_type { + FileType::File | FileType::BlockDevice => {} + _ => return Err(SystemError::EINVAL), + } + + self.bind_file(inode, read_only)?; + Ok(0) + } + LOOP_CLR_FD => { + self.clear_file()?; + Ok(0) + } + _ => Err(SystemError::ENOSYS), + } + } } impl DeviceINode for LoopDevice { @@ -422,7 +526,12 @@ impl BlockDevice for LoopDevice { fn disk_range(&self) -> GeneralBlockRange { let inner = self.inner(); - let blocks = inner.file_size / LBA_SIZE; + let blocks = if inner.file_size == 0 { + 0 + } else { + //饱和式加法,溢出返回类型最大值 + inner.file_size.saturating_add(LBA_SIZE - 1) / LBA_SIZE + }; drop(inner); GeneralBlockRange::new(0, blocks).unwrap_or(GeneralBlockRange { lba_start: 0, @@ -435,29 +544,33 @@ impl BlockDevice for LoopDevice { count: usize, buf: &mut [u8], ) -> Result { - let inner = self.inner(); - let offset = inner.offset + lba_id_start * LBA_SIZE; - let len = count * LBA_SIZE; + if count == 0 { + return Ok(0); + } + let len = count + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + if len > buf.len() { + return Err(SystemError::EINVAL); + } + + let (file_inode, base_offset) = { + let inner = self.inner(); + let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; + (inode, inner.offset) + }; + + let block_offset = lba_id_start + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + let file_offset = base_offset + .checked_add(block_offset) + .ok_or(SystemError::EOVERFLOW)?; - // 通过文件 inode 读取数据 - // 使用一个空的 FilePrivateData 作为占位符 - use crate::filesystem::vfs::FilePrivateData; - use crate::libs::spinlock::SpinLock; let data = SpinLock::new(FilePrivateData::Unused); let data_guard = data.lock(); - // 处理 Option 类型的 file_inode - match &inner.file_inode { - Some(inode) => { - // 计算实际的文件偏移量 - let file_offset = inner.offset + offset; - inode.read_at(file_offset, len, buf, data_guard) - } - None => { - // 如果没有关联的文件,返回错误 - Err(SystemError::ENODEV) - } - } + file_inode.read_at(file_offset, len, &mut buf[..len], data_guard) } fn write_at_sync( @@ -466,35 +579,48 @@ impl BlockDevice for LoopDevice { count: usize, buf: &[u8], ) -> Result { - let inner = self.inner(); + if count == 0 { + return Ok(0); + } + let len = count + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + if len > buf.len() { + return Err(SystemError::EINVAL); + } - // 检查是否只读 - if inner.read_only { + let (file_inode, base_offset, read_only) = { + let inner = self.inner(); + let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; + (inode, inner.offset, inner.read_only) + }; + + if read_only { return Err(SystemError::EROFS); } - let offset = inner.offset + lba_id_start * LBA_SIZE; - let len = count * LBA_SIZE; + let block_offset = lba_id_start + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + let file_offset = base_offset + .checked_add(block_offset) + .ok_or(SystemError::EOVERFLOW)?; - // 通过文件 inode 写入数据 - // 使用一个空的 FilePrivateData 作为占位符 - use crate::filesystem::vfs::FilePrivateData; - use crate::libs::spinlock::SpinLock; let data = SpinLock::new(FilePrivateData::Unused); let data_guard = data.lock(); - // 处理 Option 类型的 file_inode - match &inner.file_inode { - Some(inode) => { - // 计算实际的文件偏移量 - let file_offset = inner.offset + offset; - inode.write_at(file_offset, len, buf, data_guard) - } - None => { - // 如果没有关联的文件,返回错误 - Err(SystemError::ENODEV) + let written = file_inode.write_at(file_offset, len, &buf[..len], data_guard)?; + + if written > 0 { + if let Ok(metadata) = file_inode.metadata() { + if metadata.size >= 0 { + let mut inner = self.inner(); + inner.file_size = metadata.size as usize; + } } } + + Ok(written) } fn sync(&self) -> Result<(), SystemError> { @@ -709,113 +835,113 @@ impl LoopManager { 请求队列,工作队列未实现 */ - /* - loop_a思路 - 1.检查请求的次设备号是否有效且未被占用-》直接返回当前设备 - 2.如果未指定次设备号,遍历设备数组寻找第一个未被占用的次设备号 - 3.如果都不行,创建LoopDevice实例,注册到块设备管理器 - */ - pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { - // 锁定 LoopManager,获取可变访问权限 - let mut inner_manager_guard = self.inner(); - log::info!("Adding loop device with requested minor: {:?}", requested_minor); - let minor_to_use: u32 = match requested_minor { - // ====================================================== - // 1. 指定次设备号 (Some) 逻辑 - // ====================================================== - Some(req_minor) => { - if req_minor >= Self::MAX_DEVICES as u32 { - // 检查次设备号是否超出最大限制 - return Err(SystemError::EINVAL); - } + pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { + let mut inner = self.inner(); + match requested_minor { + Some(req_minor) => self.loop_add_specific_locked(&mut inner, req_minor), + None => self.loop_add_first_available_locked(&mut inner), + } + } - // 检查设备数组中该位置是否有设备 (Option>) - if let Some(existing_dev) = &inner_manager_guard.devices[req_minor as usize] { - let inner_dev_guard = existing_dev.inner(); - // 如果设备已存在且处于 Bound 状态,则不能复用,返回 EEXIST。 - if matches!(inner_dev_guard.state, LoopState::Bound) { - return Err(SystemError::EEXIST); // 设备已绑定,不可用 - } - - // 如果设备已存在但处于 Unbound 或 Dead 状态,则复用该次设备号 - req_minor - } else { - // 设备数组中该位置为空 (None),直接使用该次设备号创建新设备 - req_minor - } + fn loop_add_specific_locked( + &self, + inner: &mut LoopManagerInner, + minor: u32, + ) -> Result, SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + + if let Some(device) = inner.devices[minor as usize].as_ref() { + if device.is_bound() { + return Err(SystemError::EEXIST); } - - // ====================================================== - // 2. 未指定次设备号 (None) 逻辑:查找第一个可用的次设备号 - // ====================================================== - None => { - let start_minor = inner_manager_guard.next_free_minor; - let mut current_search_minor = start_minor; - let mut found_minor_candidate = None; - - // 遍历整个设备数组寻找空闲次设备号 - for _ in 0..Self::MAX_DEVICES { - let index = current_search_minor as usize; - - if let Some(dev) = &inner_manager_guard.devices[index] { - let inner_dev_guard = dev.inner(); - - // 找到一个已存在但处于 Unbound 状态的设备,可以选择复用 - if matches!(inner_dev_guard.state, LoopState::Unbound) { - found_minor_candidate = Some(current_search_minor); - break; - } - // 如果是 Bound 状态,则跳过继续查找下一个 - } else { - // 找到一个数组中为 None 的位置(完全空闲) - found_minor_candidate = Some(current_search_minor); - break; - } - - // 循环到下一个次设备号 - current_search_minor = (current_search_minor + 1) % (Self::MAX_DEVICES as u32); - - // 检查是否已经循环回起点 - if current_search_minor == start_minor { - break; // 遍历了一圈,没有找到空闲的,退出循环 - } - } + inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; + return Ok(device.clone()); + } - // 更新 next_free_minor,以便下次查找时从找到的次设备号的下一个开始 - if let Some(minor) = found_minor_candidate { - inner_manager_guard.next_free_minor = (minor + 1) % (Self::MAX_DEVICES as u32); + self.create_and_register_device_locked(inner, minor) + } + + fn loop_add_first_available_locked( + &self, + inner: &mut LoopManagerInner, + ) -> Result, SystemError> { + for _ in 0..Self::MAX_DEVICES { + let idx = inner.next_free_minor; + inner.next_free_minor = (inner.next_free_minor + 1) % Self::MAX_DEVICES as u32; + + match &inner.devices[idx as usize] { + Some(device) if !device.is_bound() => return Ok(device.clone()), + Some(_) => continue, + None => { + return self.create_and_register_device_locked(inner, idx); } + } + } + + Err(SystemError::ENOSPC) + } + + fn create_and_register_device_locked( + &self, + inner: &mut LoopManagerInner, + minor: u32, + ) -> Result, SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } - // 如果找到,则使用;否则返回 ENOSPC (没有空间/资源) - found_minor_candidate.ok_or(SystemError::ENOSPC)? + let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor as usize); + let loop_dev = + LoopDevice::new_empty_loop_device(devname, minor).ok_or(SystemError::ENOMEM)?; + + if let Err(e) = block_dev_manager().register(loop_dev.clone()) { + if e == SystemError::EEXIST { + if let Some(existing) = inner.devices[minor as usize].clone() { + return Ok(existing); + } } - }; + return Err(e); + } - // ====================================================== - // 3. 创建和注册 LoopDevice - // ====================================================== - - let devname = DevName::new( - format!("{}{}", LOOP_BASENAME, minor_to_use), - minor_to_use as usize, - ); - - // 创建新的 LoopDevice 实例 - let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor_to_use) - .ok_or(SystemError::ENOMEM)?; - - // 注册到块设备管理器 - log::info!("Registing loop device: {}", loop_dev.block_dev_meta.devname); - block_dev_manager().register(loop_dev.clone())?; - - // 将新设备存入 Manager 的设备数组 - inner_manager_guard.devices[minor_to_use as usize] = Some(loop_dev.clone()); - - log::info!("Loop device loop{} added successfully.", minor_to_use); - - // 返回新创建的 LoopDevice + inner.devices[minor as usize] = Some(loop_dev.clone()); + inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; + log::info!("Loop device loop{} added successfully.", minor); Ok(loop_dev) } + + pub fn loop_clear(&self, minor: u32) -> Result<(), SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + + let device = { + let inner = self.inner(); + inner.devices[minor as usize].clone() + } + .ok_or(SystemError::ENODEV)?; + + device.clear_file()?; + + let mut inner = self.inner(); + inner.next_free_minor = minor; + log::info!("Loop device loop{} cleared.", minor); + Ok(()) + } + + pub fn find_free_minor(&self) -> Option { + let mut inner = self.inner(); + for _ in 0..Self::MAX_DEVICES { + let idx = inner.next_free_minor; + inner.next_free_minor = (inner.next_free_minor + 1) % Self::MAX_DEVICES as u32; + match &inner.devices[idx as usize] { + Some(device) if device.is_bound() => continue, + _ => return Some(idx), + } + } + None + } pub fn find_device_by_minor(&self, minor: u32) -> Option> { let inner = self.inner(); if minor < Self::MAX_DEVICES as u32 { @@ -861,7 +987,7 @@ impl LoopManager { let mut inner_guard = device.inner(); inner_guard.set_state(LoopState::Unbound)?; inner_guard.file_inode = None; - inner_guard.file_size - 0; + inner_guard.file_size = 0; inner_guard.offset = 0; inner_guard.size_limit = 0; inner_guard.read_only = false; @@ -969,6 +1095,12 @@ impl IndexNode for LoopControlDevice { // 若文件系统没有实现此方法,则返回“不支持” return Ok(()); } + fn close( + &self, + _data: SpinLockGuard, + ) -> Result<(), SystemError> { + Ok(()) + } fn metadata(&self) -> Result { use crate::filesystem::vfs::{syscall::ModeType, FileType, InodeId}; use crate::time::PosixTimeSpec; @@ -999,46 +1131,35 @@ impl IndexNode for LoopControlDevice { &self, cmd: u32, data: usize, - private_data: &FilePrivateData, + _private_data: &FilePrivateData, ) -> Result { match cmd { LOOP_CTL_ADD => { log::info!("Starting LOOP_CTL_ADD ioctl"); let requested_index = data as u32; - match self.loop_mgr.loop_add(Some(requested_index)) { - - Ok(loop_dev) => - { log::info!("LOOP_CTL_ADD ioctl succeeded, allocated loop device loop{}", loop_dev.inner().device_number.minor()); - Ok(loop_dev.inner().device_number.minor() as usize) - } - Err(e) => Err(e), - } + let loop_dev = if requested_index == u32::MAX { + self.loop_mgr.loop_add(None)? + } else { + self.loop_mgr.loop_add(Some(requested_index))? + }; + let minor = { + let inner = loop_dev.inner(); + let minor = inner.device_number.minor(); + log::info!( + "LOOP_CTL_ADD ioctl succeeded, allocated loop device loop{}", + minor + ); + minor + }; + Ok(minor as usize) } LOOP_CTL_REMOVE => { let minor_to_remove = data as u32; - // self.loop_mgr.loop_remove(minor_to_remove)?; + self.loop_mgr.loop_clear(minor_to_remove)?; Ok(0) } LOOP_CTL_GET_FREE => { - let mut inner_guard = self.loop_mgr.inner(); - let start_minor = inner_guard.next_free_minor; - let mut found_minor = None; - for _ in 0..LoopManager::MAX_DEVICES { - let current_minor = inner_guard.next_free_minor; - //轮询找到一个空闲的loop设备好 - inner_guard.next_free_minor = - (inner_guard.next_free_minor + 1) % LoopManager::MAX_DEVICES as u32; - if inner_guard.devices[current_minor as usize].is_none() { - found_minor = Some(current_minor); - break; - } - if inner_guard.next_free_minor == start_minor { - //没找到 - break; - } - } - drop(inner_guard); - match found_minor { + match self.loop_mgr.find_free_minor() { Some(minor) => Ok(minor as usize), None => Err(SystemError::ENOSPC), } diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index a83e389eb..fa71a864e 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -9,6 +9,8 @@ #define LOOP_CTL_ADD 0x4C80 #define LOOP_CTL_REMOVE 0x4C81 #define LOOP_CTL_GET_FREE 0x4C82 +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 //调用open和ioctl()接口实现通信 #define LOOP_DEVICE_CONTROL "/dev/loop-control" #define TEST_FILE_NAME "test_image.img" @@ -39,16 +41,24 @@ int main() { int loop_minor; char loop_dev_path[64]; int loop_fd; + int backing_fd = -1; char write_buf[512] = "Hello Loop Device!"; char read_buf[512]; create_test_file(); // Create a file to back a loop device + backing_fd = open(TEST_FILE_NAME, O_RDWR); + if (backing_fd < 0) { + perror("Failed to open backing file"); + exit(EXIT_FAILURE); + } + // 1. Open the loop-control device printf("Opening loop control device: %s\n", LOOP_DEVICE_CONTROL); control_fd = open(LOOP_DEVICE_CONTROL, O_RDWR); if (control_fd < 0) { perror("Failed to open loop control device. Make sure your kernel module is loaded and /dev/loop-control exists."); + close(backing_fd); exit(EXIT_FAILURE); } printf("Loop control device opened successfully (fd=%d).\n", control_fd); @@ -57,6 +67,7 @@ int main() { printf("Requesting a free loop device minor...\n"); if (ioctl(control_fd, LOOP_CTL_GET_FREE, &loop_minor) < 0) { perror("Failed to get free loop device minor"); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } @@ -70,20 +81,15 @@ int main() { if (returned_minor < 0) { perror("Failed to add loop device"); printf("returned_minor: %d\n", returned_minor); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } - if (returned_minor != loop_minor) { - - + if (returned_minor != loop_minor) { fprintf(stderr, "Warning: LOOP_CTL_ADD returned minor %d, expected %d\n", returned_minor, loop_minor); } printf("Loop device loop%d added (kernel returned minor: %d).\n", loop_minor, returned_minor); - // In a real system, you would now open the test_image.img and associate it with the loop device. - // Your Rust code `set_file` is internal. For user-space, you'd typically use another ioctl on /dev/loopX - // to bind a file descriptor to it. Let's simulate opening the block device. - // 4. Try to open the newly created loop block device sprintf(loop_dev_path, "/dev/loop%d", loop_minor); printf("Attempting to open block device: %s\n", loop_dev_path); @@ -91,30 +97,36 @@ int main() { if (loop_fd < 0) { perror("Failed to open loop block device. This might mean the block device node wasn't created/registered correctly, or permissions."); fprintf(stderr, "Make sure /dev/loop%d exists as a block device.\n", loop_minor); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } printf("Loop block device %s opened successfully (fd=%d).\n", loop_dev_path, loop_fd); + printf("Associating backing file %s with loop device using LOOP_SET_FD...\n", TEST_FILE_NAME); + if (ioctl(loop_fd, LOOP_SET_FD, backing_fd) < 0) { + perror("Failed to associate backing file with loop device"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("Backing file associated successfully.\n"); + // 5. Test read/write operations on the loop block device - // NOTE: For these to work, your Rust LoopDevice needs to be bound to `TEST_FILE_NAME` - // This binding mechanism is not exposed via an IOCTL in your current Rust code. - // In a full implementation, you would have an IOCTL like LOOP_SET_FD to pass the file descriptor of `TEST_FILE_NAME` - // to the kernel loop device. For this test, we'll assume the kernel somehow handles this or mock it. - - // For now, let's assume the kernel has a way to bind a file to the loop device, - // and we are simply interacting with the block device /dev/loopX. printf("Writing to loop device %s...\n", loop_dev_path); if (lseek(loop_fd, 0, SEEK_SET) < 0) { perror("lseek failed before write"); close(loop_fd); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } if (write(loop_fd, write_buf, sizeof(write_buf)) != sizeof(write_buf)) { perror("Failed to write to loop device"); close(loop_fd); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } @@ -125,12 +137,14 @@ int main() { if (lseek(loop_fd, 0, SEEK_SET) < 0) { perror("lseek failed before read"); close(loop_fd); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } if (read(loop_fd, read_buf, sizeof(read_buf)) != sizeof(read_buf)) { perror("Failed to read from loop device"); close(loop_fd); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } @@ -143,10 +157,16 @@ int main() { } // 6. Remove the loop device + printf("Clearing loop device loop%d backing file...\n", loop_minor); + if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { + perror("Failed to clear loop device backing file"); + } + printf("Removing loop device loop%d...\n", loop_minor); if (ioctl(control_fd, LOOP_CTL_REMOVE, loop_minor) < 0) { perror("Failed to remove loop device"); close(loop_fd); + close(backing_fd); close(control_fd); exit(EXIT_FAILURE); } @@ -154,9 +174,10 @@ int main() { // Clean up close(loop_fd); + close(backing_fd); close(control_fd); unlink(TEST_FILE_NAME); printf("All tests completed. Cleaned up.\n"); return 0; -} \ No newline at end of file +} From e87dcd87b9516b05fb5650aadb137942d0fa8cea Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sun, 2 Nov 2025 16:35:21 +0000 Subject: [PATCH 14/39] =?UTF-8?q?feat:=E5=A2=9E=E6=B7=BB=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E9=80=BB=E8=BE=91=E5=92=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 90 +++++++++++---------- kernel/src/driver/base/block/manager.rs | 31 +++++-- kernel/src/filesystem/devfs/mod.rs | 22 ++--- user/apps/c_unitest/test_loop.c | 43 ++++++---- 4 files changed, 112 insertions(+), 74 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index dc114f481..deec3e7d9 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -102,21 +102,8 @@ pub struct LoopDeviceInner { pub file_size: usize, // 数据偏移量 pub offset: usize, - // 数据大小限制 - pub size_limit: usize, - //文件名缓存 - pub file_name: u8, - - // 是否允许用户直接 I/O 操作 - pub user_direct_io: bool, - //标志位 - pub flags: u32, // 是否只读 pub read_only: bool, - // 是否可见 - pub visible: bool, - // 使用弱引用避免循环引用 - pub self_ref: Weak, // KObject的公共数据 pub kobject_common: KObjectCommonData, // 设备的公共数据 @@ -134,6 +121,8 @@ impl LoopDeviceInner { (LoopState::Bound, LoopState::Unbound) => {} (LoopState::Bound, LoopState::Rundown) => {} (LoopState::Rundown, LoopState::Deleting) => {} + (LoopState::Rundown, LoopState::Unbound) => {} + (LoopState::Unbound, LoopState::Deleting) => {} _ => return Err(SystemError::EINVAL), } @@ -169,15 +158,9 @@ impl LoopDevice { file_size: 0, device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), // Loop 设备主设备号为 7 offset: 0, - size_limit: 0, - user_direct_io: false, read_only: false, - visible: true, - self_ref: self_ref.clone(), kobject_common: KObjectCommonData::default(), device_common: DeviceCommonData::default(), - file_name: 0, - flags: 0, state: LoopState::Unbound, state_lock: SpinLock::new(()), //work_queue: None, @@ -203,7 +186,6 @@ impl LoopDevice { let mut inner = self.inner(); inner.file_inode = Some(file_inode); inner.file_size = file_size; - inner.size_limit = file_size; inner.offset = 0; Ok(()) @@ -242,21 +224,9 @@ impl LoopDevice { self.set_file(file_inode.clone())?; - let metadata = file_inode.metadata()?; - if metadata.size < 0 { - return Err(SystemError::EINVAL); - } - let file_size = metadata.size as usize; - let mut inner = self.inner(); inner.set_state(LoopState::Bound)?; inner.read_only = read_only; - inner.size_limit = file_size; - inner.flags = 0; - inner.user_direct_io = false; - inner.visible = true; - // file_name目前仅作为占位字段 - inner.file_name = 0; Ok(()) } @@ -270,12 +240,8 @@ impl LoopDevice { inner.file_inode = None; inner.file_size = 0; - inner.size_limit = 0; inner.offset = 0; inner.read_only = false; - inner.user_direct_io = false; - inner.flags = 0; - inner.file_name = 0; Ok(()) } } @@ -930,6 +896,52 @@ impl LoopManager { Ok(()) } + pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + + let device = { + let inner = self.inner(); + inner.devices[minor as usize].clone() + }; + + let device = match device { + Some(dev) => dev, + None => return Err(SystemError::ENODEV), + }; + + { + let mut guard = device.inner(); + match guard.state { + LoopState::Bound => { + guard.set_state(LoopState::Rundown)?; + } + LoopState::Rundown | LoopState::Unbound => {} + LoopState::Deleting => return Ok(()), + } + } + + device.clear_file()?; + + { + let mut guard = device.inner(); + guard.set_state(LoopState::Deleting)?; + } + + let block_dev: Arc = device.clone(); + block_dev_manager().unregister(&block_dev)?; + + { + let mut inner = self.inner(); + inner.devices[minor as usize] = None; + inner.next_free_minor = minor; + } + + log::info!("Loop device loop{} removed.", minor); + Ok(()) + } + pub fn find_free_minor(&self) -> Option { let mut inner = self.inner(); for _ in 0..Self::MAX_DEVICES { @@ -989,11 +1001,7 @@ impl LoopManager { inner_guard.file_inode = None; inner_guard.file_size = 0; inner_guard.offset = 0; - inner_guard.size_limit = 0; inner_guard.read_only = false; - inner_guard.user_direct_io = false; - inner_guard.flags = 0; - inner_guard.file_name = 0; drop(inner_guard); let minor = device.inner().device_number.minor() as usize; let mut loop_mgr_inner = self.inner(); // Lock the LoopManager @@ -1155,7 +1163,7 @@ impl IndexNode for LoopControlDevice { } LOOP_CTL_REMOVE => { let minor_to_remove = data as u32; - self.loop_mgr.loop_clear(minor_to_remove)?; + self.loop_mgr.loop_remove(minor_to_remove)?; Ok(0) } LOOP_CTL_GET_FREE => { diff --git a/kernel/src/driver/base/block/manager.rs b/kernel/src/driver/base/block/manager.rs index 3eb735ce8..7e7539392 100644 --- a/kernel/src/driver/base/block/manager.rs +++ b/kernel/src/driver/base/block/manager.rs @@ -1,6 +1,6 @@ use core::{fmt::Formatter, sync::atomic::AtomicU32}; -use alloc::sync::Arc; +use alloc::{sync::Arc, vec::Vec}; use hashbrown::HashMap; use system_error::SystemError; use unified_init::macros::unified_init; @@ -11,7 +11,7 @@ use crate::{ device::{device_number::Major, DevName}, }, filesystem::{ - devfs::devfs_register, + devfs::{devfs_register, devfs_unregister}, mbr::MbrDiskPartionTable, vfs::{utils::DName, IndexNode}, }, @@ -167,11 +167,28 @@ impl BlockDevManager { /// 卸载磁盘设备 #[allow(dead_code)] - pub fn unregister(&self, dev: &Arc) { - let mut inner = self.inner(); - inner.disks.remove(dev.dev_name()); - // todo: 这里应该callback一下磁盘设备,但是现在还没实现热插拔,所以暂时没做这里 - todo!("BlockDevManager: unregister disk") + pub fn unregister(&self, dev: &Arc) -> Result<(), SystemError> { + { + let mut inner = self.inner(); + if inner.disks.remove(dev.dev_name()).is_none() { + return Err(SystemError::ENOENT); + } + } + + let blk_meta = dev.blkdev_meta(); + let gendisks = { + let mut meta_inner = blk_meta.inner(); + let disks: Vec> = meta_inner.gendisks.values().cloned().collect(); + meta_inner.gendisks.clear(); + disks + }; + + for gendisk in gendisks { + let dname = gendisk.dname()?; + devfs_unregister(dname.as_ref(), gendisk)?; + } + + Ok(()) } /// 通过路径查找gendisk diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index 7c6394c1f..9336120fa 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -242,17 +242,21 @@ impl DevFS { dev_char_inode.remove(name)?; } FileType::BlockDevice => { - if dev_root_inode.find("block").is_err() { - return Err(SystemError::ENOENT); - } + if name.starts_with("loop") { + dev_root_inode.remove(name)?; + } else { + if dev_root_inode.find("block").is_err() { + return Err(SystemError::ENOENT); + } - let any_block_inode = dev_root_inode.find("block")?; - let dev_block_inode = any_block_inode - .as_any_ref() - .downcast_ref::() - .unwrap(); + let any_block_inode = dev_root_inode.find("block")?; + let dev_block_inode = any_block_inode + .as_any_ref() + .downcast_ref::() + .unwrap(); - dev_block_inode.remove(name)?; + dev_block_inode.remove(name)?; + } } _ => { return Err(SystemError::ENOSYS); diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index fa71a864e..ac8000c17 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -4,18 +4,19 @@ #include #include #include -#include // For fstat -// magic +#include // 用于 fstat +#include +// 控制命令常量 #define LOOP_CTL_ADD 0x4C80 #define LOOP_CTL_REMOVE 0x4C81 #define LOOP_CTL_GET_FREE 0x4C82 #define LOOP_SET_FD 0x4C00 #define LOOP_CLR_FD 0x4C01 -//调用open和ioctl()接口实现通信 +// 与内核通信的设备路径 #define LOOP_DEVICE_CONTROL "/dev/loop-control" #define TEST_FILE_NAME "test_image.img" -#define TEST_FILE_SIZE (1024 * 1024) // 1MB for the test image -//创建测试文件 +#define TEST_FILE_SIZE (1024 * 1024) // 测试镜像大小 1MB +// 创建测试镜像文件 void create_test_file() { printf("Creating test file: %s with size %d bytes\n", TEST_FILE_NAME, TEST_FILE_SIZE); int fd = open(TEST_FILE_NAME, O_CREAT | O_TRUNC | O_RDWR, 0644); @@ -23,7 +24,7 @@ void create_test_file() { perror("Failed to create test file"); exit(EXIT_FAILURE); } - // Write some data to make it a non-empty file + // 写入零填充数据以确保文件占满容量 char zero_block[512] = {0}; for (int i = 0; i < TEST_FILE_SIZE / 512; ++i) { if (write(fd, zero_block, 512) != 512) { @@ -43,9 +44,9 @@ int main() { int loop_fd; int backing_fd = -1; char write_buf[512] = "Hello Loop Device!"; - char read_buf[512]; + char read_buf[512]; - create_test_file(); // Create a file to back a loop device + create_test_file(); // 创建作为 loop 设备后端的文件 backing_fd = open(TEST_FILE_NAME, O_RDWR); if (backing_fd < 0) { @@ -53,7 +54,7 @@ int main() { exit(EXIT_FAILURE); } - // 1. Open the loop-control device + // 1. 打开 loop-control 字符设备 printf("Opening loop control device: %s\n", LOOP_DEVICE_CONTROL); control_fd = open(LOOP_DEVICE_CONTROL, O_RDWR); if (control_fd < 0) { @@ -63,7 +64,7 @@ int main() { } printf("Loop control device opened successfully (fd=%d).\n", control_fd); - // 2. Get a free loop device minor number + // 2. 获取一个空闲的 loop 次设备号 printf("Requesting a free loop device minor...\n"); if (ioctl(control_fd, LOOP_CTL_GET_FREE, &loop_minor) < 0) { perror("Failed to get free loop device minor"); @@ -73,9 +74,7 @@ int main() { } printf("Got free loop minor: %d\n", loop_minor); - // 3. Add a new loop device using the minor number - // Note: The `LOOP_CTL_ADD` in your Rust code takes the minor as `data: usize`. - // We'll pass `loop_minor` directly. Your Rust code then creates an empty device. + // 3. 请求内核以该次设备号创建新的 loop 设备 printf("Adding loop device loop%d...\n", loop_minor); int returned_minor = ioctl(control_fd, LOOP_CTL_ADD, loop_minor); if (returned_minor < 0) { @@ -90,7 +89,7 @@ int main() { } printf("Loop device loop%d added (kernel returned minor: %d).\n", loop_minor, returned_minor); - // 4. Try to open the newly created loop block device + // 4. 打开刚创建的块设备节点 sprintf(loop_dev_path, "/dev/loop%d", loop_minor); printf("Attempting to open block device: %s\n", loop_dev_path); loop_fd = open(loop_dev_path, O_RDWR); @@ -113,7 +112,7 @@ int main() { } printf("Backing file associated successfully.\n"); - // 5. Test read/write operations on the loop block device + // 5. 对 loop 块设备执行读写测试 printf("Writing to loop device %s...\n", loop_dev_path); if (lseek(loop_fd, 0, SEEK_SET) < 0) { @@ -156,7 +155,7 @@ int main() { printf("Read/write test FAILED: Mismatch in data.\n"); } - // 6. Remove the loop device + // 6. 清理并删除 loop 设备 printf("Clearing loop device loop%d backing file...\n", loop_minor); if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { perror("Failed to clear loop device backing file"); @@ -172,12 +171,22 @@ int main() { } printf("Loop device loop%d removed successfully.\n", loop_minor); - // Clean up + // 释放资源并删除测试文件 close(loop_fd); close(backing_fd); close(control_fd); unlink(TEST_FILE_NAME); printf("All tests completed. Cleaned up.\n"); + // 校验设备删除后不可再次打开 + int reopen_fd = open(loop_dev_path, O_RDWR); + if (reopen_fd >= 0) { + printf("Unexpectedly reopened %s after removal (fd=%d).\n", loop_dev_path, reopen_fd); + close(reopen_fd); + return EXIT_FAILURE; + } else { + printf("Confirmed %s is inaccessible after removal (errno=%d).\n", loop_dev_path, errno); + } + return 0; } From 0b4377702cf1b46686bba344132a0819170b8e0f Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sun, 2 Nov 2025 16:35:38 +0000 Subject: [PATCH 15/39] fmt --- kernel/src/driver/base/block/gendisk/mod.rs | 4 +-- kernel/src/driver/base/block/loop_device.rs | 40 ++++++++------------- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/kernel/src/driver/base/block/gendisk/mod.rs b/kernel/src/driver/base/block/gendisk/mod.rs index a9e969579..eafc6c4eb 100644 --- a/kernel/src/driver/base/block/gendisk/mod.rs +++ b/kernel/src/driver/base/block/gendisk/mod.rs @@ -309,9 +309,7 @@ impl IndexNode for GenDisk { private_data: &crate::filesystem::vfs::FilePrivateData, ) -> Result { let bdev = self.block_device(); - if let Some(loop_dev) = - BlockDevice::as_any_ref(&*bdev).downcast_ref::() - { + if let Some(loop_dev) = BlockDevice::as_any_ref(&*bdev).downcast_ref::() { loop_dev.ioctl(cmd, data, private_data) } else { Err(SystemError::ENOSYS) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index deec3e7d9..16c520839 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -19,9 +19,7 @@ use crate::{ filesystem::{ devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, kernfs::KernFSInode, - vfs::{ - file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata, - }, + vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata}, }, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, @@ -384,7 +382,8 @@ impl IndexNode for LoopDevice { .ok_or(SystemError::EBADF)?; let mode = file.mode(); - let read_only = !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); + let read_only = + !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); let inode = file.inode(); let metadata = inode.metadata()?; @@ -513,9 +512,7 @@ impl BlockDevice for LoopDevice { if count == 0 { return Ok(0); } - let len = count - .checked_mul(LBA_SIZE) - .ok_or(SystemError::EOVERFLOW)?; + let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; if len > buf.len() { return Err(SystemError::EINVAL); } @@ -548,9 +545,7 @@ impl BlockDevice for LoopDevice { if count == 0 { return Ok(0); } - let len = count - .checked_mul(LBA_SIZE) - .ok_or(SystemError::EOVERFLOW)?; + let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; if len > buf.len() { return Err(SystemError::EINVAL); } @@ -652,7 +647,7 @@ impl LoopDeviceDriver { } fn new_loop_device(&self, minor: usize) -> Result, SystemError> { let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor); - let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) + let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) .ok_or_else(|| { error!("Failed to create loop device for minor {}", minor); SystemError::ENOMEM // 如果创建失败,返回具体的错误 @@ -663,7 +658,7 @@ impl LoopDeviceDriver { ); // 先注册到块设备管理器,让它可用 block_dev_manager().register(loop_dev.clone())?; - + // 返回创建的设备,让 LoopManager 能够存储它 Ok(loop_dev) } @@ -1023,11 +1018,11 @@ impl LoopManager { Ok(()) // Indicate success } pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { - let mut inner =self.inner(); + let mut inner = self.inner(); // 注册 loop 设备 for minor in 0..Self::MAX_INIT_DEVICES { - let loop_dev =driver.new_loop_device(minor)?; - inner.devices[minor]=Some(loop_dev); + let loop_dev = driver.new_loop_device(minor)?; + inner.devices[minor] = Some(loop_dev); } log::info!("Loop devices initialized"); @@ -1103,10 +1098,7 @@ impl IndexNode for LoopControlDevice { // 若文件系统没有实现此方法,则返回“不支持” return Ok(()); } - fn close( - &self, - _data: SpinLockGuard, - ) -> Result<(), SystemError> { + fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { Ok(()) } fn metadata(&self) -> Result { @@ -1166,12 +1158,10 @@ impl IndexNode for LoopControlDevice { self.loop_mgr.loop_remove(minor_to_remove)?; Ok(0) } - LOOP_CTL_GET_FREE => { - match self.loop_mgr.find_free_minor() { - Some(minor) => Ok(minor as usize), - None => Err(SystemError::ENOSPC), - } - } + LOOP_CTL_GET_FREE => match self.loop_mgr.find_free_minor() { + Some(minor) => Ok(minor as usize), + None => Err(SystemError::ENOSPC), + }, _ => Err(SystemError::ENOSYS), } } From bd115d94feaf6a0ae6759bdb4e37361bff559e75 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Mon, 3 Nov 2025 08:01:07 +0000 Subject: [PATCH 16/39] - feat: add loop_set_status and loop_get_status - feat: supplement test_loop --- kernel/src/driver/base/block/loop_device.rs | 203 ++++++++++++++++++-- user/apps/c_unitest/test_loop.c | 123 +++++++++++- 2 files changed, 312 insertions(+), 14 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 16c520839..0f8ca748c 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -26,6 +26,7 @@ use crate::{ spinlock::{SpinLock, SpinLockGuard}, }, process::ProcessManager, + syscall::user_access::{UserBufferReader, UserBufferWriter}, }; use alloc::{ string::{String, ToString}, @@ -58,14 +59,26 @@ pub const LOOP_SET_FD: u32 = 0x4C00; pub const LOOP_CLR_FD: u32 = 0x4C01; // pub const LOOP_SET_STATUS: u32 = 0x4C02; // pub const LOOP_GET_STATUS: u32 = 0x4C03; -// pub const LOOP_SET_STATUS64: u32 = 0x4C04; -// pub const LOOP_GET_STATUS64: u32 = 0x4C05; +pub const LOOP_SET_STATUS64: u32 = 0x4C04; +pub const LOOP_GET_STATUS64: u32 = 0x4C05; // pub const LOOP_CHANGE_FD: u32 = 0x4C06; // pub const LOOP_SET_CAPACITY: u32 = 0x4C07; // pub const LOOP_SET_DIRECT_IO: u32 = 0x4C08; // pub const LOOP_SET_BLOCK_SIZE: u32 = 0x4C09; // pub const LOOP_CONFIGURE: u32 = 0x4C0A; +pub const LO_FLAGS_READ_ONLY: u32 = 1 << 0; +pub const SUPPORTED_LOOP_FLAGS: u32 = LO_FLAGS_READ_ONLY; + +#[repr(C)] +#[derive(Default, Clone, Copy)] +pub struct LoopStatus64 { + pub lo_offset: u64, + pub lo_sizelimit: u64, + pub lo_flags: u32, + pub __pad: u32, +} + // /dev/loop-control 接口 pub const LOOP_CTL_ADD: u32 = 0x4C80; pub const LOOP_CTL_REMOVE: u32 = 0x4C81; @@ -100,6 +113,10 @@ pub struct LoopDeviceInner { pub file_size: usize, // 数据偏移量 pub offset: usize, + // 数据大小限制(0 表示不限制) + pub size_limit: usize, + // 标志位 + pub flags: u32, // 是否只读 pub read_only: bool, // KObject的公共数据 @@ -156,6 +173,8 @@ impl LoopDevice { file_size: 0, device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), // Loop 设备主设备号为 7 offset: 0, + size_limit: 0, + flags: 0, read_only: false, kobject_common: KObjectCommonData::default(), device_common: DeviceCommonData::default(), @@ -185,6 +204,8 @@ impl LoopDevice { inner.file_inode = Some(file_inode); inner.file_size = file_size; inner.offset = 0; + inner.size_limit = 0; + inner.flags = 0; Ok(()) } @@ -196,7 +217,13 @@ impl LoopDevice { // 设置只读模式 pub fn set_read_only(&self, read_only: bool) { - self.inner().read_only = read_only; + let mut inner = self.inner(); + inner.read_only = read_only; + if read_only { + inner.flags |= LO_FLAGS_READ_ONLY; + } else { + inner.flags &= !LO_FLAGS_READ_ONLY; + } } // 检查是否为只读 @@ -204,6 +231,31 @@ impl LoopDevice { self.inner().read_only } + fn recalc_effective_size(&self) -> Result<(), SystemError> { + let (file_inode, offset, size_limit) = { + let inner = self.inner(); + (inner.file_inode.clone(), inner.offset, inner.size_limit) + }; + + let inode = file_inode.ok_or(SystemError::ENODEV)?; + let metadata = inode.metadata()?; + if metadata.size < 0 { + return Err(SystemError::EINVAL); + } + let total_size = metadata.size as usize; + if offset > total_size { + return Err(SystemError::EINVAL); + } + let mut effective = total_size - offset; + if size_limit > 0 { + effective = effective.min(size_limit); + } + + let mut inner = self.inner(); + inner.file_size = effective; + Ok(()) + } + pub fn is_bound(&self) -> bool { matches!(self.inner().state, LoopState::Bound) } @@ -225,6 +277,10 @@ impl LoopDevice { let mut inner = self.inner(); inner.set_state(LoopState::Bound)?; inner.read_only = read_only; + inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; + inner.size_limit = 0; + drop(inner); + self.recalc_effective_size()?; Ok(()) } @@ -239,7 +295,107 @@ impl LoopDevice { inner.file_inode = None; inner.file_size = 0; inner.offset = 0; + inner.size_limit = 0; inner.read_only = false; + inner.flags = 0; + Ok(()) + } + + fn set_status64(&self, user_ptr: usize) -> Result<(), SystemError> { + if user_ptr == 0 { + return Err(SystemError::EINVAL); + } + + let reader = UserBufferReader::new::( + user_ptr as *const LoopStatus64, + core::mem::size_of::(), + true, + )?; + let mut info = LoopStatus64::default(); + reader.copy_one_from_user(&mut info, 0)?; + + if info.lo_offset % LBA_SIZE as u64 != 0 { + return Err(SystemError::EINVAL); + } + if info.lo_offset > usize::MAX as u64 || info.lo_sizelimit > usize::MAX as u64 { + return Err(SystemError::EINVAL); + } + if info.lo_sizelimit != 0 && info.lo_sizelimit % LBA_SIZE as u64 != 0 { + return Err(SystemError::EINVAL); + } + if info.lo_flags & !SUPPORTED_LOOP_FLAGS != 0 { + return Err(SystemError::EINVAL); + } + + let new_offset = info.lo_offset as usize; + let new_limit = if info.lo_sizelimit == 0 { + 0 + } else { + info.lo_sizelimit as usize + }; + let new_read_only = (info.lo_flags & LO_FLAGS_READ_ONLY) != 0; + + let (old_offset, old_limit, old_flags, old_ro) = { + let inner = self.inner(); + if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + (inner.offset, inner.size_limit, inner.flags, inner.read_only) + }; + + { + let mut inner = self.inner(); + if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + inner.offset = new_offset; + inner.size_limit = new_limit; + inner.flags = info.lo_flags; + inner.read_only = new_read_only; + } + + if let Err(err) = self.recalc_effective_size() { + let mut inner = self.inner(); + inner.offset = old_offset; + inner.size_limit = old_limit; + inner.flags = old_flags; + inner.read_only = old_ro; + drop(inner); + let _ = self.recalc_effective_size(); + return Err(err); + } + + Ok(()) + } + + fn get_status64(&self, user_ptr: usize) -> Result<(), SystemError> { + if user_ptr == 0 { + return Err(SystemError::EINVAL); + } + + let info = { + let inner = self.inner(); + if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + LoopStatus64 { + lo_offset: inner.offset as u64, + lo_sizelimit: inner.size_limit as u64, + lo_flags: if inner.read_only { + inner.flags | LO_FLAGS_READ_ONLY + } else { + inner.flags & !LO_FLAGS_READ_ONLY + }, + __pad: 0, + } + }; + + let mut writer = UserBufferWriter::new::( + user_ptr as *mut LoopStatus64, + core::mem::size_of::(), + true, + )?; + writer.copy_one_to_user(&info, 0)?; Ok(()) } } @@ -399,6 +555,14 @@ impl IndexNode for LoopDevice { self.clear_file()?; Ok(0) } + LOOP_SET_STATUS64 => { + self.set_status64(data)?; + Ok(0) + } + LOOP_GET_STATUS64 => { + self.get_status64(data)?; + Ok(0) + } _ => Err(SystemError::ENOSYS), } } @@ -517,10 +681,14 @@ impl BlockDevice for LoopDevice { return Err(SystemError::EINVAL); } - let (file_inode, base_offset) = { + let (file_inode, base_offset, limit_end) = { let inner = self.inner(); let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; - (inode, inner.offset) + let limit = inner + .offset + .checked_add(inner.file_size) + .ok_or(SystemError::EOVERFLOW)?; + (inode, inner.offset, limit) }; let block_offset = lba_id_start @@ -530,6 +698,11 @@ impl BlockDevice for LoopDevice { .checked_add(block_offset) .ok_or(SystemError::EOVERFLOW)?; + let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; + if end > limit_end { + return Err(SystemError::ENOSPC); + } + let data = SpinLock::new(FilePrivateData::Unused); let data_guard = data.lock(); @@ -550,10 +723,14 @@ impl BlockDevice for LoopDevice { return Err(SystemError::EINVAL); } - let (file_inode, base_offset, read_only) = { + let (file_inode, base_offset, limit_end, read_only) = { let inner = self.inner(); let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; - (inode, inner.offset, inner.read_only) + let limit = inner + .offset + .checked_add(inner.file_size) + .ok_or(SystemError::EOVERFLOW)?; + (inode, inner.offset, limit, inner.read_only) }; if read_only { @@ -567,18 +744,18 @@ impl BlockDevice for LoopDevice { .checked_add(block_offset) .ok_or(SystemError::EOVERFLOW)?; + let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; + if end > limit_end { + return Err(SystemError::ENOSPC); + } + let data = SpinLock::new(FilePrivateData::Unused); let data_guard = data.lock(); let written = file_inode.write_at(file_offset, len, &buf[..len], data_guard)?; if written > 0 { - if let Ok(metadata) = file_inode.metadata() { - if metadata.size >= 0 { - let mut inner = self.inner(); - inner.file_size = metadata.size as usize; - } - } + let _ = self.recalc_effective_size(); } Ok(written) diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index ac8000c17..9e1c1b16d 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -5,6 +5,7 @@ #include #include #include // 用于 fstat +#include #include // 控制命令常量 #define LOOP_CTL_ADD 0x4C80 @@ -12,10 +13,20 @@ #define LOOP_CTL_GET_FREE 0x4C82 #define LOOP_SET_FD 0x4C00 #define LOOP_CLR_FD 0x4C01 +#define LOOP_SET_STATUS64 0x4C04 +#define LOOP_GET_STATUS64 0x4C05 // 与内核通信的设备路径 #define LOOP_DEVICE_CONTROL "/dev/loop-control" +#define LO_FLAGS_READ_ONLY 0x1 #define TEST_FILE_NAME "test_image.img" #define TEST_FILE_SIZE (1024 * 1024) // 测试镜像大小 1MB +struct loop_status64 { + uint64_t lo_offset; + uint64_t lo_sizelimit; + uint32_t lo_flags; + uint32_t __pad; +}; + // 创建测试镜像文件 void create_test_file() { printf("Creating test file: %s with size %d bytes\n", TEST_FILE_NAME, TEST_FILE_SIZE); @@ -43,8 +54,11 @@ int main() { char loop_dev_path[64]; int loop_fd; int backing_fd = -1; + struct loop_status64 status; + memset(&status, 0, sizeof(status)); char write_buf[512] = "Hello Loop Device!"; - char read_buf[512]; + char read_buf[512]; + char verify_buf[512]; create_test_file(); // 创建作为 loop 设备后端的文件 @@ -112,6 +126,45 @@ int main() { } printf("Backing file associated successfully.\n"); + // 配置偏移和大小限制,使 loop 设备从文件第 512 字节开始映射 + status.lo_offset = 512; + status.lo_sizelimit = TEST_FILE_SIZE - status.lo_offset; + status.lo_flags = 0; + status.__pad = 0; + + printf("配置 loop 设备的偏移和大小限制...\n"); + if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { + perror("Failed to set loop status64"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + + struct loop_status64 status_readback = {0}; + if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { + perror("Failed to get loop status64"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("loop 偏移: %llu, 映射字节数: %llu, 标志: 0x%x\n", + (unsigned long long)status_readback.lo_offset, + (unsigned long long)status_readback.lo_sizelimit, + status_readback.lo_flags); + + if (status_readback.lo_offset != status.lo_offset || + status_readback.lo_sizelimit != status.lo_sizelimit) { + fprintf(stderr, "Loop status mismatch after configuration.\n"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + + status = status_readback; + // 5. 对 loop 块设备执行读写测试 printf("Writing to loop device %s...\n", loop_dev_path); @@ -131,6 +184,41 @@ int main() { } printf("Successfully wrote '%s' to loop device.\n", write_buf); + // 校验后端文件对应偏移512字节的数据是否与写入内容一致 + int verify_fd = open(TEST_FILE_NAME, O_RDONLY); + if (verify_fd < 0) { + perror("Failed to reopen backing file for verification"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + if (lseek(verify_fd, (off_t)status.lo_offset, SEEK_SET) < 0) { + perror("Failed to seek backing file"); + close(verify_fd); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + if (read(verify_fd, verify_buf, sizeof(write_buf)) != sizeof(write_buf)) { + perror("Failed to read back from backing file"); + close(verify_fd); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + close(verify_fd); + if (memcmp(write_buf, verify_buf, sizeof(write_buf)) != 0) { + fprintf(stderr, "Backing file data mismatch.\n"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("镜像文件内容验证通过。\n"); + printf("Reading from loop device %s...\n", loop_dev_path); memset(read_buf, 0, sizeof(read_buf)); if (lseek(loop_fd, 0, SEEK_SET) < 0) { @@ -155,6 +243,39 @@ int main() { printf("Read/write test FAILED: Mismatch in data.\n"); } + // 将设备切换到只读模式,验证写入被阻止 + printf("切换 loop 设备为只读模式...\n"); + status.lo_flags |= LO_FLAGS_READ_ONLY; + if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { + perror("Failed to enable read-only flag"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + + errno = 0; + if (lseek(loop_fd, 0, SEEK_SET) < 0) { + perror("Failed to seek loop device"); + } + if (write(loop_fd, write_buf, sizeof(write_buf)) >= 0 || errno != EROFS) { + fprintf(stderr, "Write unexpectedly succeeded under read-only mode (errno=%d).\n", errno); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + printf("只读模式下写入被正确阻止。\n"); + + status.lo_flags &= ~LO_FLAGS_READ_ONLY; + if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { + perror("Failed to restore writeable mode"); + close(loop_fd); + close(backing_fd); + close(control_fd); + exit(EXIT_FAILURE); + } + // 6. 清理并删除 loop 设备 printf("Clearing loop device loop%d backing file...\n", loop_minor); if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { From 293f529caabdc3369ff849f8787294baa988d2df Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sun, 9 Nov 2025 02:15:13 +0800 Subject: [PATCH 17/39] - add ioctl change_fd and set_capacity - add docs - delete some useless code - cargo fmt --- docs/kernel/device/index.rst | 1 + docs/kernel/device/loop_device.md | 149 +++++++++ kernel/src/driver/base/block/loop_device.rs | 219 +++++-------- user/apps/c_unitest/test_loop.c | 344 ++++++++++++++++---- 4 files changed, 496 insertions(+), 217 deletions(-) create mode 100644 docs/kernel/device/loop_device.md diff --git a/docs/kernel/device/index.rst b/docs/kernel/device/index.rst index dc9184c7f..e189422d5 100644 --- a/docs/kernel/device/index.rst +++ b/docs/kernel/device/index.rst @@ -6,3 +6,4 @@ Device :maxdepth: 1 tty + loop_device diff --git a/docs/kernel/device/loop_device.md b/docs/kernel/device/loop_device.md new file mode 100644 index 000000000..9b37382ac --- /dev/null +++ b/docs/kernel/device/loop_device.md @@ -0,0 +1,149 @@ +# Loop Device 模块与测试详解 + +本文档总结 `feat/loop-device` 分支中 loop 设备子系统与配套用户态测试的现状,用于 PR 审阅和后续开发。内容包括模块目标、组件设计、已完成功能、未完项、测试覆盖及下一步建议。 + +## 模块定位与目标 + +Loop 设备用于将普通文件映射为内核可识别的块设备,实现与 Linux `loop` 驱动类似的功能,适用于: + +- 将镜像文件挂载到 DragonOS 的虚拟块层,便于文件系统测试或容器环境。 +- 通过 `IOCTL` 动态绑定/解绑后端文件,无需内核重新加载驱动。 +- 支持只读标记、偏移映射、大小限制等基础特性,为后续扩展(加密、分片)打基础。 + +## 组件结构概览 + +| 组件 | 角色 | 关键字段/方法 | 说明 | +| :------------------ | :------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | +| `LoopDevice` | 块设备实现 | `inner: SpinLock`、`block_dev_meta`、`bind_file`、`read_at_sync`、`write_at_sync` | 针对单个 loopX 设备的核心逻辑,提供块读写接口,并维护设备状态和元数据。 | +| `LoopDeviceInner` | 设备内部状态 | `device_number`、`state`、`file_inode`、`file_size`、`offset`、`size_limit`、`flags`、`read_only` | 受自旋锁保护;记录绑定文件、状态机、映射参数和只读标志。 | +| `LoopDeviceDriver` | 驱动入口 | `new_loop_device` | 负责创建空设备、向块设备管理器注册,并作为内核对象自身具备 KObject 和 Driver 特性。 | +| `LoopManager` | 管理器 | `devices: [Option>; 256]`、`loop_add`、`loop_remove`、`find_free_minor` | 管理最多 256 个 loop 设备,初始化时预注册 0-7,共 8 个占位设备,并提供动态分配和回收接口。 | +| `LoopControlDevice` | 字符控制接口 | `ioctl` (LOOP_CTL_ADD/REMOVE/GET_FREE) | 对应 `/dev/loop-control` 节点,供用户态分配、回收,撤销 loop 设备。 | +| `LoopStatus64` | IOCTL 数据结构 | `lo_offset`、`lo_sizelimit`、`lo_flags` | 对标 Linux `LOOP_SET_STATUS64` 数据结构,用于用户态和内核态之间传递 loop 设备参数。 | + +### 状态机 (`LoopState`) + +Loop 设备以 `LoopState` 枚举管理生命周期: + +| 当前状态 | 允许迁移 | 场景 | +| :--------- | :-------------------- | :-------------------------------------- | +| `Unbound` | `Bound`、`Deleting` | 空闲设备,可绑定或直接删除。 | +| `Bound` | `Unbound`、`Rundown` | 已关联后端文件;解绑或进入下线流程。 | +| `Rundown` | `Deleting`、`Unbound` | 下线/清理阶段;可安全删除或回到未绑定。 | +| `Deleting` | — | 正在注销,拒绝再次绑定。 | + +状态转换由 `LoopDeviceInner::set_state` 强制检查,防止非法跃迁,并由 `state_lock` 自旋锁保护。 + +### I/O 数据路径 + +1. **设备绑定**: + * `LOOP_SET_FD` IOCTL 接收一个文件描述符,通过 `ProcessManager::current_pcb().fd_table()` 获取对应的 `File` 和 `IndexNode`。 + * `LoopDevice::bind_file` 方法根据文件模式判断是否只读,并调用 `set_file` 将后端文件 inode 关联到 LoopDevice,同时设置 `flags` 和 `read_only` 状态。 + * 最终会调用 `recalc_effective_size` 重新计算设备可见大小。 +2. **设备参数配置**: + * `LOOP_SET_STATUS64` IOCTL 接收 `LoopStatus64` 结构体,用于配置 `offset`(偏移量)、`size_limit`(大小限制)和 `lo_flags`(只读等标志)。 + * 内核会进行参数校验(如偏移和限制是否 LBA_SIZE 对齐,flags 是否支持)。 + * 成功设置后,同样会调用 `recalc_effective_size` 更新设备可见容量。 +3. **块读写**: + * ioctl的读写操作会先传入`Gendisk`然后再通过`read`函数传递到`loopX`的`read`or `write`函数 + * 块设备的读写操作 (`BlockDevice::read_at_sync` / `write_at_sync`) 将 LBA 地址和长度转换为后端文件的字节偏移和长度。 + * 计算后的文件偏移量会加上 `LoopDeviceInner::offset`。 + * 读写操作通过后端文件 `IndexNode::read_at`/`write_at` 实现。 + * 如果设备被标记为只读 (`inner.read_only` 为 true),`write_at_sync` 将返回 `SystemError::EROFS`。 + * 写入成功后,会再次调用 `recalc_effective_size` 确保块层容量与后端文件状态一致。 + +### 设备控制接口 + +- **块设备 IOCTL** (针对 `/dev/loopX` 节点): + * `LOOP_SET_FD`:绑定一个文件描述符到 loop 设备。 + * `LOOP_CLR_FD`:解绑当前关联的文件,并将 loop 设备置于 `Unbound` 状态。 + * `LOOP_SET_STATUS` / `LOOP_GET_STATUS`:设置/获取 32 位状态,目前直接委托给 `_STATUS64` 版本。 + * `LOOP_SET_STATUS64` / `LOOP_GET_STATUS64`:设置/获取 64 位状态,包括文件偏移、大小限制和标志位。 + * `LOOP_CHANGE_FD`: 更换后端文件描述符,同时更新只读状态。 + * `LOOP_SET_CAPACITY`: 重新计算设备容量,通常在后端文件大小或参数改变后调用。 +- **控制字符设备 IOCTL** (针对 `/dev/loop-control` 节点): + * `LOOP_CTL_ADD`:根据用户请求的 minor 号(或自动查找空闲 minor)分配一个新的 `LoopDevice`。 + * `LOOP_CTL_REMOVE`:根据 minor 号移除一个 loop 设备,将其从块设备管理器中注销。 + * `LOOP_CTL_GET_FREE`:查找并返回一个当前未绑定后端文件的空闲 loop 设备的 minor 号。 + +## 已完成的工作 + +### 内核部分 + +- `LoopDevice` 作为虚拟块设备,实现了 `BlockDevice`、`Device`、`KObject` 和 `IndexNode` 接口,具备完整的块设备读写能力。 +- 引入 `LoopState` 状态机,并通过 `SpinLock` 保护其转换,确保设备生命周期管理严谨。 +- `LoopDevice` 支持文件偏移 (`offset`) 和大小限制 (`size_limit`),使得用户可以精确控制 loop 设备可见的后端文件区域。 +- 实现了 `LO_FLAGS_READ_ONLY` 标志,在 `write_at_sync` 路径中正确阻止写入并返回 `EROFS`。 +- `LoopManager` 负责集中管理 `LoopDevice` 实例,初始化时预注册 8 个占位设备,并支持动态分配和回收多达 256 个设备。 +- `LoopControlDevice` 作为字符设备,提供了用户态与 `LoopManager` 交互的控制接口 (`/dev/loop-control`),支持 `LOOP_CTL_ADD`、`LOOP_CTL_REMOVE` 和 `LOOP_CTL_GET_FREE` IOCTL。 +- `LOOP_SET_FD`, `LOOP_CLR_FD`, `LOOP_SET_STATUS64`, `LOOP_GET_STATUS64`, `LOOP_CHANGE_FD`, `LOOP_SET_CAPACITY` 等关键块设备 IOCTL 已实现,覆盖了 loop 设备的基本配置功能。 +- 用户态和内核态之间的数据拷贝使用了 `UserBufferReader/Writer`,确保了内存访问的安全性。 +- `loop_init` 函数在系统启动时通过 `unified_init` 宏自动注册 `LoopControlDevice` 并初始化 `LoopManager`,预分配了初始的 loop 设备。 +- 完善的错误处理机制:在文件绑定、状态转换、参数校验和读写操作中,会返回具体的 `SystemError`。 +- `LoopDevice` 的 `metadata()` 方法能够正确反映后端文件和 loop 设备自身的元数据,包括设备类型、大小、块数等。 + +### 用户态测试 (`user/apps/c_unitest/test_loop.c`) + +- **测试镜像生成**:自动创建两个测试文件 (`test_image.img`, `test_image_2.img`) 作为 loop 设备的后端存储,分别大小为 1 MiB 和 512 KiB,并在后续测试中通过 `ftruncate` 动态调整大小。 +- **设备分配与绑定**: + * 通过 `/dev/loop-control` 接口调用 `LOOP_CTL_GET_FREE` 获取空闲 minor,然后使用 `LOOP_CTL_ADD` 分配并创建对应的 `/dev/loopX` 设备节点。 + * 对新分配的 `/dev/loopX` 设备执行 `LOOP_SET_FD`,将 `test_image.img` 文件绑定到该 loop 设备。 +- **参数配置与校验**: + * 使用 `LOOP_SET_STATUS64` 配置 loop 设备,例如设置一个 512 字节的偏移量 (`lo_offset`) 和一个有效大小限制 (`lo_sizelimit`)。 + * 接着使用 `LOOP_GET_STATUS64` 读取设备状态,验证之前设置的参数是否正确回读。 +- **数据读写验证 (初始后端文件)**: + * 写入 512 字节的数据到 loop 设备。 + * 验证写入的数据在原始文件对应偏移处是否一致。 + * 从 loop 设备读回数据,并验证其与写入内容的一致性。 +- **只读模式测试**: + * 通过 `LOOP_SET_STATUS64` 设置 `LO_FLAGS_READ_ONLY` 标志,将 loop 设备切换到只读模式。 + * 尝试向只读设备写入数据,验证写入操作是否被 `EROFS` 错误拒绝。 + * 恢复设备的读写权限,确保功能正常。 +- **`LOOP_CHANGE_FD` 测试**: + * 调用 `ioctl(loop_fd, LOOP_CHANGE_FD, backing_fd_2)` 将 loop 设备绑定的后端文件从 `test_image.img` 动态切换到 `test_image_2.img`,无需解绑和重新绑定。 + * 验证切换后,能够成功向新的后端文件 (`test_image_2.img`) 写入数据,并通过直接读取 `test_image_2.img` 校验数据一致性。 +- **`LOOP_SET_CAPACITY` 测试**: + * **后端文件大小调整**: 通过 `ftruncate` 动态增大 `test_image_2.img` 的大小。 + * **触发容量重新计算**: 调用 `ioctl(loop_fd, LOOP_SET_CAPACITY, 0)` 触发 loop 设备重新评估其容量。 + * **验证容量限制行为**: + * 首先在 `lo_sizelimit` 非零的情况下进行测试,观察容量是否受限于 `lo_sizelimit`。 + * 随后将 `lo_sizelimit` 清零,再次调用 `LOOP_SET_CAPACITY`,验证 loop 设备能够正确反映后端文件的新增容量。 + * **扩展区域读写验证**: 尝试向新扩展的区域写入数据,并通过直接读取后端文件校验数据是否成功写入。 +- **设备清理**: + * 调用 `LOOP_CLR_FD` 解绑后端文件。 + * 通过 `LOOP_CTL_REMOVE` 移除 loop 设备,并验证设备节点是否不再可访问。 +- **资源清理**:测试结束后删除所有生成的测试镜像文件,确保环境干净。 + +## 未完成/待完善事项 + +### 内核侧限制 + +- **文件系统连接 (`fs()`)**:`LoopDevice::fs()` 和 `LoopControlDevice::fs()` 方法目前仍为 `todo!()`。 +- **I/O 调度和工作队列**:当前所有读写操作都是同步直通的。缺少异步 I/O 队列或工作队列的实现,可能在高负载情况下影响系统响应和性能。 +- **加密类型实现**:代码中保留了加密类型常量 (`LO_CRYPT_NONE` 等),但未有任何实际的加密/解密逻辑实现。 +- **`LoopDevice::sync()` 空实现**:`sync()` 方法目前仅返回 `Ok(())`,未实现对后端文件的实际 `flush` 或 `fsync` 操作,可能导致数据持久性问题。 +- **分区支持**:`BlockDevice::partitions()` 返回空集合。这意味着 loop 设备目前不支持解析或呈现后端镜像文件中的分区表。 +- **错误回滚不足**:在 `LoopManager::create_and_register_device_locked` 中,如果 `block_dev_manager().register` 失败,虽然返回错误,但未清除 `inner.devices[minor]` 中可能残留的 `Some`,可能导致状态不一致。 +- **内核侧单元测试**:目前缺乏针对 `LoopDevice`、`LoopManager` 和 `LoopControlDevice` 核心逻辑的独立内核单元测试或集成测试,只有一个`ctest` + +### 用户态测试缺口 + +- **设备节点依赖**:测试依赖 `/dev/loop-control` 与 `/dev/loopX` 节点预先存在且权限正确。若 `udev`/`devfs` 未创建节点或权限不符,测试会失败。 +- **并发与压力测试**:目前的测试集中于单个设备、单线程的场景。未验证并发绑定/解绑、多设备同时读写、极限容量或高 I/O 负载下的行为。 +- **负向测试**:缺乏对非法参数(如非 LBA_SIZE 对齐的偏移/大小限制)、读写越界、重复绑定、非文件类型后端文件等边界条件的测试。**(部分覆盖,但仍需更全面)** +- **IOCTL 完整性测试**:虽然已覆盖 `LOOP_SET_FD`, `LOOP_CLR_FD`, `LOOP_SET_STATUS64`, `LOOP_GET_STATUS64`, `LOOP_CHANGE_FD`, `LOOP_SET_CAPACITY` 等,但针对这些 IOCTL 的所有参数组合和异常情况的测试仍可扩展。 + +## 运行测试的基本步骤 + +1. **启动 DragonOS**:确保系统启动并成功执行 `loop_init` 函数。您可以通过查看内核日志确认“Loop control device initialized.”等消息。 + +2. **进入用户态环境**:在 DragonOS 的 shell 中,导航到用户态测试目录。 + +3. **编译并运行 `test_loop`**: + + ``` + ./bin/test_loop + ``` + +4. **观察输出**:如果所有测试步骤成功,您将看到类似“Read/write test PASSED.”、“只读模式下写入被正确阻止。”等成功的提示信息。任何错误都会以 `ERROR:` 标志并在日志中指明。 + diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 0f8ca748c..78d6c4fa7 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -9,7 +9,7 @@ use crate::{ device::{ bus::Bus, device_number::{DeviceNumber, Major}, - device_register, device_unregister, + device_register, driver::{Driver, DriverCommonData}, DevName, Device, DeviceCommonData, DeviceType, IdTable, }, @@ -57,12 +57,12 @@ const LOOP_BASENAME: &str = "loop"; // // IOCTL 命令 - 使用 0x4C ('L') pub const LOOP_SET_FD: u32 = 0x4C00; pub const LOOP_CLR_FD: u32 = 0x4C01; -// pub const LOOP_SET_STATUS: u32 = 0x4C02; -// pub const LOOP_GET_STATUS: u32 = 0x4C03; +pub const LOOP_SET_STATUS: u32 = 0x4C02; +pub const LOOP_GET_STATUS: u32 = 0x4C03; pub const LOOP_SET_STATUS64: u32 = 0x4C04; pub const LOOP_GET_STATUS64: u32 = 0x4C05; -// pub const LOOP_CHANGE_FD: u32 = 0x4C06; -// pub const LOOP_SET_CAPACITY: u32 = 0x4C07; +pub const LOOP_CHANGE_FD: u32 = 0x4C06; +pub const LOOP_SET_CAPACITY: u32 = 0x4C07; // pub const LOOP_SET_DIRECT_IO: u32 = 0x4C08; // pub const LOOP_SET_BLOCK_SIZE: u32 = 0x4C09; // pub const LOOP_CONFIGURE: u32 = 0x4C0A; @@ -153,14 +153,14 @@ pub enum LoopState { Deleting, } impl Debug for LoopDevice { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + fn fmt(&'_ self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("LoopDevice") .field("devname", &self.block_dev_meta.devname) .finish() } } impl LoopDevice { - fn inner(&self) -> SpinLockGuard { + fn inner(&'_ self) -> SpinLockGuard<'_, LoopDeviceInner> { // 获取 LoopDeviceInner 的自旋锁 self.inner.lock() } @@ -205,32 +205,12 @@ impl LoopDevice { inner.file_size = file_size; inner.offset = 0; inner.size_limit = 0; - inner.flags = 0; - + inner.flags = 0; // Reset flags + inner.read_only = false; // Reset read_only + drop(inner); + self.recalc_effective_size()?; // Recalculate size based on new file Ok(()) } - - // 获取文件大小 - pub fn file_size(&self) -> usize { - self.inner().file_size - } - - // 设置只读模式 - pub fn set_read_only(&self, read_only: bool) { - let mut inner = self.inner(); - inner.read_only = read_only; - if read_only { - inner.flags |= LO_FLAGS_READ_ONLY; - } else { - inner.flags &= !LO_FLAGS_READ_ONLY; - } - } - - // 检查是否为只读 - pub fn is_read_only(&self) -> bool { - self.inner().read_only - } - fn recalc_effective_size(&self) -> Result<(), SystemError> { let (file_inode, offset, size_limit) = { let inner = self.inner(); @@ -398,6 +378,41 @@ impl LoopDevice { writer.copy_one_to_user(&info, 0)?; Ok(()) } + fn set_status(&self, user_ptr: usize) -> Result<(), SystemError> { + self.set_status64(user_ptr) + } + fn get_status(&self, user_ptr: usize) -> Result<(), SystemError> { + self.get_status64(user_ptr) + } + fn change_fd(&self, new_file_fd: i32) -> Result<(), SystemError> { + let fd_table = ProcessManager::current_pcb().fd_table(); + let file = { + let guard = fd_table.read(); + guard.get_file_by_fd(new_file_fd) + } + .ok_or(SystemError::EBADF)?; + + let mode = file.mode(); + let read_only = !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); + + let inode = file.inode(); + let metadata = inode.metadata()?; + match metadata.file_type { + FileType::File | FileType::BlockDevice => {} + _ => return Err(SystemError::EINVAL), + } + let mut inner = self.inner(); + inner.file_inode = Some(inode); + inner.read_only = read_only; + inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; + drop(inner); + self.recalc_effective_size()?; + Ok(()) + } + fn set_capacity(&self, _arg: usize) -> Result<(), SystemError> { + self.recalc_effective_size()?; + Ok(()) + } } impl KObject for LoopDevice { @@ -443,11 +458,11 @@ impl KObject for LoopDevice { // do nothing,不支持设置loop为别的名称 } - fn kobj_state(&self) -> RwLockReadGuard { + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { self.locked_kobj_state.read() } - fn kobj_state_mut(&self) -> RwLockWriteGuard { + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { self.locked_kobj_state.write() } @@ -555,6 +570,14 @@ impl IndexNode for LoopDevice { self.clear_file()?; Ok(0) } + LOOP_SET_STATUS => { + self.set_status(data)?; + Ok(0) + } + LOOP_GET_STATUS => { + self.get_status(data)?; + Ok(0) + } LOOP_SET_STATUS64 => { self.set_status64(data)?; Ok(0) @@ -563,6 +586,14 @@ impl IndexNode for LoopDevice { self.get_status64(data)?; Ok(0) } + LOOP_CHANGE_FD => { + self.change_fd(data as i32)?; + Ok(0) + } + LOOP_SET_CAPACITY => { + self.set_capacity(data)?; + Ok(0) + } _ => Err(SystemError::ENOSYS), } } @@ -819,7 +850,7 @@ impl LoopDeviceDriver { kobj_state: LockedKObjectState::default(), }) } - fn inner(&self) -> SpinLockGuard { + fn inner(&'_ self) -> SpinLockGuard<'_, InnerLoopDeviceDriver> { self.inner.lock() } fn new_loop_device(&self, minor: usize) -> Result, SystemError> { @@ -928,11 +959,11 @@ impl KObject for LoopDeviceDriver { // do nothing } - fn kobj_state(&self) -> RwLockReadGuard { + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { self.kobj_state.read() } - fn kobj_state_mut(&self) -> RwLockWriteGuard { + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { self.kobj_state.write() } @@ -959,20 +990,12 @@ impl LoopManager { }), } } - fn inner(&self) -> SpinLockGuard { + fn inner(&'_ self) -> SpinLockGuard<'_, LoopManagerInner> { self.inner.lock() } - //index: 次设备号 - pub fn register_device(&self, index: usize, device: Arc) { - if index < Self::MAX_DEVICES { - let mut inner = self.inner(); - inner.devices[index] = Some(device); - } - } /* 请求队列,工作队列未实现 */ - pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { let mut inner = self.inner(); match requested_minor { @@ -980,7 +1003,6 @@ impl LoopManager { None => self.loop_add_first_available_locked(&mut inner), } } - fn loop_add_specific_locked( &self, inner: &mut LoopManagerInner, @@ -1048,26 +1070,6 @@ impl LoopManager { log::info!("Loop device loop{} added successfully.", minor); Ok(loop_dev) } - - pub fn loop_clear(&self, minor: u32) -> Result<(), SystemError> { - if minor >= Self::MAX_DEVICES as u32 { - return Err(SystemError::EINVAL); - } - - let device = { - let inner = self.inner(); - inner.devices[minor as usize].clone() - } - .ok_or(SystemError::ENODEV)?; - - device.clear_file()?; - - let mut inner = self.inner(); - inner.next_free_minor = minor; - log::info!("Loop device loop{} cleared.", minor); - Ok(()) - } - pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { if minor >= Self::MAX_DEVICES as u32 { return Err(SystemError::EINVAL); @@ -1126,74 +1128,6 @@ impl LoopManager { } None } - pub fn find_device_by_minor(&self, minor: u32) -> Option> { - let inner = self.inner(); - if minor < Self::MAX_DEVICES as u32 { - inner.devices[minor as usize].clone() - } else { - None - } - } - // pub fn loop_remove(&self ,minor:u32)-> Result<(),SystemError>{ - // let mut inner_guard=self.inner(); - // if minor >=Self::MAX_DEVICES as u32{ - // return Err(SystemError::EINVAL); - // } - // if let Some(loop_dev)=inner_guard.devices[minor as usize ].take(){ - // //loop_dev.clear_file()?; - // //loop_dev.inner().set_stable(LoopState::Deleting)?; - - // block_dev_manager().unregister(loop_dev.dev_name())?; - // } - // } - // 动态分配空闲的loop设备,与指定文件inode关联 - pub fn alloc_device( - &self, - file_inode: Arc, - ) -> Result, SystemError> { - let mut inner = self.inner(); - for (i, device) in inner.devices.iter_mut().enumerate() { - if device.is_none() { - let devname = DevName::new(format!("{}{}", LOOP_BASENAME, i), i); - let loop_device = LoopDevice::new_empty_loop_device(devname, i as u32) - .ok_or(SystemError::ENOMEM)?; - loop_device.set_file(file_inode.clone())?; - *device = Some(loop_device.clone()); - return Ok(loop_device); - } - } - Err(SystemError::ENOSPC) - } - pub fn deallocate_device(&self, device: &Arc) -> Result<(), SystemError> { - /* - 重置状态unbound - */ - let mut inner_guard = device.inner(); - inner_guard.set_state(LoopState::Unbound)?; - inner_guard.file_inode = None; - inner_guard.file_size = 0; - inner_guard.offset = 0; - inner_guard.read_only = false; - drop(inner_guard); - let minor = device.inner().device_number.minor() as usize; - let mut loop_mgr_inner = self.inner(); // Lock the LoopManager - if minor < LoopManager::MAX_DEVICES { - if let Some(removed_device) = loop_mgr_inner.devices[minor].take() { - log::info!("Deallocated loop device loop{} from manager.", minor); - // Unregister from block device manager - device_unregister(removed_device.clone()); - } else { - log::warn!( - "Attempted to deallocate loop device loop{} but it was not found in manager.", - minor - ); - } - } else { - return Err(SystemError::EINVAL); // Minor out of bounds - } - - Ok(()) // Indicate success - } pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { let mut inner = self.inner(); // 注册 loop 设备 @@ -1223,19 +1157,14 @@ pub struct LoopControlDevice { } struct LoopControlDeviceInner { // 设备的公共数据 - pub device_common: DeviceCommonData, + device_common: DeviceCommonData, // KObject的公共数据 - pub kobject_common: KObjectCommonData, + kobject_common: KObjectCommonData, parent: RwLock>, device_inode_fs: RwLock>>, - devfs_metadata: Metadata, } impl LoopControlDevice { - pub fn loop_add(&self, index: u32) -> Result, SystemError> { - //let loop_dri= LoopDeviceDriver::new(); - self.loop_mgr.loop_add(Some(index)) - } pub fn new(loop_mgr: Arc) -> Arc { Arc::new(Self { inner: SpinLock::new(LoopControlDeviceInner { @@ -1243,13 +1172,13 @@ impl LoopControlDevice { device_common: DeviceCommonData::default(), parent: RwLock::new(Weak::default()), device_inode_fs: RwLock::new(None), - devfs_metadata: Metadata::default(), + // devfs_metadata: Metadata::default(), }), locked_kobj_state: LockedKObjectState::default(), loop_mgr, }) } - pub fn inner(&self) -> SpinLockGuard { + fn inner(&'_ self) -> SpinLockGuard<'_, LoopControlDeviceInner> { self.inner.lock() } } @@ -1484,11 +1413,11 @@ impl KObject for LoopControlDevice { // do nothing } - fn kobj_state(&self) -> RwLockReadGuard { + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { self.locked_kobj_state.read() } - fn kobj_state_mut(&self) -> RwLockWriteGuard { + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { self.locked_kobj_state.write() } diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index 9e1c1b16d..32476bce9 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -7,6 +7,7 @@ #include // 用于 fstat #include #include + // 控制命令常量 #define LOOP_CTL_ADD 0x4C80 #define LOOP_CTL_REMOVE 0x4C81 @@ -15,11 +16,17 @@ #define LOOP_CLR_FD 0x4C01 #define LOOP_SET_STATUS64 0x4C04 #define LOOP_GET_STATUS64 0x4C05 +#define LOOP_CHANGE_FD 0x4C06 // 新增 +#define LOOP_SET_CAPACITY 0x4C07 // 新增 + // 与内核通信的设备路径 #define LOOP_DEVICE_CONTROL "/dev/loop-control" #define LO_FLAGS_READ_ONLY 0x1 #define TEST_FILE_NAME "test_image.img" +#define TEST_FILE_NAME_2 "test_image_2.img" // 第二个测试文件 #define TEST_FILE_SIZE (1024 * 1024) // 测试镜像大小 1MB +#define TEST_FILE_SIZE_2 (512 * 1024) // 第二个测试镜像大小 512KB + struct loop_status64 { uint64_t lo_offset; uint64_t lo_sizelimit; @@ -28,43 +35,63 @@ struct loop_status64 { }; // 创建测试镜像文件 -void create_test_file() { - printf("Creating test file: %s with size %d bytes\n", TEST_FILE_NAME, TEST_FILE_SIZE); - int fd = open(TEST_FILE_NAME, O_CREAT | O_TRUNC | O_RDWR, 0644); +void create_test_file(const char* filename, int size) { + printf("Creating test file: %s with size %d bytes\n", filename, size); + int fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0644); if (fd < 0) { perror("Failed to create test file"); exit(EXIT_FAILURE); } // 写入零填充数据以确保文件占满容量 char zero_block[512] = {0}; - for (int i = 0; i < TEST_FILE_SIZE / 512; ++i) { + for (int i = 0; i < size / 512; ++i) { if (write(fd, zero_block, 512) != 512) { perror("Failed to write to test file"); close(fd); exit(EXIT_FAILURE); } } - printf("Test file created successfully.\n"); + printf("Test file %s created successfully.\n", filename); close(fd); } +// 获取文件大小的辅助函数 +long get_file_size(int fd) { + struct stat st; + if (fstat(fd, &st) < 0) { + perror("fstat failed"); + return -1; + } + return st.st_size; +} + int main() { int control_fd; int loop_minor; char loop_dev_path[64]; int loop_fd; - int backing_fd = -1; + int backing_fd_1 = -1; + int backing_fd_2 = -1; // 第二个后端文件描述符 struct loop_status64 status; memset(&status, 0, sizeof(status)); char write_buf[512] = "Hello Loop Device!"; + char write_buf_2[512] = "New Backing File Data!"; // 第二个文件写入数据 char read_buf[512]; char verify_buf[512]; - create_test_file(); // 创建作为 loop 设备后端的文件 + create_test_file(TEST_FILE_NAME, TEST_FILE_SIZE); // 创建作为 loop 设备后端的文件 1 + create_test_file(TEST_FILE_NAME_2, TEST_FILE_SIZE_2); // 创建作为 loop 设备后端的文件 2 + + backing_fd_1 = open(TEST_FILE_NAME, O_RDWR); + if (backing_fd_1 < 0) { + perror("Failed to open backing file 1"); + exit(EXIT_FAILURE); + } - backing_fd = open(TEST_FILE_NAME, O_RDWR); - if (backing_fd < 0) { - perror("Failed to open backing file"); + backing_fd_2 = open(TEST_FILE_NAME_2, O_RDWR); + if (backing_fd_2 < 0) { + perror("Failed to open backing file 2"); + close(backing_fd_1); exit(EXIT_FAILURE); } @@ -73,7 +100,8 @@ int main() { control_fd = open(LOOP_DEVICE_CONTROL, O_RDWR); if (control_fd < 0) { perror("Failed to open loop control device. Make sure your kernel module is loaded and /dev/loop-control exists."); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); exit(EXIT_FAILURE); } printf("Loop control device opened successfully (fd=%d).\n", control_fd); @@ -82,7 +110,8 @@ int main() { printf("Requesting a free loop device minor...\n"); if (ioctl(control_fd, LOOP_CTL_GET_FREE, &loop_minor) < 0) { perror("Failed to get free loop device minor"); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); exit(EXIT_FAILURE); } @@ -94,7 +123,8 @@ int main() { if (returned_minor < 0) { perror("Failed to add loop device"); printf("returned_minor: %d\n", returned_minor); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); exit(EXIT_FAILURE); } @@ -110,17 +140,19 @@ int main() { if (loop_fd < 0) { perror("Failed to open loop block device. This might mean the block device node wasn't created/registered correctly, or permissions."); fprintf(stderr, "Make sure /dev/loop%d exists as a block device.\n", loop_minor); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); exit(EXIT_FAILURE); } printf("Loop block device %s opened successfully (fd=%d).\n", loop_dev_path, loop_fd); printf("Associating backing file %s with loop device using LOOP_SET_FD...\n", TEST_FILE_NAME); - if (ioctl(loop_fd, LOOP_SET_FD, backing_fd) < 0) { + if (ioctl(loop_fd, LOOP_SET_FD, backing_fd_1) < 0) { perror("Failed to associate backing file with loop device"); close(loop_fd); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); exit(EXIT_FAILURE); } @@ -136,7 +168,8 @@ int main() { if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { perror("Failed to set loop status64"); close(loop_fd); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); exit(EXIT_FAILURE); } @@ -145,7 +178,8 @@ int main() { if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { perror("Failed to get loop status64"); close(loop_fd); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); exit(EXIT_FAILURE); } @@ -158,29 +192,24 @@ int main() { status_readback.lo_sizelimit != status.lo_sizelimit) { fprintf(stderr, "Loop status mismatch after configuration.\n"); close(loop_fd); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); exit(EXIT_FAILURE); } status = status_readback; - // 5. 对 loop 块设备执行读写测试 + // 5. 对 loop 块设备执行读写测试 (针对第一个文件) - printf("Writing to loop device %s...\n", loop_dev_path); + printf("Writing to loop device %s (via %s)...\n", loop_dev_path, TEST_FILE_NAME); if (lseek(loop_fd, 0, SEEK_SET) < 0) { perror("lseek failed before write"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } if (write(loop_fd, write_buf, sizeof(write_buf)) != sizeof(write_buf)) { perror("Failed to write to loop device"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } printf("Successfully wrote '%s' to loop device.\n", write_buf); @@ -188,34 +217,22 @@ int main() { int verify_fd = open(TEST_FILE_NAME, O_RDONLY); if (verify_fd < 0) { perror("Failed to reopen backing file for verification"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } if (lseek(verify_fd, (off_t)status.lo_offset, SEEK_SET) < 0) { perror("Failed to seek backing file"); close(verify_fd); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } if (read(verify_fd, verify_buf, sizeof(write_buf)) != sizeof(write_buf)) { perror("Failed to read back from backing file"); close(verify_fd); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } close(verify_fd); if (memcmp(write_buf, verify_buf, sizeof(write_buf)) != 0) { fprintf(stderr, "Backing file data mismatch.\n"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } printf("镜像文件内容验证通过。\n"); @@ -223,17 +240,11 @@ int main() { memset(read_buf, 0, sizeof(read_buf)); if (lseek(loop_fd, 0, SEEK_SET) < 0) { perror("lseek failed before read"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } if (read(loop_fd, read_buf, sizeof(read_buf)) != sizeof(read_buf)) { perror("Failed to read from loop device"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } printf("Successfully read '%s' from loop device.\n", read_buf); @@ -241,6 +252,7 @@ int main() { printf("Read/write test PASSED.\n"); } else { printf("Read/write test FAILED: Mismatch in data.\n"); + goto cleanup; } // 将设备切换到只读模式,验证写入被阻止 @@ -248,10 +260,7 @@ int main() { status.lo_flags |= LO_FLAGS_READ_ONLY; if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { perror("Failed to enable read-only flag"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } errno = 0; @@ -260,23 +269,214 @@ int main() { } if (write(loop_fd, write_buf, sizeof(write_buf)) >= 0 || errno != EROFS) { fprintf(stderr, "Write unexpectedly succeeded under read-only mode (errno=%d).\n", errno); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; } printf("只读模式下写入被正确阻止。\n"); status.lo_flags &= ~LO_FLAGS_READ_ONLY; if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { perror("Failed to restore writeable mode"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + goto cleanup; + } + + // ======================================================= + // 新增测试用例:LOOP_CHANGE_FD + // ======================================================= + printf("\n--- Testing LOOP_CHANGE_FD ---\n"); + printf("Changing backing file from %s to %s using LOOP_CHANGE_FD...\n", TEST_FILE_NAME, TEST_FILE_NAME_2); + if (ioctl(loop_fd, LOOP_CHANGE_FD, backing_fd_2) < 0) { + perror("Failed to change backing file via LOOP_CHANGE_FD"); + goto cleanup; + } + printf("Backing file changed successfully to %s.\n", TEST_FILE_NAME_2); + + // 验证 loop 设备现在映射到第二个文件 + status_readback = (struct loop_status64){0}; + if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { + perror("Failed to get loop status64 after LOOP_CHANGE_FD"); + goto cleanup; + } + printf("After LOOP_CHANGE_FD, loop current offset: %llu, sizelimit: %llu, flags: 0x%x\n", + (unsigned long long)status_readback.lo_offset, + (unsigned long long)status_readback.lo_sizelimit, + status_readback.lo_flags); + + // 确保偏移和大小限制保持,但实际大小应该基于新文件 + long actual_file_2_size = get_file_size(backing_fd_2); + if (actual_file_2_size < 0) goto cleanup; + + // 此时 lo_sizelimit 应该反映出 TEST_FILE_NAME_2 的大小 + // 因为 LOOP_CHANGE_FD 会调用 recalc_effective_size + // 并且默认的 sizelimit 是 0,表示不限制 + // 所以 effective_size 应该等于 file_size - offset + // 我们需要重新计算预期的 effective_size + uint64_t expected_sizelimit_after_change = (actual_file_2_size > status_readback.lo_offset) ? (actual_file_2_size - status_readback.lo_offset) : 0; + + // 注意:内核中的 `recalc_effective_size` 会将 `inner.file_size` 更新为有效大小 + // 但是 `lo_sizelimit` 字段在 `LoopStatus64` 中是用户设定的限制,它不会自动改变 + // 这里的验证需要更精确:`lo_sizelimit` 应该和我们之前设置的相同 (即 TEST_FILE_SIZE - 512) + // 但当 `LOOP_CHANGE_FD` 成功时,其内部会重新计算 `file_size` + // 如果 `lo_sizelimit` 保持为非0值,并且大于新文件大小,则 `file_size` 会被截断 + // 让我们先简单地检查是否能对新文件进行读写。 + + // 写入新数据到 loop 设备,应该写入到 TEST_FILE_NAME_2 + printf("Writing to loop device %s (via %s)...\n", loop_dev_path, TEST_FILE_NAME_2); + if (lseek(loop_fd, 0, SEEK_SET) < 0) { + perror("lseek failed before write to new backing file"); + goto cleanup; } + if (write(loop_fd, write_buf_2, sizeof(write_buf_2)) != sizeof(write_buf_2)) { + perror("Failed to write to loop device with new backing file"); + goto cleanup; + } + printf("Successfully wrote '%s' to loop device with new backing file.\n", write_buf_2); + + // 校验第二个后端文件对应偏移512字节的数据是否与写入内容一致 + verify_fd = open(TEST_FILE_NAME_2, O_RDONLY); + if (verify_fd < 0) { + perror("Failed to reopen new backing file for verification"); + goto cleanup; + } + if (lseek(verify_fd, (off_t)status.lo_offset, SEEK_SET) < 0) { // 使用之前设置的偏移量 + perror("Failed to seek new backing file"); + close(verify_fd); + goto cleanup; + } + memset(verify_buf, 0, sizeof(verify_buf)); + if (read(verify_fd, verify_buf, sizeof(write_buf_2)) != sizeof(write_buf_2)) { + perror("Failed to read back from new backing file"); + close(verify_fd); + goto cleanup; + } + close(verify_fd); + if (memcmp(write_buf_2, verify_buf, sizeof(write_buf_2)) != 0) { + fprintf(stderr, "New backing file data mismatch after LOOP_CHANGE_FD.\n"); + goto cleanup; + } + printf("New backing file content verification passed after LOOP_CHANGE_FD.\n"); + + // ======================================================= + // 新增测试用例:LOOP_SET_CAPACITY + // ======================================================= + printf("\n--- Testing LOOP_SET_CAPACITY ---\n"); + // 增大 TEST_FILE_NAME_2 的大小 + int resize_fd = open(TEST_FILE_NAME_2, O_RDWR); + if (resize_fd < 0) { + perror("Failed to open TEST_FILE_NAME_2 for resizing"); + goto cleanup; + } + int new_backing_file_size = TEST_FILE_SIZE_2 * 2; // 双倍大小 + if (ftruncate(resize_fd, new_backing_file_size) < 0) { + perror("Failed to ftruncate TEST_FILE_NAME_2"); + close(resize_fd); + goto cleanup; + } + close(resize_fd); + printf("Resized %s to %d bytes.\n", TEST_FILE_NAME_2, new_backing_file_size); + + printf("Calling LOOP_SET_CAPACITY to re-evaluate loop device size...\n"); + if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0) { // 参数通常为0 + perror("Failed to set loop capacity"); + goto cleanup; + } + printf("LOOP_SET_CAPACITY called successfully.\n"); + + // 获取并验证新的容量 + status_readback = (struct loop_status64){0}; + if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { + perror("Failed to get loop status64 after LOOP_SET_CAPACITY"); + goto cleanup; + } + printf("After LOOP_SET_CAPACITY, loop current offset: %llu, sizelimit: %llu, flags: 0x%x\n", + (unsigned long long)status_readback.lo_offset, + (unsigned long long)status_readback.lo_sizelimit, + status_readback.lo_flags); + + // 重新计算预期大小。由于 lo_sizelimit 仍为非零值 (TEST_FILE_SIZE - 512), + // 并且新文件大小 (new_backing_file_size) 仍然可能小于 (lo_offset + lo_sizelimit) + // 实际有效大小应为 min(new_backing_file_size - lo_offset, lo_sizelimit) + uint64_t expected_effective_size = (new_backing_file_size > status_readback.lo_offset) ? (new_backing_file_size - status_readback.lo_offset) : 0; + expected_effective_size = (status_readback.lo_sizelimit > 0) ? + expected_effective_size < status_readback.lo_sizelimit ? expected_effective_size : status_readback.lo_sizelimit : + expected_effective_size; + + + // 实际验证 read/write 是否能访问到更大的区域。 + // 由于我们之前设置了 lo_sizelimit,它会限制设备可见的大小。 + // 如果想要反映出 ftruncate 后更大的大小,需要将 lo_sizelimit 设为 0。 + // 让我们先将 lo_sizelimit 清零,再测试 LOOP_SET_CAPACITY。 + + printf("Clearing lo_sizelimit and re-testing LOOP_SET_CAPACITY...\n"); + status.lo_sizelimit = 0; // 清零,表示不限制 + if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { + perror("Failed to clear lo_sizelimit"); + goto cleanup; + } + printf("lo_sizelimit cleared. Calling LOOP_SET_CAPACITY again.\n"); + if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0) { + perror("Failed to set loop capacity after clearing sizelimit"); + goto cleanup; + } + printf("LOOP_SET_CAPACITY called successfully after clearing sizelimit.\n"); + + if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { + perror("Failed to get loop status64 after LOOP_SET_CAPACITY (sizelimit cleared)"); + goto cleanup; + } + printf("After LOOP_SET_CAPACITY (sizelimit cleared), loop current offset: %llu, sizelimit: %llu, flags: 0x%x\n", + (unsigned long long)status_readback.lo_offset, + (unsigned long long)status_readback.lo_sizelimit, + status_readback.lo_flags); + + // 现在 lo_sizelimit 应该为 0,有效大小应为 (new_backing_file_size - lo_offset) + expected_effective_size = (new_backing_file_size > status_readback.lo_offset) ? (new_backing_file_size - status_readback.lo_offset) : 0; + + // 尝试写入到新扩展的区域 (假设扩展区域在原文件大小之后) + // 计算旧文件大小的最后一个块的偏移,然后写入一个块 + off_t write_offset_extended = (off_t)status_readback.lo_offset + TEST_FILE_SIZE_2; // 从原文件大小之后开始写 + char extended_write_buf[512] = "Extended Data!"; + + printf("Attempting to write to extended region at offset %lld (device offset: %lld)...\n", + (long long)write_offset_extended, (long long)(TEST_FILE_SIZE_2)); // loop 设备上的相对偏移 + if (lseek(loop_fd, TEST_FILE_SIZE_2, SEEK_SET) < 0) { // 在 loop 设备上的相对偏移 + perror("lseek to extended region failed"); + goto cleanup; + } + if (write(loop_fd, extended_write_buf, sizeof(extended_write_buf)) != sizeof(extended_write_buf)) { + perror("Failed to write to extended region of loop device"); + goto cleanup; + } + printf("Successfully wrote to extended region of loop device.\n"); + + // 校验第二个后端文件扩展区域的数据 + verify_fd = open(TEST_FILE_NAME_2, O_RDONLY); + if (verify_fd < 0) { + perror("Failed to reopen new backing file for extended verification"); + goto cleanup; + } + if (lseek(verify_fd, write_offset_extended, SEEK_SET) < 0) { + perror("Failed to seek new backing file for extended verification"); + close(verify_fd); + goto cleanup; + } + memset(verify_buf, 0, sizeof(verify_buf)); + if (read(verify_fd, verify_buf, sizeof(extended_write_buf)) != sizeof(extended_write_buf)) { + perror("Failed to read back from new backing file extended region"); + close(verify_fd); + goto cleanup; + } + close(verify_fd); + if (memcmp(extended_write_buf, verify_buf, sizeof(extended_write_buf)) != 0) { + fprintf(stderr, "New backing file extended data mismatch after LOOP_SET_CAPACITY.\n"); + goto cleanup; + } + printf("New backing file extended content verification passed.\n"); + + +cleanup: // 6. 清理并删除 loop 设备 + printf("\n--- Cleaning up ---\n"); printf("Clearing loop device loop%d backing file...\n", loop_minor); if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { perror("Failed to clear loop device backing file"); @@ -285,18 +485,18 @@ int main() { printf("Removing loop device loop%d...\n", loop_minor); if (ioctl(control_fd, LOOP_CTL_REMOVE, loop_minor) < 0) { perror("Failed to remove loop device"); - close(loop_fd); - close(backing_fd); - close(control_fd); - exit(EXIT_FAILURE); + // 尝试关闭所有打开的fd,即使删除失败也继续清理 + } else { + printf("Loop device loop%d removed successfully.\n", loop_minor); } - printf("Loop device loop%d removed successfully.\n", loop_minor); // 释放资源并删除测试文件 close(loop_fd); - close(backing_fd); + close(backing_fd_1); + close(backing_fd_2); close(control_fd); unlink(TEST_FILE_NAME); + unlink(TEST_FILE_NAME_2); printf("All tests completed. Cleaned up.\n"); // 校验设备删除后不可再次打开 @@ -310,4 +510,4 @@ int main() { } return 0; -} +} \ No newline at end of file From 2715d3a81cf1175ebae1f21a5196e583066bfc86 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Tue, 11 Nov 2025 14:55:52 +0800 Subject: [PATCH 18/39] =?UTF-8?q?-=20=E4=BF=AE=E6=94=B9=E4=B8=BA=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE=20-=20=E5=B8=B8=E9=87=8F=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 76 +++++++++++---------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 78d6c4fa7..6be41a6bb 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -38,9 +38,11 @@ use core::{ fmt::{Debug, Formatter}, }; use log::error; +use num_traits::FromPrimitive; use system_error::SystemError; use unified_init::macros::unified_init; const LOOP_BASENAME: &str = "loop"; +const LOOP_CONTROL_BASENAME: &str = "loop-control"; // // loop device 加密类型 // pub const LO_CRYPT_NONE: u32 = 0; // pub const LO_CRYPT_XOR: u32 = 1; @@ -55,21 +57,30 @@ const LOOP_BASENAME: &str = "loop"; // pub const MAX_LO_CRYPT: u32 = 20; // // IOCTL 命令 - 使用 0x4C ('L') -pub const LOOP_SET_FD: u32 = 0x4C00; -pub const LOOP_CLR_FD: u32 = 0x4C01; -pub const LOOP_SET_STATUS: u32 = 0x4C02; -pub const LOOP_GET_STATUS: u32 = 0x4C03; -pub const LOOP_SET_STATUS64: u32 = 0x4C04; -pub const LOOP_GET_STATUS64: u32 = 0x4C05; -pub const LOOP_CHANGE_FD: u32 = 0x4C06; -pub const LOOP_SET_CAPACITY: u32 = 0x4C07; -// pub const LOOP_SET_DIRECT_IO: u32 = 0x4C08; -// pub const LOOP_SET_BLOCK_SIZE: u32 = 0x4C09; -// pub const LOOP_CONFIGURE: u32 = 0x4C0A; - +#[repr(u32)] // 这一行告诉 Rust 将枚举表示为 u32 类型 +#[derive(Debug, FromPrimitive)] +pub enum LoopIoctl { + LoopSetFd = 0x4C00, + LoopClrFd = 0x4C01, + LoopSetStatus = 0x4C02, + LoopGetStatus = 0x4C03, + LoopSetStatus64 = 0x4C04, + LoopGetStatus64 = 0x4C05, + LoopChangeFd = 0x4C06, + LoopSetCapacity = 0x4C07, + LoopSetDirectIo = 0x4c08, + LoopSetBlockSize = 0x4c09, + LoopConfigure = 0x4c0a, +} +#[repr(u32)] +#[derive(Debug, FromPrimitive)] +pub enum LoopControlIoctl { + LoopCtlAdd = 0x4C80, + LoopCtlRemove = 0x4C81, + LoopCtlGetFree = 0x4C82, +} pub const LO_FLAGS_READ_ONLY: u32 = 1 << 0; pub const SUPPORTED_LOOP_FLAGS: u32 = LO_FLAGS_READ_ONLY; - #[repr(C)] #[derive(Default, Clone, Copy)] pub struct LoopStatus64 { @@ -78,11 +89,6 @@ pub struct LoopStatus64 { pub lo_flags: u32, pub __pad: u32, } - -// /dev/loop-control 接口 -pub const LOOP_CTL_ADD: u32 = 0x4C80; -pub const LOOP_CTL_REMOVE: u32 = 0x4C81; -pub const LOOP_CTL_GET_FREE: u32 = 0x4C82; //LoopDevice是一个虚拟的块设备,它将文件映射到块设备上. pub struct LoopDevice { inner: SpinLock, //加锁保护LoopDeviceInner @@ -542,8 +548,8 @@ impl IndexNode for LoopDevice { data: usize, _private_data: &FilePrivateData, ) -> Result { - match cmd { - LOOP_SET_FD => { + match LoopIoctl::from_u32(cmd) { + Some(LoopIoctl::LoopSetFd) => { let file_fd = data as i32; let fd_table = ProcessManager::current_pcb().fd_table(); let file = { @@ -566,31 +572,31 @@ impl IndexNode for LoopDevice { self.bind_file(inode, read_only)?; Ok(0) } - LOOP_CLR_FD => { + Some(LoopIoctl::LoopClrFd) => { self.clear_file()?; Ok(0) } - LOOP_SET_STATUS => { + Some(LoopIoctl::LoopSetStatus) => { self.set_status(data)?; Ok(0) } - LOOP_GET_STATUS => { + Some(LoopIoctl::LoopGetStatus) => { self.get_status(data)?; Ok(0) } - LOOP_SET_STATUS64 => { + Some(LoopIoctl::LoopSetStatus64) => { self.set_status64(data)?; Ok(0) } - LOOP_GET_STATUS64 => { + Some(LoopIoctl::LoopGetStatus64) => { self.get_status64(data)?; Ok(0) } - LOOP_CHANGE_FD => { + Some(LoopIoctl::LoopChangeFd) => { self.change_fd(data as i32)?; Ok(0) } - LOOP_SET_CAPACITY => { + Some(LoopIoctl::LoopSetCapacity) => { self.set_capacity(data)?; Ok(0) } @@ -882,7 +888,7 @@ pub fn loop_init() -> Result<(), SystemError> { //注册loop_control设备 device_register(loop_ctl.clone())?; log::info!("Loop control device registered."); - devfs_register("loop-control", loop_ctl.clone())?; + devfs_register(LOOP_CONTROL_BASENAME, loop_ctl.clone())?; log::info!("Loop control device initialized."); loop_mgr.loop_init(driver)?; Ok(()) @@ -890,7 +896,7 @@ pub fn loop_init() -> Result<(), SystemError> { impl Driver for LoopDeviceDriver { fn id_table(&self) -> Option { - Some(IdTable::new("loop".to_string(), None)) + Some(IdTable::new(LOOP_BASENAME.to_string(), None)) } fn devices(&self) -> Vec> { @@ -952,7 +958,7 @@ impl KObject for LoopDeviceDriver { } fn name(&self) -> String { - "loop".to_string() + LOOP_BASENAME.to_string() } fn set_name(&self, _name: String) { @@ -1239,8 +1245,8 @@ impl IndexNode for LoopControlDevice { data: usize, _private_data: &FilePrivateData, ) -> Result { - match cmd { - LOOP_CTL_ADD => { + match LoopControlIoctl::from_u32(cmd) { + Some(LoopControlIoctl::LoopCtlAdd) => { log::info!("Starting LOOP_CTL_ADD ioctl"); let requested_index = data as u32; let loop_dev = if requested_index == u32::MAX { @@ -1259,12 +1265,12 @@ impl IndexNode for LoopControlDevice { }; Ok(minor as usize) } - LOOP_CTL_REMOVE => { + Some(LoopControlIoctl::LoopCtlRemove) => { let minor_to_remove = data as u32; self.loop_mgr.loop_remove(minor_to_remove)?; Ok(0) } - LOOP_CTL_GET_FREE => match self.loop_mgr.find_free_minor() { + Some(LoopControlIoctl::LoopCtlGetFree) => match self.loop_mgr.find_free_minor() { Some(minor) => Ok(minor as usize), None => Err(SystemError::ENOSPC), }, @@ -1406,7 +1412,7 @@ impl KObject for LoopControlDevice { } fn name(&self) -> String { - "loop-control".to_string() + LOOP_CONTROL_BASENAME.to_string() } fn set_name(&self, _name: String) { From 6df9ba3cca9a88e3c2c8c314123d49c5177e5ad5 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Tue, 11 Nov 2025 15:35:23 +0800 Subject: [PATCH 19/39] =?UTF-8?q?-=20=E4=BF=AE=E6=94=B9major=E7=AE=A1?= =?UTF-8?q?=E7=90=86=20-=20=E4=BF=AE=E6=94=B9=E4=B8=80=E4=BA=9B=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=EF=BC=8C=E4=BD=BF=E5=85=B6=E6=9B=B4=E7=AC=A6=E5=90=88?= =?UTF-8?q?rust=E6=B3=A8=E9=87=8A=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 228 +++++++++++------- .../src/driver/base/device/device_number.rs | 1 + 2 files changed, 147 insertions(+), 82 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 6be41a6bb..382286459 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -43,21 +43,7 @@ use system_error::SystemError; use unified_init::macros::unified_init; const LOOP_BASENAME: &str = "loop"; const LOOP_CONTROL_BASENAME: &str = "loop-control"; -// // loop device 加密类型 -// pub const LO_CRYPT_NONE: u32 = 0; -// pub const LO_CRYPT_XOR: u32 = 1; -// pub const LO_CRYPT_DES: u32 = 2; -// pub const LO_CRYPT_FISH2: u32 = 3; // Twofish encryption -// pub const LO_CRYPT_BLOW: u32 = 4; -// pub const LO_CRYPT_CAST128: u32 = 5; -// pub const LO_CRYPT_IDEA: u32 = 6; -// pub const LO_CRYPT_DUMMY: u32 = 9; -// pub const LO_CRYPT_SKIPJACK: u32 = 10; -// pub const LO_CRYPT_CRYPTOAPI: u32 = 18; -// pub const MAX_LO_CRYPT: u32 = 20; - -// // IOCTL 命令 - 使用 0x4C ('L') -#[repr(u32)] // 这一行告诉 Rust 将枚举表示为 u32 类型 +#[repr(u32)] #[derive(Debug, FromPrimitive)] pub enum LoopIoctl { LoopSetFd = 0x4C00, @@ -89,54 +75,35 @@ pub struct LoopStatus64 { pub lo_flags: u32, pub __pad: u32, } -//LoopDevice是一个虚拟的块设备,它将文件映射到块设备上. pub struct LoopDevice { - inner: SpinLock, //加锁保护LoopDeviceInner - //有主设备次设备号 + inner: SpinLock, block_dev_meta: BlockDevMeta, - //dev_id: Arc, - locked_kobj_state: LockedKObjectState, //对Kobject状态的锁 - self_ref: Weak, //对自身的弱引用 - fs: RwLock>, //文件系统弱引用 + locked_kobj_state: LockedKObjectState, + self_ref: Weak, + fs: RwLock>, parent: RwLock>, } #[derive(Debug, Clone)] pub struct LoopPrivateData { - //索引号 pub parms: u32, } -//Inner内数据会改变所以加锁 pub struct LoopDeviceInner { - // 设备名称 Major和Minor pub device_number: DeviceNumber, - //状态管理 state: LoopState, state_lock: SpinLock<()>, - //后端文件相关 - // 关联的文件节点 pub file_inode: Option>, - // 文件大小 pub file_size: usize, - // 数据偏移量 pub offset: usize, - // 数据大小限制(0 表示不限制) pub size_limit: usize, - // 标志位 pub flags: u32, - // 是否只读 pub read_only: bool, - // KObject的公共数据 pub kobject_common: KObjectCommonData, - // 设备的公共数据 pub device_common: DeviceCommonData, - //工作管理 todo - //work_queue: Option>, } impl LoopDeviceInner { fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { let _guard = self.state_lock.lock(); - // 状态转换检查 match (&self.state, &new_state) { (LoopState::Unbound, LoopState::Bound) => {} (LoopState::Bound, LoopState::Unbound) => {} @@ -167,12 +134,21 @@ impl Debug for LoopDevice { } impl LoopDevice { fn inner(&'_ self) -> SpinLockGuard<'_, LoopDeviceInner> { - // 获取 LoopDeviceInner 的自旋锁 self.inner.lock() } - //注册一个新的空loop设备占位 + /// # 功能 + /// + /// 创建一个未绑定文件的 loop 设备实例。 + /// + /// ## 参数 + /// + /// - `devname`: 设备名称。 + /// - `minor`: 次设备号。 + /// + /// ## 返回值 + /// - `Some(Arc)`: 成功创建的 loop 设备。 + /// - `None`: 内存不足或创建失败。 pub fn new_empty_loop_device(devname: DevName, minor: u32) -> Option> { - // 创建一个空的 LoopDevice let dev = Arc::new_cyclic(|self_ref| Self { inner: SpinLock::new(LoopDeviceInner { file_inode: None, // 默认的虚拟 inode @@ -188,8 +164,7 @@ impl LoopDevice { state_lock: SpinLock::new(()), //work_queue: None, }), - //只用重复8次,就会有从0-7八个次设备号 - block_dev_meta: BlockDevMeta::new(devname, Major::new(7)), // Loop 设备主设备号为 7 + block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), // Loop 设备主设备号为 7 locked_kobj_state: LockedKObjectState::default(), self_ref: self_ref.clone(), fs: RwLock::new(Weak::default()), @@ -198,7 +173,17 @@ impl LoopDevice { Some(dev) } - /// 设置 loop 设备关联的文件 + /// # 功能 + /// + /// 为 loop 设备绑定后端文件并重置相关状态。 + /// + /// ## 参数 + /// + /// - `file_inode`: 需要绑定的文件节点。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功绑定文件。 + /// - `Err(SystemError)`: 绑定失败的错误原因。 pub fn set_file(&self, file_inode: Arc) -> Result<(), SystemError> { let metadata = file_inode.metadata()?; if metadata.size < 0 { @@ -245,7 +230,18 @@ impl LoopDevice { pub fn is_bound(&self) -> bool { matches!(self.inner().state, LoopState::Bound) } - + /// # 功能 + /// + /// 将文件绑定到 loop 设备并设置访问权限。 + /// + /// ## 参数 + /// + /// - `file_inode`: 需要绑定的文件节点。 + /// - `read_only`: 是否以只读方式绑定。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功绑定。 + /// - `Err(SystemError)`: 绑定失败的原因。 pub fn bind_file( &self, file_inode: Arc, @@ -269,7 +265,17 @@ impl LoopDevice { self.recalc_effective_size()?; Ok(()) } - + /// # 功能 + /// + /// 清除 loop 设备的文件绑定并复位状态。 + /// + /// ## 参数 + /// + /// - 无。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功清除。 + /// - `Err(SystemError)`: 清除过程中的错误。 pub fn clear_file(&self) -> Result<(), SystemError> { let mut inner = self.inner(); match inner.state { @@ -286,20 +292,7 @@ impl LoopDevice { inner.flags = 0; Ok(()) } - - fn set_status64(&self, user_ptr: usize) -> Result<(), SystemError> { - if user_ptr == 0 { - return Err(SystemError::EINVAL); - } - - let reader = UserBufferReader::new::( - user_ptr as *const LoopStatus64, - core::mem::size_of::(), - true, - )?; - let mut info = LoopStatus64::default(); - reader.copy_one_from_user(&mut info, 0)?; - + fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { if info.lo_offset % LBA_SIZE as u64 != 0 { return Err(SystemError::EINVAL); } @@ -312,7 +305,31 @@ impl LoopDevice { if info.lo_flags & !SUPPORTED_LOOP_FLAGS != 0 { return Err(SystemError::EINVAL); } + Ok(()) + } + /// 设置 loop 设备的状态(64 位版本)。 + /// + /// ## 参数 + /// + /// - `user_ptr`: 用户空间传入的 `LoopStatus64` 结构体指针。 + /// + /// ## 返回值 + /// - `Ok(())`: 状态设置成功。 + /// - `Err(SystemError::EINVAL)`: 无效的参数或标志位。 + /// - `Err(SystemError::ENXIO)`: 设备未绑定或已卸载。 + fn set_status64(&self, user_ptr: usize) -> Result<(), SystemError> { + if user_ptr == 0 { + return Err(SystemError::EINVAL); + } + let reader = UserBufferReader::new::( + user_ptr as *const LoopStatus64, + core::mem::size_of::(), + true, + )?; + let mut info = LoopStatus64::default(); + reader.copy_one_from_user(&mut info, 0)?; + Self::validate_loop_status64_params(&info)?; let new_offset = info.lo_offset as usize; let new_limit = if info.lo_sizelimit == 0 { 0 @@ -353,7 +370,18 @@ impl LoopDevice { Ok(()) } - + /// # 功能 + /// + /// 获取 loop 设备的 LoopStatus64 信息并写回用户态。 + /// + /// ## 参数 + /// + /// - `user_ptr`: 用户态缓冲区地址。 + /// + /// ## 返回值 + /// - `Ok(())`: 信息写回成功。 + /// - `Err(SystemError)`: 读取状态失败。 + /// fn get_status64(&self, user_ptr: usize) -> Result<(), SystemError> { if user_ptr == 0 { return Err(SystemError::EINVAL); @@ -390,6 +418,17 @@ impl LoopDevice { fn get_status(&self, user_ptr: usize) -> Result<(), SystemError> { self.get_status64(user_ptr) } + /// # 功能 + /// + /// 将 loop 设备切换到新的文件描述符。 + /// + /// ## 参数 + /// + /// - `new_file_fd`: 新的文件描述符。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功切换。 + /// - `Err(SystemError)`: 切换失败原因。 fn change_fd(&self, new_file_fd: i32) -> Result<(), SystemError> { let fd_table = ProcessManager::current_pcb().fd_table(); let file = { @@ -477,7 +516,6 @@ impl KObject for LoopDevice { } } -//对loopdevice进行抽象 impl IndexNode for LoopDevice { fn fs(&self) -> Arc { todo!() @@ -525,10 +563,10 @@ impl IndexNode for LoopDevice { }; let metadata = Metadata { dev_id: 0, - inode_id: InodeId::new(0), // Loop 设备通常没有实际的 inode ID + inode_id: InodeId::new(0), size: self.inner().file_size as i64, blk_size: LBA_SIZE, - blocks: (self.inner().file_size + LBA_SIZE - 1) / LBA_SIZE, // 计算块数 + blocks: (self.inner().file_size + LBA_SIZE - 1) / LBA_SIZE, atime: file_metadata.atime, mtime: file_metadata.mtime, ctime: file_metadata.ctime, @@ -536,8 +574,8 @@ impl IndexNode for LoopDevice { file_type: crate::filesystem::vfs::FileType::BlockDevice, mode: crate::filesystem::vfs::syscall::ModeType::from_bits_truncate(0o644), nlinks: 1, - uid: 0, // 默认用户 ID - gid: 0, // 默认组 ID + uid: 0, + gid: 0, raw_dev: self.inner().device_number, }; Ok(metadata.clone()) @@ -695,7 +733,6 @@ impl BlockDevice for LoopDevice { let blocks = if inner.file_size == 0 { 0 } else { - //饱和式加法,溢出返回类型最大值 inner.file_size.saturating_add(LBA_SIZE - 1) / LBA_SIZE }; drop(inner); @@ -799,12 +836,11 @@ impl BlockDevice for LoopDevice { } fn sync(&self) -> Result<(), SystemError> { - // Loop 设备的同步操作 Ok(()) } fn blk_size_log2(&self) -> u8 { - 9 // 512 bytes = 2^9 + 9 } fn as_any_ref(&self) -> &dyn Any { @@ -820,7 +856,6 @@ impl BlockDevice for LoopDevice { } fn partitions(&self) -> Vec> { - // Loop 设备通常不支持分区 Vec::new() } } @@ -859,33 +894,39 @@ impl LoopDeviceDriver { fn inner(&'_ self) -> SpinLockGuard<'_, InnerLoopDeviceDriver> { self.inner.lock() } + /// # 功能 + /// + /// 创建并注册指定次设备号的 loop 设备。 + /// + /// ## 参数 + /// + /// - `minor`: 目标次设备号。 + /// + /// ## 返回值 + /// - `Ok(Arc)`: 成功创建并注册的设备。 + /// - `Err(SystemError)`: 创建或注册失败原因。 fn new_loop_device(&self, minor: usize) -> Result, SystemError> { let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor); let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) .ok_or_else(|| { error!("Failed to create loop device for minor {}", minor); - SystemError::ENOMEM // 如果创建失败,返回具体的错误 + SystemError::ENOMEM })?; log::info!( "Registering loop device: {}", loop_dev.block_dev_meta.devname ); - // 先注册到块设备管理器,让它可用 block_dev_manager().register(loop_dev.clone())?; - - // 返回创建的设备,让 LoopManager 能够存储它 Ok(loop_dev) } } -//初始化函数,注册1个loopcontrol设备和8个loop设备备用 use crate::init::initcall::INITCALL_DEVICE; #[unified_init(INITCALL_DEVICE)] pub fn loop_init() -> Result<(), SystemError> { let loop_mgr = Arc::new(LoopManager::new()); - // 获取 LoopDeviceDriver 的单例并调用初始化函数 let driver = LoopDeviceDriver::new(); let loop_ctl = LoopControlDevice::new(loop_mgr.clone()); - //注册loop_control设备 + device_register(loop_ctl.clone())?; log::info!("Loop control device registered."); devfs_register(LOOP_CONTROL_BASENAME, loop_ctl.clone())?; @@ -986,8 +1027,8 @@ pub struct LoopManagerInner { next_free_minor: u32, } impl LoopManager { - const MAX_DEVICES: usize = 256; // 支持的最大 loop 设备数量 - const MAX_INIT_DEVICES: usize = 8; //初始化loop设备数量 + const MAX_DEVICES: usize = 256; + const MAX_INIT_DEVICES: usize = 8; pub fn new() -> Self { Self { inner: SpinLock::new(LoopManagerInner { @@ -1002,6 +1043,17 @@ impl LoopManager { /* 请求队列,工作队列未实现 */ + /// # 功能 + /// + /// 根据请求的次设备号分配或复用 loop 设备。 + /// + /// ## 参数 + /// + /// - `requested_minor`: 指定的次设备号,`None` 表示自动分配。 + /// + /// ## 返回值 + /// - `Ok(Arc)`: 成功获得的设备。 + /// - `Err(SystemError)`: 无可用设备或参数错误。 pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { let mut inner = self.inner(); match requested_minor { @@ -1009,6 +1061,18 @@ impl LoopManager { None => self.loop_add_first_available_locked(&mut inner), } } + /// # 功能 + /// + /// 在锁作用域内分配指定次设备号的 loop 设备。 + /// + /// ## 参数 + /// + /// - `inner`: 管理器内部状态锁。 + /// - `minor`: 目标次设备号。 + /// + /// ## 返回值 + /// - `Ok(Arc)`: 成功获得的设备实例。 + /// - `Err(SystemError)`: 参数无效或设备已被占用。 fn loop_add_specific_locked( &self, inner: &mut LoopManagerInner, @@ -1230,9 +1294,9 @@ impl IndexNode for LoopControlDevice { file_type: FileType::CharDevice, // 字符设备类型 mode: ModeType::from_bits_truncate(0o600), // 读写权限,仅owner可访问 nlinks: 1, - uid: 0, // root用户 - gid: 0, // root组 - raw_dev: DeviceNumber::new(Major::new(10), 237), // loop-control设备号通常是(10, 237) + uid: 0, // root用户 + gid: 0, // root组 + raw_dev: DeviceNumber::new(Major::LOOP_CONTROL_MAJOR, 237), // loop-control设备号通常是(10, 237) }; Ok(metadata) } diff --git a/kernel/src/driver/base/device/device_number.rs b/kernel/src/driver/base/device/device_number.rs index 20f0183d6..79f19d1cb 100644 --- a/kernel/src/driver/base/device/device_number.rs +++ b/kernel/src/driver/base/device/device_number.rs @@ -43,6 +43,7 @@ impl Major { self.0 } pub const LOOP_MAJOR: Self = Self::new(7); + pub const LOOP_CONTROL_MAJOR: Self = Self::new(10); } impl Hash for Major { From 3431ff18e23103968d3ccff76d939f7580b7ec8a Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 12 Nov 2025 01:46:33 +0800 Subject: [PATCH 20/39] =?UTF-8?q?-=20add=20idallocator=EF=BC=8C=E6=8A=8A?= =?UTF-8?q?=E5=92=8Cid=E5=92=8Cminor=E8=A7=A3=E8=80=A6=EF=BC=8C=E5=87=8F?= =?UTF-8?q?=E5=B0=91=E9=81=8D=E5=8E=86=E7=9A=84=E6=AC=A1=E6=95=B0=20-=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B3=A8=E9=87=8A=E4=B8=BArust=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 224 +++++++++++++------- 1 file changed, 148 insertions(+), 76 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 382286459..3e7a9590b 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -37,12 +37,13 @@ use core::{ any::Any, fmt::{Debug, Formatter}, }; -use log::error; +use ida::IdAllocator; use num_traits::FromPrimitive; use system_error::SystemError; use unified_init::macros::unified_init; const LOOP_BASENAME: &str = "loop"; const LOOP_CONTROL_BASENAME: &str = "loop-control"; +pub const LOOP_CONTROL_MINOR: u32 = 237; #[repr(u32)] #[derive(Debug, FromPrimitive)] pub enum LoopIoctl { @@ -76,6 +77,8 @@ pub struct LoopStatus64 { pub __pad: u32, } pub struct LoopDevice { + id: usize, + minor: u32, inner: SpinLock, block_dev_meta: BlockDevMeta, locked_kobj_state: LockedKObjectState, @@ -128,6 +131,7 @@ pub enum LoopState { impl Debug for LoopDevice { fn fmt(&'_ self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("LoopDevice") + .field("id", &self.id) .field("devname", &self.block_dev_meta.devname) .finish() } @@ -136,6 +140,12 @@ impl LoopDevice { fn inner(&'_ self) -> SpinLockGuard<'_, LoopDeviceInner> { self.inner.lock() } + pub fn id(&self) -> usize { + self.id + } + pub fn minor(&self) -> u32 { + self.minor + } /// # 功能 /// /// 创建一个未绑定文件的 loop 设备实例。 @@ -148,8 +158,10 @@ impl LoopDevice { /// ## 返回值 /// - `Some(Arc)`: 成功创建的 loop 设备。 /// - `None`: 内存不足或创建失败。 - pub fn new_empty_loop_device(devname: DevName, minor: u32) -> Option> { + pub fn new_empty_loop_device(devname: DevName, id: usize, minor: u32) -> Option> { let dev = Arc::new_cyclic(|self_ref| Self { + id, + minor, inner: SpinLock::new(LoopDeviceInner { file_inode: None, // 默认的虚拟 inode file_size: 0, @@ -894,31 +906,6 @@ impl LoopDeviceDriver { fn inner(&'_ self) -> SpinLockGuard<'_, InnerLoopDeviceDriver> { self.inner.lock() } - /// # 功能 - /// - /// 创建并注册指定次设备号的 loop 设备。 - /// - /// ## 参数 - /// - /// - `minor`: 目标次设备号。 - /// - /// ## 返回值 - /// - `Ok(Arc)`: 成功创建并注册的设备。 - /// - `Err(SystemError)`: 创建或注册失败原因。 - fn new_loop_device(&self, minor: usize) -> Result, SystemError> { - let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor); - let loop_dev = LoopDevice::new_empty_loop_device(devname.clone(), minor as u32) - .ok_or_else(|| { - error!("Failed to create loop device for minor {}", minor); - SystemError::ENOMEM - })?; - log::info!( - "Registering loop device: {}", - loop_dev.block_dev_meta.devname - ); - block_dev_manager().register(loop_dev.clone())?; - Ok(loop_dev) - } } use crate::init::initcall::INITCALL_DEVICE; #[unified_init(INITCALL_DEVICE)] @@ -1024,6 +1011,7 @@ pub struct LoopManager { } pub struct LoopManagerInner { devices: [Option>; LoopManager::MAX_DEVICES], + id_alloc: IdAllocator, next_free_minor: u32, } impl LoopManager { @@ -1033,6 +1021,8 @@ impl LoopManager { Self { inner: SpinLock::new(LoopManagerInner { devices: [const { None }; Self::MAX_DEVICES], + id_alloc: IdAllocator::new(0, Self::MAX_DEVICES) + .expect("create IdAllocator failed"), next_free_minor: 0, }), } @@ -1040,6 +1030,49 @@ impl LoopManager { fn inner(&'_ self) -> SpinLockGuard<'_, LoopManagerInner> { self.inner.lock() } + #[inline] + fn alloc_id_locked(inner: &mut LoopManagerInner) -> Option { + inner.id_alloc.alloc() + } + #[inline] + fn free_id_locked(inner: &mut LoopManagerInner, id: usize) { + if id < Self::MAX_DEVICES && inner.id_alloc.exists(id) { + inner.id_alloc.free(id); + } + } + #[inline] + pub fn format_name(id: usize) -> DevName { + DevName::new(format!("{}{}", LOOP_BASENAME, id), id) + } + fn find_device_by_minor_locked( + inner: &LoopManagerInner, + minor: u32, + ) -> Option> { + inner + .devices + .iter() + .flatten() + .find(|device| device.minor() == minor) + .map(Arc::clone) + } + + fn find_unused_minor_locked(inner: &LoopManagerInner) -> Option { + let mut candidate = inner.next_free_minor; + for _ in 0..Self::MAX_DEVICES as u32 { + let mut used = false; + for dev in inner.devices.iter().flatten() { + if dev.minor() == candidate { + used = true; + break; + } + } + if !used { + return Some(candidate); + } + candidate = (candidate + 1) % Self::MAX_DEVICES as u32; + } + None + } /* 请求队列,工作队列未实现 */ @@ -1082,62 +1115,81 @@ impl LoopManager { return Err(SystemError::EINVAL); } - if let Some(device) = inner.devices[minor as usize].as_ref() { + if let Some(device) = Self::find_device_by_minor_locked(inner, minor) { if device.is_bound() { return Err(SystemError::EEXIST); } - inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; - return Ok(device.clone()); + return Ok(device); } - self.create_and_register_device_locked(inner, minor) + let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; + match self.create_and_register_device_locked(inner, id, minor) { + Ok(device) => Ok(device), + Err(e) => { + Self::free_id_locked(inner, id); + Err(e) + } + } } fn loop_add_first_available_locked( &self, inner: &mut LoopManagerInner, ) -> Result, SystemError> { - for _ in 0..Self::MAX_DEVICES { - let idx = inner.next_free_minor; - inner.next_free_minor = (inner.next_free_minor + 1) % Self::MAX_DEVICES as u32; - - match &inner.devices[idx as usize] { - Some(device) if !device.is_bound() => return Ok(device.clone()), - Some(_) => continue, - None => { - return self.create_and_register_device_locked(inner, idx); - } - } + if let Some(device) = inner + .devices + .iter() + .flatten() + .find(|device| !device.is_bound()) + { + return Ok(device.clone()); } - Err(SystemError::ENOSPC) + let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; + let minor = match Self::find_unused_minor_locked(inner) { + Some(minor) => minor, + None => { + Self::free_id_locked(inner, id); + return Err(SystemError::ENOSPC); + } + }; + let result = self.create_and_register_device_locked(inner, id, minor); + if result.is_err() { + Self::free_id_locked(inner, id); + } + result } fn create_and_register_device_locked( &self, inner: &mut LoopManagerInner, + id: usize, minor: u32, ) -> Result, SystemError> { if minor >= Self::MAX_DEVICES as u32 { return Err(SystemError::EINVAL); } - let devname = DevName::new(format!("{}{}", LOOP_BASENAME, minor), minor as usize); + let devname = Self::format_name(id); let loop_dev = - LoopDevice::new_empty_loop_device(devname, minor).ok_or(SystemError::ENOMEM)?; + LoopDevice::new_empty_loop_device(devname, id, minor).ok_or(SystemError::ENOMEM)?; if let Err(e) = block_dev_manager().register(loop_dev.clone()) { if e == SystemError::EEXIST { - if let Some(existing) = inner.devices[minor as usize].clone() { + if let Some(existing) = inner.devices[id].clone() { return Ok(existing); } } return Err(e); } - inner.devices[minor as usize] = Some(loop_dev.clone()); + inner.devices[id] = Some(loop_dev.clone()); inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; - log::info!("Loop device loop{} added successfully.", minor); + log::info!( + "Loop device id {} (minor {}) added successfully.", + id, + minor + ); Ok(loop_dev) } pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { @@ -1147,13 +1199,10 @@ impl LoopManager { let device = { let inner = self.inner(); - inner.devices[minor as usize].clone() - }; - - let device = match device { - Some(dev) => dev, - None => return Err(SystemError::ENODEV), - }; + Self::find_device_by_minor_locked(&inner, minor) + } + .ok_or(SystemError::ENODEV)?; + let id = device.id(); { let mut guard = device.inner(); @@ -1178,32 +1227,43 @@ impl LoopManager { { let mut inner = self.inner(); - inner.devices[minor as usize] = None; + inner.devices[id] = None; + Self::free_id_locked(&mut inner, id); inner.next_free_minor = minor; } - log::info!("Loop device loop{} removed.", minor); + log::info!("Loop device id {} (minor {}) removed.", id, minor); Ok(()) } pub fn find_free_minor(&self) -> Option { - let mut inner = self.inner(); - for _ in 0..Self::MAX_DEVICES { - let idx = inner.next_free_minor; - inner.next_free_minor = (inner.next_free_minor + 1) % Self::MAX_DEVICES as u32; - match &inner.devices[idx as usize] { - Some(device) if device.is_bound() => continue, - _ => return Some(idx), + let inner = self.inner(); + 'outer: for minor in 0..Self::MAX_DEVICES as u32 { + for dev in inner.devices.iter().flatten() { + if dev.minor() == minor { + if !dev.is_bound() { + return Some(minor); + } + continue 'outer; + } } + return Some(minor); } None } - pub fn loop_init(&self, driver: Arc) -> Result<(), SystemError> { + pub fn loop_init(&self, _driver: Arc) -> Result<(), SystemError> { let mut inner = self.inner(); // 注册 loop 设备 for minor in 0..Self::MAX_INIT_DEVICES { - let loop_dev = driver.new_loop_device(minor)?; - inner.devices[minor] = Some(loop_dev); + let minor_u32 = minor as u32; + if Self::find_device_by_minor_locked(&inner, minor_u32).is_some() { + continue; + } + let id = Self::alloc_id_locked(&mut inner).ok_or(SystemError::ENOSPC)?; + if let Err(e) = self.create_and_register_device_locked(&mut inner, id, minor_u32) { + Self::free_id_locked(&mut inner, id); + return Err(e); + } } log::info!("Loop devices initialized"); @@ -1277,26 +1337,38 @@ impl IndexNode for LoopControlDevice { fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { Ok(()) } + /// # 功能 + /// + /// 获取 loop-control 设备的元数据信息。 + /// + /// ## 参数 + /// + /// - 无 + /// + /// ## 返回值 + /// - `Ok(Metadata)`: 成功获取设备元数据 + /// - 包含设备类型、权限、设备号等信息 + /// fn metadata(&self) -> Result { use crate::filesystem::vfs::{syscall::ModeType, FileType, InodeId}; use crate::time::PosixTimeSpec; let metadata = Metadata { dev_id: 0, - inode_id: InodeId::new(0), // Loop control 设备的 inode ID - size: 0, // 字符设备大小通常为0 - blk_size: 0, // 字符设备不使用块大小 - blocks: 0, // 字符设备不使用块数 + inode_id: InodeId::new(0), + size: 0, + blk_size: 0, + blocks: 0, atime: PosixTimeSpec::default(), mtime: PosixTimeSpec::default(), ctime: PosixTimeSpec::default(), btime: PosixTimeSpec::default(), - file_type: FileType::CharDevice, // 字符设备类型 - mode: ModeType::from_bits_truncate(0o600), // 读写权限,仅owner可访问 + file_type: FileType::CharDevice, + mode: ModeType::from_bits_truncate(0o600), nlinks: 1, - uid: 0, // root用户 - gid: 0, // root组 - raw_dev: DeviceNumber::new(Major::LOOP_CONTROL_MAJOR, 237), // loop-control设备号通常是(10, 237) + uid: 0, + gid: 0, + raw_dev: DeviceNumber::new(Major::LOOP_CONTROL_MAJOR, LOOP_CONTROL_MINOR), }; Ok(metadata) } From 332dd9c02ddf1ff0b42a963ff6b5adde9e2b4108 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 12 Nov 2025 02:03:42 +0800 Subject: [PATCH 21/39] - fix docs --- docs/kernel/device/loop_device.md | 274 +++++++++++------------- kernel/src/driver/base/block/manager.rs | 6 - 2 files changed, 126 insertions(+), 154 deletions(-) diff --git a/docs/kernel/device/loop_device.md b/docs/kernel/device/loop_device.md index 9b37382ac..5ec1469f6 100644 --- a/docs/kernel/device/loop_device.md +++ b/docs/kernel/device/loop_device.md @@ -1,149 +1,127 @@ -# Loop Device 模块与测试详解 - -本文档总结 `feat/loop-device` 分支中 loop 设备子系统与配套用户态测试的现状,用于 PR 审阅和后续开发。内容包括模块目标、组件设计、已完成功能、未完项、测试覆盖及下一步建议。 - -## 模块定位与目标 - -Loop 设备用于将普通文件映射为内核可识别的块设备,实现与 Linux `loop` 驱动类似的功能,适用于: - -- 将镜像文件挂载到 DragonOS 的虚拟块层,便于文件系统测试或容器环境。 -- 通过 `IOCTL` 动态绑定/解绑后端文件,无需内核重新加载驱动。 -- 支持只读标记、偏移映射、大小限制等基础特性,为后续扩展(加密、分片)打基础。 - -## 组件结构概览 - -| 组件 | 角色 | 关键字段/方法 | 说明 | -| :------------------ | :------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | -| `LoopDevice` | 块设备实现 | `inner: SpinLock`、`block_dev_meta`、`bind_file`、`read_at_sync`、`write_at_sync` | 针对单个 loopX 设备的核心逻辑,提供块读写接口,并维护设备状态和元数据。 | -| `LoopDeviceInner` | 设备内部状态 | `device_number`、`state`、`file_inode`、`file_size`、`offset`、`size_limit`、`flags`、`read_only` | 受自旋锁保护;记录绑定文件、状态机、映射参数和只读标志。 | -| `LoopDeviceDriver` | 驱动入口 | `new_loop_device` | 负责创建空设备、向块设备管理器注册,并作为内核对象自身具备 KObject 和 Driver 特性。 | -| `LoopManager` | 管理器 | `devices: [Option>; 256]`、`loop_add`、`loop_remove`、`find_free_minor` | 管理最多 256 个 loop 设备,初始化时预注册 0-7,共 8 个占位设备,并提供动态分配和回收接口。 | -| `LoopControlDevice` | 字符控制接口 | `ioctl` (LOOP_CTL_ADD/REMOVE/GET_FREE) | 对应 `/dev/loop-control` 节点,供用户态分配、回收,撤销 loop 设备。 | -| `LoopStatus64` | IOCTL 数据结构 | `lo_offset`、`lo_sizelimit`、`lo_flags` | 对标 Linux `LOOP_SET_STATUS64` 数据结构,用于用户态和内核态之间传递 loop 设备参数。 | - -### 状态机 (`LoopState`) - -Loop 设备以 `LoopState` 枚举管理生命周期: - -| 当前状态 | 允许迁移 | 场景 | -| :--------- | :-------------------- | :-------------------------------------- | -| `Unbound` | `Bound`、`Deleting` | 空闲设备,可绑定或直接删除。 | -| `Bound` | `Unbound`、`Rundown` | 已关联后端文件;解绑或进入下线流程。 | -| `Rundown` | `Deleting`、`Unbound` | 下线/清理阶段;可安全删除或回到未绑定。 | -| `Deleting` | — | 正在注销,拒绝再次绑定。 | - -状态转换由 `LoopDeviceInner::set_state` 强制检查,防止非法跃迁,并由 `state_lock` 自旋锁保护。 - -### I/O 数据路径 - -1. **设备绑定**: - * `LOOP_SET_FD` IOCTL 接收一个文件描述符,通过 `ProcessManager::current_pcb().fd_table()` 获取对应的 `File` 和 `IndexNode`。 - * `LoopDevice::bind_file` 方法根据文件模式判断是否只读,并调用 `set_file` 将后端文件 inode 关联到 LoopDevice,同时设置 `flags` 和 `read_only` 状态。 - * 最终会调用 `recalc_effective_size` 重新计算设备可见大小。 -2. **设备参数配置**: - * `LOOP_SET_STATUS64` IOCTL 接收 `LoopStatus64` 结构体,用于配置 `offset`(偏移量)、`size_limit`(大小限制)和 `lo_flags`(只读等标志)。 - * 内核会进行参数校验(如偏移和限制是否 LBA_SIZE 对齐,flags 是否支持)。 - * 成功设置后,同样会调用 `recalc_effective_size` 更新设备可见容量。 -3. **块读写**: - * ioctl的读写操作会先传入`Gendisk`然后再通过`read`函数传递到`loopX`的`read`or `write`函数 - * 块设备的读写操作 (`BlockDevice::read_at_sync` / `write_at_sync`) 将 LBA 地址和长度转换为后端文件的字节偏移和长度。 - * 计算后的文件偏移量会加上 `LoopDeviceInner::offset`。 - * 读写操作通过后端文件 `IndexNode::read_at`/`write_at` 实现。 - * 如果设备被标记为只读 (`inner.read_only` 为 true),`write_at_sync` 将返回 `SystemError::EROFS`。 - * 写入成功后,会再次调用 `recalc_effective_size` 确保块层容量与后端文件状态一致。 - -### 设备控制接口 - -- **块设备 IOCTL** (针对 `/dev/loopX` 节点): - * `LOOP_SET_FD`:绑定一个文件描述符到 loop 设备。 - * `LOOP_CLR_FD`:解绑当前关联的文件,并将 loop 设备置于 `Unbound` 状态。 - * `LOOP_SET_STATUS` / `LOOP_GET_STATUS`:设置/获取 32 位状态,目前直接委托给 `_STATUS64` 版本。 - * `LOOP_SET_STATUS64` / `LOOP_GET_STATUS64`:设置/获取 64 位状态,包括文件偏移、大小限制和标志位。 - * `LOOP_CHANGE_FD`: 更换后端文件描述符,同时更新只读状态。 - * `LOOP_SET_CAPACITY`: 重新计算设备容量,通常在后端文件大小或参数改变后调用。 -- **控制字符设备 IOCTL** (针对 `/dev/loop-control` 节点): - * `LOOP_CTL_ADD`:根据用户请求的 minor 号(或自动查找空闲 minor)分配一个新的 `LoopDevice`。 - * `LOOP_CTL_REMOVE`:根据 minor 号移除一个 loop 设备,将其从块设备管理器中注销。 - * `LOOP_CTL_GET_FREE`:查找并返回一个当前未绑定后端文件的空闲 loop 设备的 minor 号。 - -## 已完成的工作 - -### 内核部分 - -- `LoopDevice` 作为虚拟块设备,实现了 `BlockDevice`、`Device`、`KObject` 和 `IndexNode` 接口,具备完整的块设备读写能力。 -- 引入 `LoopState` 状态机,并通过 `SpinLock` 保护其转换,确保设备生命周期管理严谨。 -- `LoopDevice` 支持文件偏移 (`offset`) 和大小限制 (`size_limit`),使得用户可以精确控制 loop 设备可见的后端文件区域。 -- 实现了 `LO_FLAGS_READ_ONLY` 标志,在 `write_at_sync` 路径中正确阻止写入并返回 `EROFS`。 -- `LoopManager` 负责集中管理 `LoopDevice` 实例,初始化时预注册 8 个占位设备,并支持动态分配和回收多达 256 个设备。 -- `LoopControlDevice` 作为字符设备,提供了用户态与 `LoopManager` 交互的控制接口 (`/dev/loop-control`),支持 `LOOP_CTL_ADD`、`LOOP_CTL_REMOVE` 和 `LOOP_CTL_GET_FREE` IOCTL。 -- `LOOP_SET_FD`, `LOOP_CLR_FD`, `LOOP_SET_STATUS64`, `LOOP_GET_STATUS64`, `LOOP_CHANGE_FD`, `LOOP_SET_CAPACITY` 等关键块设备 IOCTL 已实现,覆盖了 loop 设备的基本配置功能。 -- 用户态和内核态之间的数据拷贝使用了 `UserBufferReader/Writer`,确保了内存访问的安全性。 -- `loop_init` 函数在系统启动时通过 `unified_init` 宏自动注册 `LoopControlDevice` 并初始化 `LoopManager`,预分配了初始的 loop 设备。 -- 完善的错误处理机制:在文件绑定、状态转换、参数校验和读写操作中,会返回具体的 `SystemError`。 -- `LoopDevice` 的 `metadata()` 方法能够正确反映后端文件和 loop 设备自身的元数据,包括设备类型、大小、块数等。 - -### 用户态测试 (`user/apps/c_unitest/test_loop.c`) - -- **测试镜像生成**:自动创建两个测试文件 (`test_image.img`, `test_image_2.img`) 作为 loop 设备的后端存储,分别大小为 1 MiB 和 512 KiB,并在后续测试中通过 `ftruncate` 动态调整大小。 -- **设备分配与绑定**: - * 通过 `/dev/loop-control` 接口调用 `LOOP_CTL_GET_FREE` 获取空闲 minor,然后使用 `LOOP_CTL_ADD` 分配并创建对应的 `/dev/loopX` 设备节点。 - * 对新分配的 `/dev/loopX` 设备执行 `LOOP_SET_FD`,将 `test_image.img` 文件绑定到该 loop 设备。 -- **参数配置与校验**: - * 使用 `LOOP_SET_STATUS64` 配置 loop 设备,例如设置一个 512 字节的偏移量 (`lo_offset`) 和一个有效大小限制 (`lo_sizelimit`)。 - * 接着使用 `LOOP_GET_STATUS64` 读取设备状态,验证之前设置的参数是否正确回读。 -- **数据读写验证 (初始后端文件)**: - * 写入 512 字节的数据到 loop 设备。 - * 验证写入的数据在原始文件对应偏移处是否一致。 - * 从 loop 设备读回数据,并验证其与写入内容的一致性。 -- **只读模式测试**: - * 通过 `LOOP_SET_STATUS64` 设置 `LO_FLAGS_READ_ONLY` 标志,将 loop 设备切换到只读模式。 - * 尝试向只读设备写入数据,验证写入操作是否被 `EROFS` 错误拒绝。 - * 恢复设备的读写权限,确保功能正常。 -- **`LOOP_CHANGE_FD` 测试**: - * 调用 `ioctl(loop_fd, LOOP_CHANGE_FD, backing_fd_2)` 将 loop 设备绑定的后端文件从 `test_image.img` 动态切换到 `test_image_2.img`,无需解绑和重新绑定。 - * 验证切换后,能够成功向新的后端文件 (`test_image_2.img`) 写入数据,并通过直接读取 `test_image_2.img` 校验数据一致性。 -- **`LOOP_SET_CAPACITY` 测试**: - * **后端文件大小调整**: 通过 `ftruncate` 动态增大 `test_image_2.img` 的大小。 - * **触发容量重新计算**: 调用 `ioctl(loop_fd, LOOP_SET_CAPACITY, 0)` 触发 loop 设备重新评估其容量。 - * **验证容量限制行为**: - * 首先在 `lo_sizelimit` 非零的情况下进行测试,观察容量是否受限于 `lo_sizelimit`。 - * 随后将 `lo_sizelimit` 清零,再次调用 `LOOP_SET_CAPACITY`,验证 loop 设备能够正确反映后端文件的新增容量。 - * **扩展区域读写验证**: 尝试向新扩展的区域写入数据,并通过直接读取后端文件校验数据是否成功写入。 -- **设备清理**: - * 调用 `LOOP_CLR_FD` 解绑后端文件。 - * 通过 `LOOP_CTL_REMOVE` 移除 loop 设备,并验证设备节点是否不再可访问。 -- **资源清理**:测试结束后删除所有生成的测试镜像文件,确保环境干净。 - -## 未完成/待完善事项 - -### 内核侧限制 - -- **文件系统连接 (`fs()`)**:`LoopDevice::fs()` 和 `LoopControlDevice::fs()` 方法目前仍为 `todo!()`。 -- **I/O 调度和工作队列**:当前所有读写操作都是同步直通的。缺少异步 I/O 队列或工作队列的实现,可能在高负载情况下影响系统响应和性能。 -- **加密类型实现**:代码中保留了加密类型常量 (`LO_CRYPT_NONE` 等),但未有任何实际的加密/解密逻辑实现。 -- **`LoopDevice::sync()` 空实现**:`sync()` 方法目前仅返回 `Ok(())`,未实现对后端文件的实际 `flush` 或 `fsync` 操作,可能导致数据持久性问题。 -- **分区支持**:`BlockDevice::partitions()` 返回空集合。这意味着 loop 设备目前不支持解析或呈现后端镜像文件中的分区表。 -- **错误回滚不足**:在 `LoopManager::create_and_register_device_locked` 中,如果 `block_dev_manager().register` 失败,虽然返回错误,但未清除 `inner.devices[minor]` 中可能残留的 `Some`,可能导致状态不一致。 -- **内核侧单元测试**:目前缺乏针对 `LoopDevice`、`LoopManager` 和 `LoopControlDevice` 核心逻辑的独立内核单元测试或集成测试,只有一个`ctest` - -### 用户态测试缺口 - -- **设备节点依赖**:测试依赖 `/dev/loop-control` 与 `/dev/loopX` 节点预先存在且权限正确。若 `udev`/`devfs` 未创建节点或权限不符,测试会失败。 -- **并发与压力测试**:目前的测试集中于单个设备、单线程的场景。未验证并发绑定/解绑、多设备同时读写、极限容量或高 I/O 负载下的行为。 -- **负向测试**:缺乏对非法参数(如非 LBA_SIZE 对齐的偏移/大小限制)、读写越界、重复绑定、非文件类型后端文件等边界条件的测试。**(部分覆盖,但仍需更全面)** -- **IOCTL 完整性测试**:虽然已覆盖 `LOOP_SET_FD`, `LOOP_CLR_FD`, `LOOP_SET_STATUS64`, `LOOP_GET_STATUS64`, `LOOP_CHANGE_FD`, `LOOP_SET_CAPACITY` 等,但针对这些 IOCTL 的所有参数组合和异常情况的测试仍可扩展。 - -## 运行测试的基本步骤 - -1. **启动 DragonOS**:确保系统启动并成功执行 `loop_init` 函数。您可以通过查看内核日志确认“Loop control device initialized.”等消息。 - -2. **进入用户态环境**:在 DragonOS 的 shell 中,导航到用户态测试目录。 - -3. **编译并运行 `test_loop`**: - - ``` - ./bin/test_loop - ``` - -4. **观察输出**:如果所有测试步骤成功,您将看到类似“Read/write test PASSED.”、“只读模式下写入被正确阻止。”等成功的提示信息。任何错误都会以 `ERROR:` 标志并在日志中指明。 +# Loop Device 架构设计 + +本文档阐述 DragonOS 中 loop 设备子系统的架构设计思路,用于指导开发和后续演进。 + +## 问题背景 + +在操作系统开发中,我们经常面临这样的需求: +- 如何将一个镜像文件当作块设备使用? +- 如何在不重启系统的情况下动态创建/删除虚拟块设备? + +loop 设备正是解决这些问题的关键组件。 + +## 系统架构定位 + +loop 设备在 DragonOS 架构中扮演着"虚拟化桥梁"的角色: + +``` +用户态应用 + ↓ +loop-control 接口 (字符设备) + ↓ +LoopManager (设备生命周期管理) + ↓ +LoopDevice[] (虚拟块设备数组) + ↓ +块设备层 ←→ 后端文件系统 +``` + +这种分层设计的核心思想是:**将控制平面与数据平面分离**。 + +## 核心设计哲学 + +### 1. 状态驱动的设备管理 + +我们仿照linux设计引入状态机来管理设备生命周期 + +``` +Unbound → Bound → Rundown → Deleting + ↓ ↓ ↓ +Deleting Unbound Deleting +``` + +**设计考量**: +- 防止非法状态转换(如直接在 Bound 状态删除设备) +- 提供清晰的设备生命周期语义 +- 为未来的扩展(如设备热插拔)奠定基础 + +### 2. 双重接口策略 + +我们的设计刻意区分了两种接口: + +**字符控制接口** (`/dev/loop-control`): +- 负责设备的生命周期管理 +- 提供用户友好的设备分配/回收机制 +- 与 Linux 标准接口保持兼容 + +**块设备接口** (`/dev/loopX`): +- 专注于数据读写功能 +- 提供标准的块设备语义 +- 支持偏移、大小限制等高级功能 + +**设计价值**:这种分离使得控制逻辑与数据路径互不干扰,提高了系统的可维护性。 + +### 3. 安全性优先 + +在与用户态交互时,我们采用了多重安全检查: + +- **参数边界检查**:所有偏移和大小都必须 LBA 对齐 +- **内存安全**:使用 `UserBufferReader/Writer` 进行用户态数据拷贝 +- **权限验证**:只读设备拒绝写入操作 +- **状态验证**:每个操作前都检查当前设备状态是否允许 + +## 模块协作架构 + +### LoopManager 的定位 +LoopManager 不是简单的设备数组管理器,而是整个子系统的"调度中心": + +- **设备分配策略**:采用"就近分配"原则,优先复用空闲设备 +- **资源池管理**:预注册 8 个设备,避免运行时分配开销 +- **并发安全**:所有设备操作都在锁保护下进行 + +### LoopDevice 的抽象设计 +LoopDevice 的核心抽象是"**后端文件的块设备视图**": + +``` +用户视角 内部实现 +/dev/loop0 ←→ 文件偏移 + 大小限制 + 块0-100 文件偏移0-51200 + 块101-200 文件偏移51200-102400 +``` + +这种设计允许用户将文件的任意部分映射为块设备,为容器等应用场景提供了极大的灵活性。 + +## 关键设计 + +### 为什么选择 256 个设备上限? +- 足够满足大多数应用场景需求 +- 避免无限制增长导致的资源耗尽 +- 与 Linux 系统默认上限保持一致,保证兼容性 + +### 为什么预注册 8 个设备? +- 覆盖常见的测试场景(通常不超过 4-5 个) +- 减少首次使用的等待时间 +- 提供一个合理的初始工作集 + +### 为什么使用 SpinLock 而不是其他锁? +- loop 设备操作大多是短时操作 +- 避免复杂的锁层级和死锁问题 +- 简化实现,提高性能 + +## 兼容性考量 + +我们的设计在很大程度上参考了 Linux loop 驱动的接口,这是有意的选择: + +1. **用户态软件兼容**:现有的 loop 工具无需修改即可使用 +2. **API 契约一致性**:避免因接口差异导致的潜在问题 +3. **社区知识复用**:开发者可以复用现有的 loop 设备知识 + +## 总结 + +DragonOS 的 loop 设备设计遵循以下核心原则: +1. **架构清晰**:控制平面与数据平面分离 +2. **状态安全**:基于状态机的设备生命周期管理 +3. **接口兼容**:与 Linux 标准接口保持兼容 +4. **扩展友好**:为未来功能预留架构空间 +5. **测试完备**:通过多层级测试保证质量 diff --git a/kernel/src/driver/base/block/manager.rs b/kernel/src/driver/base/block/manager.rs index 7e7539392..f553b05af 100644 --- a/kernel/src/driver/base/block/manager.rs +++ b/kernel/src/driver/base/block/manager.rs @@ -168,13 +168,10 @@ impl BlockDevManager { /// 卸载磁盘设备 #[allow(dead_code)] pub fn unregister(&self, dev: &Arc) -> Result<(), SystemError> { - { let mut inner = self.inner(); if inner.disks.remove(dev.dev_name()).is_none() { return Err(SystemError::ENOENT); } - } - let blk_meta = dev.blkdev_meta(); let gendisks = { let mut meta_inner = blk_meta.inner(); @@ -182,15 +179,12 @@ impl BlockDevManager { meta_inner.gendisks.clear(); disks }; - for gendisk in gendisks { let dname = gendisk.dname()?; devfs_unregister(dname.as_ref(), gendisk)?; } - Ok(()) } - /// 通过路径查找gendisk /// /// # 参数 From eda602a451b6a2900db304036a08f4cf512edc09 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 12 Nov 2025 23:20:25 +0800 Subject: [PATCH 22/39] =?UTF-8?q?=E4=BF=AE=E6=AD=A3clippy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index 3e7a9590b..b0740f37a 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -62,9 +62,9 @@ pub enum LoopIoctl { #[repr(u32)] #[derive(Debug, FromPrimitive)] pub enum LoopControlIoctl { - LoopCtlAdd = 0x4C80, - LoopCtlRemove = 0x4C81, - LoopCtlGetFree = 0x4C82, + Add = 0x4C80, + Remove = 0x4C81, + GetFree = 0x4C82, } pub const LO_FLAGS_READ_ONLY: u32 = 1 << 0; pub const SUPPORTED_LOOP_FLAGS: u32 = LO_FLAGS_READ_ONLY; @@ -305,13 +305,13 @@ impl LoopDevice { Ok(()) } fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { - if info.lo_offset % LBA_SIZE as u64 != 0 { + if info.lo_offset.is_multiple_of(LBA_SIZE as u64) == false { return Err(SystemError::EINVAL); } if info.lo_offset > usize::MAX as u64 || info.lo_sizelimit > usize::MAX as u64 { return Err(SystemError::EINVAL); } - if info.lo_sizelimit != 0 && info.lo_sizelimit % LBA_SIZE as u64 != 0 { + if info.lo_sizelimit != 0 && info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) == false { return Err(SystemError::EINVAL); } if info.lo_flags & !SUPPORTED_LOOP_FLAGS != 0 { @@ -578,7 +578,7 @@ impl IndexNode for LoopDevice { inode_id: InodeId::new(0), size: self.inner().file_size as i64, blk_size: LBA_SIZE, - blocks: (self.inner().file_size + LBA_SIZE - 1) / LBA_SIZE, + blocks: (self.inner().file_size.div_ceil(LBA_SIZE)), atime: file_metadata.atime, mtime: file_metadata.mtime, ctime: file_metadata.ctime, @@ -1382,7 +1382,7 @@ impl IndexNode for LoopControlDevice { _private_data: &FilePrivateData, ) -> Result { match LoopControlIoctl::from_u32(cmd) { - Some(LoopControlIoctl::LoopCtlAdd) => { + Some(LoopControlIoctl::Add) => { log::info!("Starting LOOP_CTL_ADD ioctl"); let requested_index = data as u32; let loop_dev = if requested_index == u32::MAX { @@ -1401,12 +1401,12 @@ impl IndexNode for LoopControlDevice { }; Ok(minor as usize) } - Some(LoopControlIoctl::LoopCtlRemove) => { + Some(LoopControlIoctl::Remove) => { let minor_to_remove = data as u32; self.loop_mgr.loop_remove(minor_to_remove)?; Ok(0) } - Some(LoopControlIoctl::LoopCtlGetFree) => match self.loop_mgr.find_free_minor() { + Some(LoopControlIoctl::GetFree) => match self.loop_mgr.find_free_minor() { Some(minor) => Ok(minor as usize), None => Err(SystemError::ENOSPC), }, From 87ba21d8dd7938f11740b875e0c4a603659597b8 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 12 Nov 2025 23:41:44 +0800 Subject: [PATCH 23/39] =?UTF-8?q?copilot=E5=AE=A1=E6=9F=A5=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/loop_device.rs | 17 ++++------------- kernel/src/filesystem/vfs/file.rs | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/base/block/loop_device.rs index b0740f37a..13c8c7d9f 100644 --- a/kernel/src/driver/base/block/loop_device.rs +++ b/kernel/src/driver/base/block/loop_device.rs @@ -305,13 +305,13 @@ impl LoopDevice { Ok(()) } fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { - if info.lo_offset.is_multiple_of(LBA_SIZE as u64) == false { + if !info.lo_offset.is_multiple_of(LBA_SIZE as u64) { return Err(SystemError::EINVAL); } if info.lo_offset > usize::MAX as u64 || info.lo_sizelimit > usize::MAX as u64 { return Err(SystemError::EINVAL); } - if info.lo_sizelimit != 0 && info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) == false { + if info.lo_sizelimit != 0 && !info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) { return Err(SystemError::EINVAL); } if info.lo_flags & !SUPPORTED_LOOP_FLAGS != 0 { @@ -590,7 +590,7 @@ impl IndexNode for LoopDevice { gid: 0, raw_dev: self.inner().device_number, }; - Ok(metadata.clone()) + Ok(metadata) } fn ioctl( &self, @@ -1253,7 +1253,6 @@ impl LoopManager { } pub fn loop_init(&self, _driver: Arc) -> Result<(), SystemError> { let mut inner = self.inner(); - // 注册 loop 设备 for minor in 0..Self::MAX_INIT_DEVICES { let minor_u32 = minor as u32; if Self::find_device_by_minor_locked(&inner, minor_u32).is_some() { @@ -1266,10 +1265,6 @@ impl LoopManager { } } log::info!("Loop devices initialized"); - - //添加到loop_manager中 - - log::info!("Loop devices initialized."); Ok(()) } } @@ -1302,7 +1297,6 @@ impl LoopControlDevice { device_common: DeviceCommonData::default(), parent: RwLock::new(Weak::default()), device_inode_fs: RwLock::new(None), - // devfs_metadata: Metadata::default(), }), locked_kobj_state: LockedKObjectState::default(), loop_mgr, @@ -1440,9 +1434,6 @@ impl IndexNode for LoopControlDevice { fn list(&self) -> Result, system_error::SystemError> { Err(SystemError::ENOSYS) } - // fn metadata(&self) -> Result { - // Metadata - // } } impl Device for LoopControlDevice { fn dev_type(&self) -> DeviceType { @@ -1450,7 +1441,7 @@ impl Device for LoopControlDevice { } fn id_table(&self) -> IdTable { - IdTable::new(LOOP_BASENAME.to_string(), None) + IdTable::new(LOOP_CONTROL_BASENAME.to_string(), None) } fn bus(&self) -> Option> { diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 245658a80..d2bd3a83f 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -38,7 +38,7 @@ pub enum FilePrivateData { EPoll(EPollPrivateData), /// pid私有信息 Pid(PidPrivateData), - //lop私有信息 + //loop私有信息 Loop(LoopPrivateData), /// 不需要文件私有信息 Unused, From 2360c1bd4d8db32c67b88e5beb55f3c5c78539d8 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 13 Nov 2025 02:20:19 +0800 Subject: [PATCH 24/39] =?UTF-8?q?-=20=E6=94=B9=E5=8A=A8loop=5Fdevice?= =?UTF-8?q?=E7=9A=84=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/gendisk/mod.rs | 7 ++----- kernel/src/driver/base/block/mod.rs | 1 - .../{base/block => block/loop_device}/loop_device.rs | 0 kernel/src/driver/block/loop_device/mod.rs | 1 + kernel/src/driver/block/mod.rs | 1 + kernel/src/filesystem/vfs/file.rs | 3 ++- 6 files changed, 6 insertions(+), 7 deletions(-) rename kernel/src/driver/{base/block => block/loop_device}/loop_device.rs (100%) create mode 100644 kernel/src/driver/block/loop_device/mod.rs diff --git a/kernel/src/driver/base/block/gendisk/mod.rs b/kernel/src/driver/base/block/gendisk/mod.rs index eafc6c4eb..70321cdc8 100644 --- a/kernel/src/driver/base/block/gendisk/mod.rs +++ b/kernel/src/driver/base/block/gendisk/mod.rs @@ -11,8 +11,10 @@ use alloc::{ use hashbrown::HashMap; use system_error::SystemError; +use super::block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}; use crate::{ driver::base::device::device_number::DeviceNumber, + driver::block::loop_device::loop_device::LoopDevice, filesystem::{ devfs::{DevFS, DeviceINode, LockedDevFSInode}, vfs::{syscall::ModeType, utils::DName, IndexNode, Metadata}, @@ -20,11 +22,6 @@ use crate::{ libs::{rwlock::RwLock, spinlock::SpinLockGuard}, }; -use super::{ - block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, - loop_device::LoopDevice, -}; - const MINORS_PER_DISK: u32 = 256; #[derive(Debug)] diff --git a/kernel/src/driver/base/block/mod.rs b/kernel/src/driver/base/block/mod.rs index 8b7a38db4..1d3211973 100644 --- a/kernel/src/driver/base/block/mod.rs +++ b/kernel/src/driver/base/block/mod.rs @@ -1,7 +1,6 @@ pub mod block_device; pub mod disk_info; pub mod gendisk; -pub mod loop_device; pub mod manager; #[derive(Debug)] #[allow(dead_code)] diff --git a/kernel/src/driver/base/block/loop_device.rs b/kernel/src/driver/block/loop_device/loop_device.rs similarity index 100% rename from kernel/src/driver/base/block/loop_device.rs rename to kernel/src/driver/block/loop_device/loop_device.rs diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs new file mode 100644 index 000000000..718dd7381 --- /dev/null +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -0,0 +1 @@ +pub mod loop_device; diff --git a/kernel/src/driver/block/mod.rs b/kernel/src/driver/block/mod.rs index 6a91ec54f..b249e6643 100644 --- a/kernel/src/driver/block/mod.rs +++ b/kernel/src/driver/block/mod.rs @@ -1,2 +1,3 @@ pub mod cache; +pub mod loop_device; pub mod virtio_blk; diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index d2bd3a83f..9c35d8690 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -8,7 +8,8 @@ use super::{FileType, IndexNode, InodeId, Metadata, SpecialNodeData}; use crate::process::pid::PidPrivateData; use crate::{ driver::{ - base::{block::loop_device::LoopPrivateData, block::SeekFrom, device::DevicePrivateData}, + base::{block::SeekFrom, device::DevicePrivateData}, + block::loop_device::loop_device::LoopPrivateData, tty::tty_device::TtyFilePrivateData, }, filesystem::{ From 2ebf53379665da94d3f577906a9069b808c895be Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 27 Nov 2025 18:55:32 +0800 Subject: [PATCH 25/39] =?UTF-8?q?-=20=E6=B7=BB=E5=8A=A0=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=8C=E9=98=BB=E5=A1=9Eio=EF=BC=8C?= =?UTF-8?q?=E4=BF=9D=E8=AF=81io=E7=BB=93=E6=9D=9F=E5=90=8E=E5=86=8D?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E9=87=8A=E6=94=BE=E8=B5=84=E6=BA=90=20-=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=A4=9A=E7=BA=BF=E7=A8=8B=E8=AF=BB=E5=86=99?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../driver/block/loop_device/loop_device.rs | 265 +++++++++- user/apps/c_unitest/test_loop.c | 482 +++++++++++++++++- 2 files changed, 725 insertions(+), 22 deletions(-) diff --git a/kernel/src/driver/block/loop_device/loop_device.rs b/kernel/src/driver/block/loop_device/loop_device.rs index 13c8c7d9f..c14a993dd 100644 --- a/kernel/src/driver/block/loop_device/loop_device.rs +++ b/kernel/src/driver/block/loop_device/loop_device.rs @@ -13,12 +13,16 @@ use crate::{ driver::{Driver, DriverCommonData}, DevName, Device, DeviceCommonData, DeviceType, IdTable, }, - kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kobject::{ + KObjType, KObject, KObjectCommonData, KObjectManager, KObjectState, KObjectSysFSOps, + LockedKObjectState, + }, kset::KSet, }, filesystem::{ devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, kernfs::KernFSInode, + sysfs::{AttributeGroup, SysFSOps}, vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata}, }, libs::{ @@ -36,8 +40,10 @@ use alloc::{ use core::{ any::Any, fmt::{Debug, Formatter}, + sync::atomic::{AtomicU32, Ordering}, }; use ida::IdAllocator; +use log::{error, info, warn}; use num_traits::FromPrimitive; use system_error::SystemError; use unified_init::macros::unified_init; @@ -76,6 +82,42 @@ pub struct LoopStatus64 { pub lo_flags: u32, pub __pad: u32, } +#[derive(Debug)] +pub struct LoopDeviceKObjType; + +impl KObjType for LoopDeviceKObjType { + fn release(&self, kobj: Arc) { + if let Some(loop_dev) = kobj.as_any_ref().downcast_ref::() { + loop_dev.final_cleanup(); + } + } + + fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { + Some(&KObjectSysFSOps) + } + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + None + } +} +static LOOP_DEVICE_KOBJ_TYPE: LoopDeviceKObjType = LoopDeviceKObjType; +struct IoGuard<'a> { + device: &'a LoopDevice, +} + +impl<'a> IoGuard<'a> { + fn new(device: &'a LoopDevice) -> Result { + device.io_start()?; + Ok(Self { device }) + } +} + +impl<'a> Drop for IoGuard<'a> { + fn drop(&mut self) { + self.device.io_end(); + } +} + pub struct LoopDevice { id: usize, minor: u32, @@ -85,6 +127,8 @@ pub struct LoopDevice { self_ref: Weak, fs: RwLock>, parent: RwLock>, + /// 活跃的 I/O 操作计数 + active_io_count: AtomicU32, } #[derive(Debug, Clone)] pub struct LoopPrivateData { @@ -111,8 +155,10 @@ impl LoopDeviceInner { (LoopState::Unbound, LoopState::Bound) => {} (LoopState::Bound, LoopState::Unbound) => {} (LoopState::Bound, LoopState::Rundown) => {} + (LoopState::Rundown, LoopState::Draining) => {} (LoopState::Rundown, LoopState::Deleting) => {} (LoopState::Rundown, LoopState::Unbound) => {} + (LoopState::Draining, LoopState::Deleting) => {} (LoopState::Unbound, LoopState::Deleting) => {} _ => return Err(SystemError::EINVAL), } @@ -126,6 +172,7 @@ pub enum LoopState { Unbound, Bound, Rundown, + Draining, Deleting, } impl Debug for LoopDevice { @@ -181,7 +228,12 @@ impl LoopDevice { self_ref: self_ref.clone(), fs: RwLock::new(Weak::default()), parent: RwLock::new(Weak::default()), + active_io_count: AtomicU32::new(0), }); + + // 设置 KObjType + dev.set_kobj_type(Some(&LOOP_DEVICE_KOBJ_TYPE)); + Some(dev) } @@ -293,7 +345,11 @@ impl LoopDevice { match inner.state { LoopState::Bound | LoopState::Rundown => inner.set_state(LoopState::Unbound)?, LoopState::Unbound => {} - LoopState::Deleting => return Err(SystemError::EBUSY), + LoopState::Draining => return Err(SystemError::EBUSY), + LoopState::Deleting => { + // 在删除流程中,允许清理文件 + // 状态已经是Deleting,无需改变 + } } inner.file_inode = None; @@ -470,6 +526,164 @@ impl LoopDevice { self.recalc_effective_size()?; Ok(()) } + + /// # 功能 + /// + /// I/O 操作开始时调用,增加活跃 I/O 计数 + /// + /// ## 返回值 + /// - `Ok(())`: 成功增加计数 + /// - `Err(SystemError::ENODEV)`: 设备正在删除,拒绝新的 I/O + fn io_start(&self) -> Result<(), SystemError> { + let inner = self.inner(); + if matches!( + inner.state, + LoopState::Rundown | LoopState::Draining | LoopState::Deleting + ) { + return Err(SystemError::ENODEV); + } + + self.active_io_count.fetch_add(1, Ordering::AcqRel); + Ok(()) + } + + /// # 功能 + /// + /// I/O 操作完成时调用,减少活跃 I/O 计数 + fn io_end(&self) { + let prev = self.active_io_count.fetch_sub(1, Ordering::AcqRel); + if prev == 0 { + warn!( + "Loop device loop{}: I/O count underflow", + self.inner().device_number.minor() + ); + } + } + + /// # 功能 + /// + /// 进入 Rundown 状态,停止接受新的 I/O 请求 + /// + /// ## 返回值 + /// - `Ok(())`: 成功进入 Rundown 状态 + /// - `Err(SystemError)`: 状态转换失败 + fn enter_rundown_state(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + match inner.state { + LoopState::Bound => { + inner.set_state(LoopState::Rundown)?; + info!( + "Loop device loop{} entering rundown state", + inner.device_number.minor() + ); + } + LoopState::Unbound => { + // 空设备可以直接删除 + inner.set_state(LoopState::Deleting)?; + info!( + "Loop device loop{} is unbound, skipping to deleting state", + inner.device_number.minor() + ); + } + LoopState::Rundown => {} + LoopState::Draining | LoopState::Deleting => { + return Err(SystemError::EBUSY); + } + } + Ok(()) + } + + /// # 功能 + /// + /// 等待所有活跃的 I/O 操作完成 + /// + /// ## 返回值 + /// - `Ok(())`: 所有 I/O 已完成 + /// - `Err(SystemError::ETIMEDOUT)`: 等待超时 + fn drain_active_io(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + if matches!(inner.state, LoopState::Rundown) { + inner.set_state(LoopState::Draining)?; + info!( + "Loop device loop{} entering draining state", + inner.device_number.minor() + ); + } + drop(inner); + + let timeout_ms = 30_000; + let check_interval_us = 10_000; + let max_checks = timeout_ms * 1000 / check_interval_us; + + for _i in 0..max_checks { + let count = self.active_io_count.load(Ordering::Acquire); + if count == 0 { + break; + } + + core::hint::spin_loop(); + } + + let final_count = self.active_io_count.load(Ordering::Acquire); + if final_count != 0 { + error!( + "Timeout waiting for I/O to drain on loop{}: {} operations still active", + self.minor(), + final_count + ); + return Err(SystemError::ETIMEDOUT); + } + + info!( + "All I/O operations drained for loop device loop{}", + self.minor() + ); + + let mut inner = self.inner(); + inner.set_state(LoopState::Deleting)?; + + Ok(()) + } + + /// # 功能 + /// + /// 从 sysfs 中移除设备 + /// + /// ## 返回值 + /// - `Ok(())`: 成功移除 + /// - `Err(SystemError)`: 移除失败 + fn remove_from_sysfs(&self) -> Result<(), SystemError> { + // 使用 KObjectManager 从 sysfs 中移除 + if let Some(kobj) = self.self_ref.upgrade() { + KObjectManager::remove_kobj(kobj as Arc); + info!("Removed loop device loop{} from sysfs", self.minor()); + } + Ok(()) + } + + /// # 功能 + /// + /// 最终清理函数,由 KObjType::release 调用 + /// 执行设备删除的最后清理工作 + fn final_cleanup(&self) { + info!( + "Final cleanup for loop device loop{} (id {})", + self.minor(), + self.id() + ); + let mut inner = self.inner(); + if let Some(file_inode) = inner.file_inode.take() { + drop(file_inode); + warn!( + "File inode was still present during final cleanup for loop{}", + self.minor() + ); + } + inner.file_size = 0; + inner.offset = 0; + inner.size_limit = 0; + info!("Loop device loop{} cleanup complete", self.minor()); + } } impl KObject for LoopDevice { @@ -759,6 +973,9 @@ impl BlockDevice for LoopDevice { count: usize, buf: &mut [u8], ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + if count == 0 { return Ok(0); } @@ -801,6 +1018,9 @@ impl BlockDevice for LoopDevice { count: usize, buf: &[u8], ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + if count == 0 { return Ok(0); } @@ -1192,35 +1412,42 @@ impl LoopManager { ); Ok(loop_dev) } + /// # 功能 + /// + /// 删除指定 minor 的 loop 设备 + /// 实现规范的删除流程,包括状态转换、I/O 排空、资源清理 + /// + /// ## 参数 + /// + /// - `minor`: 要删除的设备的次设备号 + /// + /// ## 返回值 + /// - `Ok(())`: 成功删除设备 + /// - `Err(SystemError)`: 删除失败 pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { if minor >= Self::MAX_DEVICES as u32 { return Err(SystemError::EINVAL); } - let device = { let inner = self.inner(); Self::find_device_by_minor_locked(&inner, minor) } .ok_or(SystemError::ENODEV)?; let id = device.id(); + info!("Starting removal of loop device loop{} (id {})", minor, id); + device.enter_rundown_state()?; + let needs_drain = { + let inner = device.inner(); + !matches!(inner.state, LoopState::Deleting) + }; - { - let mut guard = device.inner(); - match guard.state { - LoopState::Bound => { - guard.set_state(LoopState::Rundown)?; - } - LoopState::Rundown | LoopState::Unbound => {} - LoopState::Deleting => return Ok(()), - } + if needs_drain { + device.drain_active_io()?; } device.clear_file()?; - { - let mut guard = device.inner(); - guard.set_state(LoopState::Deleting)?; - } + let _ = device.remove_from_sysfs(); let block_dev: Arc = device.clone(); block_dev_manager().unregister(&block_dev)?; @@ -1231,8 +1458,10 @@ impl LoopManager { Self::free_id_locked(&mut inner, id); inner.next_free_minor = minor; } - - log::info!("Loop device id {} (minor {}) removed.", id, minor); + info!( + "Loop device id {} (minor {}) removed successfully.", + id, minor + ); Ok(()) } diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index 32476bce9..9acbbcadf 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -7,6 +7,8 @@ #include // 用于 fstat #include #include +#include +#include // 控制命令常量 #define LOOP_CTL_ADD 0x4C80 @@ -65,6 +67,73 @@ long get_file_size(int fd) { return st.st_size; } +// =================================================================== +// 资源回收测试辅助结构和函数 +// =================================================================== + +// 线程参数结构,用于并发I/O测试 +struct io_thread_args { + char loop_dev_path[64]; + int duration_seconds; + volatile int should_stop; + int io_count; + int error_count; +}; + +// 并发读写线程函数 +void* io_worker_thread(void* arg) { + struct io_thread_args* args = (struct io_thread_args*)arg; + char buffer[512]; + time_t start_time = time(NULL); + + while (!args->should_stop && (time(NULL) - start_time) < args->duration_seconds) { + int fd = open(args->loop_dev_path, O_RDWR); + if (fd < 0) { + if (errno == ENODEV || errno == ENOENT) { + // 设备正在删除或已删除,这是预期的 + break; + } + args->error_count++; + usleep(10000); // 10ms + continue; + } + + // 尝试读取 + if (read(fd, buffer, sizeof(buffer)) < 0) { + if (errno != ENODEV) { + args->error_count++; + } + } else { + args->io_count++; + } + + close(fd); + usleep(1000); // 1ms + } + + return NULL; +} + +// 删除设备线程函数 +struct delete_thread_args { + int control_fd; + int loop_minor; + int result; + int error_code; +}; + +void* delete_worker_thread(void* arg) { + struct delete_thread_args* args = (struct delete_thread_args*)arg; + + // 稍微延迟以确保I/O线程已经开始 + usleep(50000); // 50ms + + args->result = ioctl(args->control_fd, LOOP_CTL_REMOVE, args->loop_minor); + args->error_code = errno; + + return NULL; +} + int main() { int control_fd; int loop_minor; @@ -310,8 +379,8 @@ int main() { // 并且默认的 sizelimit 是 0,表示不限制 // 所以 effective_size 应该等于 file_size - offset // 我们需要重新计算预期的 effective_size - uint64_t expected_sizelimit_after_change = (actual_file_2_size > status_readback.lo_offset) ? (actual_file_2_size - status_readback.lo_offset) : 0; - + // uint64_t expected_sizelimit_after_change = (actual_file_2_size > status_readback.lo_offset) ? (actual_file_2_size - status_readback.lo_offset) : 0; + // 注意:内核中的 `recalc_effective_size` 会将 `inner.file_size` 更新为有效大小 // 但是 `lo_sizelimit` 字段在 `LoopStatus64` 中是用户设定的限制,它不会自动改变 // 这里的验证需要更精确:`lo_sizelimit` 应该和我们之前设置的相同 (即 TEST_FILE_SIZE - 512) @@ -473,6 +542,408 @@ int main() { } printf("New backing file extended content verification passed.\n"); + // ======================================================= + // 资源回收测试 1: 并发I/O期间删除设备 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Concurrent I/O During Deletion ---\n"); + + // 创建新的loop设备用于此测试,使用重试机制处理可能的竞态条件 + int test_minor = -1; + int returned_minor_test = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &test_minor) < 0) { + perror("Failed to get free loop device for reclamation test"); + goto cleanup; + } + + returned_minor_test = ioctl(control_fd, LOOP_CTL_ADD, test_minor); + if (returned_minor_test >= 0) { + test_minor = returned_minor_test; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for reclamation test"); + goto cleanup; + } + // 如果设备已存在,重试获取新的minor号 + printf("Device loop%d already exists, retrying...\n", test_minor); + } + + if (returned_minor_test < 0) { + fprintf(stderr, "Failed to create loop device after 10 retries\n"); + goto cleanup; + } + + char test_loop_path[64]; + sprintf(test_loop_path, "/dev/loop%d", test_minor); + int test_loop_fd = open(test_loop_path, O_RDWR); + if (test_loop_fd < 0) { + perror("Failed to open test loop device"); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + + // 绑定到测试文件 + if (ioctl(test_loop_fd, LOOP_SET_FD, backing_fd_1) < 0) { + perror("Failed to bind test loop device"); + close(test_loop_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + printf("Created test loop device loop%d for concurrent I/O test.\n", test_minor); + + // 启动多个I/O线程 + #define NUM_IO_THREADS 4 + pthread_t io_threads[NUM_IO_THREADS]; + struct io_thread_args io_args[NUM_IO_THREADS]; + + for (int i = 0; i < NUM_IO_THREADS; i++) { + strcpy(io_args[i].loop_dev_path, test_loop_path); + io_args[i].duration_seconds = 5; + io_args[i].should_stop = 0; + io_args[i].io_count = 0; + io_args[i].error_count = 0; + + if (pthread_create(&io_threads[i], NULL, io_worker_thread, &io_args[i]) != 0) { + perror("Failed to create I/O thread"); + // 清理已创建的线程 + for (int j = 0; j < i; j++) { + io_args[j].should_stop = 1; + pthread_join(io_threads[j], NULL); + } + close(test_loop_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + } + printf("Started %d concurrent I/O threads.\n", NUM_IO_THREADS); + + // 关闭主文件描述符,避免在删除时引用计数不为0 + // I/O线程会重新打开设备进行操作 + close(test_loop_fd); + printf("Closed main loop device file descriptor.\n"); + + // 启动删除线程 + pthread_t delete_thread; + struct delete_thread_args delete_args; + delete_args.control_fd = control_fd; + delete_args.loop_minor = test_minor; + delete_args.result = 0; + delete_args.error_code = 0; + //创建失败回退删除所有线程 + if (pthread_create(&delete_thread, NULL, delete_worker_thread, &delete_args) != 0) { + perror("Failed to create delete thread"); + for (int i = 0; i < NUM_IO_THREADS; i++) { + io_args[i].should_stop = 1; + pthread_join(io_threads[i], NULL); + } + close(test_loop_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + printf("Started deletion thread.\n"); + + // 等待删除完成 + pthread_join(delete_thread, NULL); + printf("Deletion thread completed with result: %d (errno: %d)\n", + delete_args.result, delete_args.error_code); + + // 停止I/O线程 + for (int i = 0; i < NUM_IO_THREADS; i++) { + io_args[i].should_stop = 1; + } + + // 等待所有I/O线程完成 + int total_io_count = 0; + int total_error_count = 0; + for (int i = 0; i < NUM_IO_THREADS; i++) { + pthread_join(io_threads[i], NULL); + total_io_count += io_args[i].io_count; + total_error_count += io_args[i].error_count; + printf("I/O thread %d: %d successful ops, %d errors\n", + i, io_args[i].io_count, io_args[i].error_count); + } + printf("Total I/O operations: %d successful, %d errors\n", + total_io_count, total_error_count); + + // test_loop_fd 已经在删除前关闭了 + + if (delete_args.result == 0) { + printf("✓ Concurrent I/O deletion test PASSED: Device deleted successfully while I/O was active.\n"); + } else { + printf("✗ Concurrent I/O deletion test FAILED: Deletion returned %d (errno: %d)\n", + delete_args.result, delete_args.error_code); + } + + // 验证设备已被删除 + int verify_test_fd = open(test_loop_path, O_RDWR); + if (verify_test_fd < 0 && (errno == ENOENT || errno == ENODEV)) { + printf("✓ Device %s is correctly inaccessible after deletion.\n", test_loop_path); + } else { + if (verify_test_fd >= 0) { + printf("✗ FAILED: Device %s still accessible after deletion!\n", test_loop_path); + close(verify_test_fd); + } + } + + // ======================================================= + // 资源回收测试 2: 删除未绑定的设备 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Deleting Unbound Device ---\n"); + + int unbound_minor = -1; + int ret_unbound = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &unbound_minor) < 0) { + perror("Failed to get free loop device for unbound test"); + goto cleanup; + } + + ret_unbound = ioctl(control_fd, LOOP_CTL_ADD, unbound_minor); + if (ret_unbound >= 0) { + unbound_minor = ret_unbound; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for unbound test"); + goto cleanup; + } + } + + if (ret_unbound < 0) { + fprintf(stderr, "Failed to create unbound loop device after retries\n"); + goto cleanup; + } + printf("Created unbound loop device loop%d.\n", unbound_minor); + + // 立即删除未绑定的设备 + if (ioctl(control_fd, LOOP_CTL_REMOVE, unbound_minor) < 0) { + perror("Failed to remove unbound loop device"); + printf("✗ Unbound device deletion test FAILED.\n"); + } else { + printf("✓ Unbound device deletion test PASSED: Successfully deleted loop%d.\n", unbound_minor); + } + + // ======================================================= + // 资源回收测试 3: 重复删除同一设备 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Duplicate Deletion ---\n"); + + int dup_minor = -1; + int ret_dup = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &dup_minor) < 0) { + perror("Failed to get free loop device for duplicate deletion test"); + goto cleanup; + } + + ret_dup = ioctl(control_fd, LOOP_CTL_ADD, dup_minor); + if (ret_dup >= 0) { + dup_minor = ret_dup; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for duplicate deletion test"); + goto cleanup; + } + } + + if (ret_dup < 0) { + fprintf(stderr, "Failed to create loop device for duplicate deletion test after retries\n"); + goto cleanup; + } + printf("Created loop device loop%d for duplicate deletion test.\n", dup_minor); + + // 第一次删除 + if (ioctl(control_fd, LOOP_CTL_REMOVE, dup_minor) < 0) { + perror("First deletion failed"); + printf("✗ Duplicate deletion test FAILED: First deletion failed.\n"); + goto cleanup; + } + printf("First deletion of loop%d succeeded.\n", dup_minor); + + // 第二次删除(应该失败) + errno = 0; + int second_delete = ioctl(control_fd, LOOP_CTL_REMOVE, dup_minor); + if (second_delete < 0 && (errno == ENODEV || errno == EINVAL)) { + printf("✓ Duplicate deletion test PASSED: Second deletion correctly failed with errno %d.\n", errno); + } else { + printf("✗ Duplicate deletion test FAILED: Second deletion returned %d (errno: %d), expected failure.\n", + second_delete, errno); + } + + // ======================================================= + // 资源回收测试 4: 文件描述符泄漏检测 + // ======================================================= + printf("\n--- Testing Resource Reclamation: File Descriptor Leak Detection ---\n"); + + // 创建多个loop设备并快速删除,检查是否有FD泄漏 + #define LEAK_TEST_COUNT 10 + int leak_test_minors[LEAK_TEST_COUNT]; + int leak_test_fds[LEAK_TEST_COUNT]; + + printf("Creating and deleting %d loop devices to test for FD leaks...\n", LEAK_TEST_COUNT); + + for (int i = 0; i < LEAK_TEST_COUNT; i++) { + leak_test_minors[i] = -1; + leak_test_fds[i] = -1; + + // 使用重试机制创建设备 + for (int retry = 0; retry < 10; retry++) { + int free_minor; + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &free_minor) < 0) { + perror("Failed to get free loop device for leak test"); + // 清理已创建的设备 + for (int j = 0; j < i; j++) { + if (leak_test_minors[j] >= 0) { + ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); + } + } + goto cleanup; + } + + int ret_leak = ioctl(control_fd, LOOP_CTL_ADD, free_minor); + if (ret_leak >= 0) { + leak_test_minors[i] = ret_leak; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for leak test"); + for (int j = 0; j < i; j++) { + if (leak_test_minors[j] >= 0) { + ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); + } + } + goto cleanup; + } + } + + if (leak_test_minors[i] < 0) { + fprintf(stderr, "Failed to create loop device %d for leak test\n", i); + for (int j = 0; j < i; j++) { + if (leak_test_minors[j] >= 0) { + ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); + } + } + goto cleanup; + } + + // 打开并绑定设备 + char leak_path[64]; + sprintf(leak_path, "/dev/loop%d", leak_test_minors[i]); + leak_test_fds[i] = open(leak_path, O_RDWR); + if (leak_test_fds[i] >= 0) { + ioctl(leak_test_fds[i], LOOP_SET_FD, backing_fd_1); + } + } + + // 删除所有设备 + int leak_delete_success = 0; + for (int i = 0; i < LEAK_TEST_COUNT; i++) { + if (leak_test_fds[i] >= 0) { + ioctl(leak_test_fds[i], LOOP_CLR_FD, 0); + close(leak_test_fds[i]); + } + + if (ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[i]) == 0) { + leak_delete_success++; + } + } + + printf("Successfully deleted %d out of %d devices.\n", leak_delete_success, LEAK_TEST_COUNT); + if (leak_delete_success == LEAK_TEST_COUNT) { + printf("✓ FD leak test PASSED: All devices deleted successfully.\n"); + } else { + printf("⚠ FD leak test: %d devices failed to delete.\n", LEAK_TEST_COUNT - leak_delete_success); + } + + // ======================================================= + // 资源回收测试 5: 删除后设备不可访问 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Device Inaccessibility After Deletion ---\n"); + + int reject_minor = -1; + int ret_reject = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &reject_minor) < 0) { + perror("Failed to get free loop device for I/O rejection test"); + goto cleanup; + } + + ret_reject = ioctl(control_fd, LOOP_CTL_ADD, reject_minor); + if (ret_reject >= 0) { + reject_minor = ret_reject; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for I/O rejection test"); + goto cleanup; + } + } + + if (ret_reject < 0) { + fprintf(stderr, "Failed to create loop device for I/O rejection test after retries\n"); + goto cleanup; + } + + char reject_path[64]; + sprintf(reject_path, "/dev/loop%d", reject_minor); + int reject_fd = open(reject_path, O_RDWR); + if (reject_fd < 0) { + perror("Failed to open loop device for I/O rejection test"); + ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor); + goto cleanup; + } + + if (ioctl(reject_fd, LOOP_SET_FD, backing_fd_1) < 0) { + perror("Failed to bind loop device for I/O rejection test"); + close(reject_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor); + goto cleanup; + } + printf("Created and bound loop device loop%d for I/O rejection test.\n", reject_minor); + + // 执行一次成功的I/O操作 + char reject_buf[512] = "Test data"; + if (write(reject_fd, reject_buf, sizeof(reject_buf)) != sizeof(reject_buf)) { + perror("Initial write failed"); + } else { + printf("Initial write succeeded (expected).\n"); + } + + // 关闭文件描述符,准备删除 + close(reject_fd); + printf("Closed device file descriptor.\n"); + + // 触发删除 + printf("Triggering device deletion...\n"); + if (ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor) < 0) { + perror("Failed to trigger deletion for I/O rejection test"); + goto cleanup; + } + printf("Deletion triggered successfully.\n"); + + // 尝试重新打开设备(应该失败) + errno = 0; + int reopen_reject_fd = open(reject_path, O_RDWR); + if (reopen_reject_fd < 0 && (errno == ENODEV || errno == ENOENT)) { + printf("✓ I/O rejection test PASSED: Device correctly inaccessible after deletion (errno: %d).\n", errno); + } else { + if (reopen_reject_fd >= 0) { + printf("✗ I/O rejection test FAILED: Device still accessible after deletion.\n"); + close(reopen_reject_fd); + } else { + printf("✗ I/O rejection test FAILED: Unexpected errno %d (expected ENODEV or ENOENT).\n", errno); + } + } + + printf("\n=== All Resource Reclamation Tests Completed ===\n"); + cleanup: // 6. 清理并删除 loop 设备 @@ -482,16 +953,19 @@ int main() { perror("Failed to clear loop device backing file"); } + // 在删除设备前先关闭文件描述符,避免引用计数问题 + close(loop_fd); + printf("Closed loop device file descriptor.\n"); + printf("Removing loop device loop%d...\n", loop_minor); if (ioctl(control_fd, LOOP_CTL_REMOVE, loop_minor) < 0) { perror("Failed to remove loop device"); - // 尝试关闭所有打开的fd,即使删除失败也继续清理 + // 即使删除失败也继续清理 } else { printf("Loop device loop%d removed successfully.\n", loop_minor); } // 释放资源并删除测试文件 - close(loop_fd); close(backing_fd_1); close(backing_fd_2); close(control_fd); From 912bc23d9f15cabecab39d4d59bab52ffabd794d Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 27 Nov 2025 18:55:32 +0800 Subject: [PATCH 26/39] =?UTF-8?q?-=20=E6=B7=BB=E5=8A=A0=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E5=87=BD=E6=95=B0=EF=BC=8C=E9=98=BB=E5=A1=9Eio=EF=BC=8C?= =?UTF-8?q?=E4=BF=9D=E8=AF=81io=E7=BB=93=E6=9D=9F=E5=90=8E=E5=86=8D?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E9=87=8A=E6=94=BE=E8=B5=84=E6=BA=90=20-=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=A4=9A=E7=BA=BF=E7=A8=8B=E8=AF=BB=E5=86=99?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../driver/block/loop_device/loop_device.rs | 265 +++++++++- user/apps/c_unitest/test_loop.c | 482 +++++++++++++++++- 2 files changed, 725 insertions(+), 22 deletions(-) diff --git a/kernel/src/driver/block/loop_device/loop_device.rs b/kernel/src/driver/block/loop_device/loop_device.rs index 13c8c7d9f..fcaa2253d 100644 --- a/kernel/src/driver/block/loop_device/loop_device.rs +++ b/kernel/src/driver/block/loop_device/loop_device.rs @@ -13,12 +13,16 @@ use crate::{ driver::{Driver, DriverCommonData}, DevName, Device, DeviceCommonData, DeviceType, IdTable, }, - kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kobject::{ + KObjType, KObject, KObjectCommonData, KObjectManager, KObjectState, KObjectSysFSOps, + LockedKObjectState, + }, kset::KSet, }, filesystem::{ devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, kernfs::KernFSInode, + sysfs::{AttributeGroup, SysFSOps}, vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata}, }, libs::{ @@ -36,8 +40,10 @@ use alloc::{ use core::{ any::Any, fmt::{Debug, Formatter}, + sync::atomic::{AtomicU32, Ordering}, }; use ida::IdAllocator; +use log::{error, info, warn}; use num_traits::FromPrimitive; use system_error::SystemError; use unified_init::macros::unified_init; @@ -76,6 +82,42 @@ pub struct LoopStatus64 { pub lo_flags: u32, pub __pad: u32, } +#[derive(Debug)] +pub struct LoopDeviceKObjType; + +impl KObjType for LoopDeviceKObjType { + fn release(&self, kobj: Arc) { + if let Some(loop_dev) = kobj.as_any_ref().downcast_ref::() { + loop_dev.final_cleanup(); + } + } + + fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { + Some(&KObjectSysFSOps) + } + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + None + } +} +static LOOP_DEVICE_KOBJ_TYPE: LoopDeviceKObjType = LoopDeviceKObjType; +struct IoGuard<'a> { + device: &'a LoopDevice, +} + +impl<'a> IoGuard<'a> { + fn new(device: &'a LoopDevice) -> Result { + device.io_start()?; + Ok(Self { device }) + } +} + +impl<'a> Drop for IoGuard<'a> { + fn drop(&mut self) { + self.device.io_end(); + } +} + pub struct LoopDevice { id: usize, minor: u32, @@ -85,6 +127,8 @@ pub struct LoopDevice { self_ref: Weak, fs: RwLock>, parent: RwLock>, + /// 活跃的 I/O 操作计数 + active_io_count: AtomicU32, } #[derive(Debug, Clone)] pub struct LoopPrivateData { @@ -111,8 +155,10 @@ impl LoopDeviceInner { (LoopState::Unbound, LoopState::Bound) => {} (LoopState::Bound, LoopState::Unbound) => {} (LoopState::Bound, LoopState::Rundown) => {} + (LoopState::Rundown, LoopState::Draining) => {} (LoopState::Rundown, LoopState::Deleting) => {} (LoopState::Rundown, LoopState::Unbound) => {} + (LoopState::Draining, LoopState::Deleting) => {} (LoopState::Unbound, LoopState::Deleting) => {} _ => return Err(SystemError::EINVAL), } @@ -126,6 +172,7 @@ pub enum LoopState { Unbound, Bound, Rundown, + Draining, Deleting, } impl Debug for LoopDevice { @@ -181,7 +228,12 @@ impl LoopDevice { self_ref: self_ref.clone(), fs: RwLock::new(Weak::default()), parent: RwLock::new(Weak::default()), + active_io_count: AtomicU32::new(0), }); + + // 设置 KObjType + dev.set_kobj_type(Some(&LOOP_DEVICE_KOBJ_TYPE)); + Some(dev) } @@ -293,7 +345,11 @@ impl LoopDevice { match inner.state { LoopState::Bound | LoopState::Rundown => inner.set_state(LoopState::Unbound)?, LoopState::Unbound => {} - LoopState::Deleting => return Err(SystemError::EBUSY), + LoopState::Draining => return Err(SystemError::EBUSY), + LoopState::Deleting => { + // 在删除流程中,允许清理文件 + // 状态已经是Deleting,无需改变 + } } inner.file_inode = None; @@ -470,6 +526,164 @@ impl LoopDevice { self.recalc_effective_size()?; Ok(()) } + + /// # 功能 + /// + /// I/O 操作开始时调用,增加活跃 I/O 计数 + /// + /// ## 返回值 + /// - `Ok(())`: 成功增加计数 + /// - `Err(SystemError::ENODEV)`: 设备正在删除,拒绝新的 I/O + fn io_start(&self) -> Result<(), SystemError> { + let inner = self.inner(); + if matches!( + inner.state, + LoopState::Rundown | LoopState::Draining | LoopState::Deleting + ) { + return Err(SystemError::ENODEV); + } + + self.active_io_count.fetch_add(1, Ordering::AcqRel); + Ok(()) + } + + /// # 功能 + /// + /// I/O 操作完成时调用,减少活跃 I/O 计数 + fn io_end(&self) { + let prev = self.active_io_count.fetch_sub(1, Ordering::AcqRel); + if prev == 0 { + warn!( + "Loop device loop{}: I/O count underflow", + self.inner().device_number.minor() + ); + } + } + + /// # 功能 + /// + /// 进入 Rundown 状态,停止接受新的 I/O 请求 + /// + /// ## 返回值 + /// - `Ok(())`: 成功进入 Rundown 状态 + /// - `Err(SystemError)`: 状态转换失败 + fn enter_rundown_state(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + match inner.state { + LoopState::Bound => { + inner.set_state(LoopState::Rundown)?; + info!( + "Loop device loop{} entering rundown state", + inner.device_number.minor() + ); + } + LoopState::Unbound => { + // 空设备可以直接删除 + inner.set_state(LoopState::Deleting)?; + info!( + "Loop device loop{} is unbound, skipping to deleting state", + inner.device_number.minor() + ); + } + LoopState::Rundown => {} + LoopState::Draining | LoopState::Deleting => { + return Err(SystemError::EBUSY); + } + } + Ok(()) + } + + /// # 功能 + /// + /// 等待所有活跃的 I/O 操作完成 + /// + /// ## 返回值 + /// - `Ok(())`: 所有 I/O 已完成 + /// - `Err(SystemError::ETIMEDOUT)`: 等待超时 + fn drain_active_io(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + if matches!(inner.state, LoopState::Rundown) { + inner.set_state(LoopState::Draining)?; + info!( + "Loop device loop{} entering draining state", + inner.device_number.minor() + ); + } + drop(inner); + + let timeout_ms = 30_000; + let check_interval_us = 10_000; + let max_checks = timeout_ms * 1000 / check_interval_us; + + for _i in 0..max_checks { + let count = self.active_io_count.load(Ordering::Acquire); + if count == 0 { + break; + } + + core::hint::spin_loop(); + } + + let final_count = self.active_io_count.load(Ordering::Acquire); + if final_count != 0 { + error!( + "Timeout waiting for I/O to drain on loop{}: {} operations still active", + self.minor(), + final_count + ); + return Err(SystemError::ETIMEDOUT); + } + + info!( + "All I/O operations drained for loop device loop{}", + self.minor() + ); + + let mut inner = self.inner(); + inner.set_state(LoopState::Deleting)?; + + Ok(()) + } + + /// # 功能 + /// + /// 从 sysfs 中移除设备 + /// + /// ## 返回值 + /// - `Ok(())`: 成功移除 + /// - `Err(SystemError)`: 移除失败 + fn remove_from_sysfs(&self) -> Result<(), SystemError> { + // 使用 KObjectManager 从 sysfs 中移除 + if let Some(kobj) = self.self_ref.upgrade() { + KObjectManager::remove_kobj(kobj as Arc); + info!("Removed loop device loop{} from sysfs", self.minor()); + } + Ok(()) + } + + /// # 功能 + /// + /// 最终清理函数,由 KObjType::release 调用 + /// 执行设备删除的最后清理工作 + fn final_cleanup(&self) { + info!( + "Final cleanup for loop device loop{} (id {})", + self.minor(), + self.id() + ); + let mut inner = self.inner(); + if let Some(file_inode) = inner.file_inode.take() { + drop(file_inode); + warn!( + "File inode was still present during final cleanup for loop{}", + self.minor() + ); + } + inner.file_size = 0; + inner.offset = 0; + inner.size_limit = 0; + info!("Loop device loop{} cleanup complete", self.minor()); + } } impl KObject for LoopDevice { @@ -759,6 +973,9 @@ impl BlockDevice for LoopDevice { count: usize, buf: &mut [u8], ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + if count == 0 { return Ok(0); } @@ -801,6 +1018,9 @@ impl BlockDevice for LoopDevice { count: usize, buf: &[u8], ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + if count == 0 { return Ok(0); } @@ -1192,35 +1412,42 @@ impl LoopManager { ); Ok(loop_dev) } + /// # 功能 + /// + /// 删除指定 minor 的 loop 设备 + /// 实现规范的删除流程,包括状态转换、I/O 排空、资源清理 + /// + /// ## 参数 + /// + /// - `minor`: 要删除的设备的次设备号 + /// + /// ## 返回值 + /// - `Ok(())`: 成功删除设备 + /// - `Err(SystemError)`: 删除失败 pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { if minor >= Self::MAX_DEVICES as u32 { return Err(SystemError::EINVAL); } - let device = { let inner = self.inner(); Self::find_device_by_minor_locked(&inner, minor) } .ok_or(SystemError::ENODEV)?; let id = device.id(); + info!("Starting removal of loop device loop{} (id {})", minor, id); + device.enter_rundown_state()?; + let needs_drain = { + let inner = device.inner(); + !matches!(inner.state, LoopState::Deleting) + }; - { - let mut guard = device.inner(); - match guard.state { - LoopState::Bound => { - guard.set_state(LoopState::Rundown)?; - } - LoopState::Rundown | LoopState::Unbound => {} - LoopState::Deleting => return Ok(()), - } + if needs_drain { + device.drain_active_io()?; } device.clear_file()?; - { - let mut guard = device.inner(); - guard.set_state(LoopState::Deleting)?; - } + let _ = device.remove_from_sysfs(); let block_dev: Arc = device.clone(); block_dev_manager().unregister(&block_dev)?; @@ -1231,8 +1458,10 @@ impl LoopManager { Self::free_id_locked(&mut inner, id); inner.next_free_minor = minor; } - - log::info!("Loop device id {} (minor {}) removed.", id, minor); + info!( + "Loop device id {} (minor {}) removed successfully.", + id, minor + ); Ok(()) } diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index 32476bce9..9acbbcadf 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -7,6 +7,8 @@ #include // 用于 fstat #include #include +#include +#include // 控制命令常量 #define LOOP_CTL_ADD 0x4C80 @@ -65,6 +67,73 @@ long get_file_size(int fd) { return st.st_size; } +// =================================================================== +// 资源回收测试辅助结构和函数 +// =================================================================== + +// 线程参数结构,用于并发I/O测试 +struct io_thread_args { + char loop_dev_path[64]; + int duration_seconds; + volatile int should_stop; + int io_count; + int error_count; +}; + +// 并发读写线程函数 +void* io_worker_thread(void* arg) { + struct io_thread_args* args = (struct io_thread_args*)arg; + char buffer[512]; + time_t start_time = time(NULL); + + while (!args->should_stop && (time(NULL) - start_time) < args->duration_seconds) { + int fd = open(args->loop_dev_path, O_RDWR); + if (fd < 0) { + if (errno == ENODEV || errno == ENOENT) { + // 设备正在删除或已删除,这是预期的 + break; + } + args->error_count++; + usleep(10000); // 10ms + continue; + } + + // 尝试读取 + if (read(fd, buffer, sizeof(buffer)) < 0) { + if (errno != ENODEV) { + args->error_count++; + } + } else { + args->io_count++; + } + + close(fd); + usleep(1000); // 1ms + } + + return NULL; +} + +// 删除设备线程函数 +struct delete_thread_args { + int control_fd; + int loop_minor; + int result; + int error_code; +}; + +void* delete_worker_thread(void* arg) { + struct delete_thread_args* args = (struct delete_thread_args*)arg; + + // 稍微延迟以确保I/O线程已经开始 + usleep(50000); // 50ms + + args->result = ioctl(args->control_fd, LOOP_CTL_REMOVE, args->loop_minor); + args->error_code = errno; + + return NULL; +} + int main() { int control_fd; int loop_minor; @@ -310,8 +379,8 @@ int main() { // 并且默认的 sizelimit 是 0,表示不限制 // 所以 effective_size 应该等于 file_size - offset // 我们需要重新计算预期的 effective_size - uint64_t expected_sizelimit_after_change = (actual_file_2_size > status_readback.lo_offset) ? (actual_file_2_size - status_readback.lo_offset) : 0; - + // uint64_t expected_sizelimit_after_change = (actual_file_2_size > status_readback.lo_offset) ? (actual_file_2_size - status_readback.lo_offset) : 0; + // 注意:内核中的 `recalc_effective_size` 会将 `inner.file_size` 更新为有效大小 // 但是 `lo_sizelimit` 字段在 `LoopStatus64` 中是用户设定的限制,它不会自动改变 // 这里的验证需要更精确:`lo_sizelimit` 应该和我们之前设置的相同 (即 TEST_FILE_SIZE - 512) @@ -473,6 +542,408 @@ int main() { } printf("New backing file extended content verification passed.\n"); + // ======================================================= + // 资源回收测试 1: 并发I/O期间删除设备 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Concurrent I/O During Deletion ---\n"); + + // 创建新的loop设备用于此测试,使用重试机制处理可能的竞态条件 + int test_minor = -1; + int returned_minor_test = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &test_minor) < 0) { + perror("Failed to get free loop device for reclamation test"); + goto cleanup; + } + + returned_minor_test = ioctl(control_fd, LOOP_CTL_ADD, test_minor); + if (returned_minor_test >= 0) { + test_minor = returned_minor_test; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for reclamation test"); + goto cleanup; + } + // 如果设备已存在,重试获取新的minor号 + printf("Device loop%d already exists, retrying...\n", test_minor); + } + + if (returned_minor_test < 0) { + fprintf(stderr, "Failed to create loop device after 10 retries\n"); + goto cleanup; + } + + char test_loop_path[64]; + sprintf(test_loop_path, "/dev/loop%d", test_minor); + int test_loop_fd = open(test_loop_path, O_RDWR); + if (test_loop_fd < 0) { + perror("Failed to open test loop device"); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + + // 绑定到测试文件 + if (ioctl(test_loop_fd, LOOP_SET_FD, backing_fd_1) < 0) { + perror("Failed to bind test loop device"); + close(test_loop_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + printf("Created test loop device loop%d for concurrent I/O test.\n", test_minor); + + // 启动多个I/O线程 + #define NUM_IO_THREADS 4 + pthread_t io_threads[NUM_IO_THREADS]; + struct io_thread_args io_args[NUM_IO_THREADS]; + + for (int i = 0; i < NUM_IO_THREADS; i++) { + strcpy(io_args[i].loop_dev_path, test_loop_path); + io_args[i].duration_seconds = 5; + io_args[i].should_stop = 0; + io_args[i].io_count = 0; + io_args[i].error_count = 0; + + if (pthread_create(&io_threads[i], NULL, io_worker_thread, &io_args[i]) != 0) { + perror("Failed to create I/O thread"); + // 清理已创建的线程 + for (int j = 0; j < i; j++) { + io_args[j].should_stop = 1; + pthread_join(io_threads[j], NULL); + } + close(test_loop_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + } + printf("Started %d concurrent I/O threads.\n", NUM_IO_THREADS); + + // 关闭主文件描述符,避免在删除时引用计数不为0 + // I/O线程会重新打开设备进行操作 + close(test_loop_fd); + printf("Closed main loop device file descriptor.\n"); + + // 启动删除线程 + pthread_t delete_thread; + struct delete_thread_args delete_args; + delete_args.control_fd = control_fd; + delete_args.loop_minor = test_minor; + delete_args.result = 0; + delete_args.error_code = 0; + //创建失败回退删除所有线程 + if (pthread_create(&delete_thread, NULL, delete_worker_thread, &delete_args) != 0) { + perror("Failed to create delete thread"); + for (int i = 0; i < NUM_IO_THREADS; i++) { + io_args[i].should_stop = 1; + pthread_join(io_threads[i], NULL); + } + close(test_loop_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); + goto cleanup; + } + printf("Started deletion thread.\n"); + + // 等待删除完成 + pthread_join(delete_thread, NULL); + printf("Deletion thread completed with result: %d (errno: %d)\n", + delete_args.result, delete_args.error_code); + + // 停止I/O线程 + for (int i = 0; i < NUM_IO_THREADS; i++) { + io_args[i].should_stop = 1; + } + + // 等待所有I/O线程完成 + int total_io_count = 0; + int total_error_count = 0; + for (int i = 0; i < NUM_IO_THREADS; i++) { + pthread_join(io_threads[i], NULL); + total_io_count += io_args[i].io_count; + total_error_count += io_args[i].error_count; + printf("I/O thread %d: %d successful ops, %d errors\n", + i, io_args[i].io_count, io_args[i].error_count); + } + printf("Total I/O operations: %d successful, %d errors\n", + total_io_count, total_error_count); + + // test_loop_fd 已经在删除前关闭了 + + if (delete_args.result == 0) { + printf("✓ Concurrent I/O deletion test PASSED: Device deleted successfully while I/O was active.\n"); + } else { + printf("✗ Concurrent I/O deletion test FAILED: Deletion returned %d (errno: %d)\n", + delete_args.result, delete_args.error_code); + } + + // 验证设备已被删除 + int verify_test_fd = open(test_loop_path, O_RDWR); + if (verify_test_fd < 0 && (errno == ENOENT || errno == ENODEV)) { + printf("✓ Device %s is correctly inaccessible after deletion.\n", test_loop_path); + } else { + if (verify_test_fd >= 0) { + printf("✗ FAILED: Device %s still accessible after deletion!\n", test_loop_path); + close(verify_test_fd); + } + } + + // ======================================================= + // 资源回收测试 2: 删除未绑定的设备 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Deleting Unbound Device ---\n"); + + int unbound_minor = -1; + int ret_unbound = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &unbound_minor) < 0) { + perror("Failed to get free loop device for unbound test"); + goto cleanup; + } + + ret_unbound = ioctl(control_fd, LOOP_CTL_ADD, unbound_minor); + if (ret_unbound >= 0) { + unbound_minor = ret_unbound; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for unbound test"); + goto cleanup; + } + } + + if (ret_unbound < 0) { + fprintf(stderr, "Failed to create unbound loop device after retries\n"); + goto cleanup; + } + printf("Created unbound loop device loop%d.\n", unbound_minor); + + // 立即删除未绑定的设备 + if (ioctl(control_fd, LOOP_CTL_REMOVE, unbound_minor) < 0) { + perror("Failed to remove unbound loop device"); + printf("✗ Unbound device deletion test FAILED.\n"); + } else { + printf("✓ Unbound device deletion test PASSED: Successfully deleted loop%d.\n", unbound_minor); + } + + // ======================================================= + // 资源回收测试 3: 重复删除同一设备 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Duplicate Deletion ---\n"); + + int dup_minor = -1; + int ret_dup = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &dup_minor) < 0) { + perror("Failed to get free loop device for duplicate deletion test"); + goto cleanup; + } + + ret_dup = ioctl(control_fd, LOOP_CTL_ADD, dup_minor); + if (ret_dup >= 0) { + dup_minor = ret_dup; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for duplicate deletion test"); + goto cleanup; + } + } + + if (ret_dup < 0) { + fprintf(stderr, "Failed to create loop device for duplicate deletion test after retries\n"); + goto cleanup; + } + printf("Created loop device loop%d for duplicate deletion test.\n", dup_minor); + + // 第一次删除 + if (ioctl(control_fd, LOOP_CTL_REMOVE, dup_minor) < 0) { + perror("First deletion failed"); + printf("✗ Duplicate deletion test FAILED: First deletion failed.\n"); + goto cleanup; + } + printf("First deletion of loop%d succeeded.\n", dup_minor); + + // 第二次删除(应该失败) + errno = 0; + int second_delete = ioctl(control_fd, LOOP_CTL_REMOVE, dup_minor); + if (second_delete < 0 && (errno == ENODEV || errno == EINVAL)) { + printf("✓ Duplicate deletion test PASSED: Second deletion correctly failed with errno %d.\n", errno); + } else { + printf("✗ Duplicate deletion test FAILED: Second deletion returned %d (errno: %d), expected failure.\n", + second_delete, errno); + } + + // ======================================================= + // 资源回收测试 4: 文件描述符泄漏检测 + // ======================================================= + printf("\n--- Testing Resource Reclamation: File Descriptor Leak Detection ---\n"); + + // 创建多个loop设备并快速删除,检查是否有FD泄漏 + #define LEAK_TEST_COUNT 10 + int leak_test_minors[LEAK_TEST_COUNT]; + int leak_test_fds[LEAK_TEST_COUNT]; + + printf("Creating and deleting %d loop devices to test for FD leaks...\n", LEAK_TEST_COUNT); + + for (int i = 0; i < LEAK_TEST_COUNT; i++) { + leak_test_minors[i] = -1; + leak_test_fds[i] = -1; + + // 使用重试机制创建设备 + for (int retry = 0; retry < 10; retry++) { + int free_minor; + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &free_minor) < 0) { + perror("Failed to get free loop device for leak test"); + // 清理已创建的设备 + for (int j = 0; j < i; j++) { + if (leak_test_minors[j] >= 0) { + ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); + } + } + goto cleanup; + } + + int ret_leak = ioctl(control_fd, LOOP_CTL_ADD, free_minor); + if (ret_leak >= 0) { + leak_test_minors[i] = ret_leak; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for leak test"); + for (int j = 0; j < i; j++) { + if (leak_test_minors[j] >= 0) { + ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); + } + } + goto cleanup; + } + } + + if (leak_test_minors[i] < 0) { + fprintf(stderr, "Failed to create loop device %d for leak test\n", i); + for (int j = 0; j < i; j++) { + if (leak_test_minors[j] >= 0) { + ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); + } + } + goto cleanup; + } + + // 打开并绑定设备 + char leak_path[64]; + sprintf(leak_path, "/dev/loop%d", leak_test_minors[i]); + leak_test_fds[i] = open(leak_path, O_RDWR); + if (leak_test_fds[i] >= 0) { + ioctl(leak_test_fds[i], LOOP_SET_FD, backing_fd_1); + } + } + + // 删除所有设备 + int leak_delete_success = 0; + for (int i = 0; i < LEAK_TEST_COUNT; i++) { + if (leak_test_fds[i] >= 0) { + ioctl(leak_test_fds[i], LOOP_CLR_FD, 0); + close(leak_test_fds[i]); + } + + if (ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[i]) == 0) { + leak_delete_success++; + } + } + + printf("Successfully deleted %d out of %d devices.\n", leak_delete_success, LEAK_TEST_COUNT); + if (leak_delete_success == LEAK_TEST_COUNT) { + printf("✓ FD leak test PASSED: All devices deleted successfully.\n"); + } else { + printf("⚠ FD leak test: %d devices failed to delete.\n", LEAK_TEST_COUNT - leak_delete_success); + } + + // ======================================================= + // 资源回收测试 5: 删除后设备不可访问 + // ======================================================= + printf("\n--- Testing Resource Reclamation: Device Inaccessibility After Deletion ---\n"); + + int reject_minor = -1; + int ret_reject = -1; + for (int retry = 0; retry < 10; retry++) { + if (ioctl(control_fd, LOOP_CTL_GET_FREE, &reject_minor) < 0) { + perror("Failed to get free loop device for I/O rejection test"); + goto cleanup; + } + + ret_reject = ioctl(control_fd, LOOP_CTL_ADD, reject_minor); + if (ret_reject >= 0) { + reject_minor = ret_reject; + break; + } + + if (errno != EEXIST) { + perror("Failed to add loop device for I/O rejection test"); + goto cleanup; + } + } + + if (ret_reject < 0) { + fprintf(stderr, "Failed to create loop device for I/O rejection test after retries\n"); + goto cleanup; + } + + char reject_path[64]; + sprintf(reject_path, "/dev/loop%d", reject_minor); + int reject_fd = open(reject_path, O_RDWR); + if (reject_fd < 0) { + perror("Failed to open loop device for I/O rejection test"); + ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor); + goto cleanup; + } + + if (ioctl(reject_fd, LOOP_SET_FD, backing_fd_1) < 0) { + perror("Failed to bind loop device for I/O rejection test"); + close(reject_fd); + ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor); + goto cleanup; + } + printf("Created and bound loop device loop%d for I/O rejection test.\n", reject_minor); + + // 执行一次成功的I/O操作 + char reject_buf[512] = "Test data"; + if (write(reject_fd, reject_buf, sizeof(reject_buf)) != sizeof(reject_buf)) { + perror("Initial write failed"); + } else { + printf("Initial write succeeded (expected).\n"); + } + + // 关闭文件描述符,准备删除 + close(reject_fd); + printf("Closed device file descriptor.\n"); + + // 触发删除 + printf("Triggering device deletion...\n"); + if (ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor) < 0) { + perror("Failed to trigger deletion for I/O rejection test"); + goto cleanup; + } + printf("Deletion triggered successfully.\n"); + + // 尝试重新打开设备(应该失败) + errno = 0; + int reopen_reject_fd = open(reject_path, O_RDWR); + if (reopen_reject_fd < 0 && (errno == ENODEV || errno == ENOENT)) { + printf("✓ I/O rejection test PASSED: Device correctly inaccessible after deletion (errno: %d).\n", errno); + } else { + if (reopen_reject_fd >= 0) { + printf("✗ I/O rejection test FAILED: Device still accessible after deletion.\n"); + close(reopen_reject_fd); + } else { + printf("✗ I/O rejection test FAILED: Unexpected errno %d (expected ENODEV or ENOENT).\n", errno); + } + } + + printf("\n=== All Resource Reclamation Tests Completed ===\n"); + cleanup: // 6. 清理并删除 loop 设备 @@ -482,16 +953,19 @@ int main() { perror("Failed to clear loop device backing file"); } + // 在删除设备前先关闭文件描述符,避免引用计数问题 + close(loop_fd); + printf("Closed loop device file descriptor.\n"); + printf("Removing loop device loop%d...\n", loop_minor); if (ioctl(control_fd, LOOP_CTL_REMOVE, loop_minor) < 0) { perror("Failed to remove loop device"); - // 尝试关闭所有打开的fd,即使删除失败也继续清理 + // 即使删除失败也继续清理 } else { printf("Loop device loop%d removed successfully.\n", loop_minor); } // 释放资源并删除测试文件 - close(loop_fd); close(backing_fd_1); close(backing_fd_2); close(control_fd); From 126bc5a1b23b7bd36e77b4f091b7868c2b069397 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 27 Nov 2025 22:41:46 +0800 Subject: [PATCH 27/39] =?UTF-8?q?-=20refactor:=20=E8=B0=83=E6=95=B4loop=5F?= =?UTF-8?q?device=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/base/block/gendisk/mod.rs | 2 +- .../driver/block/loop_device/loop_device.rs | 1788 ---------------- kernel/src/driver/block/loop_device/mod.rs | 1789 ++++++++++++++++- kernel/src/filesystem/vfs/file.rs | 2 +- 4 files changed, 1790 insertions(+), 1791 deletions(-) delete mode 100644 kernel/src/driver/block/loop_device/loop_device.rs diff --git a/kernel/src/driver/base/block/gendisk/mod.rs b/kernel/src/driver/base/block/gendisk/mod.rs index 70321cdc8..e63de5148 100644 --- a/kernel/src/driver/base/block/gendisk/mod.rs +++ b/kernel/src/driver/base/block/gendisk/mod.rs @@ -14,7 +14,7 @@ use system_error::SystemError; use super::block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}; use crate::{ driver::base::device::device_number::DeviceNumber, - driver::block::loop_device::loop_device::LoopDevice, + driver::block::loop_device::LoopDevice, filesystem::{ devfs::{DevFS, DeviceINode, LockedDevFSInode}, vfs::{syscall::ModeType, utils::DName, IndexNode, Metadata}, diff --git a/kernel/src/driver/block/loop_device/loop_device.rs b/kernel/src/driver/block/loop_device/loop_device.rs deleted file mode 100644 index b4cc582f5..000000000 --- a/kernel/src/driver/block/loop_device/loop_device.rs +++ /dev/null @@ -1,1788 +0,0 @@ -use crate::{ - driver::base::{ - block::{ - block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, - disk_info::Partition, - manager::{block_dev_manager, BlockDevMeta}, - }, - class::Class, - device::{ - bus::Bus, - device_number::{DeviceNumber, Major}, - device_register, - driver::{Driver, DriverCommonData}, - DevName, Device, DeviceCommonData, DeviceType, IdTable, - }, - kobject::{ - KObjType, KObject, KObjectCommonData, KObjectManager, KObjectState, KObjectSysFSOps, - LockedKObjectState, - }, - kset::KSet, - }, - filesystem::{ - devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, - kernfs::KernFSInode, - sysfs::{AttributeGroup, SysFSOps}, - vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata}, - }, - libs::{ - rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, - spinlock::{SpinLock, SpinLockGuard}, - }, - process::ProcessManager, - syscall::user_access::{UserBufferReader, UserBufferWriter}, -}; -use alloc::{ - string::{String, ToString}, - sync::{Arc, Weak}, - vec::Vec, -}; -use core::{ - any::Any, - fmt::{Debug, Formatter}, - sync::atomic::{AtomicU32, Ordering}, -}; -use ida::IdAllocator; -use log::{error, info, warn}; -use num_traits::FromPrimitive; -use system_error::SystemError; -use unified_init::macros::unified_init; -const LOOP_BASENAME: &str = "loop"; -const LOOP_CONTROL_BASENAME: &str = "loop-control"; -pub const LOOP_CONTROL_MINOR: u32 = 237; -#[repr(u32)] -#[derive(Debug, FromPrimitive)] -pub enum LoopIoctl { - LoopSetFd = 0x4C00, - LoopClrFd = 0x4C01, - LoopSetStatus = 0x4C02, - LoopGetStatus = 0x4C03, - LoopSetStatus64 = 0x4C04, - LoopGetStatus64 = 0x4C05, - LoopChangeFd = 0x4C06, - LoopSetCapacity = 0x4C07, - LoopSetDirectIo = 0x4c08, - LoopSetBlockSize = 0x4c09, - LoopConfigure = 0x4c0a, -} -#[repr(u32)] -#[derive(Debug, FromPrimitive)] -pub enum LoopControlIoctl { - Add = 0x4C80, - Remove = 0x4C81, - GetFree = 0x4C82, -} -pub const LO_FLAGS_READ_ONLY: u32 = 1 << 0; -pub const SUPPORTED_LOOP_FLAGS: u32 = LO_FLAGS_READ_ONLY; -#[repr(C)] -#[derive(Default, Clone, Copy)] -pub struct LoopStatus64 { - pub lo_offset: u64, - pub lo_sizelimit: u64, - pub lo_flags: u32, - pub __pad: u32, -} -#[derive(Debug)] -pub struct LoopDeviceKObjType; - -impl KObjType for LoopDeviceKObjType { - fn release(&self, kobj: Arc) { - if let Some(loop_dev) = kobj.as_any_ref().downcast_ref::() { - loop_dev.final_cleanup(); - } - } - - fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { - Some(&KObjectSysFSOps) - } - - fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { - None - } -} -static LOOP_DEVICE_KOBJ_TYPE: LoopDeviceKObjType = LoopDeviceKObjType; -struct IoGuard<'a> { - device: &'a LoopDevice, -} - -impl<'a> IoGuard<'a> { - fn new(device: &'a LoopDevice) -> Result { - device.io_start()?; - Ok(Self { device }) - } -} - -impl<'a> Drop for IoGuard<'a> { - fn drop(&mut self) { - self.device.io_end(); - } -} - -pub struct LoopDevice { - id: usize, - minor: u32, - inner: SpinLock, - block_dev_meta: BlockDevMeta, - locked_kobj_state: LockedKObjectState, - self_ref: Weak, - fs: RwLock>, - parent: RwLock>, - /// 活跃的 I/O 操作计数 - active_io_count: AtomicU32, -} -#[derive(Debug, Clone)] -pub struct LoopPrivateData { - pub parms: u32, -} -pub struct LoopDeviceInner { - pub device_number: DeviceNumber, - state: LoopState, - state_lock: SpinLock<()>, - pub file_inode: Option>, - pub file_size: usize, - pub offset: usize, - pub size_limit: usize, - pub flags: u32, - pub read_only: bool, - pub kobject_common: KObjectCommonData, - pub device_common: DeviceCommonData, -} -impl LoopDeviceInner { - fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { - let _guard = self.state_lock.lock(); - - match (&self.state, &new_state) { - (LoopState::Unbound, LoopState::Bound) => {} - (LoopState::Bound, LoopState::Unbound) => {} - (LoopState::Bound, LoopState::Rundown) => {} - (LoopState::Rundown, LoopState::Draining) => {} - (LoopState::Rundown, LoopState::Deleting) => {} - (LoopState::Rundown, LoopState::Unbound) => {} - (LoopState::Draining, LoopState::Deleting) => {} - (LoopState::Unbound, LoopState::Deleting) => {} - _ => return Err(SystemError::EINVAL), - } - - self.state = new_state; - Ok(()) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LoopState { - Unbound, - Bound, - Rundown, - Draining, - Deleting, -} -impl Debug for LoopDevice { - fn fmt(&'_ self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("LoopDevice") - .field("id", &self.id) - .field("devname", &self.block_dev_meta.devname) - .finish() - } -} -impl LoopDevice { - fn inner(&'_ self) -> SpinLockGuard<'_, LoopDeviceInner> { - self.inner.lock() - } - pub fn id(&self) -> usize { - self.id - } - pub fn minor(&self) -> u32 { - self.minor - } - /// # 功能 - /// - /// 创建一个未绑定文件的 loop 设备实例。 - /// - /// ## 参数 - /// - /// - `devname`: 设备名称。 - /// - `minor`: 次设备号。 - /// - /// ## 返回值 - /// - `Some(Arc)`: 成功创建的 loop 设备。 - /// - `None`: 内存不足或创建失败。 - pub fn new_empty_loop_device(devname: DevName, id: usize, minor: u32) -> Option> { - let dev = Arc::new_cyclic(|self_ref| Self { - id, - minor, - inner: SpinLock::new(LoopDeviceInner { - file_inode: None, // 默认的虚拟 inode - file_size: 0, - device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), // Loop 设备主设备号为 7 - offset: 0, - size_limit: 0, - flags: 0, - read_only: false, - kobject_common: KObjectCommonData::default(), - device_common: DeviceCommonData::default(), - state: LoopState::Unbound, - state_lock: SpinLock::new(()), - //work_queue: None, - }), - block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), // Loop 设备主设备号为 7 - locked_kobj_state: LockedKObjectState::default(), - self_ref: self_ref.clone(), - fs: RwLock::new(Weak::default()), - parent: RwLock::new(Weak::default()), - active_io_count: AtomicU32::new(0), - }); - - // 设置 KObjType - dev.set_kobj_type(Some(&LOOP_DEVICE_KOBJ_TYPE)); - - Some(dev) - } - - /// # 功能 - /// - /// 为 loop 设备绑定后端文件并重置相关状态。 - /// - /// ## 参数 - /// - /// - `file_inode`: 需要绑定的文件节点。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功绑定文件。 - /// - `Err(SystemError)`: 绑定失败的错误原因。 - pub fn set_file(&self, file_inode: Arc) -> Result<(), SystemError> { - let metadata = file_inode.metadata()?; - if metadata.size < 0 { - return Err(SystemError::EINVAL); - } - let file_size = metadata.size as usize; - - let mut inner = self.inner(); - inner.file_inode = Some(file_inode); - inner.file_size = file_size; - inner.offset = 0; - inner.size_limit = 0; - inner.flags = 0; // Reset flags - inner.read_only = false; // Reset read_only - drop(inner); - self.recalc_effective_size()?; // Recalculate size based on new file - Ok(()) - } - fn recalc_effective_size(&self) -> Result<(), SystemError> { - let (file_inode, offset, size_limit) = { - let inner = self.inner(); - (inner.file_inode.clone(), inner.offset, inner.size_limit) - }; - - let inode = file_inode.ok_or(SystemError::ENODEV)?; - let metadata = inode.metadata()?; - if metadata.size < 0 { - return Err(SystemError::EINVAL); - } - let total_size = metadata.size as usize; - if offset > total_size { - return Err(SystemError::EINVAL); - } - let mut effective = total_size - offset; - if size_limit > 0 { - effective = effective.min(size_limit); - } - - let mut inner = self.inner(); - inner.file_size = effective; - Ok(()) - } - - pub fn is_bound(&self) -> bool { - matches!(self.inner().state, LoopState::Bound) - } - /// # 功能 - /// - /// 将文件绑定到 loop 设备并设置访问权限。 - /// - /// ## 参数 - /// - /// - `file_inode`: 需要绑定的文件节点。 - /// - `read_only`: 是否以只读方式绑定。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功绑定。 - /// - `Err(SystemError)`: 绑定失败的原因。 - pub fn bind_file( - &self, - file_inode: Arc, - read_only: bool, - ) -> Result<(), SystemError> { - { - let inner = self.inner(); - if matches!(inner.state, LoopState::Bound) { - return Err(SystemError::EBUSY); - } - } - - self.set_file(file_inode.clone())?; - - let mut inner = self.inner(); - inner.set_state(LoopState::Bound)?; - inner.read_only = read_only; - inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; - inner.size_limit = 0; - drop(inner); - self.recalc_effective_size()?; - Ok(()) - } - /// # 功能 - /// - /// 清除 loop 设备的文件绑定并复位状态。 - /// - /// ## 参数 - /// - /// - 无。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功清除。 - /// - `Err(SystemError)`: 清除过程中的错误。 - pub fn clear_file(&self) -> Result<(), SystemError> { - let mut inner = self.inner(); - match inner.state { - LoopState::Bound | LoopState::Rundown => inner.set_state(LoopState::Unbound)?, - LoopState::Unbound => {} - LoopState::Draining => return Err(SystemError::EBUSY), - LoopState::Deleting => { - // 在删除流程中,允许清理文件 - // 状态已经是Deleting,无需改变 - } - } - - inner.file_inode = None; - inner.file_size = 0; - inner.offset = 0; - inner.size_limit = 0; - inner.read_only = false; - inner.flags = 0; - Ok(()) - } - fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { - if !info.lo_offset.is_multiple_of(LBA_SIZE as u64) { - return Err(SystemError::EINVAL); - } - if info.lo_offset > usize::MAX as u64 || info.lo_sizelimit > usize::MAX as u64 { - return Err(SystemError::EINVAL); - } - if info.lo_sizelimit != 0 && !info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) { - return Err(SystemError::EINVAL); - } - if info.lo_flags & !SUPPORTED_LOOP_FLAGS != 0 { - return Err(SystemError::EINVAL); - } - Ok(()) - } - /// 设置 loop 设备的状态(64 位版本)。 - /// - /// ## 参数 - /// - /// - `user_ptr`: 用户空间传入的 `LoopStatus64` 结构体指针。 - /// - /// ## 返回值 - /// - `Ok(())`: 状态设置成功。 - /// - `Err(SystemError::EINVAL)`: 无效的参数或标志位。 - /// - `Err(SystemError::ENXIO)`: 设备未绑定或已卸载。 - fn set_status64(&self, user_ptr: usize) -> Result<(), SystemError> { - if user_ptr == 0 { - return Err(SystemError::EINVAL); - } - - let reader = UserBufferReader::new::( - user_ptr as *const LoopStatus64, - core::mem::size_of::(), - true, - )?; - let mut info = LoopStatus64::default(); - reader.copy_one_from_user(&mut info, 0)?; - Self::validate_loop_status64_params(&info)?; - let new_offset = info.lo_offset as usize; - let new_limit = if info.lo_sizelimit == 0 { - 0 - } else { - info.lo_sizelimit as usize - }; - let new_read_only = (info.lo_flags & LO_FLAGS_READ_ONLY) != 0; - - let (old_offset, old_limit, old_flags, old_ro) = { - let inner = self.inner(); - if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { - return Err(SystemError::ENXIO); - } - (inner.offset, inner.size_limit, inner.flags, inner.read_only) - }; - - { - let mut inner = self.inner(); - if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { - return Err(SystemError::ENXIO); - } - inner.offset = new_offset; - inner.size_limit = new_limit; - inner.flags = info.lo_flags; - inner.read_only = new_read_only; - } - - if let Err(err) = self.recalc_effective_size() { - let mut inner = self.inner(); - inner.offset = old_offset; - inner.size_limit = old_limit; - inner.flags = old_flags; - inner.read_only = old_ro; - drop(inner); - let _ = self.recalc_effective_size(); - return Err(err); - } - - Ok(()) - } - /// # 功能 - /// - /// 获取 loop 设备的 LoopStatus64 信息并写回用户态。 - /// - /// ## 参数 - /// - /// - `user_ptr`: 用户态缓冲区地址。 - /// - /// ## 返回值 - /// - `Ok(())`: 信息写回成功。 - /// - `Err(SystemError)`: 读取状态失败。 - /// - fn get_status64(&self, user_ptr: usize) -> Result<(), SystemError> { - if user_ptr == 0 { - return Err(SystemError::EINVAL); - } - - let info = { - let inner = self.inner(); - if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { - return Err(SystemError::ENXIO); - } - LoopStatus64 { - lo_offset: inner.offset as u64, - lo_sizelimit: inner.size_limit as u64, - lo_flags: if inner.read_only { - inner.flags | LO_FLAGS_READ_ONLY - } else { - inner.flags & !LO_FLAGS_READ_ONLY - }, - __pad: 0, - } - }; - - let mut writer = UserBufferWriter::new::( - user_ptr as *mut LoopStatus64, - core::mem::size_of::(), - true, - )?; - writer.copy_one_to_user(&info, 0)?; - Ok(()) - } - fn set_status(&self, user_ptr: usize) -> Result<(), SystemError> { - self.set_status64(user_ptr) - } - fn get_status(&self, user_ptr: usize) -> Result<(), SystemError> { - self.get_status64(user_ptr) - } - /// # 功能 - /// - /// 将 loop 设备切换到新的文件描述符。 - /// - /// ## 参数 - /// - /// - `new_file_fd`: 新的文件描述符。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功切换。 - /// - `Err(SystemError)`: 切换失败原因。 - fn change_fd(&self, new_file_fd: i32) -> Result<(), SystemError> { - let fd_table = ProcessManager::current_pcb().fd_table(); - let file = { - let guard = fd_table.read(); - guard.get_file_by_fd(new_file_fd) - } - .ok_or(SystemError::EBADF)?; - - let mode = file.mode(); - let read_only = !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); - - let inode = file.inode(); - let metadata = inode.metadata()?; - match metadata.file_type { - FileType::File | FileType::BlockDevice => {} - _ => return Err(SystemError::EINVAL), - } - let mut inner = self.inner(); - inner.file_inode = Some(inode); - inner.read_only = read_only; - inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; - drop(inner); - self.recalc_effective_size()?; - Ok(()) - } - fn set_capacity(&self, _arg: usize) -> Result<(), SystemError> { - self.recalc_effective_size()?; - Ok(()) - } - - /// # 功能 - /// - /// I/O 操作开始时调用,增加活跃 I/O 计数 - /// - /// ## 返回值 - /// - `Ok(())`: 成功增加计数 - /// - `Err(SystemError::ENODEV)`: 设备正在删除,拒绝新的 I/O - fn io_start(&self) -> Result<(), SystemError> { - let inner = self.inner(); - if matches!( - inner.state, - LoopState::Rundown | LoopState::Draining | LoopState::Deleting - ) { - return Err(SystemError::ENODEV); - } - - self.active_io_count.fetch_add(1, Ordering::AcqRel); - Ok(()) - } - - /// # 功能 - /// - /// I/O 操作完成时调用,减少活跃 I/O 计数 - fn io_end(&self) { - let prev = self.active_io_count.fetch_sub(1, Ordering::AcqRel); - if prev == 0 { - warn!( - "Loop device loop{}: I/O count underflow", - self.inner().device_number.minor() - ); - } - } - - /// # 功能 - /// - /// 进入 Rundown 状态,停止接受新的 I/O 请求 - /// - /// ## 返回值 - /// - `Ok(())`: 成功进入 Rundown 状态 - /// - `Err(SystemError)`: 状态转换失败 - fn enter_rundown_state(&self) -> Result<(), SystemError> { - let mut inner = self.inner(); - match inner.state { - LoopState::Bound => { - inner.set_state(LoopState::Rundown)?; - info!( - "Loop device loop{} entering rundown state", - inner.device_number.minor() - ); - } - LoopState::Unbound => { - // 空设备可以直接删除 - inner.set_state(LoopState::Deleting)?; - info!( - "Loop device loop{} is unbound, skipping to deleting state", - inner.device_number.minor() - ); - } - LoopState::Rundown => {} - LoopState::Draining | LoopState::Deleting => { - return Err(SystemError::EBUSY); - } - } - Ok(()) - } - - /// # 功能 - /// - /// 等待所有活跃的 I/O 操作完成 - /// - /// ## 返回值 - /// - `Ok(())`: 所有 I/O 已完成 - /// - `Err(SystemError::ETIMEDOUT)`: 等待超时 - fn drain_active_io(&self) -> Result<(), SystemError> { - let mut inner = self.inner(); - if matches!(inner.state, LoopState::Rundown) { - inner.set_state(LoopState::Draining)?; - info!( - "Loop device loop{} entering draining state", - inner.device_number.minor() - ); - } - drop(inner); - let timeout_ms = 30_000; - let check_interval_us = 10_000; - let max_checks = timeout_ms * 1000 / check_interval_us; - - for _i in 0..max_checks { - let count = self.active_io_count.load(Ordering::Acquire); - if count == 0 { - break; - } - - core::hint::spin_loop(); - } - - let final_count = self.active_io_count.load(Ordering::Acquire); - if final_count != 0 { - error!( - "Timeout waiting for I/O to drain on loop{}: {} operations still active", - self.minor(), - final_count - ); - return Err(SystemError::ETIMEDOUT); - } - - info!( - "All I/O operations drained for loop device loop{}", - self.minor() - ); - - let mut inner = self.inner(); - inner.set_state(LoopState::Deleting)?; - - Ok(()) - } - - /// # 功能 - /// - /// 从 sysfs 中移除设备 - /// - /// ## 返回值 - /// - `Ok(())`: 成功移除 - /// - `Err(SystemError)`: 移除失败 - fn remove_from_sysfs(&self) -> Result<(), SystemError> { - // 使用 KObjectManager 从 sysfs 中移除 - if let Some(kobj) = self.self_ref.upgrade() { - KObjectManager::remove_kobj(kobj as Arc); - info!("Removed loop device loop{} from sysfs", self.minor()); - } - Ok(()) - } - - /// # 功能 - /// - /// 最终清理函数,由 KObjType::release 调用 - /// 执行设备删除的最后清理工作 - fn final_cleanup(&self) { - info!( - "Final cleanup for loop device loop{} (id {})", - self.minor(), - self.id() - ); - let mut inner = self.inner(); - if let Some(file_inode) = inner.file_inode.take() { - drop(file_inode); - warn!( - "File inode was still present during final cleanup for loop{}", - self.minor() - ); - } - inner.file_size = 0; - inner.offset = 0; - inner.size_limit = 0; - info!("Loop device loop{} cleanup complete", self.minor()); - } -} - -impl KObject for LoopDevice { - fn as_any_ref(&self) -> &dyn Any { - self - } - fn set_inode(&self, inode: Option>) { - self.inner().kobject_common.kern_inode = inode; - } - fn inode(&self) -> Option> { - self.inner().kobject_common.kern_inode.clone() - } - - fn parent(&self) -> Option> { - self.inner().kobject_common.parent.clone() - } - - fn set_parent(&self, parent: Option>) { - self.inner().kobject_common.parent = parent; - } - - fn kset(&self) -> Option> { - self.inner().kobject_common.kset.clone() - } - - fn set_kset(&self, kset: Option>) { - self.inner().kobject_common.kset = kset; - } - - fn kobj_type(&self) -> Option<&'static dyn KObjType> { - self.inner().kobject_common.kobj_type - } - - fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { - self.inner().kobject_common.kobj_type = ktype; - } - - fn name(&self) -> String { - LOOP_BASENAME.to_string() - } - - fn set_name(&self, _name: String) { - // do nothing,不支持设置loop为别的名称 - } - - fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { - self.locked_kobj_state.read() - } - - fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { - self.locked_kobj_state.write() - } - - fn set_kobj_state(&self, state: KObjectState) { - *self.locked_kobj_state.write() = state; - } -} - -impl IndexNode for LoopDevice { - fn fs(&self) -> Arc { - todo!() - } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } - - fn read_at( - &self, - offset: usize, - len: usize, - buf: &mut [u8], - _data: SpinLockGuard, - ) -> Result { - if len > buf.len() { - return Err(SystemError::ENOBUFS); - } - BlockDevice::read_at_bytes(self, offset, len, buf) - } - - fn write_at( - &self, - offset: usize, - len: usize, - buf: &[u8], - _data: SpinLockGuard, - ) -> Result { - if len > buf.len() { - return Err(SystemError::E2BIG); - } - BlockDevice::write_at_bytes(self, offset, len, &buf[..len]) - } - - fn list(&self) -> Result, system_error::SystemError> { - Err(SystemError::ENOSYS) - } - fn metadata(&self) -> Result { - let file_metadata = match &self.inner().file_inode { - Some(inode) => inode.metadata()?, - None => { - return Err(SystemError::EPERM); - } - }; - let metadata = Metadata { - dev_id: 0, - inode_id: InodeId::new(0), - size: self.inner().file_size as i64, - blk_size: LBA_SIZE, - blocks: (self.inner().file_size.div_ceil(LBA_SIZE)), - atime: file_metadata.atime, - mtime: file_metadata.mtime, - ctime: file_metadata.ctime, - btime: file_metadata.btime, - file_type: crate::filesystem::vfs::FileType::BlockDevice, - mode: crate::filesystem::vfs::syscall::ModeType::from_bits_truncate(0o644), - nlinks: 1, - uid: 0, - gid: 0, - raw_dev: self.inner().device_number, - }; - Ok(metadata) - } - fn ioctl( - &self, - cmd: u32, - data: usize, - _private_data: &FilePrivateData, - ) -> Result { - match LoopIoctl::from_u32(cmd) { - Some(LoopIoctl::LoopSetFd) => { - let file_fd = data as i32; - let fd_table = ProcessManager::current_pcb().fd_table(); - let file = { - let guard = fd_table.read(); - guard.get_file_by_fd(file_fd) - } - .ok_or(SystemError::EBADF)?; - - let mode = file.mode(); - let read_only = - !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); - - let inode = file.inode(); - let metadata = inode.metadata()?; - match metadata.file_type { - FileType::File | FileType::BlockDevice => {} - _ => return Err(SystemError::EINVAL), - } - - self.bind_file(inode, read_only)?; - Ok(0) - } - Some(LoopIoctl::LoopClrFd) => { - self.clear_file()?; - Ok(0) - } - Some(LoopIoctl::LoopSetStatus) => { - self.set_status(data)?; - Ok(0) - } - Some(LoopIoctl::LoopGetStatus) => { - self.get_status(data)?; - Ok(0) - } - Some(LoopIoctl::LoopSetStatus64) => { - self.set_status64(data)?; - Ok(0) - } - Some(LoopIoctl::LoopGetStatus64) => { - self.get_status64(data)?; - Ok(0) - } - Some(LoopIoctl::LoopChangeFd) => { - self.change_fd(data as i32)?; - Ok(0) - } - Some(LoopIoctl::LoopSetCapacity) => { - self.set_capacity(data)?; - Ok(0) - } - _ => Err(SystemError::ENOSYS), - } - } -} - -impl DeviceINode for LoopDevice { - fn set_fs(&self, fs: alloc::sync::Weak) { - *self.fs.write() = fs; - } - fn set_parent(&self, parent: Weak) { - *self.parent.write() = parent; - } -} - -impl Device for LoopDevice { - fn dev_type(&self) -> DeviceType { - DeviceType::Block - } - - fn id_table(&self) -> IdTable { - IdTable::new(LOOP_BASENAME.to_string(), None) - } - - fn bus(&self) -> Option> { - self.inner().device_common.bus.clone() - } - - fn set_bus(&self, bus: Option>) { - self.inner().device_common.bus = bus; - } - - fn class(&self) -> Option> { - let mut guard = self.inner(); - let r = guard.device_common.class.clone()?.upgrade(); - if r.is_none() { - guard.device_common.class = None; - } - return r; - } - - fn set_class(&self, class: Option>) { - self.inner().device_common.class = class; - } - - fn driver(&self) -> Option> { - let r = self.inner().device_common.driver.clone()?.upgrade(); - if r.is_none() { - self.inner().device_common.driver = None; - } - return r; - } - - fn set_driver(&self, driver: Option>) { - self.inner().device_common.driver = driver; - } - - fn is_dead(&self) -> bool { - false - } - - fn can_match(&self) -> bool { - self.inner().device_common.can_match - } - - fn set_can_match(&self, can_match: bool) { - self.inner().device_common.can_match = can_match; - } - - fn state_synced(&self) -> bool { - true - } - - fn dev_parent(&self) -> Option> { - self.inner().device_common.get_parent_weak_or_clear() - } - - fn set_dev_parent(&self, parent: Option>) { - self.inner().device_common.parent = parent; - } -} - -impl BlockDevice for LoopDevice { - fn dev_name(&self) -> &DevName { - &self.block_dev_meta.devname - } - - fn blkdev_meta(&self) -> &BlockDevMeta { - &self.block_dev_meta - } - - fn disk_range(&self) -> GeneralBlockRange { - let inner = self.inner(); - let blocks = if inner.file_size == 0 { - 0 - } else { - inner.file_size.saturating_add(LBA_SIZE - 1) / LBA_SIZE - }; - drop(inner); - GeneralBlockRange::new(0, blocks).unwrap_or(GeneralBlockRange { - lba_start: 0, - lba_end: 0, - }) - } - fn read_at_sync( - &self, - lba_id_start: BlockId, - count: usize, - buf: &mut [u8], - ) -> Result { - // 使用 IoGuard 确保 I/O 计数正确管理 - let _io_guard = IoGuard::new(self)?; - - if count == 0 { - return Ok(0); - } - let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; - if len > buf.len() { - return Err(SystemError::EINVAL); - } - - let (file_inode, base_offset, limit_end) = { - let inner = self.inner(); - let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; - let limit = inner - .offset - .checked_add(inner.file_size) - .ok_or(SystemError::EOVERFLOW)?; - (inode, inner.offset, limit) - }; - - let block_offset = lba_id_start - .checked_mul(LBA_SIZE) - .ok_or(SystemError::EOVERFLOW)?; - let file_offset = base_offset - .checked_add(block_offset) - .ok_or(SystemError::EOVERFLOW)?; - - let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; - if end > limit_end { - return Err(SystemError::ENOSPC); - } - - let data = SpinLock::new(FilePrivateData::Unused); - let data_guard = data.lock(); - - file_inode.read_at(file_offset, len, &mut buf[..len], data_guard) - } - - fn write_at_sync( - &self, - lba_id_start: BlockId, - count: usize, - buf: &[u8], - ) -> Result { - // 使用 IoGuard 确保 I/O 计数正确管理 - let _io_guard = IoGuard::new(self)?; - - if count == 0 { - return Ok(0); - } - let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; - if len > buf.len() { - return Err(SystemError::EINVAL); - } - - let (file_inode, base_offset, limit_end, read_only) = { - let inner = self.inner(); - let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; - let limit = inner - .offset - .checked_add(inner.file_size) - .ok_or(SystemError::EOVERFLOW)?; - (inode, inner.offset, limit, inner.read_only) - }; - - if read_only { - return Err(SystemError::EROFS); - } - - let block_offset = lba_id_start - .checked_mul(LBA_SIZE) - .ok_or(SystemError::EOVERFLOW)?; - let file_offset = base_offset - .checked_add(block_offset) - .ok_or(SystemError::EOVERFLOW)?; - - let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; - if end > limit_end { - return Err(SystemError::ENOSPC); - } - - let data = SpinLock::new(FilePrivateData::Unused); - let data_guard = data.lock(); - - let written = file_inode.write_at(file_offset, len, &buf[..len], data_guard)?; - - if written > 0 { - let _ = self.recalc_effective_size(); - } - - Ok(written) - } - - fn sync(&self) -> Result<(), SystemError> { - Ok(()) - } - - fn blk_size_log2(&self) -> u8 { - 9 - } - - fn as_any_ref(&self) -> &dyn Any { - self - } - - fn device(&self) -> Arc { - self.self_ref.upgrade().unwrap() - } - - fn block_size(&self) -> usize { - LBA_SIZE - } - - fn partitions(&self) -> Vec> { - Vec::new() - } -} - -/// Loop设备驱动 -/// 参考Virtio_blk驱动的实现 -#[derive(Debug)] -#[cast_to([sync] Driver)] -pub struct LoopDeviceDriver { - inner: SpinLock, - kobj_state: LockedKObjectState, -} -struct InnerLoopDeviceDriver { - driver_common: DriverCommonData, - kobj_common: KObjectCommonData, -} -impl Debug for InnerLoopDeviceDriver { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("InnerLoopDeviceDriver") - .field("driver_common", &self.driver_common) - .field("kobj_common", &self.kobj_common) - .finish() - } -} -impl LoopDeviceDriver { - pub fn new() -> Arc { - let inner = InnerLoopDeviceDriver { - driver_common: DriverCommonData::default(), - kobj_common: KObjectCommonData::default(), - }; - Arc::new(Self { - inner: SpinLock::new(inner), - kobj_state: LockedKObjectState::default(), - }) - } - fn inner(&'_ self) -> SpinLockGuard<'_, InnerLoopDeviceDriver> { - self.inner.lock() - } -} -use crate::init::initcall::INITCALL_DEVICE; -#[unified_init(INITCALL_DEVICE)] -pub fn loop_init() -> Result<(), SystemError> { - let loop_mgr = Arc::new(LoopManager::new()); - let driver = LoopDeviceDriver::new(); - let loop_ctl = LoopControlDevice::new(loop_mgr.clone()); - - device_register(loop_ctl.clone())?; - log::info!("Loop control device registered."); - devfs_register(LOOP_CONTROL_BASENAME, loop_ctl.clone())?; - log::info!("Loop control device initialized."); - loop_mgr.loop_init(driver)?; - Ok(()) -} - -impl Driver for LoopDeviceDriver { - fn id_table(&self) -> Option { - Some(IdTable::new(LOOP_BASENAME.to_string(), None)) - } - - fn devices(&self) -> Vec> { - self.inner().driver_common.devices.clone() - } - - fn add_device(&self, device: Arc) { - self.inner().driver_common.push_device(device); - } - - fn delete_device(&self, device: &Arc) { - self.inner().driver_common.delete_device(device); - } - - fn bus(&self) -> Option> { - self.inner().driver_common.bus.clone() - } - - fn set_bus(&self, bus: Option>) { - self.inner().driver_common.bus = bus; - } -} - -impl KObject for LoopDeviceDriver { - fn as_any_ref(&self) -> &dyn Any { - self - } - - fn set_inode(&self, inode: Option>) { - self.inner().kobj_common.kern_inode = inode; - } - - fn inode(&self) -> Option> { - self.inner().kobj_common.kern_inode.clone() - } - - fn parent(&self) -> Option> { - self.inner().kobj_common.parent.clone() - } - - fn set_parent(&self, parent: Option>) { - self.inner().kobj_common.parent = parent; - } - - fn kset(&self) -> Option> { - self.inner().kobj_common.kset.clone() - } - - fn set_kset(&self, kset: Option>) { - self.inner().kobj_common.kset = kset; - } - - fn kobj_type(&self) -> Option<&'static dyn KObjType> { - self.inner().kobj_common.kobj_type - } - - fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { - self.inner().kobj_common.kobj_type = ktype; - } - - fn name(&self) -> String { - LOOP_BASENAME.to_string() - } - - fn set_name(&self, _name: String) { - // do nothing - } - - fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { - self.kobj_state.read() - } - - fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { - self.kobj_state.write() - } - - fn set_kobj_state(&self, state: KObjectState) { - *self.kobj_state.write() = state; - } -} - -pub struct LoopManager { - inner: SpinLock, -} -pub struct LoopManagerInner { - devices: [Option>; LoopManager::MAX_DEVICES], - id_alloc: IdAllocator, - next_free_minor: u32, -} -impl LoopManager { - const MAX_DEVICES: usize = 256; - const MAX_INIT_DEVICES: usize = 8; - pub fn new() -> Self { - Self { - inner: SpinLock::new(LoopManagerInner { - devices: [const { None }; Self::MAX_DEVICES], - id_alloc: IdAllocator::new(0, Self::MAX_DEVICES) - .expect("create IdAllocator failed"), - next_free_minor: 0, - }), - } - } - fn inner(&'_ self) -> SpinLockGuard<'_, LoopManagerInner> { - self.inner.lock() - } - #[inline] - fn alloc_id_locked(inner: &mut LoopManagerInner) -> Option { - inner.id_alloc.alloc() - } - #[inline] - fn free_id_locked(inner: &mut LoopManagerInner, id: usize) { - if id < Self::MAX_DEVICES && inner.id_alloc.exists(id) { - inner.id_alloc.free(id); - } - } - #[inline] - pub fn format_name(id: usize) -> DevName { - DevName::new(format!("{}{}", LOOP_BASENAME, id), id) - } - fn find_device_by_minor_locked( - inner: &LoopManagerInner, - minor: u32, - ) -> Option> { - inner - .devices - .iter() - .flatten() - .find(|device| device.minor() == minor) - .map(Arc::clone) - } - - fn find_unused_minor_locked(inner: &LoopManagerInner) -> Option { - let mut candidate = inner.next_free_minor; - for _ in 0..Self::MAX_DEVICES as u32 { - let mut used = false; - for dev in inner.devices.iter().flatten() { - if dev.minor() == candidate { - used = true; - break; - } - } - if !used { - return Some(candidate); - } - candidate = (candidate + 1) % Self::MAX_DEVICES as u32; - } - None - } - /* - 请求队列,工作队列未实现 - */ - /// # 功能 - /// - /// 根据请求的次设备号分配或复用 loop 设备。 - /// - /// ## 参数 - /// - /// - `requested_minor`: 指定的次设备号,`None` 表示自动分配。 - /// - /// ## 返回值 - /// - `Ok(Arc)`: 成功获得的设备。 - /// - `Err(SystemError)`: 无可用设备或参数错误。 - pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { - let mut inner = self.inner(); - match requested_minor { - Some(req_minor) => self.loop_add_specific_locked(&mut inner, req_minor), - None => self.loop_add_first_available_locked(&mut inner), - } - } - /// # 功能 - /// - /// 在锁作用域内分配指定次设备号的 loop 设备。 - /// - /// ## 参数 - /// - /// - `inner`: 管理器内部状态锁。 - /// - `minor`: 目标次设备号。 - /// - /// ## 返回值 - /// - `Ok(Arc)`: 成功获得的设备实例。 - /// - `Err(SystemError)`: 参数无效或设备已被占用。 - fn loop_add_specific_locked( - &self, - inner: &mut LoopManagerInner, - minor: u32, - ) -> Result, SystemError> { - if minor >= Self::MAX_DEVICES as u32 { - return Err(SystemError::EINVAL); - } - - if let Some(device) = Self::find_device_by_minor_locked(inner, minor) { - if device.is_bound() { - return Err(SystemError::EEXIST); - } - return Ok(device); - } - - let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; - match self.create_and_register_device_locked(inner, id, minor) { - Ok(device) => Ok(device), - Err(e) => { - Self::free_id_locked(inner, id); - Err(e) - } - } - } - - fn loop_add_first_available_locked( - &self, - inner: &mut LoopManagerInner, - ) -> Result, SystemError> { - if let Some(device) = inner - .devices - .iter() - .flatten() - .find(|device| !device.is_bound()) - { - return Ok(device.clone()); - } - - let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; - let minor = match Self::find_unused_minor_locked(inner) { - Some(minor) => minor, - None => { - Self::free_id_locked(inner, id); - return Err(SystemError::ENOSPC); - } - }; - let result = self.create_and_register_device_locked(inner, id, minor); - if result.is_err() { - Self::free_id_locked(inner, id); - } - result - } - - fn create_and_register_device_locked( - &self, - inner: &mut LoopManagerInner, - id: usize, - minor: u32, - ) -> Result, SystemError> { - if minor >= Self::MAX_DEVICES as u32 { - return Err(SystemError::EINVAL); - } - - let devname = Self::format_name(id); - let loop_dev = - LoopDevice::new_empty_loop_device(devname, id, minor).ok_or(SystemError::ENOMEM)?; - - if let Err(e) = block_dev_manager().register(loop_dev.clone()) { - if e == SystemError::EEXIST { - if let Some(existing) = inner.devices[id].clone() { - return Ok(existing); - } - } - return Err(e); - } - - inner.devices[id] = Some(loop_dev.clone()); - inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; - log::info!( - "Loop device id {} (minor {}) added successfully.", - id, - minor - ); - Ok(loop_dev) - } - /// # 功能 - /// - /// 删除指定 minor 的 loop 设备 - /// 实现规范的删除流程,包括状态转换、I/O 排空、资源清理 - /// - /// ## 参数 - /// - /// - `minor`: 要删除的设备的次设备号 - /// - /// ## 返回值 - /// - `Ok(())`: 成功删除设备 - /// - `Err(SystemError)`: 删除失败 - pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { - if minor >= Self::MAX_DEVICES as u32 { - return Err(SystemError::EINVAL); - } - let device = { - let inner = self.inner(); - Self::find_device_by_minor_locked(&inner, minor) - } - .ok_or(SystemError::ENODEV)?; - let id = device.id(); - info!("Starting removal of loop device loop{} (id {})", minor, id); - device.enter_rundown_state()?; - let needs_drain = { - let inner = device.inner(); - !matches!(inner.state, LoopState::Deleting) - }; - - if needs_drain { - device.drain_active_io()?; - } - - device.clear_file()?; - - let _ = device.remove_from_sysfs(); - - let block_dev: Arc = device.clone(); - block_dev_manager().unregister(&block_dev)?; - - { - let mut inner = self.inner(); - inner.devices[id] = None; - Self::free_id_locked(&mut inner, id); - inner.next_free_minor = minor; - } - info!( - "Loop device id {} (minor {}) removed successfully.", - id, minor - ); - Ok(()) - } - - pub fn find_free_minor(&self) -> Option { - let inner = self.inner(); - 'outer: for minor in 0..Self::MAX_DEVICES as u32 { - for dev in inner.devices.iter().flatten() { - if dev.minor() == minor { - if !dev.is_bound() { - return Some(minor); - } - continue 'outer; - } - } - return Some(minor); - } - None - } - pub fn loop_init(&self, _driver: Arc) -> Result<(), SystemError> { - let mut inner = self.inner(); - for minor in 0..Self::MAX_INIT_DEVICES { - let minor_u32 = minor as u32; - if Self::find_device_by_minor_locked(&inner, minor_u32).is_some() { - continue; - } - let id = Self::alloc_id_locked(&mut inner).ok_or(SystemError::ENOSPC)?; - if let Err(e) = self.create_and_register_device_locked(&mut inner, id, minor_u32) { - Self::free_id_locked(&mut inner, id); - return Err(e); - } - } - log::info!("Loop devices initialized"); - Ok(()) - } -} -//一个字符设备,作为一个抽象接口控制loop设备的创建,绑定和删除 -/* -设备分配和查找 -设备绑定和解绑 -设备状态查询和配置(配置设备参数,如偏移量、大小限制等) -*/ - -pub struct LoopControlDevice { - inner: SpinLock, - locked_kobj_state: LockedKObjectState, - loop_mgr: Arc, -} -struct LoopControlDeviceInner { - // 设备的公共数据 - device_common: DeviceCommonData, - // KObject的公共数据 - kobject_common: KObjectCommonData, - - parent: RwLock>, - device_inode_fs: RwLock>>, -} -impl LoopControlDevice { - pub fn new(loop_mgr: Arc) -> Arc { - Arc::new(Self { - inner: SpinLock::new(LoopControlDeviceInner { - kobject_common: KObjectCommonData::default(), - device_common: DeviceCommonData::default(), - parent: RwLock::new(Weak::default()), - device_inode_fs: RwLock::new(None), - }), - locked_kobj_state: LockedKObjectState::default(), - loop_mgr, - }) - } - fn inner(&'_ self) -> SpinLockGuard<'_, LoopControlDeviceInner> { - self.inner.lock() - } -} -impl DeviceINode for LoopControlDevice { - fn set_fs(&self, fs: alloc::sync::Weak) { - *self.inner().device_inode_fs.write() = Some(fs); - } - fn set_parent(&self, parent: Weak) { - *self.inner().parent.write() = parent; - } -} -impl Debug for LoopControlDevice { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("LoopControlDevice").finish() - } -} -impl IndexNode for LoopControlDevice { - fn open( - &self, - _data: SpinLockGuard, - _mode: &FileMode, - ) -> Result<(), SystemError> { - // 若文件系统没有实现此方法,则返回“不支持” - return Ok(()); - } - fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { - Ok(()) - } - /// # 功能 - /// - /// 获取 loop-control 设备的元数据信息。 - /// - /// ## 参数 - /// - /// - 无 - /// - /// ## 返回值 - /// - `Ok(Metadata)`: 成功获取设备元数据 - /// - 包含设备类型、权限、设备号等信息 - /// - fn metadata(&self) -> Result { - use crate::filesystem::vfs::{syscall::ModeType, FileType, InodeId}; - use crate::time::PosixTimeSpec; - - let metadata = Metadata { - dev_id: 0, - inode_id: InodeId::new(0), - size: 0, - blk_size: 0, - blocks: 0, - atime: PosixTimeSpec::default(), - mtime: PosixTimeSpec::default(), - ctime: PosixTimeSpec::default(), - btime: PosixTimeSpec::default(), - file_type: FileType::CharDevice, - mode: ModeType::from_bits_truncate(0o600), - nlinks: 1, - uid: 0, - gid: 0, - raw_dev: DeviceNumber::new(Major::LOOP_CONTROL_MAJOR, LOOP_CONTROL_MINOR), - }; - Ok(metadata) - } - fn fs(&self) -> Arc { - todo!() - } - fn ioctl( - &self, - cmd: u32, - data: usize, - _private_data: &FilePrivateData, - ) -> Result { - match LoopControlIoctl::from_u32(cmd) { - Some(LoopControlIoctl::Add) => { - log::info!("Starting LOOP_CTL_ADD ioctl"); - let requested_index = data as u32; - let loop_dev = if requested_index == u32::MAX { - self.loop_mgr.loop_add(None)? - } else { - self.loop_mgr.loop_add(Some(requested_index))? - }; - let minor = { - let inner = loop_dev.inner(); - let minor = inner.device_number.minor(); - log::info!( - "LOOP_CTL_ADD ioctl succeeded, allocated loop device loop{}", - minor - ); - minor - }; - Ok(minor as usize) - } - Some(LoopControlIoctl::Remove) => { - let minor_to_remove = data as u32; - self.loop_mgr.loop_remove(minor_to_remove)?; - Ok(0) - } - Some(LoopControlIoctl::GetFree) => match self.loop_mgr.find_free_minor() { - Some(minor) => Ok(minor as usize), - None => Err(SystemError::ENOSPC), - }, - _ => Err(SystemError::ENOSYS), - } - } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } - fn read_at( - &self, - _offset: usize, - _len: usize, - _buf: &mut [u8], - _data: SpinLockGuard, - ) -> Result { - Err(SystemError::ENOSYS) - } - - fn write_at( - &self, - _offset: usize, - _len: usize, - _buf: &[u8], - _data: SpinLockGuard, - ) -> Result { - Err(SystemError::ENOSYS) - } - - fn list(&self) -> Result, system_error::SystemError> { - Err(SystemError::ENOSYS) - } -} -impl Device for LoopControlDevice { - fn dev_type(&self) -> DeviceType { - DeviceType::Char - } - - fn id_table(&self) -> IdTable { - IdTable::new(LOOP_CONTROL_BASENAME.to_string(), None) - } - - fn bus(&self) -> Option> { - self.inner().device_common.bus.clone() - } - - fn set_bus(&self, bus: Option>) { - self.inner().device_common.bus = bus; - } - - fn class(&self) -> Option> { - let mut guard = self.inner(); - let r = guard.device_common.class.clone()?.upgrade(); - if r.is_none() { - guard.device_common.class = None; - } - return r; - } - - fn set_class(&self, class: Option>) { - self.inner().device_common.class = class; - } - - fn driver(&self) -> Option> { - let r = self.inner().device_common.driver.clone()?.upgrade(); - if r.is_none() { - self.inner().device_common.driver = None; - } - return r; - } - - fn set_driver(&self, driver: Option>) { - self.inner().device_common.driver = driver; - } - - fn is_dead(&self) -> bool { - false - } - - fn can_match(&self) -> bool { - self.inner().device_common.can_match - } - - fn set_can_match(&self, can_match: bool) { - self.inner().device_common.can_match = can_match; - } - - fn state_synced(&self) -> bool { - true - } - - fn dev_parent(&self) -> Option> { - self.inner().device_common.get_parent_weak_or_clear() - } - - fn set_dev_parent(&self, parent: Option>) { - self.inner().device_common.parent = parent; - } -} -impl KObject for LoopControlDevice { - fn as_any_ref(&self) -> &dyn Any { - self - } - - fn set_inode(&self, inode: Option>) { - self.inner().kobject_common.kern_inode = inode; - } - - fn inode(&self) -> Option> { - self.inner().kobject_common.kern_inode.clone() - } - - fn parent(&self) -> Option> { - self.inner().kobject_common.parent.clone() - } - - fn set_parent(&self, parent: Option>) { - self.inner().kobject_common.parent = parent; - } - - fn kset(&self) -> Option> { - self.inner().kobject_common.kset.clone() - } - - fn set_kset(&self, kset: Option>) { - self.inner().kobject_common.kset = kset; - } - - fn kobj_type(&self) -> Option<&'static dyn KObjType> { - self.inner().kobject_common.kobj_type - } - - fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { - self.inner().kobject_common.kobj_type = ktype; - } - - fn name(&self) -> String { - LOOP_CONTROL_BASENAME.to_string() - } - - fn set_name(&self, _name: String) { - // do nothing - } - - fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { - self.locked_kobj_state.read() - } - - fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { - self.locked_kobj_state.write() - } - - fn set_kobj_state(&self, state: KObjectState) { - *self.locked_kobj_state.write() = state; - } -} diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs index 718dd7381..b4cc582f5 100644 --- a/kernel/src/driver/block/loop_device/mod.rs +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -1 +1,1788 @@ -pub mod loop_device; +use crate::{ + driver::base::{ + block::{ + block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, + disk_info::Partition, + manager::{block_dev_manager, BlockDevMeta}, + }, + class::Class, + device::{ + bus::Bus, + device_number::{DeviceNumber, Major}, + device_register, + driver::{Driver, DriverCommonData}, + DevName, Device, DeviceCommonData, DeviceType, IdTable, + }, + kobject::{ + KObjType, KObject, KObjectCommonData, KObjectManager, KObjectState, KObjectSysFSOps, + LockedKObjectState, + }, + kset::KSet, + }, + filesystem::{ + devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, + kernfs::KernFSInode, + sysfs::{AttributeGroup, SysFSOps}, + vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata}, + }, + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, + process::ProcessManager, + syscall::user_access::{UserBufferReader, UserBufferWriter}, +}; +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use core::{ + any::Any, + fmt::{Debug, Formatter}, + sync::atomic::{AtomicU32, Ordering}, +}; +use ida::IdAllocator; +use log::{error, info, warn}; +use num_traits::FromPrimitive; +use system_error::SystemError; +use unified_init::macros::unified_init; +const LOOP_BASENAME: &str = "loop"; +const LOOP_CONTROL_BASENAME: &str = "loop-control"; +pub const LOOP_CONTROL_MINOR: u32 = 237; +#[repr(u32)] +#[derive(Debug, FromPrimitive)] +pub enum LoopIoctl { + LoopSetFd = 0x4C00, + LoopClrFd = 0x4C01, + LoopSetStatus = 0x4C02, + LoopGetStatus = 0x4C03, + LoopSetStatus64 = 0x4C04, + LoopGetStatus64 = 0x4C05, + LoopChangeFd = 0x4C06, + LoopSetCapacity = 0x4C07, + LoopSetDirectIo = 0x4c08, + LoopSetBlockSize = 0x4c09, + LoopConfigure = 0x4c0a, +} +#[repr(u32)] +#[derive(Debug, FromPrimitive)] +pub enum LoopControlIoctl { + Add = 0x4C80, + Remove = 0x4C81, + GetFree = 0x4C82, +} +pub const LO_FLAGS_READ_ONLY: u32 = 1 << 0; +pub const SUPPORTED_LOOP_FLAGS: u32 = LO_FLAGS_READ_ONLY; +#[repr(C)] +#[derive(Default, Clone, Copy)] +pub struct LoopStatus64 { + pub lo_offset: u64, + pub lo_sizelimit: u64, + pub lo_flags: u32, + pub __pad: u32, +} +#[derive(Debug)] +pub struct LoopDeviceKObjType; + +impl KObjType for LoopDeviceKObjType { + fn release(&self, kobj: Arc) { + if let Some(loop_dev) = kobj.as_any_ref().downcast_ref::() { + loop_dev.final_cleanup(); + } + } + + fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { + Some(&KObjectSysFSOps) + } + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + None + } +} +static LOOP_DEVICE_KOBJ_TYPE: LoopDeviceKObjType = LoopDeviceKObjType; +struct IoGuard<'a> { + device: &'a LoopDevice, +} + +impl<'a> IoGuard<'a> { + fn new(device: &'a LoopDevice) -> Result { + device.io_start()?; + Ok(Self { device }) + } +} + +impl<'a> Drop for IoGuard<'a> { + fn drop(&mut self) { + self.device.io_end(); + } +} + +pub struct LoopDevice { + id: usize, + minor: u32, + inner: SpinLock, + block_dev_meta: BlockDevMeta, + locked_kobj_state: LockedKObjectState, + self_ref: Weak, + fs: RwLock>, + parent: RwLock>, + /// 活跃的 I/O 操作计数 + active_io_count: AtomicU32, +} +#[derive(Debug, Clone)] +pub struct LoopPrivateData { + pub parms: u32, +} +pub struct LoopDeviceInner { + pub device_number: DeviceNumber, + state: LoopState, + state_lock: SpinLock<()>, + pub file_inode: Option>, + pub file_size: usize, + pub offset: usize, + pub size_limit: usize, + pub flags: u32, + pub read_only: bool, + pub kobject_common: KObjectCommonData, + pub device_common: DeviceCommonData, +} +impl LoopDeviceInner { + fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { + let _guard = self.state_lock.lock(); + + match (&self.state, &new_state) { + (LoopState::Unbound, LoopState::Bound) => {} + (LoopState::Bound, LoopState::Unbound) => {} + (LoopState::Bound, LoopState::Rundown) => {} + (LoopState::Rundown, LoopState::Draining) => {} + (LoopState::Rundown, LoopState::Deleting) => {} + (LoopState::Rundown, LoopState::Unbound) => {} + (LoopState::Draining, LoopState::Deleting) => {} + (LoopState::Unbound, LoopState::Deleting) => {} + _ => return Err(SystemError::EINVAL), + } + + self.state = new_state; + Ok(()) + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LoopState { + Unbound, + Bound, + Rundown, + Draining, + Deleting, +} +impl Debug for LoopDevice { + fn fmt(&'_ self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LoopDevice") + .field("id", &self.id) + .field("devname", &self.block_dev_meta.devname) + .finish() + } +} +impl LoopDevice { + fn inner(&'_ self) -> SpinLockGuard<'_, LoopDeviceInner> { + self.inner.lock() + } + pub fn id(&self) -> usize { + self.id + } + pub fn minor(&self) -> u32 { + self.minor + } + /// # 功能 + /// + /// 创建一个未绑定文件的 loop 设备实例。 + /// + /// ## 参数 + /// + /// - `devname`: 设备名称。 + /// - `minor`: 次设备号。 + /// + /// ## 返回值 + /// - `Some(Arc)`: 成功创建的 loop 设备。 + /// - `None`: 内存不足或创建失败。 + pub fn new_empty_loop_device(devname: DevName, id: usize, minor: u32) -> Option> { + let dev = Arc::new_cyclic(|self_ref| Self { + id, + minor, + inner: SpinLock::new(LoopDeviceInner { + file_inode: None, // 默认的虚拟 inode + file_size: 0, + device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), // Loop 设备主设备号为 7 + offset: 0, + size_limit: 0, + flags: 0, + read_only: false, + kobject_common: KObjectCommonData::default(), + device_common: DeviceCommonData::default(), + state: LoopState::Unbound, + state_lock: SpinLock::new(()), + //work_queue: None, + }), + block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), // Loop 设备主设备号为 7 + locked_kobj_state: LockedKObjectState::default(), + self_ref: self_ref.clone(), + fs: RwLock::new(Weak::default()), + parent: RwLock::new(Weak::default()), + active_io_count: AtomicU32::new(0), + }); + + // 设置 KObjType + dev.set_kobj_type(Some(&LOOP_DEVICE_KOBJ_TYPE)); + + Some(dev) + } + + /// # 功能 + /// + /// 为 loop 设备绑定后端文件并重置相关状态。 + /// + /// ## 参数 + /// + /// - `file_inode`: 需要绑定的文件节点。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功绑定文件。 + /// - `Err(SystemError)`: 绑定失败的错误原因。 + pub fn set_file(&self, file_inode: Arc) -> Result<(), SystemError> { + let metadata = file_inode.metadata()?; + if metadata.size < 0 { + return Err(SystemError::EINVAL); + } + let file_size = metadata.size as usize; + + let mut inner = self.inner(); + inner.file_inode = Some(file_inode); + inner.file_size = file_size; + inner.offset = 0; + inner.size_limit = 0; + inner.flags = 0; // Reset flags + inner.read_only = false; // Reset read_only + drop(inner); + self.recalc_effective_size()?; // Recalculate size based on new file + Ok(()) + } + fn recalc_effective_size(&self) -> Result<(), SystemError> { + let (file_inode, offset, size_limit) = { + let inner = self.inner(); + (inner.file_inode.clone(), inner.offset, inner.size_limit) + }; + + let inode = file_inode.ok_or(SystemError::ENODEV)?; + let metadata = inode.metadata()?; + if metadata.size < 0 { + return Err(SystemError::EINVAL); + } + let total_size = metadata.size as usize; + if offset > total_size { + return Err(SystemError::EINVAL); + } + let mut effective = total_size - offset; + if size_limit > 0 { + effective = effective.min(size_limit); + } + + let mut inner = self.inner(); + inner.file_size = effective; + Ok(()) + } + + pub fn is_bound(&self) -> bool { + matches!(self.inner().state, LoopState::Bound) + } + /// # 功能 + /// + /// 将文件绑定到 loop 设备并设置访问权限。 + /// + /// ## 参数 + /// + /// - `file_inode`: 需要绑定的文件节点。 + /// - `read_only`: 是否以只读方式绑定。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功绑定。 + /// - `Err(SystemError)`: 绑定失败的原因。 + pub fn bind_file( + &self, + file_inode: Arc, + read_only: bool, + ) -> Result<(), SystemError> { + { + let inner = self.inner(); + if matches!(inner.state, LoopState::Bound) { + return Err(SystemError::EBUSY); + } + } + + self.set_file(file_inode.clone())?; + + let mut inner = self.inner(); + inner.set_state(LoopState::Bound)?; + inner.read_only = read_only; + inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; + inner.size_limit = 0; + drop(inner); + self.recalc_effective_size()?; + Ok(()) + } + /// # 功能 + /// + /// 清除 loop 设备的文件绑定并复位状态。 + /// + /// ## 参数 + /// + /// - 无。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功清除。 + /// - `Err(SystemError)`: 清除过程中的错误。 + pub fn clear_file(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + match inner.state { + LoopState::Bound | LoopState::Rundown => inner.set_state(LoopState::Unbound)?, + LoopState::Unbound => {} + LoopState::Draining => return Err(SystemError::EBUSY), + LoopState::Deleting => { + // 在删除流程中,允许清理文件 + // 状态已经是Deleting,无需改变 + } + } + + inner.file_inode = None; + inner.file_size = 0; + inner.offset = 0; + inner.size_limit = 0; + inner.read_only = false; + inner.flags = 0; + Ok(()) + } + fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { + if !info.lo_offset.is_multiple_of(LBA_SIZE as u64) { + return Err(SystemError::EINVAL); + } + if info.lo_offset > usize::MAX as u64 || info.lo_sizelimit > usize::MAX as u64 { + return Err(SystemError::EINVAL); + } + if info.lo_sizelimit != 0 && !info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) { + return Err(SystemError::EINVAL); + } + if info.lo_flags & !SUPPORTED_LOOP_FLAGS != 0 { + return Err(SystemError::EINVAL); + } + Ok(()) + } + /// 设置 loop 设备的状态(64 位版本)。 + /// + /// ## 参数 + /// + /// - `user_ptr`: 用户空间传入的 `LoopStatus64` 结构体指针。 + /// + /// ## 返回值 + /// - `Ok(())`: 状态设置成功。 + /// - `Err(SystemError::EINVAL)`: 无效的参数或标志位。 + /// - `Err(SystemError::ENXIO)`: 设备未绑定或已卸载。 + fn set_status64(&self, user_ptr: usize) -> Result<(), SystemError> { + if user_ptr == 0 { + return Err(SystemError::EINVAL); + } + + let reader = UserBufferReader::new::( + user_ptr as *const LoopStatus64, + core::mem::size_of::(), + true, + )?; + let mut info = LoopStatus64::default(); + reader.copy_one_from_user(&mut info, 0)?; + Self::validate_loop_status64_params(&info)?; + let new_offset = info.lo_offset as usize; + let new_limit = if info.lo_sizelimit == 0 { + 0 + } else { + info.lo_sizelimit as usize + }; + let new_read_only = (info.lo_flags & LO_FLAGS_READ_ONLY) != 0; + + let (old_offset, old_limit, old_flags, old_ro) = { + let inner = self.inner(); + if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + (inner.offset, inner.size_limit, inner.flags, inner.read_only) + }; + + { + let mut inner = self.inner(); + if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + inner.offset = new_offset; + inner.size_limit = new_limit; + inner.flags = info.lo_flags; + inner.read_only = new_read_only; + } + + if let Err(err) = self.recalc_effective_size() { + let mut inner = self.inner(); + inner.offset = old_offset; + inner.size_limit = old_limit; + inner.flags = old_flags; + inner.read_only = old_ro; + drop(inner); + let _ = self.recalc_effective_size(); + return Err(err); + } + + Ok(()) + } + /// # 功能 + /// + /// 获取 loop 设备的 LoopStatus64 信息并写回用户态。 + /// + /// ## 参数 + /// + /// - `user_ptr`: 用户态缓冲区地址。 + /// + /// ## 返回值 + /// - `Ok(())`: 信息写回成功。 + /// - `Err(SystemError)`: 读取状态失败。 + /// + fn get_status64(&self, user_ptr: usize) -> Result<(), SystemError> { + if user_ptr == 0 { + return Err(SystemError::EINVAL); + } + + let info = { + let inner = self.inner(); + if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + LoopStatus64 { + lo_offset: inner.offset as u64, + lo_sizelimit: inner.size_limit as u64, + lo_flags: if inner.read_only { + inner.flags | LO_FLAGS_READ_ONLY + } else { + inner.flags & !LO_FLAGS_READ_ONLY + }, + __pad: 0, + } + }; + + let mut writer = UserBufferWriter::new::( + user_ptr as *mut LoopStatus64, + core::mem::size_of::(), + true, + )?; + writer.copy_one_to_user(&info, 0)?; + Ok(()) + } + fn set_status(&self, user_ptr: usize) -> Result<(), SystemError> { + self.set_status64(user_ptr) + } + fn get_status(&self, user_ptr: usize) -> Result<(), SystemError> { + self.get_status64(user_ptr) + } + /// # 功能 + /// + /// 将 loop 设备切换到新的文件描述符。 + /// + /// ## 参数 + /// + /// - `new_file_fd`: 新的文件描述符。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功切换。 + /// - `Err(SystemError)`: 切换失败原因。 + fn change_fd(&self, new_file_fd: i32) -> Result<(), SystemError> { + let fd_table = ProcessManager::current_pcb().fd_table(); + let file = { + let guard = fd_table.read(); + guard.get_file_by_fd(new_file_fd) + } + .ok_or(SystemError::EBADF)?; + + let mode = file.mode(); + let read_only = !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); + + let inode = file.inode(); + let metadata = inode.metadata()?; + match metadata.file_type { + FileType::File | FileType::BlockDevice => {} + _ => return Err(SystemError::EINVAL), + } + let mut inner = self.inner(); + inner.file_inode = Some(inode); + inner.read_only = read_only; + inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; + drop(inner); + self.recalc_effective_size()?; + Ok(()) + } + fn set_capacity(&self, _arg: usize) -> Result<(), SystemError> { + self.recalc_effective_size()?; + Ok(()) + } + + /// # 功能 + /// + /// I/O 操作开始时调用,增加活跃 I/O 计数 + /// + /// ## 返回值 + /// - `Ok(())`: 成功增加计数 + /// - `Err(SystemError::ENODEV)`: 设备正在删除,拒绝新的 I/O + fn io_start(&self) -> Result<(), SystemError> { + let inner = self.inner(); + if matches!( + inner.state, + LoopState::Rundown | LoopState::Draining | LoopState::Deleting + ) { + return Err(SystemError::ENODEV); + } + + self.active_io_count.fetch_add(1, Ordering::AcqRel); + Ok(()) + } + + /// # 功能 + /// + /// I/O 操作完成时调用,减少活跃 I/O 计数 + fn io_end(&self) { + let prev = self.active_io_count.fetch_sub(1, Ordering::AcqRel); + if prev == 0 { + warn!( + "Loop device loop{}: I/O count underflow", + self.inner().device_number.minor() + ); + } + } + + /// # 功能 + /// + /// 进入 Rundown 状态,停止接受新的 I/O 请求 + /// + /// ## 返回值 + /// - `Ok(())`: 成功进入 Rundown 状态 + /// - `Err(SystemError)`: 状态转换失败 + fn enter_rundown_state(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + match inner.state { + LoopState::Bound => { + inner.set_state(LoopState::Rundown)?; + info!( + "Loop device loop{} entering rundown state", + inner.device_number.minor() + ); + } + LoopState::Unbound => { + // 空设备可以直接删除 + inner.set_state(LoopState::Deleting)?; + info!( + "Loop device loop{} is unbound, skipping to deleting state", + inner.device_number.minor() + ); + } + LoopState::Rundown => {} + LoopState::Draining | LoopState::Deleting => { + return Err(SystemError::EBUSY); + } + } + Ok(()) + } + + /// # 功能 + /// + /// 等待所有活跃的 I/O 操作完成 + /// + /// ## 返回值 + /// - `Ok(())`: 所有 I/O 已完成 + /// - `Err(SystemError::ETIMEDOUT)`: 等待超时 + fn drain_active_io(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + if matches!(inner.state, LoopState::Rundown) { + inner.set_state(LoopState::Draining)?; + info!( + "Loop device loop{} entering draining state", + inner.device_number.minor() + ); + } + drop(inner); + let timeout_ms = 30_000; + let check_interval_us = 10_000; + let max_checks = timeout_ms * 1000 / check_interval_us; + + for _i in 0..max_checks { + let count = self.active_io_count.load(Ordering::Acquire); + if count == 0 { + break; + } + + core::hint::spin_loop(); + } + + let final_count = self.active_io_count.load(Ordering::Acquire); + if final_count != 0 { + error!( + "Timeout waiting for I/O to drain on loop{}: {} operations still active", + self.minor(), + final_count + ); + return Err(SystemError::ETIMEDOUT); + } + + info!( + "All I/O operations drained for loop device loop{}", + self.minor() + ); + + let mut inner = self.inner(); + inner.set_state(LoopState::Deleting)?; + + Ok(()) + } + + /// # 功能 + /// + /// 从 sysfs 中移除设备 + /// + /// ## 返回值 + /// - `Ok(())`: 成功移除 + /// - `Err(SystemError)`: 移除失败 + fn remove_from_sysfs(&self) -> Result<(), SystemError> { + // 使用 KObjectManager 从 sysfs 中移除 + if let Some(kobj) = self.self_ref.upgrade() { + KObjectManager::remove_kobj(kobj as Arc); + info!("Removed loop device loop{} from sysfs", self.minor()); + } + Ok(()) + } + + /// # 功能 + /// + /// 最终清理函数,由 KObjType::release 调用 + /// 执行设备删除的最后清理工作 + fn final_cleanup(&self) { + info!( + "Final cleanup for loop device loop{} (id {})", + self.minor(), + self.id() + ); + let mut inner = self.inner(); + if let Some(file_inode) = inner.file_inode.take() { + drop(file_inode); + warn!( + "File inode was still present during final cleanup for loop{}", + self.minor() + ); + } + inner.file_size = 0; + inner.offset = 0; + inner.size_limit = 0; + info!("Loop device loop{} cleanup complete", self.minor()); + } +} + +impl KObject for LoopDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + LOOP_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing,不支持设置loop为别的名称 + } + + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { + self.locked_kobj_state.read() + } + + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { + self.locked_kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobj_state.write() = state; + } +} + +impl IndexNode for LoopDevice { + fn fs(&self) -> Arc { + todo!() + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + if len > buf.len() { + return Err(SystemError::ENOBUFS); + } + BlockDevice::read_at_bytes(self, offset, len, buf) + } + + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + if len > buf.len() { + return Err(SystemError::E2BIG); + } + BlockDevice::write_at_bytes(self, offset, len, &buf[..len]) + } + + fn list(&self) -> Result, system_error::SystemError> { + Err(SystemError::ENOSYS) + } + fn metadata(&self) -> Result { + let file_metadata = match &self.inner().file_inode { + Some(inode) => inode.metadata()?, + None => { + return Err(SystemError::EPERM); + } + }; + let metadata = Metadata { + dev_id: 0, + inode_id: InodeId::new(0), + size: self.inner().file_size as i64, + blk_size: LBA_SIZE, + blocks: (self.inner().file_size.div_ceil(LBA_SIZE)), + atime: file_metadata.atime, + mtime: file_metadata.mtime, + ctime: file_metadata.ctime, + btime: file_metadata.btime, + file_type: crate::filesystem::vfs::FileType::BlockDevice, + mode: crate::filesystem::vfs::syscall::ModeType::from_bits_truncate(0o644), + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: self.inner().device_number, + }; + Ok(metadata) + } + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { + match LoopIoctl::from_u32(cmd) { + Some(LoopIoctl::LoopSetFd) => { + let file_fd = data as i32; + let fd_table = ProcessManager::current_pcb().fd_table(); + let file = { + let guard = fd_table.read(); + guard.get_file_by_fd(file_fd) + } + .ok_or(SystemError::EBADF)?; + + let mode = file.mode(); + let read_only = + !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); + + let inode = file.inode(); + let metadata = inode.metadata()?; + match metadata.file_type { + FileType::File | FileType::BlockDevice => {} + _ => return Err(SystemError::EINVAL), + } + + self.bind_file(inode, read_only)?; + Ok(0) + } + Some(LoopIoctl::LoopClrFd) => { + self.clear_file()?; + Ok(0) + } + Some(LoopIoctl::LoopSetStatus) => { + self.set_status(data)?; + Ok(0) + } + Some(LoopIoctl::LoopGetStatus) => { + self.get_status(data)?; + Ok(0) + } + Some(LoopIoctl::LoopSetStatus64) => { + self.set_status64(data)?; + Ok(0) + } + Some(LoopIoctl::LoopGetStatus64) => { + self.get_status64(data)?; + Ok(0) + } + Some(LoopIoctl::LoopChangeFd) => { + self.change_fd(data as i32)?; + Ok(0) + } + Some(LoopIoctl::LoopSetCapacity) => { + self.set_capacity(data)?; + Ok(0) + } + _ => Err(SystemError::ENOSYS), + } + } +} + +impl DeviceINode for LoopDevice { + fn set_fs(&self, fs: alloc::sync::Weak) { + *self.fs.write() = fs; + } + fn set_parent(&self, parent: Weak) { + *self.parent.write() = parent; + } +} + +impl Device for LoopDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Block + } + + fn id_table(&self) -> IdTable { + IdTable::new(LOOP_BASENAME.to_string(), None) + } + + fn bus(&self) -> Option> { + self.inner().device_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn class(&self) -> Option> { + let mut guard = self.inner(); + let r = guard.device_common.class.clone()?.upgrade(); + if r.is_none() { + guard.device_common.class = None; + } + return r; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn driver(&self) -> Option> { + let r = self.inner().device_common.driver.clone()?.upgrade(); + if r.is_none() { + self.inner().device_common.driver = None; + } + return r; + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn dev_parent(&self) -> Option> { + self.inner().device_common.get_parent_weak_or_clear() + } + + fn set_dev_parent(&self, parent: Option>) { + self.inner().device_common.parent = parent; + } +} + +impl BlockDevice for LoopDevice { + fn dev_name(&self) -> &DevName { + &self.block_dev_meta.devname + } + + fn blkdev_meta(&self) -> &BlockDevMeta { + &self.block_dev_meta + } + + fn disk_range(&self) -> GeneralBlockRange { + let inner = self.inner(); + let blocks = if inner.file_size == 0 { + 0 + } else { + inner.file_size.saturating_add(LBA_SIZE - 1) / LBA_SIZE + }; + drop(inner); + GeneralBlockRange::new(0, blocks).unwrap_or(GeneralBlockRange { + lba_start: 0, + lba_end: 0, + }) + } + fn read_at_sync( + &self, + lba_id_start: BlockId, + count: usize, + buf: &mut [u8], + ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + + if count == 0 { + return Ok(0); + } + let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; + if len > buf.len() { + return Err(SystemError::EINVAL); + } + + let (file_inode, base_offset, limit_end) = { + let inner = self.inner(); + let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; + let limit = inner + .offset + .checked_add(inner.file_size) + .ok_or(SystemError::EOVERFLOW)?; + (inode, inner.offset, limit) + }; + + let block_offset = lba_id_start + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + let file_offset = base_offset + .checked_add(block_offset) + .ok_or(SystemError::EOVERFLOW)?; + + let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; + if end > limit_end { + return Err(SystemError::ENOSPC); + } + + let data = SpinLock::new(FilePrivateData::Unused); + let data_guard = data.lock(); + + file_inode.read_at(file_offset, len, &mut buf[..len], data_guard) + } + + fn write_at_sync( + &self, + lba_id_start: BlockId, + count: usize, + buf: &[u8], + ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + + if count == 0 { + return Ok(0); + } + let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; + if len > buf.len() { + return Err(SystemError::EINVAL); + } + + let (file_inode, base_offset, limit_end, read_only) = { + let inner = self.inner(); + let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; + let limit = inner + .offset + .checked_add(inner.file_size) + .ok_or(SystemError::EOVERFLOW)?; + (inode, inner.offset, limit, inner.read_only) + }; + + if read_only { + return Err(SystemError::EROFS); + } + + let block_offset = lba_id_start + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + let file_offset = base_offset + .checked_add(block_offset) + .ok_or(SystemError::EOVERFLOW)?; + + let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; + if end > limit_end { + return Err(SystemError::ENOSPC); + } + + let data = SpinLock::new(FilePrivateData::Unused); + let data_guard = data.lock(); + + let written = file_inode.write_at(file_offset, len, &buf[..len], data_guard)?; + + if written > 0 { + let _ = self.recalc_effective_size(); + } + + Ok(written) + } + + fn sync(&self) -> Result<(), SystemError> { + Ok(()) + } + + fn blk_size_log2(&self) -> u8 { + 9 + } + + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn device(&self) -> Arc { + self.self_ref.upgrade().unwrap() + } + + fn block_size(&self) -> usize { + LBA_SIZE + } + + fn partitions(&self) -> Vec> { + Vec::new() + } +} + +/// Loop设备驱动 +/// 参考Virtio_blk驱动的实现 +#[derive(Debug)] +#[cast_to([sync] Driver)] +pub struct LoopDeviceDriver { + inner: SpinLock, + kobj_state: LockedKObjectState, +} +struct InnerLoopDeviceDriver { + driver_common: DriverCommonData, + kobj_common: KObjectCommonData, +} +impl Debug for InnerLoopDeviceDriver { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("InnerLoopDeviceDriver") + .field("driver_common", &self.driver_common) + .field("kobj_common", &self.kobj_common) + .finish() + } +} +impl LoopDeviceDriver { + pub fn new() -> Arc { + let inner = InnerLoopDeviceDriver { + driver_common: DriverCommonData::default(), + kobj_common: KObjectCommonData::default(), + }; + Arc::new(Self { + inner: SpinLock::new(inner), + kobj_state: LockedKObjectState::default(), + }) + } + fn inner(&'_ self) -> SpinLockGuard<'_, InnerLoopDeviceDriver> { + self.inner.lock() + } +} +use crate::init::initcall::INITCALL_DEVICE; +#[unified_init(INITCALL_DEVICE)] +pub fn loop_init() -> Result<(), SystemError> { + let loop_mgr = Arc::new(LoopManager::new()); + let driver = LoopDeviceDriver::new(); + let loop_ctl = LoopControlDevice::new(loop_mgr.clone()); + + device_register(loop_ctl.clone())?; + log::info!("Loop control device registered."); + devfs_register(LOOP_CONTROL_BASENAME, loop_ctl.clone())?; + log::info!("Loop control device initialized."); + loop_mgr.loop_init(driver)?; + Ok(()) +} + +impl Driver for LoopDeviceDriver { + fn id_table(&self) -> Option { + Some(IdTable::new(LOOP_BASENAME.to_string(), None)) + } + + fn devices(&self) -> Vec> { + self.inner().driver_common.devices.clone() + } + + fn add_device(&self, device: Arc) { + self.inner().driver_common.push_device(device); + } + + fn delete_device(&self, device: &Arc) { + self.inner().driver_common.delete_device(device); + } + + fn bus(&self) -> Option> { + self.inner().driver_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().driver_common.bus = bus; + } +} + +impl KObject for LoopDeviceDriver { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobj_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobj_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobj_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobj_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobj_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobj_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobj_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobj_common.kobj_type = ktype; + } + + fn name(&self) -> String { + LOOP_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { + self.kobj_state.read() + } + + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.kobj_state.write() = state; + } +} + +pub struct LoopManager { + inner: SpinLock, +} +pub struct LoopManagerInner { + devices: [Option>; LoopManager::MAX_DEVICES], + id_alloc: IdAllocator, + next_free_minor: u32, +} +impl LoopManager { + const MAX_DEVICES: usize = 256; + const MAX_INIT_DEVICES: usize = 8; + pub fn new() -> Self { + Self { + inner: SpinLock::new(LoopManagerInner { + devices: [const { None }; Self::MAX_DEVICES], + id_alloc: IdAllocator::new(0, Self::MAX_DEVICES) + .expect("create IdAllocator failed"), + next_free_minor: 0, + }), + } + } + fn inner(&'_ self) -> SpinLockGuard<'_, LoopManagerInner> { + self.inner.lock() + } + #[inline] + fn alloc_id_locked(inner: &mut LoopManagerInner) -> Option { + inner.id_alloc.alloc() + } + #[inline] + fn free_id_locked(inner: &mut LoopManagerInner, id: usize) { + if id < Self::MAX_DEVICES && inner.id_alloc.exists(id) { + inner.id_alloc.free(id); + } + } + #[inline] + pub fn format_name(id: usize) -> DevName { + DevName::new(format!("{}{}", LOOP_BASENAME, id), id) + } + fn find_device_by_minor_locked( + inner: &LoopManagerInner, + minor: u32, + ) -> Option> { + inner + .devices + .iter() + .flatten() + .find(|device| device.minor() == minor) + .map(Arc::clone) + } + + fn find_unused_minor_locked(inner: &LoopManagerInner) -> Option { + let mut candidate = inner.next_free_minor; + for _ in 0..Self::MAX_DEVICES as u32 { + let mut used = false; + for dev in inner.devices.iter().flatten() { + if dev.minor() == candidate { + used = true; + break; + } + } + if !used { + return Some(candidate); + } + candidate = (candidate + 1) % Self::MAX_DEVICES as u32; + } + None + } + /* + 请求队列,工作队列未实现 + */ + /// # 功能 + /// + /// 根据请求的次设备号分配或复用 loop 设备。 + /// + /// ## 参数 + /// + /// - `requested_minor`: 指定的次设备号,`None` 表示自动分配。 + /// + /// ## 返回值 + /// - `Ok(Arc)`: 成功获得的设备。 + /// - `Err(SystemError)`: 无可用设备或参数错误。 + pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { + let mut inner = self.inner(); + match requested_minor { + Some(req_minor) => self.loop_add_specific_locked(&mut inner, req_minor), + None => self.loop_add_first_available_locked(&mut inner), + } + } + /// # 功能 + /// + /// 在锁作用域内分配指定次设备号的 loop 设备。 + /// + /// ## 参数 + /// + /// - `inner`: 管理器内部状态锁。 + /// - `minor`: 目标次设备号。 + /// + /// ## 返回值 + /// - `Ok(Arc)`: 成功获得的设备实例。 + /// - `Err(SystemError)`: 参数无效或设备已被占用。 + fn loop_add_specific_locked( + &self, + inner: &mut LoopManagerInner, + minor: u32, + ) -> Result, SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + + if let Some(device) = Self::find_device_by_minor_locked(inner, minor) { + if device.is_bound() { + return Err(SystemError::EEXIST); + } + return Ok(device); + } + + let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; + match self.create_and_register_device_locked(inner, id, minor) { + Ok(device) => Ok(device), + Err(e) => { + Self::free_id_locked(inner, id); + Err(e) + } + } + } + + fn loop_add_first_available_locked( + &self, + inner: &mut LoopManagerInner, + ) -> Result, SystemError> { + if let Some(device) = inner + .devices + .iter() + .flatten() + .find(|device| !device.is_bound()) + { + return Ok(device.clone()); + } + + let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; + let minor = match Self::find_unused_minor_locked(inner) { + Some(minor) => minor, + None => { + Self::free_id_locked(inner, id); + return Err(SystemError::ENOSPC); + } + }; + let result = self.create_and_register_device_locked(inner, id, minor); + if result.is_err() { + Self::free_id_locked(inner, id); + } + result + } + + fn create_and_register_device_locked( + &self, + inner: &mut LoopManagerInner, + id: usize, + minor: u32, + ) -> Result, SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + + let devname = Self::format_name(id); + let loop_dev = + LoopDevice::new_empty_loop_device(devname, id, minor).ok_or(SystemError::ENOMEM)?; + + if let Err(e) = block_dev_manager().register(loop_dev.clone()) { + if e == SystemError::EEXIST { + if let Some(existing) = inner.devices[id].clone() { + return Ok(existing); + } + } + return Err(e); + } + + inner.devices[id] = Some(loop_dev.clone()); + inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; + log::info!( + "Loop device id {} (minor {}) added successfully.", + id, + minor + ); + Ok(loop_dev) + } + /// # 功能 + /// + /// 删除指定 minor 的 loop 设备 + /// 实现规范的删除流程,包括状态转换、I/O 排空、资源清理 + /// + /// ## 参数 + /// + /// - `minor`: 要删除的设备的次设备号 + /// + /// ## 返回值 + /// - `Ok(())`: 成功删除设备 + /// - `Err(SystemError)`: 删除失败 + pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + let device = { + let inner = self.inner(); + Self::find_device_by_minor_locked(&inner, minor) + } + .ok_or(SystemError::ENODEV)?; + let id = device.id(); + info!("Starting removal of loop device loop{} (id {})", minor, id); + device.enter_rundown_state()?; + let needs_drain = { + let inner = device.inner(); + !matches!(inner.state, LoopState::Deleting) + }; + + if needs_drain { + device.drain_active_io()?; + } + + device.clear_file()?; + + let _ = device.remove_from_sysfs(); + + let block_dev: Arc = device.clone(); + block_dev_manager().unregister(&block_dev)?; + + { + let mut inner = self.inner(); + inner.devices[id] = None; + Self::free_id_locked(&mut inner, id); + inner.next_free_minor = minor; + } + info!( + "Loop device id {} (minor {}) removed successfully.", + id, minor + ); + Ok(()) + } + + pub fn find_free_minor(&self) -> Option { + let inner = self.inner(); + 'outer: for minor in 0..Self::MAX_DEVICES as u32 { + for dev in inner.devices.iter().flatten() { + if dev.minor() == minor { + if !dev.is_bound() { + return Some(minor); + } + continue 'outer; + } + } + return Some(minor); + } + None + } + pub fn loop_init(&self, _driver: Arc) -> Result<(), SystemError> { + let mut inner = self.inner(); + for minor in 0..Self::MAX_INIT_DEVICES { + let minor_u32 = minor as u32; + if Self::find_device_by_minor_locked(&inner, minor_u32).is_some() { + continue; + } + let id = Self::alloc_id_locked(&mut inner).ok_or(SystemError::ENOSPC)?; + if let Err(e) = self.create_and_register_device_locked(&mut inner, id, minor_u32) { + Self::free_id_locked(&mut inner, id); + return Err(e); + } + } + log::info!("Loop devices initialized"); + Ok(()) + } +} +//一个字符设备,作为一个抽象接口控制loop设备的创建,绑定和删除 +/* +设备分配和查找 +设备绑定和解绑 +设备状态查询和配置(配置设备参数,如偏移量、大小限制等) +*/ + +pub struct LoopControlDevice { + inner: SpinLock, + locked_kobj_state: LockedKObjectState, + loop_mgr: Arc, +} +struct LoopControlDeviceInner { + // 设备的公共数据 + device_common: DeviceCommonData, + // KObject的公共数据 + kobject_common: KObjectCommonData, + + parent: RwLock>, + device_inode_fs: RwLock>>, +} +impl LoopControlDevice { + pub fn new(loop_mgr: Arc) -> Arc { + Arc::new(Self { + inner: SpinLock::new(LoopControlDeviceInner { + kobject_common: KObjectCommonData::default(), + device_common: DeviceCommonData::default(), + parent: RwLock::new(Weak::default()), + device_inode_fs: RwLock::new(None), + }), + locked_kobj_state: LockedKObjectState::default(), + loop_mgr, + }) + } + fn inner(&'_ self) -> SpinLockGuard<'_, LoopControlDeviceInner> { + self.inner.lock() + } +} +impl DeviceINode for LoopControlDevice { + fn set_fs(&self, fs: alloc::sync::Weak) { + *self.inner().device_inode_fs.write() = Some(fs); + } + fn set_parent(&self, parent: Weak) { + *self.inner().parent.write() = parent; + } +} +impl Debug for LoopControlDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LoopControlDevice").finish() + } +} +impl IndexNode for LoopControlDevice { + fn open( + &self, + _data: SpinLockGuard, + _mode: &FileMode, + ) -> Result<(), SystemError> { + // 若文件系统没有实现此方法,则返回“不支持” + return Ok(()); + } + fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { + Ok(()) + } + /// # 功能 + /// + /// 获取 loop-control 设备的元数据信息。 + /// + /// ## 参数 + /// + /// - 无 + /// + /// ## 返回值 + /// - `Ok(Metadata)`: 成功获取设备元数据 + /// - 包含设备类型、权限、设备号等信息 + /// + fn metadata(&self) -> Result { + use crate::filesystem::vfs::{syscall::ModeType, FileType, InodeId}; + use crate::time::PosixTimeSpec; + + let metadata = Metadata { + dev_id: 0, + inode_id: InodeId::new(0), + size: 0, + blk_size: 0, + blocks: 0, + atime: PosixTimeSpec::default(), + mtime: PosixTimeSpec::default(), + ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), + file_type: FileType::CharDevice, + mode: ModeType::from_bits_truncate(0o600), + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: DeviceNumber::new(Major::LOOP_CONTROL_MAJOR, LOOP_CONTROL_MINOR), + }; + Ok(metadata) + } + fn fs(&self) -> Arc { + todo!() + } + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { + match LoopControlIoctl::from_u32(cmd) { + Some(LoopControlIoctl::Add) => { + log::info!("Starting LOOP_CTL_ADD ioctl"); + let requested_index = data as u32; + let loop_dev = if requested_index == u32::MAX { + self.loop_mgr.loop_add(None)? + } else { + self.loop_mgr.loop_add(Some(requested_index))? + }; + let minor = { + let inner = loop_dev.inner(); + let minor = inner.device_number.minor(); + log::info!( + "LOOP_CTL_ADD ioctl succeeded, allocated loop device loop{}", + minor + ); + minor + }; + Ok(minor as usize) + } + Some(LoopControlIoctl::Remove) => { + let minor_to_remove = data as u32; + self.loop_mgr.loop_remove(minor_to_remove)?; + Ok(0) + } + Some(LoopControlIoctl::GetFree) => match self.loop_mgr.find_free_minor() { + Some(minor) => Ok(minor as usize), + None => Err(SystemError::ENOSPC), + }, + _ => Err(SystemError::ENOSYS), + } + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + fn read_at( + &self, + _offset: usize, + _len: usize, + _buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn list(&self) -> Result, system_error::SystemError> { + Err(SystemError::ENOSYS) + } +} +impl Device for LoopControlDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Char + } + + fn id_table(&self) -> IdTable { + IdTable::new(LOOP_CONTROL_BASENAME.to_string(), None) + } + + fn bus(&self) -> Option> { + self.inner().device_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn class(&self) -> Option> { + let mut guard = self.inner(); + let r = guard.device_common.class.clone()?.upgrade(); + if r.is_none() { + guard.device_common.class = None; + } + return r; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn driver(&self) -> Option> { + let r = self.inner().device_common.driver.clone()?.upgrade(); + if r.is_none() { + self.inner().device_common.driver = None; + } + return r; + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn dev_parent(&self) -> Option> { + self.inner().device_common.get_parent_weak_or_clear() + } + + fn set_dev_parent(&self, parent: Option>) { + self.inner().device_common.parent = parent; + } +} +impl KObject for LoopControlDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + LOOP_CONTROL_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { + self.locked_kobj_state.read() + } + + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { + self.locked_kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobj_state.write() = state; + } +} diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 9c35d8690..e87633552 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -9,7 +9,7 @@ use crate::process::pid::PidPrivateData; use crate::{ driver::{ base::{block::SeekFrom, device::DevicePrivateData}, - block::loop_device::loop_device::LoopPrivateData, + block::loop_device::LoopPrivateData, tty::tty_device::TtyFilePrivateData, }, filesystem::{ From f89748f89d61b4c35bcd0b2baaa7501ceea4618f Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Tue, 9 Dec 2025 18:22:23 +0800 Subject: [PATCH 28/39] =?UTF-8?q?-=20fix=EF=BC=9A=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=97=A0=E7=94=A8parms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/block/loop_device/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs index b4cc582f5..2840de8e2 100644 --- a/kernel/src/driver/block/loop_device/mod.rs +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -131,9 +131,7 @@ pub struct LoopDevice { active_io_count: AtomicU32, } #[derive(Debug, Clone)] -pub struct LoopPrivateData { - pub parms: u32, -} +pub struct LoopPrivateData {} pub struct LoopDeviceInner { pub device_number: DeviceNumber, state: LoopState, @@ -221,7 +219,6 @@ impl LoopDevice { device_common: DeviceCommonData::default(), state: LoopState::Unbound, state_lock: SpinLock::new(()), - //work_queue: None, }), block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), // Loop 设备主设备号为 7 locked_kobj_state: LockedKObjectState::default(), From b46c3d280b605c5a24b2e8575034a3f52c1f1e4a Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Tue, 9 Dec 2025 18:57:50 +0800 Subject: [PATCH 29/39] refactor fs --- kernel/src/driver/block/loop_device/mod.rs | 25 +++++++++++----------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs index 2840de8e2..5b07c0c5c 100644 --- a/kernel/src/driver/block/loop_device/mod.rs +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -23,7 +23,10 @@ use crate::{ devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, kernfs::KernFSInode, sysfs::{AttributeGroup, SysFSOps}, - vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, InodeId, Metadata}, + vfs::{ + file::FileFlags, FilePrivateData, FileType, IndexNode, InodeFlags, InodeId, InodeMode, + Metadata, + }, }, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, @@ -502,8 +505,7 @@ impl LoopDevice { } .ok_or(SystemError::EBADF)?; - let mode = file.mode(); - let read_only = !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); + let read_only = file.flags().is_read_only(); let inode = file.inode(); let metadata = inode.metadata()?; @@ -793,8 +795,9 @@ impl IndexNode for LoopDevice { mtime: file_metadata.mtime, ctime: file_metadata.ctime, btime: file_metadata.btime, - file_type: crate::filesystem::vfs::FileType::BlockDevice, - mode: crate::filesystem::vfs::syscall::ModeType::from_bits_truncate(0o644), + file_type: FileType::BlockDevice, + mode: InodeMode::from_bits_truncate(0o644), + flags: InodeFlags::empty(), nlinks: 1, uid: 0, gid: 0, @@ -817,11 +820,7 @@ impl IndexNode for LoopDevice { guard.get_file_by_fd(file_fd) } .ok_or(SystemError::EBADF)?; - - let mode = file.mode(); - let read_only = - !mode.contains(FileMode::O_WRONLY) && !mode.contains(FileMode::O_RDWR); - + let read_only = file.flags().is_read_only(); let inode = file.inode(); let metadata = inode.metadata()?; match metadata.file_type { @@ -1548,7 +1547,7 @@ impl IndexNode for LoopControlDevice { fn open( &self, _data: SpinLockGuard, - _mode: &FileMode, + _mode: &FileFlags, ) -> Result<(), SystemError> { // 若文件系统没有实现此方法,则返回“不支持” return Ok(()); @@ -1569,7 +1568,6 @@ impl IndexNode for LoopControlDevice { /// - 包含设备类型、权限、设备号等信息 /// fn metadata(&self) -> Result { - use crate::filesystem::vfs::{syscall::ModeType, FileType, InodeId}; use crate::time::PosixTimeSpec; let metadata = Metadata { @@ -1583,7 +1581,8 @@ impl IndexNode for LoopControlDevice { ctime: PosixTimeSpec::default(), btime: PosixTimeSpec::default(), file_type: FileType::CharDevice, - mode: ModeType::from_bits_truncate(0o600), + mode: InodeMode::from_bits_truncate(0o600), + flags: InodeFlags::empty(), nlinks: 1, uid: 0, gid: 0, From 9881aec976d3a19dc2629e1c4ac2ec843752bc2d Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Tue, 9 Dec 2025 19:17:21 +0800 Subject: [PATCH 30/39] =?UTF-8?q?-fix:=20=E5=88=A0=E9=99=A4=E5=86=97?= =?UTF-8?q?=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/block/loop_device/mod.rs | 103 ++++++++++----------- 1 file changed, 48 insertions(+), 55 deletions(-) diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs index 5b07c0c5c..c79057cef 100644 --- a/kernel/src/driver/block/loop_device/mod.rs +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -1,3 +1,4 @@ +use crate::init::initcall::INITCALL_DEVICE; use crate::{ driver::base::{ block::{ @@ -50,9 +51,11 @@ use log::{error, info, warn}; use num_traits::FromPrimitive; use system_error::SystemError; use unified_init::macros::unified_init; + const LOOP_BASENAME: &str = "loop"; const LOOP_CONTROL_BASENAME: &str = "loop-control"; pub const LOOP_CONTROL_MINOR: u32 = 237; + #[repr(u32)] #[derive(Debug, FromPrimitive)] pub enum LoopIoctl { @@ -64,10 +67,11 @@ pub enum LoopIoctl { LoopGetStatus64 = 0x4C05, LoopChangeFd = 0x4C06, LoopSetCapacity = 0x4C07, - LoopSetDirectIo = 0x4c08, - LoopSetBlockSize = 0x4c09, - LoopConfigure = 0x4c0a, + LoopSetDirectIo = 0x4C08, + LoopSetBlockSize = 0x4C09, + LoopConfigure = 0x4C0A, } + #[repr(u32)] #[derive(Debug, FromPrimitive)] pub enum LoopControlIoctl { @@ -75,8 +79,10 @@ pub enum LoopControlIoctl { Remove = 0x4C81, GetFree = 0x4C82, } + pub const LO_FLAGS_READ_ONLY: u32 = 1 << 0; pub const SUPPORTED_LOOP_FLAGS: u32 = LO_FLAGS_READ_ONLY; + #[repr(C)] #[derive(Default, Clone, Copy)] pub struct LoopStatus64 { @@ -85,6 +91,7 @@ pub struct LoopStatus64 { pub lo_flags: u32, pub __pad: u32, } + #[derive(Debug)] pub struct LoopDeviceKObjType; @@ -133,25 +140,27 @@ pub struct LoopDevice { /// 活跃的 I/O 操作计数 active_io_count: AtomicU32, } -#[derive(Debug, Clone)] -pub struct LoopPrivateData {} + +/// Loop 设备的私有数据(目前未使用) +#[derive(Debug, Clone, Default)] +pub struct LoopPrivateData; + pub struct LoopDeviceInner { pub device_number: DeviceNumber, state: LoopState, - state_lock: SpinLock<()>, pub file_inode: Option>, pub file_size: usize, pub offset: usize, pub size_limit: usize, pub flags: u32, - pub read_only: bool, pub kobject_common: KObjectCommonData, pub device_common: DeviceCommonData, } impl LoopDeviceInner { + /// 检查状态转换是否有效并执行转换 + /// + /// 注意:调用者必须持有 LoopDeviceInner 的锁 fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { - let _guard = self.state_lock.lock(); - match (&self.state, &new_state) { (LoopState::Unbound, LoopState::Bound) => {} (LoopState::Bound, LoopState::Unbound) => {} @@ -167,6 +176,12 @@ impl LoopDeviceInner { self.state = new_state; Ok(()) } + + /// 检查设备是否只读 + #[inline] + fn is_read_only(&self) -> bool { + (self.flags & LO_FLAGS_READ_ONLY) != 0 + } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum LoopState { @@ -211,19 +226,17 @@ impl LoopDevice { id, minor, inner: SpinLock::new(LoopDeviceInner { - file_inode: None, // 默认的虚拟 inode + file_inode: None, file_size: 0, - device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), // Loop 设备主设备号为 7 + device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), offset: 0, size_limit: 0, flags: 0, - read_only: false, kobject_common: KObjectCommonData::default(), device_common: DeviceCommonData::default(), state: LoopState::Unbound, - state_lock: SpinLock::new(()), }), - block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), // Loop 设备主设备号为 7 + block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), locked_kobj_state: LockedKObjectState::default(), self_ref: self_ref.clone(), fs: RwLock::new(Weak::default()), @@ -260,10 +273,9 @@ impl LoopDevice { inner.file_size = file_size; inner.offset = 0; inner.size_limit = 0; - inner.flags = 0; // Reset flags - inner.read_only = false; // Reset read_only + inner.flags = 0; drop(inner); - self.recalc_effective_size()?; // Recalculate size based on new file + self.recalc_effective_size()?; Ok(()) } fn recalc_effective_size(&self) -> Result<(), SystemError> { @@ -322,7 +334,6 @@ impl LoopDevice { let mut inner = self.inner(); inner.set_state(LoopState::Bound)?; - inner.read_only = read_only; inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; inner.size_limit = 0; drop(inner); @@ -356,7 +367,6 @@ impl LoopDevice { inner.file_size = 0; inner.offset = 0; inner.size_limit = 0; - inner.read_only = false; inner.flags = 0; Ok(()) } @@ -398,39 +408,33 @@ impl LoopDevice { let mut info = LoopStatus64::default(); reader.copy_one_from_user(&mut info, 0)?; Self::validate_loop_status64_params(&info)?; + let new_offset = info.lo_offset as usize; let new_limit = if info.lo_sizelimit == 0 { 0 } else { info.lo_sizelimit as usize }; - let new_read_only = (info.lo_flags & LO_FLAGS_READ_ONLY) != 0; - let (old_offset, old_limit, old_flags, old_ro) = { - let inner = self.inner(); - if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { - return Err(SystemError::ENXIO); - } - (inner.offset, inner.size_limit, inner.flags, inner.read_only) - }; - - { + // 保存旧值用于回滚,并在同一个锁作用域内更新 + let old_values = { let mut inner = self.inner(); if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { return Err(SystemError::ENXIO); } + let old = (inner.offset, inner.size_limit, inner.flags); inner.offset = new_offset; inner.size_limit = new_limit; inner.flags = info.lo_flags; - inner.read_only = new_read_only; - } + old + }; if let Err(err) = self.recalc_effective_size() { + // 回滚 let mut inner = self.inner(); - inner.offset = old_offset; - inner.size_limit = old_limit; - inner.flags = old_flags; - inner.read_only = old_ro; + inner.offset = old_values.0; + inner.size_limit = old_values.1; + inner.flags = old_values.2; drop(inner); let _ = self.recalc_effective_size(); return Err(err); @@ -463,11 +467,7 @@ impl LoopDevice { LoopStatus64 { lo_offset: inner.offset as u64, lo_sizelimit: inner.size_limit as u64, - lo_flags: if inner.read_only { - inner.flags | LO_FLAGS_READ_ONLY - } else { - inner.flags & !LO_FLAGS_READ_ONLY - }, + lo_flags: inner.flags, __pad: 0, } }; @@ -513,9 +513,9 @@ impl LoopDevice { FileType::File | FileType::BlockDevice => {} _ => return Err(SystemError::EINVAL), } + let mut inner = self.inner(); inner.file_inode = Some(inode); - inner.read_only = read_only; inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; drop(inner); self.recalc_effective_size()?; @@ -541,7 +541,6 @@ impl LoopDevice { ) { return Err(SystemError::ENODEV); } - self.active_io_count.fetch_add(1, Ordering::AcqRel); Ok(()) } @@ -551,12 +550,7 @@ impl LoopDevice { /// I/O 操作完成时调用,减少活跃 I/O 计数 fn io_end(&self) { let prev = self.active_io_count.fetch_sub(1, Ordering::AcqRel); - if prev == 0 { - warn!( - "Loop device loop{}: I/O count underflow", - self.inner().device_number.minor() - ); - } + debug_assert!(prev > 0, "Loop device I/O count underflow"); } /// # 功能 @@ -1024,20 +1018,19 @@ impl BlockDevice for LoopDevice { return Err(SystemError::EINVAL); } - let (file_inode, base_offset, limit_end, read_only) = { + let (file_inode, base_offset, limit_end) = { let inner = self.inner(); + if inner.is_read_only() { + return Err(SystemError::EROFS); + } let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; let limit = inner .offset .checked_add(inner.file_size) .ok_or(SystemError::EOVERFLOW)?; - (inode, inner.offset, limit, inner.read_only) + (inode, inner.offset, limit) }; - if read_only { - return Err(SystemError::EROFS); - } - let block_offset = lba_id_start .checked_mul(LBA_SIZE) .ok_or(SystemError::EOVERFLOW)?; @@ -1122,7 +1115,7 @@ impl LoopDeviceDriver { self.inner.lock() } } -use crate::init::initcall::INITCALL_DEVICE; + #[unified_init(INITCALL_DEVICE)] pub fn loop_init() -> Result<(), SystemError> { let loop_mgr = Arc::new(LoopManager::new()); From 43edd5930a9af02a49816a246055e13b88ffcf0b Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Tue, 9 Dec 2025 23:02:50 +0800 Subject: [PATCH 31/39] =?UTF-8?q?-=20fix:=E5=9B=A0=E4=B8=BAloop=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=90=8D=E5=92=8Cloopback=E5=90=8D=E5=AD=97=E5=89=8D?= =?UTF-8?q?=E7=BC=80=E9=87=8D=E5=90=88=EF=BC=8C=E5=9C=A8starts=5Fwith?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=B8=8B=E9=9D=A2=E7=9A=84=E6=84=8F=E5=A4=96?= =?UTF-8?q?=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/filesystem/devfs/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index 613c8f448..4de1a24bd 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -196,7 +196,12 @@ impl DevFS { } else if name.starts_with("nvme") { // NVMe设备挂载在 /dev 下 dev_root_inode.add_dev(name, device.clone())?; - } else if name.starts_with("loop") { + } else if name.starts_with("loop") + && name.len() > 4 + && name[4..].chars().all(|c| c.is_ascii_digit()) + { + // loop块设备 (loop0, loop1, ...) 挂载在 /dev 下 + // 注意:不能简单用 starts_with("loop"),因为会与网络 loopback 设备冲突 dev_root_inode.add_dev(name, device.clone())?; } else { dev_block_inode.add_dev(name, device.clone())?; @@ -242,7 +247,12 @@ impl DevFS { dev_char_inode.remove(name)?; } FileType::BlockDevice => { - if name.starts_with("loop") { + // 检查是否是 loop 块设备 (loop0, loop1, ...) + let is_loop_block_device = name.starts_with("loop") + && name.len() > 4 + && name[4..].chars().all(|c| c.is_ascii_digit()); + + if is_loop_block_device { dev_root_inode.remove(name)?; } else { if dev_root_inode.find("block").is_err() { From 08fa4100f5e94727cf18384c36a4f1e5fe9926f3 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 10 Dec 2025 00:33:40 +0800 Subject: [PATCH 32/39] =?UTF-8?q?-=20refactor=EF=BC=9A=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E5=8F=96=E4=BB=A3match=20-=20refactor:=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8bitflags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/block/loop_device/mod.rs | 54 +++++++++++++--------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs index c79057cef..f39fa193d 100644 --- a/kernel/src/driver/block/loop_device/mod.rs +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -1,3 +1,4 @@ +use bitflags::bitflags; use crate::init::initcall::INITCALL_DEVICE; use crate::{ driver::base::{ @@ -80,8 +81,14 @@ pub enum LoopControlIoctl { GetFree = 0x4C82, } -pub const LO_FLAGS_READ_ONLY: u32 = 1 << 0; -pub const SUPPORTED_LOOP_FLAGS: u32 = LO_FLAGS_READ_ONLY; +bitflags! { + /// Loop 设备标志位 + #[derive(Default)] + pub struct LoopFlags: u32 { + /// 只读模式 + const READ_ONLY = 1 << 0; + } +} #[repr(C)] #[derive(Default, Clone, Copy)] @@ -152,7 +159,7 @@ pub struct LoopDeviceInner { pub file_size: usize, pub offset: usize, pub size_limit: usize, - pub flags: u32, + pub flags: LoopFlags, pub kobject_common: KObjectCommonData, pub device_common: DeviceCommonData, } @@ -161,18 +168,19 @@ impl LoopDeviceInner { /// /// 注意:调用者必须持有 LoopDeviceInner 的锁 fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { - match (&self.state, &new_state) { - (LoopState::Unbound, LoopState::Bound) => {} - (LoopState::Bound, LoopState::Unbound) => {} - (LoopState::Bound, LoopState::Rundown) => {} - (LoopState::Rundown, LoopState::Draining) => {} - (LoopState::Rundown, LoopState::Deleting) => {} - (LoopState::Rundown, LoopState::Unbound) => {} - (LoopState::Draining, LoopState::Deleting) => {} - (LoopState::Unbound, LoopState::Deleting) => {} - _ => return Err(SystemError::EINVAL), + const VALID_TRANSITIONS: &[(LoopState, LoopState)] = &[ + (LoopState::Unbound, LoopState::Bound), + (LoopState::Bound, LoopState::Unbound), + (LoopState::Bound, LoopState::Rundown), + (LoopState::Rundown, LoopState::Draining), + (LoopState::Rundown, LoopState::Deleting), + (LoopState::Rundown, LoopState::Unbound), + (LoopState::Draining, LoopState::Deleting), + (LoopState::Unbound, LoopState::Deleting), + ]; + if !VALID_TRANSITIONS.contains(&(self.state, new_state)) { + return Err(SystemError::EINVAL); } - self.state = new_state; Ok(()) } @@ -180,7 +188,7 @@ impl LoopDeviceInner { /// 检查设备是否只读 #[inline] fn is_read_only(&self) -> bool { - (self.flags & LO_FLAGS_READ_ONLY) != 0 + self.flags.contains(LoopFlags::READ_ONLY) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -231,7 +239,7 @@ impl LoopDevice { device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), offset: 0, size_limit: 0, - flags: 0, + flags: LoopFlags::empty(), kobject_common: KObjectCommonData::default(), device_common: DeviceCommonData::default(), state: LoopState::Unbound, @@ -273,7 +281,7 @@ impl LoopDevice { inner.file_size = file_size; inner.offset = 0; inner.size_limit = 0; - inner.flags = 0; + inner.flags = LoopFlags::empty(); drop(inner); self.recalc_effective_size()?; Ok(()) @@ -334,7 +342,7 @@ impl LoopDevice { let mut inner = self.inner(); inner.set_state(LoopState::Bound)?; - inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; + inner.flags = if read_only { LoopFlags::READ_ONLY } else { LoopFlags::empty() }; inner.size_limit = 0; drop(inner); self.recalc_effective_size()?; @@ -367,7 +375,7 @@ impl LoopDevice { inner.file_size = 0; inner.offset = 0; inner.size_limit = 0; - inner.flags = 0; + inner.flags = LoopFlags::empty(); Ok(()) } fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { @@ -380,7 +388,7 @@ impl LoopDevice { if info.lo_sizelimit != 0 && !info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) { return Err(SystemError::EINVAL); } - if info.lo_flags & !SUPPORTED_LOOP_FLAGS != 0 { + if !LoopFlags::from_bits(info.lo_flags).is_some() { return Err(SystemError::EINVAL); } Ok(()) @@ -425,7 +433,7 @@ impl LoopDevice { let old = (inner.offset, inner.size_limit, inner.flags); inner.offset = new_offset; inner.size_limit = new_limit; - inner.flags = info.lo_flags; + inner.flags = LoopFlags::from_bits_truncate(info.lo_flags); old }; @@ -467,7 +475,7 @@ impl LoopDevice { LoopStatus64 { lo_offset: inner.offset as u64, lo_sizelimit: inner.size_limit as u64, - lo_flags: inner.flags, + lo_flags: inner.flags.bits(), __pad: 0, } }; @@ -516,7 +524,7 @@ impl LoopDevice { let mut inner = self.inner(); inner.file_inode = Some(inode); - inner.flags = if read_only { LO_FLAGS_READ_ONLY } else { 0 }; + inner.flags = if read_only { LoopFlags::READ_ONLY } else { LoopFlags::empty() }; drop(inner); self.recalc_effective_size()?; Ok(()) From 8c0bb2d990d24af5a3414150ca5c71ba1a0578ee Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 10 Dec 2025 00:56:57 +0800 Subject: [PATCH 33/39] =?UTF-8?q?-=20refactor:=20=E6=8B=86=E5=88=86loop?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=20//!=20#=20=E6=A8=A1=E5=9D=97=E7=BB=93?= =?UTF-8?q?=E6=9E=84=20//!=20//!=20-=20`constants`:=20=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E5=92=8C=E6=9E=9A=E4=B8=BE=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=20//!=20-=20`loop=5Fdevice`:=20Loop=20=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20//!=20-=20`loop=5Fcontrol`:=20Loop-control?= =?UTF-8?q?=20=E6=8E=A7=E5=88=B6=E8=AE=BE=E5=A4=87=E5=AE=9E=E7=8E=B0=20//!?= =?UTF-8?q?=20-=20`manager`:=20Loop=20=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=99=A8=20//!=20-=20`driver`:=20Loop=20=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E9=A9=B1=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/driver/block/loop_device/constants.rs | 87 + kernel/src/driver/block/loop_device/driver.rs | 151 ++ .../driver/block/loop_device/loop_control.rs | 341 ++++ .../driver/block/loop_device/loop_device.rs | 1070 ++++++++++ .../src/driver/block/loop_device/manager.rs | 301 +++ kernel/src/driver/block/loop_device/mod.rs | 1798 +---------------- 6 files changed, 1981 insertions(+), 1767 deletions(-) create mode 100644 kernel/src/driver/block/loop_device/constants.rs create mode 100644 kernel/src/driver/block/loop_device/driver.rs create mode 100644 kernel/src/driver/block/loop_device/loop_control.rs create mode 100644 kernel/src/driver/block/loop_device/loop_device.rs create mode 100644 kernel/src/driver/block/loop_device/manager.rs diff --git a/kernel/src/driver/block/loop_device/constants.rs b/kernel/src/driver/block/loop_device/constants.rs new file mode 100644 index 000000000..a80eeb85e --- /dev/null +++ b/kernel/src/driver/block/loop_device/constants.rs @@ -0,0 +1,87 @@ +use bitflags::bitflags; +/// Loop 设备基础名称 +pub const LOOP_BASENAME: &str = "loop"; + +/// Loop-control 设备基础名称 +pub const LOOP_CONTROL_BASENAME: &str = "loop-control"; + +/// Loop-control 设备的次设备号 +pub const LOOP_CONTROL_MINOR: u32 = 237; + +/// Loop 设备 ioctl 命令 +#[repr(u32)] +#[derive(Debug, FromPrimitive)] +pub enum LoopIoctl { + /// 设置后端文件描述符 + LoopSetFd = 0x4C00, + /// 清除后端文件绑定 + LoopClrFd = 0x4C01, + /// 设置设备状态 (32位兼容) + LoopSetStatus = 0x4C02, + /// 获取设备状态 (32位兼容) + LoopGetStatus = 0x4C03, + /// 设置设备状态 (64位) + LoopSetStatus64 = 0x4C04, + /// 获取设备状态 (64位) + LoopGetStatus64 = 0x4C05, + /// 更换后端文件描述符 + LoopChangeFd = 0x4C06, + /// 重新计算设备容量 + LoopSetCapacity = 0x4C07, + /// 设置直接I/O模式 + LoopSetDirectIo = 0x4C08, + /// 设置块大小 + LoopSetBlockSize = 0x4C09, + /// 配置设备 + LoopConfigure = 0x4C0A, +} + +/// Loop-control 设备 ioctl 命令 +#[repr(u32)] +#[derive(Debug, FromPrimitive)] +pub enum LoopControlIoctl { + /// 添加新的 loop 设备 + Add = 0x4C80, + /// 删除 loop 设备 + Remove = 0x4C81, + /// 获取空闲的 loop 设备 + GetFree = 0x4C82, +} + +bitflags! { + /// Loop 设备标志位 + #[derive(Default)] + pub struct LoopFlags: u32 { + /// 只读模式 + const READ_ONLY = 1 << 0; + } +} + +/// Loop 设备状态信息结构体 (64位版本) +#[repr(C)] +#[derive(Default, Clone, Copy)] +pub struct LoopStatus64 { + /// 文件内偏移量 + pub lo_offset: u64, + /// 大小限制 (0 表示无限制) + pub lo_sizelimit: u64, + /// 标志位 + pub lo_flags: u32, + /// 填充字段 + pub __pad: u32, +} + +/// Loop 设备状态 +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LoopState { + /// 未绑定状态 + Unbound, + /// 已绑定状态 + Bound, + /// 正在停止运行 (不再接受新 I/O) + Rundown, + /// 正在排空活跃 I/O + Draining, + /// 正在删除 + Deleting, +} diff --git a/kernel/src/driver/block/loop_device/driver.rs b/kernel/src/driver/block/loop_device/driver.rs new file mode 100644 index 000000000..842f22af4 --- /dev/null +++ b/kernel/src/driver/block/loop_device/driver.rs @@ -0,0 +1,151 @@ +use crate::{ + driver::base::{ + device::{ + bus::Bus, + driver::{Driver, DriverCommonData}, + Device, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + }, + filesystem::kernfs::KernFSInode, + libs::{ + rwlock::{RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, +}; +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use core::{ + any::Any, + fmt::{Debug, Formatter}, +}; + +use super::constants::LOOP_BASENAME; + +/// Loop设备驱动 +/// 参考Virtio_blk驱动的实现 +#[derive(Debug)] +#[cast_to([sync] Driver)] +pub struct LoopDeviceDriver { + inner: SpinLock, + kobj_state: LockedKObjectState, +} + +struct InnerLoopDeviceDriver { + driver_common: DriverCommonData, + kobj_common: KObjectCommonData, +} + +impl Debug for InnerLoopDeviceDriver { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("InnerLoopDeviceDriver") + .field("driver_common", &self.driver_common) + .field("kobj_common", &self.kobj_common) + .finish() + } +} + +impl LoopDeviceDriver { + pub fn new() -> Arc { + let inner = InnerLoopDeviceDriver { + driver_common: DriverCommonData::default(), + kobj_common: KObjectCommonData::default(), + }; + Arc::new(Self { + inner: SpinLock::new(inner), + kobj_state: LockedKObjectState::default(), + }) + } + + fn inner(&'_ self) -> SpinLockGuard<'_, InnerLoopDeviceDriver> { + self.inner.lock() + } +} + +impl Driver for LoopDeviceDriver { + fn id_table(&self) -> Option { + Some(IdTable::new(LOOP_BASENAME.to_string(), None)) + } + + fn devices(&self) -> Vec> { + self.inner().driver_common.devices.clone() + } + + fn add_device(&self, device: Arc) { + self.inner().driver_common.push_device(device); + } + + fn delete_device(&self, device: &Arc) { + self.inner().driver_common.delete_device(device); + } + + fn bus(&self) -> Option> { + self.inner().driver_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().driver_common.bus = bus; + } +} + +impl KObject for LoopDeviceDriver { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobj_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobj_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobj_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobj_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobj_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobj_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobj_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobj_common.kobj_type = ktype; + } + + fn name(&self) -> String { + LOOP_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { + self.kobj_state.read() + } + + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.kobj_state.write() = state; + } +} diff --git a/kernel/src/driver/block/loop_device/loop_control.rs b/kernel/src/driver/block/loop_device/loop_control.rs new file mode 100644 index 000000000..1a586d49c --- /dev/null +++ b/kernel/src/driver/block/loop_device/loop_control.rs @@ -0,0 +1,341 @@ +use crate::{ + driver::base::{ + class::Class, + device::{ + bus::Bus, + device_number::{DeviceNumber, Major}, + driver::Driver, + Device, DeviceCommonData, DeviceType, IdTable, + }, + kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState}, + kset::KSet, + }, + filesystem::{ + devfs::{DevFS, DeviceINode, LockedDevFSInode}, + kernfs::KernFSInode, + vfs::{ + file::FileFlags, FilePrivateData, FileType, IndexNode, InodeFlags, InodeId, InodeMode, + Metadata, + }, + }, + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, + time::PosixTimeSpec, +}; +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, +}; +use core::{ + any::Any, + fmt::{Debug, Formatter}, +}; +use num_traits::FromPrimitive; +use system_error::SystemError; + +use super::{ + constants::{LoopControlIoctl, LOOP_CONTROL_BASENAME, LOOP_CONTROL_MINOR}, + manager::LoopManager, +}; + +/// Loop-control 设备 +/// +/// 一个字符设备,作为一个抽象接口控制loop设备的创建,绑定和删除 +/// - 设备分配和查找 +/// - 设备绑定和解绑 +/// - 设备状态查询和配置(配置设备参数,如偏移量、大小限制等) +pub struct LoopControlDevice { + inner: SpinLock, + locked_kobj_state: LockedKObjectState, + loop_mgr: Arc, +} + +struct LoopControlDeviceInner { + /// 设备的公共数据 + device_common: DeviceCommonData, + /// KObject的公共数据 + kobject_common: KObjectCommonData, + + parent: RwLock>, + device_inode_fs: RwLock>>, +} + +impl LoopControlDevice { + pub fn new(loop_mgr: Arc) -> Arc { + Arc::new(Self { + inner: SpinLock::new(LoopControlDeviceInner { + kobject_common: KObjectCommonData::default(), + device_common: DeviceCommonData::default(), + parent: RwLock::new(Weak::default()), + device_inode_fs: RwLock::new(None), + }), + locked_kobj_state: LockedKObjectState::default(), + loop_mgr, + }) + } + + fn inner(&'_ self) -> SpinLockGuard<'_, LoopControlDeviceInner> { + self.inner.lock() + } +} + +impl DeviceINode for LoopControlDevice { + fn set_fs(&self, fs: alloc::sync::Weak) { + *self.inner().device_inode_fs.write() = Some(fs); + } + + fn set_parent(&self, parent: Weak) { + *self.inner().parent.write() = parent; + } +} + +impl Debug for LoopControlDevice { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LoopControlDevice").finish() + } +} + +impl IndexNode for LoopControlDevice { + fn open( + &self, + _data: SpinLockGuard, + _mode: &FileFlags, + ) -> Result<(), SystemError> { + Ok(()) + } + + fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { + Ok(()) + } + + /// # 功能 + /// + /// 获取 loop-control 设备的元数据信息。 + /// + /// ## 参数 + /// + /// - 无 + /// + /// ## 返回值 + /// - `Ok(Metadata)`: 成功获取设备元数据 + /// - 包含设备类型、权限、设备号等信息 + fn metadata(&self) -> Result { + let metadata = Metadata { + dev_id: 0, + inode_id: InodeId::new(0), + size: 0, + blk_size: 0, + blocks: 0, + atime: PosixTimeSpec::default(), + mtime: PosixTimeSpec::default(), + ctime: PosixTimeSpec::default(), + btime: PosixTimeSpec::default(), + file_type: FileType::CharDevice, + mode: InodeMode::from_bits_truncate(0o600), + flags: InodeFlags::empty(), + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: DeviceNumber::new(Major::LOOP_CONTROL_MAJOR, LOOP_CONTROL_MINOR), + }; + Ok(metadata) + } + + fn fs(&self) -> Arc { + todo!() + } + + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { + match LoopControlIoctl::from_u32(cmd) { + Some(LoopControlIoctl::Add) => { + log::info!("Starting LOOP_CTL_ADD ioctl"); + let requested_index = data as u32; + let loop_dev = if requested_index == u32::MAX { + self.loop_mgr.loop_add(None)? + } else { + self.loop_mgr.loop_add(Some(requested_index))? + }; + let minor = { + let inner = loop_dev.inner(); + let minor = inner.device_number.minor(); + log::info!( + "LOOP_CTL_ADD ioctl succeeded, allocated loop device loop{}", + minor + ); + minor + }; + Ok(minor as usize) + } + Some(LoopControlIoctl::Remove) => { + let minor_to_remove = data as u32; + self.loop_mgr.loop_remove(minor_to_remove)?; + Ok(0) + } + Some(LoopControlIoctl::GetFree) => match self.loop_mgr.find_free_minor() { + Some(minor) => Ok(minor as usize), + None => Err(SystemError::ENOSPC), + }, + _ => Err(SystemError::ENOSYS), + } + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn read_at( + &self, + _offset: usize, + _len: usize, + _buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + Err(SystemError::ENOSYS) + } + + fn list(&self) -> Result, system_error::SystemError> { + Err(SystemError::ENOSYS) + } +} + +impl Device for LoopControlDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Char + } + + fn id_table(&self) -> IdTable { + IdTable::new(LOOP_CONTROL_BASENAME.to_string(), None) + } + + fn bus(&self) -> Option> { + self.inner().device_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn class(&self) -> Option> { + let mut guard = self.inner(); + let r = guard.device_common.class.clone()?.upgrade(); + if r.is_none() { + guard.device_common.class = None; + } + return r; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn driver(&self) -> Option> { + let r = self.inner().device_common.driver.clone()?.upgrade(); + if r.is_none() { + self.inner().device_common.driver = None; + } + return r; + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn dev_parent(&self) -> Option> { + self.inner().device_common.get_parent_weak_or_clear() + } + + fn set_dev_parent(&self, parent: Option>) { + self.inner().device_common.parent = parent; + } +} + +impl KObject for LoopControlDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + LOOP_CONTROL_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing + } + + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { + self.locked_kobj_state.read() + } + + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { + self.locked_kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobj_state.write() = state; + } +} diff --git a/kernel/src/driver/block/loop_device/loop_device.rs b/kernel/src/driver/block/loop_device/loop_device.rs new file mode 100644 index 000000000..37d653482 --- /dev/null +++ b/kernel/src/driver/block/loop_device/loop_device.rs @@ -0,0 +1,1070 @@ +use crate::{ + driver::base::{ + block::{ + block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, + disk_info::Partition, + manager::BlockDevMeta, + }, + class::Class, + device::{ + bus::Bus, + device_number::{DeviceNumber, Major}, + driver::Driver, + DevName, Device, DeviceCommonData, DeviceType, IdTable, + }, + kobject::{ + KObjType, KObject, KObjectCommonData, KObjectManager, KObjectState, KObjectSysFSOps, + LockedKObjectState, + }, + kset::KSet, + }, + filesystem::{ + devfs::{DevFS, DeviceINode, LockedDevFSInode}, + kernfs::KernFSInode, + sysfs::{AttributeGroup, SysFSOps}, + vfs::{FilePrivateData, FileType, IndexNode, InodeFlags, InodeId, InodeMode, Metadata}, + }, + libs::{ + rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, + spinlock::{SpinLock, SpinLockGuard}, + }, + process::ProcessManager, + syscall::user_access::{UserBufferReader, UserBufferWriter}, +}; +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; +use core::{ + any::Any, + fmt::{Debug, Formatter}, + sync::atomic::{AtomicU32, Ordering}, +}; +use log::{error, info, warn}; +use num_traits::FromPrimitive; +use system_error::SystemError; + +use super::constants::{LoopFlags, LoopIoctl, LoopState, LoopStatus64, LOOP_BASENAME}; + +/// Loop 设备 KObject 类型 +#[derive(Debug)] +pub struct LoopDeviceKObjType; + +impl KObjType for LoopDeviceKObjType { + fn release(&self, kobj: Arc) { + if let Some(loop_dev) = kobj.as_any_ref().downcast_ref::() { + loop_dev.final_cleanup(); + } + } + + fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { + Some(&KObjectSysFSOps) + } + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + None + } +} + +pub(super) static LOOP_DEVICE_KOBJ_TYPE: LoopDeviceKObjType = LoopDeviceKObjType; + +/// I/O 操作 RAII 守卫 +struct IoGuard<'a> { + device: &'a LoopDevice, +} + +impl<'a> IoGuard<'a> { + fn new(device: &'a LoopDevice) -> Result { + device.io_start()?; + Ok(Self { device }) + } +} + +impl<'a> Drop for IoGuard<'a> { + fn drop(&mut self) { + self.device.io_end(); + } +} + +/// Loop 设备 +pub struct LoopDevice { + id: usize, + minor: u32, + inner: SpinLock, + block_dev_meta: BlockDevMeta, + locked_kobj_state: LockedKObjectState, + self_ref: Weak, + fs: RwLock>, + parent: RwLock>, + /// 活跃的 I/O 操作计数 + active_io_count: AtomicU32, +} + +/// Loop 设备的私有数据(目前未使用) +#[derive(Debug, Clone, Default)] +pub struct LoopPrivateData; + +/// Loop 设备内部状态 +pub struct LoopDeviceInner { + pub device_number: DeviceNumber, + state: LoopState, + pub file_inode: Option>, + pub file_size: usize, + pub offset: usize, + pub size_limit: usize, + pub flags: LoopFlags, + pub kobject_common: KObjectCommonData, + pub device_common: DeviceCommonData, +} + +impl LoopDeviceInner { + /// 检查状态转换是否有效并执行转换 + /// + /// 注意:调用者必须持有 LoopDeviceInner 的锁 + pub(super) fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { + const VALID_TRANSITIONS: &[(LoopState, LoopState)] = &[ + (LoopState::Unbound, LoopState::Bound), + (LoopState::Bound, LoopState::Unbound), + (LoopState::Bound, LoopState::Rundown), + (LoopState::Rundown, LoopState::Draining), + (LoopState::Rundown, LoopState::Deleting), + (LoopState::Rundown, LoopState::Unbound), + (LoopState::Draining, LoopState::Deleting), + (LoopState::Unbound, LoopState::Deleting), + ]; + if !VALID_TRANSITIONS.contains(&(self.state, new_state)) { + return Err(SystemError::EINVAL); + } + self.state = new_state; + Ok(()) + } + + /// 检查设备是否只读 + #[inline] + pub(super) fn is_read_only(&self) -> bool { + self.flags.contains(LoopFlags::READ_ONLY) + } + + /// 获取当前状态 + #[inline] + pub(super) fn state(&self) -> LoopState { + self.state + } +} + +impl Debug for LoopDevice { + fn fmt(&'_ self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LoopDevice") + .field("id", &self.id) + .field("devname", &self.block_dev_meta.devname) + .finish() + } +} + +impl LoopDevice { + pub(super) fn inner(&'_ self) -> SpinLockGuard<'_, LoopDeviceInner> { + self.inner.lock() + } + + pub fn id(&self) -> usize { + self.id + } + + pub fn minor(&self) -> u32 { + self.minor + } + + /// # 功能 + /// + /// 创建一个未绑定文件的 loop 设备实例。 + /// + /// ## 参数 + /// + /// - `devname`: 设备名称。 + /// - `minor`: 次设备号。 + /// + /// ## 返回值 + /// - `Some(Arc)`: 成功创建的 loop 设备。 + /// - `None`: 内存不足或创建失败。 + pub fn new_empty_loop_device(devname: DevName, id: usize, minor: u32) -> Option> { + let dev = Arc::new_cyclic(|self_ref| Self { + id, + minor, + inner: SpinLock::new(LoopDeviceInner { + file_inode: None, + file_size: 0, + device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), + offset: 0, + size_limit: 0, + flags: LoopFlags::empty(), + kobject_common: KObjectCommonData::default(), + device_common: DeviceCommonData::default(), + state: LoopState::Unbound, + }), + block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), + locked_kobj_state: LockedKObjectState::default(), + self_ref: self_ref.clone(), + fs: RwLock::new(Weak::default()), + parent: RwLock::new(Weak::default()), + active_io_count: AtomicU32::new(0), + }); + + // 设置 KObjType + dev.set_kobj_type(Some(&LOOP_DEVICE_KOBJ_TYPE)); + + Some(dev) + } + + /// # 功能 + /// + /// 为 loop 设备绑定后端文件并重置相关状态。 + /// + /// ## 参数 + /// + /// - `file_inode`: 需要绑定的文件节点。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功绑定文件。 + /// - `Err(SystemError)`: 绑定失败的错误原因。 + pub fn set_file(&self, file_inode: Arc) -> Result<(), SystemError> { + let metadata = file_inode.metadata()?; + if metadata.size < 0 { + return Err(SystemError::EINVAL); + } + let file_size = metadata.size as usize; + + let mut inner = self.inner(); + inner.file_inode = Some(file_inode); + inner.file_size = file_size; + inner.offset = 0; + inner.size_limit = 0; + inner.flags = LoopFlags::empty(); + drop(inner); + self.recalc_effective_size()?; + Ok(()) + } + + fn recalc_effective_size(&self) -> Result<(), SystemError> { + let (file_inode, offset, size_limit) = { + let inner = self.inner(); + (inner.file_inode.clone(), inner.offset, inner.size_limit) + }; + + let inode = file_inode.ok_or(SystemError::ENODEV)?; + let metadata = inode.metadata()?; + if metadata.size < 0 { + return Err(SystemError::EINVAL); + } + let total_size = metadata.size as usize; + if offset > total_size { + return Err(SystemError::EINVAL); + } + let mut effective = total_size - offset; + if size_limit > 0 { + effective = effective.min(size_limit); + } + + let mut inner = self.inner(); + inner.file_size = effective; + Ok(()) + } + + pub fn is_bound(&self) -> bool { + matches!(self.inner().state(), LoopState::Bound) + } + + /// # 功能 + /// + /// 将文件绑定到 loop 设备并设置访问权限。 + /// + /// ## 参数 + /// + /// - `file_inode`: 需要绑定的文件节点。 + /// - `read_only`: 是否以只读方式绑定。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功绑定。 + /// - `Err(SystemError)`: 绑定失败的原因。 + pub fn bind_file( + &self, + file_inode: Arc, + read_only: bool, + ) -> Result<(), SystemError> { + { + let inner = self.inner(); + if matches!(inner.state(), LoopState::Bound) { + return Err(SystemError::EBUSY); + } + } + + self.set_file(file_inode.clone())?; + + let mut inner = self.inner(); + inner.set_state(LoopState::Bound)?; + inner.flags = if read_only { + LoopFlags::READ_ONLY + } else { + LoopFlags::empty() + }; + inner.size_limit = 0; + drop(inner); + self.recalc_effective_size()?; + Ok(()) + } + + /// # 功能 + /// + /// 清除 loop 设备的文件绑定并复位状态。 + /// + /// ## 参数 + /// + /// - 无。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功清除。 + /// - `Err(SystemError)`: 清除过程中的错误。 + pub fn clear_file(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + match inner.state() { + LoopState::Bound | LoopState::Rundown => inner.set_state(LoopState::Unbound)?, + LoopState::Unbound => {} + LoopState::Draining => return Err(SystemError::EBUSY), + LoopState::Deleting => { + // 在删除流程中,允许清理文件 + // 状态已经是Deleting,无需改变 + } + } + + inner.file_inode = None; + inner.file_size = 0; + inner.offset = 0; + inner.size_limit = 0; + inner.flags = LoopFlags::empty(); + Ok(()) + } + + fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { + if !info.lo_offset.is_multiple_of(LBA_SIZE as u64) { + return Err(SystemError::EINVAL); + } + if info.lo_offset > usize::MAX as u64 || info.lo_sizelimit > usize::MAX as u64 { + return Err(SystemError::EINVAL); + } + if info.lo_sizelimit != 0 && !info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) { + return Err(SystemError::EINVAL); + } + if !LoopFlags::from_bits(info.lo_flags).is_some() { + return Err(SystemError::EINVAL); + } + Ok(()) + } + + /// 设置 loop 设备的状态(64 位版本)。 + /// + /// ## 参数 + /// + /// - `user_ptr`: 用户空间传入的 `LoopStatus64` 结构体指针。 + /// + /// ## 返回值 + /// - `Ok(())`: 状态设置成功。 + /// - `Err(SystemError::EINVAL)`: 无效的参数或标志位。 + /// - `Err(SystemError::ENXIO)`: 设备未绑定或已卸载。 + fn set_status64(&self, user_ptr: usize) -> Result<(), SystemError> { + if user_ptr == 0 { + return Err(SystemError::EINVAL); + } + + let reader = UserBufferReader::new::( + user_ptr as *const LoopStatus64, + core::mem::size_of::(), + true, + )?; + let mut info = LoopStatus64::default(); + reader.copy_one_from_user(&mut info, 0)?; + Self::validate_loop_status64_params(&info)?; + + let new_offset = info.lo_offset as usize; + let new_limit = if info.lo_sizelimit == 0 { + 0 + } else { + info.lo_sizelimit as usize + }; + + // 保存旧值用于回滚,并在同一个锁作用域内更新 + let old_values = { + let mut inner = self.inner(); + if !matches!(inner.state(), LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + let old = (inner.offset, inner.size_limit, inner.flags); + inner.offset = new_offset; + inner.size_limit = new_limit; + inner.flags = LoopFlags::from_bits_truncate(info.lo_flags); + old + }; + + if let Err(err) = self.recalc_effective_size() { + // 回滚 + let mut inner = self.inner(); + inner.offset = old_values.0; + inner.size_limit = old_values.1; + inner.flags = old_values.2; + drop(inner); + let _ = self.recalc_effective_size(); + return Err(err); + } + + Ok(()) + } + + /// # 功能 + /// + /// 获取 loop 设备的 LoopStatus64 信息并写回用户态。 + /// + /// ## 参数 + /// + /// - `user_ptr`: 用户态缓冲区地址。 + /// + /// ## 返回值 + /// - `Ok(())`: 信息写回成功。 + /// - `Err(SystemError)`: 读取状态失败。 + fn get_status64(&self, user_ptr: usize) -> Result<(), SystemError> { + if user_ptr == 0 { + return Err(SystemError::EINVAL); + } + + let info = { + let inner = self.inner(); + if !matches!(inner.state(), LoopState::Bound | LoopState::Rundown) { + return Err(SystemError::ENXIO); + } + LoopStatus64 { + lo_offset: inner.offset as u64, + lo_sizelimit: inner.size_limit as u64, + lo_flags: inner.flags.bits(), + __pad: 0, + } + }; + + let mut writer = UserBufferWriter::new::( + user_ptr as *mut LoopStatus64, + core::mem::size_of::(), + true, + )?; + writer.copy_one_to_user(&info, 0)?; + Ok(()) + } + + fn set_status(&self, user_ptr: usize) -> Result<(), SystemError> { + self.set_status64(user_ptr) + } + + fn get_status(&self, user_ptr: usize) -> Result<(), SystemError> { + self.get_status64(user_ptr) + } + + /// # 功能 + /// + /// 将 loop 设备切换到新的文件描述符。 + /// + /// ## 参数 + /// + /// - `new_file_fd`: 新的文件描述符。 + /// + /// ## 返回值 + /// - `Ok(())`: 成功切换。 + /// - `Err(SystemError)`: 切换失败原因。 + fn change_fd(&self, new_file_fd: i32) -> Result<(), SystemError> { + let fd_table = ProcessManager::current_pcb().fd_table(); + let file = { + let guard = fd_table.read(); + guard.get_file_by_fd(new_file_fd) + } + .ok_or(SystemError::EBADF)?; + + let read_only = file.flags().is_read_only(); + + let inode = file.inode(); + let metadata = inode.metadata()?; + match metadata.file_type { + FileType::File | FileType::BlockDevice => {} + _ => return Err(SystemError::EINVAL), + } + + let mut inner = self.inner(); + inner.file_inode = Some(inode); + inner.flags = if read_only { + LoopFlags::READ_ONLY + } else { + LoopFlags::empty() + }; + drop(inner); + self.recalc_effective_size()?; + Ok(()) + } + + fn set_capacity(&self, _arg: usize) -> Result<(), SystemError> { + self.recalc_effective_size()?; + Ok(()) + } + + /// # 功能 + /// + /// I/O 操作开始时调用,增加活跃 I/O 计数 + /// + /// ## 返回值 + /// - `Ok(())`: 成功增加计数 + /// - `Err(SystemError::ENODEV)`: 设备正在删除,拒绝新的 I/O + fn io_start(&self) -> Result<(), SystemError> { + let inner = self.inner(); + if matches!( + inner.state(), + LoopState::Rundown | LoopState::Draining | LoopState::Deleting + ) { + return Err(SystemError::ENODEV); + } + self.active_io_count.fetch_add(1, Ordering::AcqRel); + Ok(()) + } + + /// # 功能 + /// + /// I/O 操作完成时调用,减少活跃 I/O 计数 + fn io_end(&self) { + let prev = self.active_io_count.fetch_sub(1, Ordering::AcqRel); + debug_assert!(prev > 0, "Loop device I/O count underflow"); + } + + /// # 功能 + /// + /// 进入 Rundown 状态,停止接受新的 I/O 请求 + /// + /// ## 返回值 + /// - `Ok(())`: 成功进入 Rundown 状态 + /// - `Err(SystemError)`: 状态转换失败 + pub(super) fn enter_rundown_state(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + match inner.state() { + LoopState::Bound => { + inner.set_state(LoopState::Rundown)?; + info!( + "Loop device loop{} entering rundown state", + inner.device_number.minor() + ); + } + LoopState::Unbound => { + // 空设备可以直接删除 + inner.set_state(LoopState::Deleting)?; + info!( + "Loop device loop{} is unbound, skipping to deleting state", + inner.device_number.minor() + ); + } + LoopState::Rundown => {} + LoopState::Draining | LoopState::Deleting => { + return Err(SystemError::EBUSY); + } + } + Ok(()) + } + + /// # 功能 + /// + /// 等待所有活跃的 I/O 操作完成 + /// + /// ## 返回值 + /// - `Ok(())`: 所有 I/O 已完成 + /// - `Err(SystemError::ETIMEDOUT)`: 等待超时 + pub(super) fn drain_active_io(&self) -> Result<(), SystemError> { + let mut inner = self.inner(); + if matches!(inner.state(), LoopState::Rundown) { + inner.set_state(LoopState::Draining)?; + info!( + "Loop device loop{} entering draining state", + inner.device_number.minor() + ); + } + drop(inner); + let timeout_ms = 30_000; + let check_interval_us = 10_000; + let max_checks = timeout_ms * 1000 / check_interval_us; + + for _i in 0..max_checks { + let count = self.active_io_count.load(Ordering::Acquire); + if count == 0 { + break; + } + + core::hint::spin_loop(); + } + + let final_count = self.active_io_count.load(Ordering::Acquire); + if final_count != 0 { + error!( + "Timeout waiting for I/O to drain on loop{}: {} operations still active", + self.minor(), + final_count + ); + return Err(SystemError::ETIMEDOUT); + } + + info!( + "All I/O operations drained for loop device loop{}", + self.minor() + ); + + let mut inner = self.inner(); + inner.set_state(LoopState::Deleting)?; + + Ok(()) + } + + /// # 功能 + /// + /// 从 sysfs 中移除设备 + /// + /// ## 返回值 + /// - `Ok(())`: 成功移除 + /// - `Err(SystemError)`: 移除失败 + pub(super) fn remove_from_sysfs(&self) -> Result<(), SystemError> { + // 使用 KObjectManager 从 sysfs 中移除 + if let Some(kobj) = self.self_ref.upgrade() { + KObjectManager::remove_kobj(kobj as Arc); + info!("Removed loop device loop{} from sysfs", self.minor()); + } + Ok(()) + } + + /// # 功能 + /// + /// 最终清理函数,由 KObjType::release 调用 + /// 执行设备删除的最后清理工作 + fn final_cleanup(&self) { + info!( + "Final cleanup for loop device loop{} (id {})", + self.minor(), + self.id() + ); + let mut inner = self.inner(); + if let Some(file_inode) = inner.file_inode.take() { + drop(file_inode); + warn!( + "File inode was still present during final cleanup for loop{}", + self.minor() + ); + } + inner.file_size = 0; + inner.offset = 0; + inner.size_limit = 0; + info!("Loop device loop{} cleanup complete", self.minor()); + } +} + +impl KObject for LoopDevice { + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner().kobject_common.kern_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner().kobject_common.kern_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner().kobject_common.parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner().kobject_common.parent = parent; + } + + fn kset(&self) -> Option> { + self.inner().kobject_common.kset.clone() + } + + fn set_kset(&self, kset: Option>) { + self.inner().kobject_common.kset = kset; + } + + fn kobj_type(&self) -> Option<&'static dyn KObjType> { + self.inner().kobject_common.kobj_type + } + + fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { + self.inner().kobject_common.kobj_type = ktype; + } + + fn name(&self) -> String { + LOOP_BASENAME.to_string() + } + + fn set_name(&self, _name: String) { + // do nothing,不支持设置loop为别的名称 + } + + fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { + self.locked_kobj_state.read() + } + + fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { + self.locked_kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.locked_kobj_state.write() = state; + } +} + +impl IndexNode for LoopDevice { + fn fs(&self) -> Arc { + todo!() + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: SpinLockGuard, + ) -> Result { + if len > buf.len() { + return Err(SystemError::ENOBUFS); + } + BlockDevice::read_at_bytes(self, offset, len, buf) + } + + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + _data: SpinLockGuard, + ) -> Result { + if len > buf.len() { + return Err(SystemError::E2BIG); + } + BlockDevice::write_at_bytes(self, offset, len, &buf[..len]) + } + + fn list(&self) -> Result, system_error::SystemError> { + Err(SystemError::ENOSYS) + } + + fn metadata(&self) -> Result { + let file_metadata = match &self.inner().file_inode { + Some(inode) => inode.metadata()?, + None => { + return Err(SystemError::EPERM); + } + }; + let metadata = Metadata { + dev_id: 0, + inode_id: InodeId::new(0), + size: self.inner().file_size as i64, + blk_size: LBA_SIZE, + blocks: (self.inner().file_size.div_ceil(LBA_SIZE)), + atime: file_metadata.atime, + mtime: file_metadata.mtime, + ctime: file_metadata.ctime, + btime: file_metadata.btime, + file_type: FileType::BlockDevice, + mode: InodeMode::from_bits_truncate(0o644), + flags: InodeFlags::empty(), + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: self.inner().device_number, + }; + Ok(metadata) + } + + fn ioctl( + &self, + cmd: u32, + data: usize, + _private_data: &FilePrivateData, + ) -> Result { + match LoopIoctl::from_u32(cmd) { + Some(LoopIoctl::LoopSetFd) => { + let file_fd = data as i32; + let fd_table = ProcessManager::current_pcb().fd_table(); + let file = { + let guard = fd_table.read(); + guard.get_file_by_fd(file_fd) + } + .ok_or(SystemError::EBADF)?; + let read_only = file.flags().is_read_only(); + let inode = file.inode(); + let metadata = inode.metadata()?; + match metadata.file_type { + FileType::File | FileType::BlockDevice => {} + _ => return Err(SystemError::EINVAL), + } + + self.bind_file(inode, read_only)?; + Ok(0) + } + Some(LoopIoctl::LoopClrFd) => { + self.clear_file()?; + Ok(0) + } + Some(LoopIoctl::LoopSetStatus) => { + self.set_status(data)?; + Ok(0) + } + Some(LoopIoctl::LoopGetStatus) => { + self.get_status(data)?; + Ok(0) + } + Some(LoopIoctl::LoopSetStatus64) => { + self.set_status64(data)?; + Ok(0) + } + Some(LoopIoctl::LoopGetStatus64) => { + self.get_status64(data)?; + Ok(0) + } + Some(LoopIoctl::LoopChangeFd) => { + self.change_fd(data as i32)?; + Ok(0) + } + Some(LoopIoctl::LoopSetCapacity) => { + self.set_capacity(data)?; + Ok(0) + } + _ => Err(SystemError::ENOSYS), + } + } +} + +impl DeviceINode for LoopDevice { + fn set_fs(&self, fs: alloc::sync::Weak) { + *self.fs.write() = fs; + } + + fn set_parent(&self, parent: Weak) { + *self.parent.write() = parent; + } +} + +impl Device for LoopDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Block + } + + fn id_table(&self) -> IdTable { + IdTable::new(LOOP_BASENAME.to_string(), None) + } + + fn bus(&self) -> Option> { + self.inner().device_common.bus.clone() + } + + fn set_bus(&self, bus: Option>) { + self.inner().device_common.bus = bus; + } + + fn class(&self) -> Option> { + let mut guard = self.inner(); + let r = guard.device_common.class.clone()?.upgrade(); + if r.is_none() { + guard.device_common.class = None; + } + return r; + } + + fn set_class(&self, class: Option>) { + self.inner().device_common.class = class; + } + + fn driver(&self) -> Option> { + let r = self.inner().device_common.driver.clone()?.upgrade(); + if r.is_none() { + self.inner().device_common.driver = None; + } + return r; + } + + fn set_driver(&self, driver: Option>) { + self.inner().device_common.driver = driver; + } + + fn is_dead(&self) -> bool { + false + } + + fn can_match(&self) -> bool { + self.inner().device_common.can_match + } + + fn set_can_match(&self, can_match: bool) { + self.inner().device_common.can_match = can_match; + } + + fn state_synced(&self) -> bool { + true + } + + fn dev_parent(&self) -> Option> { + self.inner().device_common.get_parent_weak_or_clear() + } + + fn set_dev_parent(&self, parent: Option>) { + self.inner().device_common.parent = parent; + } +} + +impl BlockDevice for LoopDevice { + fn dev_name(&self) -> &DevName { + &self.block_dev_meta.devname + } + + fn blkdev_meta(&self) -> &BlockDevMeta { + &self.block_dev_meta + } + + fn disk_range(&self) -> GeneralBlockRange { + let inner = self.inner(); + let blocks = if inner.file_size == 0 { + 0 + } else { + inner.file_size.saturating_add(LBA_SIZE - 1) / LBA_SIZE + }; + drop(inner); + GeneralBlockRange::new(0, blocks).unwrap_or(GeneralBlockRange { + lba_start: 0, + lba_end: 0, + }) + } + + fn read_at_sync( + &self, + lba_id_start: BlockId, + count: usize, + buf: &mut [u8], + ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + + if count == 0 { + return Ok(0); + } + let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; + if len > buf.len() { + return Err(SystemError::EINVAL); + } + + let (file_inode, base_offset, limit_end) = { + let inner = self.inner(); + let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; + let limit = inner + .offset + .checked_add(inner.file_size) + .ok_or(SystemError::EOVERFLOW)?; + (inode, inner.offset, limit) + }; + + let block_offset = lba_id_start + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + let file_offset = base_offset + .checked_add(block_offset) + .ok_or(SystemError::EOVERFLOW)?; + + let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; + if end > limit_end { + return Err(SystemError::ENOSPC); + } + + let data = SpinLock::new(FilePrivateData::Unused); + let data_guard = data.lock(); + + file_inode.read_at(file_offset, len, &mut buf[..len], data_guard) + } + + fn write_at_sync( + &self, + lba_id_start: BlockId, + count: usize, + buf: &[u8], + ) -> Result { + // 使用 IoGuard 确保 I/O 计数正确管理 + let _io_guard = IoGuard::new(self)?; + + if count == 0 { + return Ok(0); + } + let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; + if len > buf.len() { + return Err(SystemError::EINVAL); + } + + let (file_inode, base_offset, limit_end) = { + let inner = self.inner(); + if inner.is_read_only() { + return Err(SystemError::EROFS); + } + let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; + let limit = inner + .offset + .checked_add(inner.file_size) + .ok_or(SystemError::EOVERFLOW)?; + (inode, inner.offset, limit) + }; + + let block_offset = lba_id_start + .checked_mul(LBA_SIZE) + .ok_or(SystemError::EOVERFLOW)?; + let file_offset = base_offset + .checked_add(block_offset) + .ok_or(SystemError::EOVERFLOW)?; + + let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; + if end > limit_end { + return Err(SystemError::ENOSPC); + } + + let data = SpinLock::new(FilePrivateData::Unused); + let data_guard = data.lock(); + + let written = file_inode.write_at(file_offset, len, &buf[..len], data_guard)?; + + if written > 0 { + let _ = self.recalc_effective_size(); + } + + Ok(written) + } + + fn sync(&self) -> Result<(), SystemError> { + Ok(()) + } + + fn blk_size_log2(&self) -> u8 { + 9 + } + + fn as_any_ref(&self) -> &dyn Any { + self + } + + fn device(&self) -> Arc { + self.self_ref.upgrade().unwrap() + } + + fn block_size(&self) -> usize { + LBA_SIZE + } + + fn partitions(&self) -> Vec> { + Vec::new() + } +} diff --git a/kernel/src/driver/block/loop_device/manager.rs b/kernel/src/driver/block/loop_device/manager.rs new file mode 100644 index 000000000..89217490d --- /dev/null +++ b/kernel/src/driver/block/loop_device/manager.rs @@ -0,0 +1,301 @@ +use crate::{ + driver::base::{ + block::{block_device::BlockDevice, manager::block_dev_manager}, + device::DevName, + }, + libs::spinlock::{SpinLock, SpinLockGuard}, +}; +use alloc::{format, sync::Arc}; +use ida::IdAllocator; +use log::info; +use system_error::SystemError; + +use super::{ + constants::{LoopState, LOOP_BASENAME}, + driver::LoopDeviceDriver, + loop_device::LoopDevice, +}; + +/// Loop 设备管理器 +pub struct LoopManager { + inner: SpinLock, +} + +pub struct LoopManagerInner { + devices: [Option>; LoopManager::MAX_DEVICES], + id_alloc: IdAllocator, + next_free_minor: u32, +} + +impl LoopManager { + /// 最大设备数量 + const MAX_DEVICES: usize = 256; + /// 初始化时创建的设备数量 + const MAX_INIT_DEVICES: usize = 8; + + pub fn new() -> Self { + Self { + inner: SpinLock::new(LoopManagerInner { + devices: [const { None }; Self::MAX_DEVICES], + id_alloc: IdAllocator::new(0, Self::MAX_DEVICES) + .expect("create IdAllocator failed"), + next_free_minor: 0, + }), + } + } + + fn inner(&'_ self) -> SpinLockGuard<'_, LoopManagerInner> { + self.inner.lock() + } + + #[inline] + fn alloc_id_locked(inner: &mut LoopManagerInner) -> Option { + inner.id_alloc.alloc() + } + + #[inline] + fn free_id_locked(inner: &mut LoopManagerInner, id: usize) { + if id < Self::MAX_DEVICES && inner.id_alloc.exists(id) { + inner.id_alloc.free(id); + } + } + + #[inline] + pub fn format_name(id: usize) -> DevName { + DevName::new(format!("{}{}", LOOP_BASENAME, id), id) + } + + fn find_device_by_minor_locked( + inner: &LoopManagerInner, + minor: u32, + ) -> Option> { + inner + .devices + .iter() + .flatten() + .find(|device| device.minor() == minor) + .map(Arc::clone) + } + + fn find_unused_minor_locked(inner: &LoopManagerInner) -> Option { + let mut candidate = inner.next_free_minor; + for _ in 0..Self::MAX_DEVICES as u32 { + let mut used = false; + for dev in inner.devices.iter().flatten() { + if dev.minor() == candidate { + used = true; + break; + } + } + if !used { + return Some(candidate); + } + candidate = (candidate + 1) % Self::MAX_DEVICES as u32; + } + None + } + + /// # 功能 + /// + /// 根据请求的次设备号分配或复用 loop 设备。 + /// + /// ## 参数 + /// + /// - `requested_minor`: 指定的次设备号,`None` 表示自动分配。 + /// + /// ## 返回值 + /// - `Ok(Arc)`: 成功获得的设备。 + /// - `Err(SystemError)`: 无可用设备或参数错误。 + pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { + let mut inner = self.inner(); + match requested_minor { + Some(req_minor) => self.loop_add_specific_locked(&mut inner, req_minor), + None => self.loop_add_first_available_locked(&mut inner), + } + } + + /// # 功能 + /// + /// 在锁作用域内分配指定次设备号的 loop 设备。 + /// + /// ## 参数 + /// + /// - `inner`: 管理器内部状态锁。 + /// - `minor`: 目标次设备号。 + /// + /// ## 返回值 + /// - `Ok(Arc)`: 成功获得的设备实例。 + /// - `Err(SystemError)`: 参数无效或设备已被占用。 + fn loop_add_specific_locked( + &self, + inner: &mut LoopManagerInner, + minor: u32, + ) -> Result, SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + + if let Some(device) = Self::find_device_by_minor_locked(inner, minor) { + if device.is_bound() { + return Err(SystemError::EEXIST); + } + return Ok(device); + } + + let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; + match self.create_and_register_device_locked(inner, id, minor) { + Ok(device) => Ok(device), + Err(e) => { + Self::free_id_locked(inner, id); + Err(e) + } + } + } + + fn loop_add_first_available_locked( + &self, + inner: &mut LoopManagerInner, + ) -> Result, SystemError> { + if let Some(device) = inner + .devices + .iter() + .flatten() + .find(|device| !device.is_bound()) + { + return Ok(device.clone()); + } + + let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; + let minor = match Self::find_unused_minor_locked(inner) { + Some(minor) => minor, + None => { + Self::free_id_locked(inner, id); + return Err(SystemError::ENOSPC); + } + }; + let result = self.create_and_register_device_locked(inner, id, minor); + if result.is_err() { + Self::free_id_locked(inner, id); + } + result + } + + fn create_and_register_device_locked( + &self, + inner: &mut LoopManagerInner, + id: usize, + minor: u32, + ) -> Result, SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + + let devname = Self::format_name(id); + let loop_dev = + LoopDevice::new_empty_loop_device(devname, id, minor).ok_or(SystemError::ENOMEM)?; + + if let Err(e) = block_dev_manager().register(loop_dev.clone()) { + if e == SystemError::EEXIST { + if let Some(existing) = inner.devices[id].clone() { + return Ok(existing); + } + } + return Err(e); + } + + inner.devices[id] = Some(loop_dev.clone()); + inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; + log::info!( + "Loop device id {} (minor {}) added successfully.", + id, + minor + ); + Ok(loop_dev) + } + + /// # 功能 + /// + /// 删除指定 minor 的 loop 设备 + /// 实现规范的删除流程,包括状态转换、I/O 排空、资源清理 + /// + /// ## 参数 + /// + /// - `minor`: 要删除的设备的次设备号 + /// + /// ## 返回值 + /// - `Ok(())`: 成功删除设备 + /// - `Err(SystemError)`: 删除失败 + pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { + if minor >= Self::MAX_DEVICES as u32 { + return Err(SystemError::EINVAL); + } + let device = { + let inner = self.inner(); + Self::find_device_by_minor_locked(&inner, minor) + } + .ok_or(SystemError::ENODEV)?; + let id = device.id(); + info!("Starting removal of loop device loop{} (id {})", minor, id); + device.enter_rundown_state()?; + let needs_drain = { + let inner = device.inner(); + !matches!(inner.state(), LoopState::Deleting) + }; + + if needs_drain { + device.drain_active_io()?; + } + + device.clear_file()?; + + let _ = device.remove_from_sysfs(); + + let block_dev: Arc = device.clone(); + block_dev_manager().unregister(&block_dev)?; + + { + let mut inner = self.inner(); + inner.devices[id] = None; + Self::free_id_locked(&mut inner, id); + inner.next_free_minor = minor; + } + info!( + "Loop device id {} (minor {}) removed successfully.", + id, minor + ); + Ok(()) + } + + pub fn find_free_minor(&self) -> Option { + let inner = self.inner(); + 'outer: for minor in 0..Self::MAX_DEVICES as u32 { + for dev in inner.devices.iter().flatten() { + if dev.minor() == minor { + if !dev.is_bound() { + return Some(minor); + } + continue 'outer; + } + } + return Some(minor); + } + None + } + + pub fn loop_init(&self, _driver: Arc) -> Result<(), SystemError> { + let mut inner = self.inner(); + for minor in 0..Self::MAX_INIT_DEVICES { + let minor_u32 = minor as u32; + if Self::find_device_by_minor_locked(&inner, minor_u32).is_some() { + continue; + } + let id = Self::alloc_id_locked(&mut inner).ok_or(SystemError::ENOSPC)?; + if let Err(e) = self.create_and_register_device_locked(&mut inner, id, minor_u32) { + Self::free_id_locked(&mut inner, id); + return Err(e); + } + } + log::info!("Loop devices initialized"); + Ok(()) + } +} diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs index f39fa193d..bd8e31a96 100644 --- a/kernel/src/driver/block/loop_device/mod.rs +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -1,1129 +1,39 @@ -use bitflags::bitflags; -use crate::init::initcall::INITCALL_DEVICE; +// SPDX-License-Identifier: GPL-2.0 +//! Loop 设备模块 +//! +//! 该模块实现了 Linux 风格的 loop 设备,允许将普通文件作为块设备使用。 +//! +//! # 模块结构 +//! +//! - `constants`: 常量和枚举类型定义 +//! - `loop_device`: Loop 设备实现 +//! - `loop_control`: Loop-control 控制设备实现 +//! - `manager`: Loop 设备管理器 +//! - `driver`: Loop 设备驱动 + +mod constants; +mod driver; +mod loop_control; +mod loop_device; +mod manager; + +use alloc::sync::Arc; +use system_error::SystemError; + use crate::{ - driver::base::{ - block::{ - block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE}, - disk_info::Partition, - manager::{block_dev_manager, BlockDevMeta}, - }, - class::Class, - device::{ - bus::Bus, - device_number::{DeviceNumber, Major}, - device_register, - driver::{Driver, DriverCommonData}, - DevName, Device, DeviceCommonData, DeviceType, IdTable, - }, - kobject::{ - KObjType, KObject, KObjectCommonData, KObjectManager, KObjectState, KObjectSysFSOps, - LockedKObjectState, - }, - kset::KSet, - }, - filesystem::{ - devfs::{devfs_register, DevFS, DeviceINode, LockedDevFSInode}, - kernfs::KernFSInode, - sysfs::{AttributeGroup, SysFSOps}, - vfs::{ - file::FileFlags, FilePrivateData, FileType, IndexNode, InodeFlags, InodeId, InodeMode, - Metadata, - }, - }, - libs::{ - rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, - spinlock::{SpinLock, SpinLockGuard}, - }, - process::ProcessManager, - syscall::user_access::{UserBufferReader, UserBufferWriter}, -}; -use alloc::{ - string::{String, ToString}, - sync::{Arc, Weak}, - vec::Vec, -}; -use core::{ - any::Any, - fmt::{Debug, Formatter}, - sync::atomic::{AtomicU32, Ordering}, + driver::base::device::device_register, filesystem::devfs::devfs_register, + init::initcall::INITCALL_DEVICE, }; -use ida::IdAllocator; -use log::{error, info, warn}; -use num_traits::FromPrimitive; -use system_error::SystemError; use unified_init::macros::unified_init; -const LOOP_BASENAME: &str = "loop"; -const LOOP_CONTROL_BASENAME: &str = "loop-control"; -pub const LOOP_CONTROL_MINOR: u32 = 237; - -#[repr(u32)] -#[derive(Debug, FromPrimitive)] -pub enum LoopIoctl { - LoopSetFd = 0x4C00, - LoopClrFd = 0x4C01, - LoopSetStatus = 0x4C02, - LoopGetStatus = 0x4C03, - LoopSetStatus64 = 0x4C04, - LoopGetStatus64 = 0x4C05, - LoopChangeFd = 0x4C06, - LoopSetCapacity = 0x4C07, - LoopSetDirectIo = 0x4C08, - LoopSetBlockSize = 0x4C09, - LoopConfigure = 0x4C0A, -} - -#[repr(u32)] -#[derive(Debug, FromPrimitive)] -pub enum LoopControlIoctl { - Add = 0x4C80, - Remove = 0x4C81, - GetFree = 0x4C82, -} - -bitflags! { - /// Loop 设备标志位 - #[derive(Default)] - pub struct LoopFlags: u32 { - /// 只读模式 - const READ_ONLY = 1 << 0; - } -} - -#[repr(C)] -#[derive(Default, Clone, Copy)] -pub struct LoopStatus64 { - pub lo_offset: u64, - pub lo_sizelimit: u64, - pub lo_flags: u32, - pub __pad: u32, -} - -#[derive(Debug)] -pub struct LoopDeviceKObjType; - -impl KObjType for LoopDeviceKObjType { - fn release(&self, kobj: Arc) { - if let Some(loop_dev) = kobj.as_any_ref().downcast_ref::() { - loop_dev.final_cleanup(); - } - } - - fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { - Some(&KObjectSysFSOps) - } - - fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { - None - } -} -static LOOP_DEVICE_KOBJ_TYPE: LoopDeviceKObjType = LoopDeviceKObjType; -struct IoGuard<'a> { - device: &'a LoopDevice, -} - -impl<'a> IoGuard<'a> { - fn new(device: &'a LoopDevice) -> Result { - device.io_start()?; - Ok(Self { device }) - } -} - -impl<'a> Drop for IoGuard<'a> { - fn drop(&mut self) { - self.device.io_end(); - } -} - -pub struct LoopDevice { - id: usize, - minor: u32, - inner: SpinLock, - block_dev_meta: BlockDevMeta, - locked_kobj_state: LockedKObjectState, - self_ref: Weak, - fs: RwLock>, - parent: RwLock>, - /// 活跃的 I/O 操作计数 - active_io_count: AtomicU32, -} - -/// Loop 设备的私有数据(目前未使用) -#[derive(Debug, Clone, Default)] -pub struct LoopPrivateData; - -pub struct LoopDeviceInner { - pub device_number: DeviceNumber, - state: LoopState, - pub file_inode: Option>, - pub file_size: usize, - pub offset: usize, - pub size_limit: usize, - pub flags: LoopFlags, - pub kobject_common: KObjectCommonData, - pub device_common: DeviceCommonData, -} -impl LoopDeviceInner { - /// 检查状态转换是否有效并执行转换 - /// - /// 注意:调用者必须持有 LoopDeviceInner 的锁 - fn set_state(&mut self, new_state: LoopState) -> Result<(), SystemError> { - const VALID_TRANSITIONS: &[(LoopState, LoopState)] = &[ - (LoopState::Unbound, LoopState::Bound), - (LoopState::Bound, LoopState::Unbound), - (LoopState::Bound, LoopState::Rundown), - (LoopState::Rundown, LoopState::Draining), - (LoopState::Rundown, LoopState::Deleting), - (LoopState::Rundown, LoopState::Unbound), - (LoopState::Draining, LoopState::Deleting), - (LoopState::Unbound, LoopState::Deleting), - ]; - if !VALID_TRANSITIONS.contains(&(self.state, new_state)) { - return Err(SystemError::EINVAL); - } - self.state = new_state; - Ok(()) - } - - /// 检查设备是否只读 - #[inline] - fn is_read_only(&self) -> bool { - self.flags.contains(LoopFlags::READ_ONLY) - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LoopState { - Unbound, - Bound, - Rundown, - Draining, - Deleting, -} -impl Debug for LoopDevice { - fn fmt(&'_ self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("LoopDevice") - .field("id", &self.id) - .field("devname", &self.block_dev_meta.devname) - .finish() - } -} -impl LoopDevice { - fn inner(&'_ self) -> SpinLockGuard<'_, LoopDeviceInner> { - self.inner.lock() - } - pub fn id(&self) -> usize { - self.id - } - pub fn minor(&self) -> u32 { - self.minor - } - /// # 功能 - /// - /// 创建一个未绑定文件的 loop 设备实例。 - /// - /// ## 参数 - /// - /// - `devname`: 设备名称。 - /// - `minor`: 次设备号。 - /// - /// ## 返回值 - /// - `Some(Arc)`: 成功创建的 loop 设备。 - /// - `None`: 内存不足或创建失败。 - pub fn new_empty_loop_device(devname: DevName, id: usize, minor: u32) -> Option> { - let dev = Arc::new_cyclic(|self_ref| Self { - id, - minor, - inner: SpinLock::new(LoopDeviceInner { - file_inode: None, - file_size: 0, - device_number: DeviceNumber::new(Major::LOOP_MAJOR, minor), - offset: 0, - size_limit: 0, - flags: LoopFlags::empty(), - kobject_common: KObjectCommonData::default(), - device_common: DeviceCommonData::default(), - state: LoopState::Unbound, - }), - block_dev_meta: BlockDevMeta::new(devname, Major::LOOP_MAJOR), - locked_kobj_state: LockedKObjectState::default(), - self_ref: self_ref.clone(), - fs: RwLock::new(Weak::default()), - parent: RwLock::new(Weak::default()), - active_io_count: AtomicU32::new(0), - }); - - // 设置 KObjType - dev.set_kobj_type(Some(&LOOP_DEVICE_KOBJ_TYPE)); - - Some(dev) - } - - /// # 功能 - /// - /// 为 loop 设备绑定后端文件并重置相关状态。 - /// - /// ## 参数 - /// - /// - `file_inode`: 需要绑定的文件节点。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功绑定文件。 - /// - `Err(SystemError)`: 绑定失败的错误原因。 - pub fn set_file(&self, file_inode: Arc) -> Result<(), SystemError> { - let metadata = file_inode.metadata()?; - if metadata.size < 0 { - return Err(SystemError::EINVAL); - } - let file_size = metadata.size as usize; - - let mut inner = self.inner(); - inner.file_inode = Some(file_inode); - inner.file_size = file_size; - inner.offset = 0; - inner.size_limit = 0; - inner.flags = LoopFlags::empty(); - drop(inner); - self.recalc_effective_size()?; - Ok(()) - } - fn recalc_effective_size(&self) -> Result<(), SystemError> { - let (file_inode, offset, size_limit) = { - let inner = self.inner(); - (inner.file_inode.clone(), inner.offset, inner.size_limit) - }; - - let inode = file_inode.ok_or(SystemError::ENODEV)?; - let metadata = inode.metadata()?; - if metadata.size < 0 { - return Err(SystemError::EINVAL); - } - let total_size = metadata.size as usize; - if offset > total_size { - return Err(SystemError::EINVAL); - } - let mut effective = total_size - offset; - if size_limit > 0 { - effective = effective.min(size_limit); - } - - let mut inner = self.inner(); - inner.file_size = effective; - Ok(()) - } - - pub fn is_bound(&self) -> bool { - matches!(self.inner().state, LoopState::Bound) - } - /// # 功能 - /// - /// 将文件绑定到 loop 设备并设置访问权限。 - /// - /// ## 参数 - /// - /// - `file_inode`: 需要绑定的文件节点。 - /// - `read_only`: 是否以只读方式绑定。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功绑定。 - /// - `Err(SystemError)`: 绑定失败的原因。 - pub fn bind_file( - &self, - file_inode: Arc, - read_only: bool, - ) -> Result<(), SystemError> { - { - let inner = self.inner(); - if matches!(inner.state, LoopState::Bound) { - return Err(SystemError::EBUSY); - } - } - - self.set_file(file_inode.clone())?; - - let mut inner = self.inner(); - inner.set_state(LoopState::Bound)?; - inner.flags = if read_only { LoopFlags::READ_ONLY } else { LoopFlags::empty() }; - inner.size_limit = 0; - drop(inner); - self.recalc_effective_size()?; - Ok(()) - } - /// # 功能 - /// - /// 清除 loop 设备的文件绑定并复位状态。 - /// - /// ## 参数 - /// - /// - 无。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功清除。 - /// - `Err(SystemError)`: 清除过程中的错误。 - pub fn clear_file(&self) -> Result<(), SystemError> { - let mut inner = self.inner(); - match inner.state { - LoopState::Bound | LoopState::Rundown => inner.set_state(LoopState::Unbound)?, - LoopState::Unbound => {} - LoopState::Draining => return Err(SystemError::EBUSY), - LoopState::Deleting => { - // 在删除流程中,允许清理文件 - // 状态已经是Deleting,无需改变 - } - } - - inner.file_inode = None; - inner.file_size = 0; - inner.offset = 0; - inner.size_limit = 0; - inner.flags = LoopFlags::empty(); - Ok(()) - } - fn validate_loop_status64_params(info: &LoopStatus64) -> Result<(), SystemError> { - if !info.lo_offset.is_multiple_of(LBA_SIZE as u64) { - return Err(SystemError::EINVAL); - } - if info.lo_offset > usize::MAX as u64 || info.lo_sizelimit > usize::MAX as u64 { - return Err(SystemError::EINVAL); - } - if info.lo_sizelimit != 0 && !info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) { - return Err(SystemError::EINVAL); - } - if !LoopFlags::from_bits(info.lo_flags).is_some() { - return Err(SystemError::EINVAL); - } - Ok(()) - } - /// 设置 loop 设备的状态(64 位版本)。 - /// - /// ## 参数 - /// - /// - `user_ptr`: 用户空间传入的 `LoopStatus64` 结构体指针。 - /// - /// ## 返回值 - /// - `Ok(())`: 状态设置成功。 - /// - `Err(SystemError::EINVAL)`: 无效的参数或标志位。 - /// - `Err(SystemError::ENXIO)`: 设备未绑定或已卸载。 - fn set_status64(&self, user_ptr: usize) -> Result<(), SystemError> { - if user_ptr == 0 { - return Err(SystemError::EINVAL); - } - - let reader = UserBufferReader::new::( - user_ptr as *const LoopStatus64, - core::mem::size_of::(), - true, - )?; - let mut info = LoopStatus64::default(); - reader.copy_one_from_user(&mut info, 0)?; - Self::validate_loop_status64_params(&info)?; - - let new_offset = info.lo_offset as usize; - let new_limit = if info.lo_sizelimit == 0 { - 0 - } else { - info.lo_sizelimit as usize - }; - - // 保存旧值用于回滚,并在同一个锁作用域内更新 - let old_values = { - let mut inner = self.inner(); - if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { - return Err(SystemError::ENXIO); - } - let old = (inner.offset, inner.size_limit, inner.flags); - inner.offset = new_offset; - inner.size_limit = new_limit; - inner.flags = LoopFlags::from_bits_truncate(info.lo_flags); - old - }; - - if let Err(err) = self.recalc_effective_size() { - // 回滚 - let mut inner = self.inner(); - inner.offset = old_values.0; - inner.size_limit = old_values.1; - inner.flags = old_values.2; - drop(inner); - let _ = self.recalc_effective_size(); - return Err(err); - } - - Ok(()) - } - /// # 功能 - /// - /// 获取 loop 设备的 LoopStatus64 信息并写回用户态。 - /// - /// ## 参数 - /// - /// - `user_ptr`: 用户态缓冲区地址。 - /// - /// ## 返回值 - /// - `Ok(())`: 信息写回成功。 - /// - `Err(SystemError)`: 读取状态失败。 - /// - fn get_status64(&self, user_ptr: usize) -> Result<(), SystemError> { - if user_ptr == 0 { - return Err(SystemError::EINVAL); - } - - let info = { - let inner = self.inner(); - if !matches!(inner.state, LoopState::Bound | LoopState::Rundown) { - return Err(SystemError::ENXIO); - } - LoopStatus64 { - lo_offset: inner.offset as u64, - lo_sizelimit: inner.size_limit as u64, - lo_flags: inner.flags.bits(), - __pad: 0, - } - }; - - let mut writer = UserBufferWriter::new::( - user_ptr as *mut LoopStatus64, - core::mem::size_of::(), - true, - )?; - writer.copy_one_to_user(&info, 0)?; - Ok(()) - } - fn set_status(&self, user_ptr: usize) -> Result<(), SystemError> { - self.set_status64(user_ptr) - } - fn get_status(&self, user_ptr: usize) -> Result<(), SystemError> { - self.get_status64(user_ptr) - } - /// # 功能 - /// - /// 将 loop 设备切换到新的文件描述符。 - /// - /// ## 参数 - /// - /// - `new_file_fd`: 新的文件描述符。 - /// - /// ## 返回值 - /// - `Ok(())`: 成功切换。 - /// - `Err(SystemError)`: 切换失败原因。 - fn change_fd(&self, new_file_fd: i32) -> Result<(), SystemError> { - let fd_table = ProcessManager::current_pcb().fd_table(); - let file = { - let guard = fd_table.read(); - guard.get_file_by_fd(new_file_fd) - } - .ok_or(SystemError::EBADF)?; - - let read_only = file.flags().is_read_only(); - - let inode = file.inode(); - let metadata = inode.metadata()?; - match metadata.file_type { - FileType::File | FileType::BlockDevice => {} - _ => return Err(SystemError::EINVAL), - } - - let mut inner = self.inner(); - inner.file_inode = Some(inode); - inner.flags = if read_only { LoopFlags::READ_ONLY } else { LoopFlags::empty() }; - drop(inner); - self.recalc_effective_size()?; - Ok(()) - } - fn set_capacity(&self, _arg: usize) -> Result<(), SystemError> { - self.recalc_effective_size()?; - Ok(()) - } - - /// # 功能 - /// - /// I/O 操作开始时调用,增加活跃 I/O 计数 - /// - /// ## 返回值 - /// - `Ok(())`: 成功增加计数 - /// - `Err(SystemError::ENODEV)`: 设备正在删除,拒绝新的 I/O - fn io_start(&self) -> Result<(), SystemError> { - let inner = self.inner(); - if matches!( - inner.state, - LoopState::Rundown | LoopState::Draining | LoopState::Deleting - ) { - return Err(SystemError::ENODEV); - } - self.active_io_count.fetch_add(1, Ordering::AcqRel); - Ok(()) - } - - /// # 功能 - /// - /// I/O 操作完成时调用,减少活跃 I/O 计数 - fn io_end(&self) { - let prev = self.active_io_count.fetch_sub(1, Ordering::AcqRel); - debug_assert!(prev > 0, "Loop device I/O count underflow"); - } - - /// # 功能 - /// - /// 进入 Rundown 状态,停止接受新的 I/O 请求 - /// - /// ## 返回值 - /// - `Ok(())`: 成功进入 Rundown 状态 - /// - `Err(SystemError)`: 状态转换失败 - fn enter_rundown_state(&self) -> Result<(), SystemError> { - let mut inner = self.inner(); - match inner.state { - LoopState::Bound => { - inner.set_state(LoopState::Rundown)?; - info!( - "Loop device loop{} entering rundown state", - inner.device_number.minor() - ); - } - LoopState::Unbound => { - // 空设备可以直接删除 - inner.set_state(LoopState::Deleting)?; - info!( - "Loop device loop{} is unbound, skipping to deleting state", - inner.device_number.minor() - ); - } - LoopState::Rundown => {} - LoopState::Draining | LoopState::Deleting => { - return Err(SystemError::EBUSY); - } - } - Ok(()) - } - - /// # 功能 - /// - /// 等待所有活跃的 I/O 操作完成 - /// - /// ## 返回值 - /// - `Ok(())`: 所有 I/O 已完成 - /// - `Err(SystemError::ETIMEDOUT)`: 等待超时 - fn drain_active_io(&self) -> Result<(), SystemError> { - let mut inner = self.inner(); - if matches!(inner.state, LoopState::Rundown) { - inner.set_state(LoopState::Draining)?; - info!( - "Loop device loop{} entering draining state", - inner.device_number.minor() - ); - } - drop(inner); - let timeout_ms = 30_000; - let check_interval_us = 10_000; - let max_checks = timeout_ms * 1000 / check_interval_us; - - for _i in 0..max_checks { - let count = self.active_io_count.load(Ordering::Acquire); - if count == 0 { - break; - } - - core::hint::spin_loop(); - } - - let final_count = self.active_io_count.load(Ordering::Acquire); - if final_count != 0 { - error!( - "Timeout waiting for I/O to drain on loop{}: {} operations still active", - self.minor(), - final_count - ); - return Err(SystemError::ETIMEDOUT); - } - - info!( - "All I/O operations drained for loop device loop{}", - self.minor() - ); - - let mut inner = self.inner(); - inner.set_state(LoopState::Deleting)?; - - Ok(()) - } - - /// # 功能 - /// - /// 从 sysfs 中移除设备 - /// - /// ## 返回值 - /// - `Ok(())`: 成功移除 - /// - `Err(SystemError)`: 移除失败 - fn remove_from_sysfs(&self) -> Result<(), SystemError> { - // 使用 KObjectManager 从 sysfs 中移除 - if let Some(kobj) = self.self_ref.upgrade() { - KObjectManager::remove_kobj(kobj as Arc); - info!("Removed loop device loop{} from sysfs", self.minor()); - } - Ok(()) - } - - /// # 功能 - /// - /// 最终清理函数,由 KObjType::release 调用 - /// 执行设备删除的最后清理工作 - fn final_cleanup(&self) { - info!( - "Final cleanup for loop device loop{} (id {})", - self.minor(), - self.id() - ); - let mut inner = self.inner(); - if let Some(file_inode) = inner.file_inode.take() { - drop(file_inode); - warn!( - "File inode was still present during final cleanup for loop{}", - self.minor() - ); - } - inner.file_size = 0; - inner.offset = 0; - inner.size_limit = 0; - info!("Loop device loop{} cleanup complete", self.minor()); - } -} - -impl KObject for LoopDevice { - fn as_any_ref(&self) -> &dyn Any { - self - } - fn set_inode(&self, inode: Option>) { - self.inner().kobject_common.kern_inode = inode; - } - fn inode(&self) -> Option> { - self.inner().kobject_common.kern_inode.clone() - } - - fn parent(&self) -> Option> { - self.inner().kobject_common.parent.clone() - } - - fn set_parent(&self, parent: Option>) { - self.inner().kobject_common.parent = parent; - } - - fn kset(&self) -> Option> { - self.inner().kobject_common.kset.clone() - } - - fn set_kset(&self, kset: Option>) { - self.inner().kobject_common.kset = kset; - } - - fn kobj_type(&self) -> Option<&'static dyn KObjType> { - self.inner().kobject_common.kobj_type - } - - fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { - self.inner().kobject_common.kobj_type = ktype; - } - - fn name(&self) -> String { - LOOP_BASENAME.to_string() - } - - fn set_name(&self, _name: String) { - // do nothing,不支持设置loop为别的名称 - } - - fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { - self.locked_kobj_state.read() - } - - fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { - self.locked_kobj_state.write() - } - - fn set_kobj_state(&self, state: KObjectState) { - *self.locked_kobj_state.write() = state; - } -} - -impl IndexNode for LoopDevice { - fn fs(&self) -> Arc { - todo!() - } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } - - fn read_at( - &self, - offset: usize, - len: usize, - buf: &mut [u8], - _data: SpinLockGuard, - ) -> Result { - if len > buf.len() { - return Err(SystemError::ENOBUFS); - } - BlockDevice::read_at_bytes(self, offset, len, buf) - } - - fn write_at( - &self, - offset: usize, - len: usize, - buf: &[u8], - _data: SpinLockGuard, - ) -> Result { - if len > buf.len() { - return Err(SystemError::E2BIG); - } - BlockDevice::write_at_bytes(self, offset, len, &buf[..len]) - } - - fn list(&self) -> Result, system_error::SystemError> { - Err(SystemError::ENOSYS) - } - fn metadata(&self) -> Result { - let file_metadata = match &self.inner().file_inode { - Some(inode) => inode.metadata()?, - None => { - return Err(SystemError::EPERM); - } - }; - let metadata = Metadata { - dev_id: 0, - inode_id: InodeId::new(0), - size: self.inner().file_size as i64, - blk_size: LBA_SIZE, - blocks: (self.inner().file_size.div_ceil(LBA_SIZE)), - atime: file_metadata.atime, - mtime: file_metadata.mtime, - ctime: file_metadata.ctime, - btime: file_metadata.btime, - file_type: FileType::BlockDevice, - mode: InodeMode::from_bits_truncate(0o644), - flags: InodeFlags::empty(), - nlinks: 1, - uid: 0, - gid: 0, - raw_dev: self.inner().device_number, - }; - Ok(metadata) - } - fn ioctl( - &self, - cmd: u32, - data: usize, - _private_data: &FilePrivateData, - ) -> Result { - match LoopIoctl::from_u32(cmd) { - Some(LoopIoctl::LoopSetFd) => { - let file_fd = data as i32; - let fd_table = ProcessManager::current_pcb().fd_table(); - let file = { - let guard = fd_table.read(); - guard.get_file_by_fd(file_fd) - } - .ok_or(SystemError::EBADF)?; - let read_only = file.flags().is_read_only(); - let inode = file.inode(); - let metadata = inode.metadata()?; - match metadata.file_type { - FileType::File | FileType::BlockDevice => {} - _ => return Err(SystemError::EINVAL), - } - - self.bind_file(inode, read_only)?; - Ok(0) - } - Some(LoopIoctl::LoopClrFd) => { - self.clear_file()?; - Ok(0) - } - Some(LoopIoctl::LoopSetStatus) => { - self.set_status(data)?; - Ok(0) - } - Some(LoopIoctl::LoopGetStatus) => { - self.get_status(data)?; - Ok(0) - } - Some(LoopIoctl::LoopSetStatus64) => { - self.set_status64(data)?; - Ok(0) - } - Some(LoopIoctl::LoopGetStatus64) => { - self.get_status64(data)?; - Ok(0) - } - Some(LoopIoctl::LoopChangeFd) => { - self.change_fd(data as i32)?; - Ok(0) - } - Some(LoopIoctl::LoopSetCapacity) => { - self.set_capacity(data)?; - Ok(0) - } - _ => Err(SystemError::ENOSYS), - } - } -} - -impl DeviceINode for LoopDevice { - fn set_fs(&self, fs: alloc::sync::Weak) { - *self.fs.write() = fs; - } - fn set_parent(&self, parent: Weak) { - *self.parent.write() = parent; - } -} - -impl Device for LoopDevice { - fn dev_type(&self) -> DeviceType { - DeviceType::Block - } - - fn id_table(&self) -> IdTable { - IdTable::new(LOOP_BASENAME.to_string(), None) - } - - fn bus(&self) -> Option> { - self.inner().device_common.bus.clone() - } - - fn set_bus(&self, bus: Option>) { - self.inner().device_common.bus = bus; - } - - fn class(&self) -> Option> { - let mut guard = self.inner(); - let r = guard.device_common.class.clone()?.upgrade(); - if r.is_none() { - guard.device_common.class = None; - } - return r; - } - - fn set_class(&self, class: Option>) { - self.inner().device_common.class = class; - } - - fn driver(&self) -> Option> { - let r = self.inner().device_common.driver.clone()?.upgrade(); - if r.is_none() { - self.inner().device_common.driver = None; - } - return r; - } - - fn set_driver(&self, driver: Option>) { - self.inner().device_common.driver = driver; - } - - fn is_dead(&self) -> bool { - false - } - - fn can_match(&self) -> bool { - self.inner().device_common.can_match - } - - fn set_can_match(&self, can_match: bool) { - self.inner().device_common.can_match = can_match; - } - - fn state_synced(&self) -> bool { - true - } - - fn dev_parent(&self) -> Option> { - self.inner().device_common.get_parent_weak_or_clear() - } - - fn set_dev_parent(&self, parent: Option>) { - self.inner().device_common.parent = parent; - } -} - -impl BlockDevice for LoopDevice { - fn dev_name(&self) -> &DevName { - &self.block_dev_meta.devname - } - - fn blkdev_meta(&self) -> &BlockDevMeta { - &self.block_dev_meta - } - - fn disk_range(&self) -> GeneralBlockRange { - let inner = self.inner(); - let blocks = if inner.file_size == 0 { - 0 - } else { - inner.file_size.saturating_add(LBA_SIZE - 1) / LBA_SIZE - }; - drop(inner); - GeneralBlockRange::new(0, blocks).unwrap_or(GeneralBlockRange { - lba_start: 0, - lba_end: 0, - }) - } - fn read_at_sync( - &self, - lba_id_start: BlockId, - count: usize, - buf: &mut [u8], - ) -> Result { - // 使用 IoGuard 确保 I/O 计数正确管理 - let _io_guard = IoGuard::new(self)?; - - if count == 0 { - return Ok(0); - } - let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; - if len > buf.len() { - return Err(SystemError::EINVAL); - } - - let (file_inode, base_offset, limit_end) = { - let inner = self.inner(); - let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; - let limit = inner - .offset - .checked_add(inner.file_size) - .ok_or(SystemError::EOVERFLOW)?; - (inode, inner.offset, limit) - }; - - let block_offset = lba_id_start - .checked_mul(LBA_SIZE) - .ok_or(SystemError::EOVERFLOW)?; - let file_offset = base_offset - .checked_add(block_offset) - .ok_or(SystemError::EOVERFLOW)?; - - let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; - if end > limit_end { - return Err(SystemError::ENOSPC); - } - - let data = SpinLock::new(FilePrivateData::Unused); - let data_guard = data.lock(); - - file_inode.read_at(file_offset, len, &mut buf[..len], data_guard) - } - - fn write_at_sync( - &self, - lba_id_start: BlockId, - count: usize, - buf: &[u8], - ) -> Result { - // 使用 IoGuard 确保 I/O 计数正确管理 - let _io_guard = IoGuard::new(self)?; - - if count == 0 { - return Ok(0); - } - let len = count.checked_mul(LBA_SIZE).ok_or(SystemError::EOVERFLOW)?; - if len > buf.len() { - return Err(SystemError::EINVAL); - } - - let (file_inode, base_offset, limit_end) = { - let inner = self.inner(); - if inner.is_read_only() { - return Err(SystemError::EROFS); - } - let inode = inner.file_inode.clone().ok_or(SystemError::ENODEV)?; - let limit = inner - .offset - .checked_add(inner.file_size) - .ok_or(SystemError::EOVERFLOW)?; - (inode, inner.offset, limit) - }; - - let block_offset = lba_id_start - .checked_mul(LBA_SIZE) - .ok_or(SystemError::EOVERFLOW)?; - let file_offset = base_offset - .checked_add(block_offset) - .ok_or(SystemError::EOVERFLOW)?; - - let end = file_offset.checked_add(len).ok_or(SystemError::EOVERFLOW)?; - if end > limit_end { - return Err(SystemError::ENOSPC); - } - - let data = SpinLock::new(FilePrivateData::Unused); - let data_guard = data.lock(); - - let written = file_inode.write_at(file_offset, len, &buf[..len], data_guard)?; - - if written > 0 { - let _ = self.recalc_effective_size(); - } - - Ok(written) - } - - fn sync(&self) -> Result<(), SystemError> { - Ok(()) - } - - fn blk_size_log2(&self) -> u8 { - 9 - } - - fn as_any_ref(&self) -> &dyn Any { - self - } - - fn device(&self) -> Arc { - self.self_ref.upgrade().unwrap() - } - - fn block_size(&self) -> usize { - LBA_SIZE - } - - fn partitions(&self) -> Vec> { - Vec::new() - } -} - -/// Loop设备驱动 -/// 参考Virtio_blk驱动的实现 -#[derive(Debug)] -#[cast_to([sync] Driver)] -pub struct LoopDeviceDriver { - inner: SpinLock, - kobj_state: LockedKObjectState, -} -struct InnerLoopDeviceDriver { - driver_common: DriverCommonData, - kobj_common: KObjectCommonData, -} -impl Debug for InnerLoopDeviceDriver { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("InnerLoopDeviceDriver") - .field("driver_common", &self.driver_common) - .field("kobj_common", &self.kobj_common) - .finish() - } -} -impl LoopDeviceDriver { - pub fn new() -> Arc { - let inner = InnerLoopDeviceDriver { - driver_common: DriverCommonData::default(), - kobj_common: KObjectCommonData::default(), - }; - Arc::new(Self { - inner: SpinLock::new(inner), - kobj_state: LockedKObjectState::default(), - }) - } - fn inner(&'_ self) -> SpinLockGuard<'_, InnerLoopDeviceDriver> { - self.inner.lock() - } -} +// 重新导出公共接口 +pub use constants::LOOP_CONTROL_BASENAME; +pub use driver::LoopDeviceDriver; +pub use loop_control::LoopControlDevice; +pub use loop_device::{LoopDevice, LoopPrivateData}; +pub use manager::LoopManager; +/// 初始化 loop 设备子系统 #[unified_init(INITCALL_DEVICE)] pub fn loop_init() -> Result<(), SystemError> { let loop_mgr = Arc::new(LoopManager::new()); @@ -1137,649 +47,3 @@ pub fn loop_init() -> Result<(), SystemError> { loop_mgr.loop_init(driver)?; Ok(()) } - -impl Driver for LoopDeviceDriver { - fn id_table(&self) -> Option { - Some(IdTable::new(LOOP_BASENAME.to_string(), None)) - } - - fn devices(&self) -> Vec> { - self.inner().driver_common.devices.clone() - } - - fn add_device(&self, device: Arc) { - self.inner().driver_common.push_device(device); - } - - fn delete_device(&self, device: &Arc) { - self.inner().driver_common.delete_device(device); - } - - fn bus(&self) -> Option> { - self.inner().driver_common.bus.clone() - } - - fn set_bus(&self, bus: Option>) { - self.inner().driver_common.bus = bus; - } -} - -impl KObject for LoopDeviceDriver { - fn as_any_ref(&self) -> &dyn Any { - self - } - - fn set_inode(&self, inode: Option>) { - self.inner().kobj_common.kern_inode = inode; - } - - fn inode(&self) -> Option> { - self.inner().kobj_common.kern_inode.clone() - } - - fn parent(&self) -> Option> { - self.inner().kobj_common.parent.clone() - } - - fn set_parent(&self, parent: Option>) { - self.inner().kobj_common.parent = parent; - } - - fn kset(&self) -> Option> { - self.inner().kobj_common.kset.clone() - } - - fn set_kset(&self, kset: Option>) { - self.inner().kobj_common.kset = kset; - } - - fn kobj_type(&self) -> Option<&'static dyn KObjType> { - self.inner().kobj_common.kobj_type - } - - fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { - self.inner().kobj_common.kobj_type = ktype; - } - - fn name(&self) -> String { - LOOP_BASENAME.to_string() - } - - fn set_name(&self, _name: String) { - // do nothing - } - - fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { - self.kobj_state.read() - } - - fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { - self.kobj_state.write() - } - - fn set_kobj_state(&self, state: KObjectState) { - *self.kobj_state.write() = state; - } -} - -pub struct LoopManager { - inner: SpinLock, -} -pub struct LoopManagerInner { - devices: [Option>; LoopManager::MAX_DEVICES], - id_alloc: IdAllocator, - next_free_minor: u32, -} -impl LoopManager { - const MAX_DEVICES: usize = 256; - const MAX_INIT_DEVICES: usize = 8; - pub fn new() -> Self { - Self { - inner: SpinLock::new(LoopManagerInner { - devices: [const { None }; Self::MAX_DEVICES], - id_alloc: IdAllocator::new(0, Self::MAX_DEVICES) - .expect("create IdAllocator failed"), - next_free_minor: 0, - }), - } - } - fn inner(&'_ self) -> SpinLockGuard<'_, LoopManagerInner> { - self.inner.lock() - } - #[inline] - fn alloc_id_locked(inner: &mut LoopManagerInner) -> Option { - inner.id_alloc.alloc() - } - #[inline] - fn free_id_locked(inner: &mut LoopManagerInner, id: usize) { - if id < Self::MAX_DEVICES && inner.id_alloc.exists(id) { - inner.id_alloc.free(id); - } - } - #[inline] - pub fn format_name(id: usize) -> DevName { - DevName::new(format!("{}{}", LOOP_BASENAME, id), id) - } - fn find_device_by_minor_locked( - inner: &LoopManagerInner, - minor: u32, - ) -> Option> { - inner - .devices - .iter() - .flatten() - .find(|device| device.minor() == minor) - .map(Arc::clone) - } - - fn find_unused_minor_locked(inner: &LoopManagerInner) -> Option { - let mut candidate = inner.next_free_minor; - for _ in 0..Self::MAX_DEVICES as u32 { - let mut used = false; - for dev in inner.devices.iter().flatten() { - if dev.minor() == candidate { - used = true; - break; - } - } - if !used { - return Some(candidate); - } - candidate = (candidate + 1) % Self::MAX_DEVICES as u32; - } - None - } - /* - 请求队列,工作队列未实现 - */ - /// # 功能 - /// - /// 根据请求的次设备号分配或复用 loop 设备。 - /// - /// ## 参数 - /// - /// - `requested_minor`: 指定的次设备号,`None` 表示自动分配。 - /// - /// ## 返回值 - /// - `Ok(Arc)`: 成功获得的设备。 - /// - `Err(SystemError)`: 无可用设备或参数错误。 - pub fn loop_add(&self, requested_minor: Option) -> Result, SystemError> { - let mut inner = self.inner(); - match requested_minor { - Some(req_minor) => self.loop_add_specific_locked(&mut inner, req_minor), - None => self.loop_add_first_available_locked(&mut inner), - } - } - /// # 功能 - /// - /// 在锁作用域内分配指定次设备号的 loop 设备。 - /// - /// ## 参数 - /// - /// - `inner`: 管理器内部状态锁。 - /// - `minor`: 目标次设备号。 - /// - /// ## 返回值 - /// - `Ok(Arc)`: 成功获得的设备实例。 - /// - `Err(SystemError)`: 参数无效或设备已被占用。 - fn loop_add_specific_locked( - &self, - inner: &mut LoopManagerInner, - minor: u32, - ) -> Result, SystemError> { - if minor >= Self::MAX_DEVICES as u32 { - return Err(SystemError::EINVAL); - } - - if let Some(device) = Self::find_device_by_minor_locked(inner, minor) { - if device.is_bound() { - return Err(SystemError::EEXIST); - } - return Ok(device); - } - - let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; - match self.create_and_register_device_locked(inner, id, minor) { - Ok(device) => Ok(device), - Err(e) => { - Self::free_id_locked(inner, id); - Err(e) - } - } - } - - fn loop_add_first_available_locked( - &self, - inner: &mut LoopManagerInner, - ) -> Result, SystemError> { - if let Some(device) = inner - .devices - .iter() - .flatten() - .find(|device| !device.is_bound()) - { - return Ok(device.clone()); - } - - let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; - let minor = match Self::find_unused_minor_locked(inner) { - Some(minor) => minor, - None => { - Self::free_id_locked(inner, id); - return Err(SystemError::ENOSPC); - } - }; - let result = self.create_and_register_device_locked(inner, id, minor); - if result.is_err() { - Self::free_id_locked(inner, id); - } - result - } - - fn create_and_register_device_locked( - &self, - inner: &mut LoopManagerInner, - id: usize, - minor: u32, - ) -> Result, SystemError> { - if minor >= Self::MAX_DEVICES as u32 { - return Err(SystemError::EINVAL); - } - - let devname = Self::format_name(id); - let loop_dev = - LoopDevice::new_empty_loop_device(devname, id, minor).ok_or(SystemError::ENOMEM)?; - - if let Err(e) = block_dev_manager().register(loop_dev.clone()) { - if e == SystemError::EEXIST { - if let Some(existing) = inner.devices[id].clone() { - return Ok(existing); - } - } - return Err(e); - } - - inner.devices[id] = Some(loop_dev.clone()); - inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; - log::info!( - "Loop device id {} (minor {}) added successfully.", - id, - minor - ); - Ok(loop_dev) - } - /// # 功能 - /// - /// 删除指定 minor 的 loop 设备 - /// 实现规范的删除流程,包括状态转换、I/O 排空、资源清理 - /// - /// ## 参数 - /// - /// - `minor`: 要删除的设备的次设备号 - /// - /// ## 返回值 - /// - `Ok(())`: 成功删除设备 - /// - `Err(SystemError)`: 删除失败 - pub fn loop_remove(&self, minor: u32) -> Result<(), SystemError> { - if minor >= Self::MAX_DEVICES as u32 { - return Err(SystemError::EINVAL); - } - let device = { - let inner = self.inner(); - Self::find_device_by_minor_locked(&inner, minor) - } - .ok_or(SystemError::ENODEV)?; - let id = device.id(); - info!("Starting removal of loop device loop{} (id {})", minor, id); - device.enter_rundown_state()?; - let needs_drain = { - let inner = device.inner(); - !matches!(inner.state, LoopState::Deleting) - }; - - if needs_drain { - device.drain_active_io()?; - } - - device.clear_file()?; - - let _ = device.remove_from_sysfs(); - - let block_dev: Arc = device.clone(); - block_dev_manager().unregister(&block_dev)?; - - { - let mut inner = self.inner(); - inner.devices[id] = None; - Self::free_id_locked(&mut inner, id); - inner.next_free_minor = minor; - } - info!( - "Loop device id {} (minor {}) removed successfully.", - id, minor - ); - Ok(()) - } - - pub fn find_free_minor(&self) -> Option { - let inner = self.inner(); - 'outer: for minor in 0..Self::MAX_DEVICES as u32 { - for dev in inner.devices.iter().flatten() { - if dev.minor() == minor { - if !dev.is_bound() { - return Some(minor); - } - continue 'outer; - } - } - return Some(minor); - } - None - } - pub fn loop_init(&self, _driver: Arc) -> Result<(), SystemError> { - let mut inner = self.inner(); - for minor in 0..Self::MAX_INIT_DEVICES { - let minor_u32 = minor as u32; - if Self::find_device_by_minor_locked(&inner, minor_u32).is_some() { - continue; - } - let id = Self::alloc_id_locked(&mut inner).ok_or(SystemError::ENOSPC)?; - if let Err(e) = self.create_and_register_device_locked(&mut inner, id, minor_u32) { - Self::free_id_locked(&mut inner, id); - return Err(e); - } - } - log::info!("Loop devices initialized"); - Ok(()) - } -} -//一个字符设备,作为一个抽象接口控制loop设备的创建,绑定和删除 -/* -设备分配和查找 -设备绑定和解绑 -设备状态查询和配置(配置设备参数,如偏移量、大小限制等) -*/ - -pub struct LoopControlDevice { - inner: SpinLock, - locked_kobj_state: LockedKObjectState, - loop_mgr: Arc, -} -struct LoopControlDeviceInner { - // 设备的公共数据 - device_common: DeviceCommonData, - // KObject的公共数据 - kobject_common: KObjectCommonData, - - parent: RwLock>, - device_inode_fs: RwLock>>, -} -impl LoopControlDevice { - pub fn new(loop_mgr: Arc) -> Arc { - Arc::new(Self { - inner: SpinLock::new(LoopControlDeviceInner { - kobject_common: KObjectCommonData::default(), - device_common: DeviceCommonData::default(), - parent: RwLock::new(Weak::default()), - device_inode_fs: RwLock::new(None), - }), - locked_kobj_state: LockedKObjectState::default(), - loop_mgr, - }) - } - fn inner(&'_ self) -> SpinLockGuard<'_, LoopControlDeviceInner> { - self.inner.lock() - } -} -impl DeviceINode for LoopControlDevice { - fn set_fs(&self, fs: alloc::sync::Weak) { - *self.inner().device_inode_fs.write() = Some(fs); - } - fn set_parent(&self, parent: Weak) { - *self.inner().parent.write() = parent; - } -} -impl Debug for LoopControlDevice { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("LoopControlDevice").finish() - } -} -impl IndexNode for LoopControlDevice { - fn open( - &self, - _data: SpinLockGuard, - _mode: &FileFlags, - ) -> Result<(), SystemError> { - // 若文件系统没有实现此方法,则返回“不支持” - return Ok(()); - } - fn close(&self, _data: SpinLockGuard) -> Result<(), SystemError> { - Ok(()) - } - /// # 功能 - /// - /// 获取 loop-control 设备的元数据信息。 - /// - /// ## 参数 - /// - /// - 无 - /// - /// ## 返回值 - /// - `Ok(Metadata)`: 成功获取设备元数据 - /// - 包含设备类型、权限、设备号等信息 - /// - fn metadata(&self) -> Result { - use crate::time::PosixTimeSpec; - - let metadata = Metadata { - dev_id: 0, - inode_id: InodeId::new(0), - size: 0, - blk_size: 0, - blocks: 0, - atime: PosixTimeSpec::default(), - mtime: PosixTimeSpec::default(), - ctime: PosixTimeSpec::default(), - btime: PosixTimeSpec::default(), - file_type: FileType::CharDevice, - mode: InodeMode::from_bits_truncate(0o600), - flags: InodeFlags::empty(), - nlinks: 1, - uid: 0, - gid: 0, - raw_dev: DeviceNumber::new(Major::LOOP_CONTROL_MAJOR, LOOP_CONTROL_MINOR), - }; - Ok(metadata) - } - fn fs(&self) -> Arc { - todo!() - } - fn ioctl( - &self, - cmd: u32, - data: usize, - _private_data: &FilePrivateData, - ) -> Result { - match LoopControlIoctl::from_u32(cmd) { - Some(LoopControlIoctl::Add) => { - log::info!("Starting LOOP_CTL_ADD ioctl"); - let requested_index = data as u32; - let loop_dev = if requested_index == u32::MAX { - self.loop_mgr.loop_add(None)? - } else { - self.loop_mgr.loop_add(Some(requested_index))? - }; - let minor = { - let inner = loop_dev.inner(); - let minor = inner.device_number.minor(); - log::info!( - "LOOP_CTL_ADD ioctl succeeded, allocated loop device loop{}", - minor - ); - minor - }; - Ok(minor as usize) - } - Some(LoopControlIoctl::Remove) => { - let minor_to_remove = data as u32; - self.loop_mgr.loop_remove(minor_to_remove)?; - Ok(0) - } - Some(LoopControlIoctl::GetFree) => match self.loop_mgr.find_free_minor() { - Some(minor) => Ok(minor as usize), - None => Err(SystemError::ENOSPC), - }, - _ => Err(SystemError::ENOSYS), - } - } - - fn as_any_ref(&self) -> &dyn core::any::Any { - self - } - fn read_at( - &self, - _offset: usize, - _len: usize, - _buf: &mut [u8], - _data: SpinLockGuard, - ) -> Result { - Err(SystemError::ENOSYS) - } - - fn write_at( - &self, - _offset: usize, - _len: usize, - _buf: &[u8], - _data: SpinLockGuard, - ) -> Result { - Err(SystemError::ENOSYS) - } - - fn list(&self) -> Result, system_error::SystemError> { - Err(SystemError::ENOSYS) - } -} -impl Device for LoopControlDevice { - fn dev_type(&self) -> DeviceType { - DeviceType::Char - } - - fn id_table(&self) -> IdTable { - IdTable::new(LOOP_CONTROL_BASENAME.to_string(), None) - } - - fn bus(&self) -> Option> { - self.inner().device_common.bus.clone() - } - - fn set_bus(&self, bus: Option>) { - self.inner().device_common.bus = bus; - } - - fn class(&self) -> Option> { - let mut guard = self.inner(); - let r = guard.device_common.class.clone()?.upgrade(); - if r.is_none() { - guard.device_common.class = None; - } - return r; - } - - fn set_class(&self, class: Option>) { - self.inner().device_common.class = class; - } - - fn driver(&self) -> Option> { - let r = self.inner().device_common.driver.clone()?.upgrade(); - if r.is_none() { - self.inner().device_common.driver = None; - } - return r; - } - - fn set_driver(&self, driver: Option>) { - self.inner().device_common.driver = driver; - } - - fn is_dead(&self) -> bool { - false - } - - fn can_match(&self) -> bool { - self.inner().device_common.can_match - } - - fn set_can_match(&self, can_match: bool) { - self.inner().device_common.can_match = can_match; - } - - fn state_synced(&self) -> bool { - true - } - - fn dev_parent(&self) -> Option> { - self.inner().device_common.get_parent_weak_or_clear() - } - - fn set_dev_parent(&self, parent: Option>) { - self.inner().device_common.parent = parent; - } -} -impl KObject for LoopControlDevice { - fn as_any_ref(&self) -> &dyn Any { - self - } - - fn set_inode(&self, inode: Option>) { - self.inner().kobject_common.kern_inode = inode; - } - - fn inode(&self) -> Option> { - self.inner().kobject_common.kern_inode.clone() - } - - fn parent(&self) -> Option> { - self.inner().kobject_common.parent.clone() - } - - fn set_parent(&self, parent: Option>) { - self.inner().kobject_common.parent = parent; - } - - fn kset(&self) -> Option> { - self.inner().kobject_common.kset.clone() - } - - fn set_kset(&self, kset: Option>) { - self.inner().kobject_common.kset = kset; - } - - fn kobj_type(&self) -> Option<&'static dyn KObjType> { - self.inner().kobject_common.kobj_type - } - - fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) { - self.inner().kobject_common.kobj_type = ktype; - } - - fn name(&self) -> String { - LOOP_CONTROL_BASENAME.to_string() - } - - fn set_name(&self, _name: String) { - // do nothing - } - - fn kobj_state(&'_ self) -> RwLockReadGuard<'_, KObjectState> { - self.locked_kobj_state.read() - } - - fn kobj_state_mut(&'_ self) -> RwLockWriteGuard<'_, KObjectState> { - self.locked_kobj_state.write() - } - - fn set_kobj_state(&self, state: KObjectState) { - *self.locked_kobj_state.write() = state; - } -} From 354af11806703ff21cb099fdd22c5b3d90c420d6 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 10 Dec 2025 10:31:08 +0800 Subject: [PATCH 34/39] - fix --- .../src/driver/block/loop_device/constants.rs | 6 ++++ .../driver/block/loop_device/loop_device.rs | 34 ++++++++++--------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/kernel/src/driver/block/loop_device/constants.rs b/kernel/src/driver/block/loop_device/constants.rs index a80eeb85e..e627f4d54 100644 --- a/kernel/src/driver/block/loop_device/constants.rs +++ b/kernel/src/driver/block/loop_device/constants.rs @@ -8,6 +8,12 @@ pub const LOOP_CONTROL_BASENAME: &str = "loop-control"; /// Loop-control 设备的次设备号 pub const LOOP_CONTROL_MINOR: u32 = 237; +/// I/O 排空超时时间 (毫秒) +pub const LOOP_IO_DRAIN_TIMEOUT_MS: u32 = 30_000; + +/// I/O 排空检查间隔 (微秒) +pub const LOOP_IO_DRAIN_CHECK_INTERVAL_US: u32 = 10_000; + /// Loop 设备 ioctl 命令 #[repr(u32)] #[derive(Debug, FromPrimitive)] diff --git a/kernel/src/driver/block/loop_device/loop_device.rs b/kernel/src/driver/block/loop_device/loop_device.rs index 37d653482..a3bb242b2 100644 --- a/kernel/src/driver/block/loop_device/loop_device.rs +++ b/kernel/src/driver/block/loop_device/loop_device.rs @@ -45,7 +45,10 @@ use log::{error, info, warn}; use num_traits::FromPrimitive; use system_error::SystemError; -use super::constants::{LoopFlags, LoopIoctl, LoopState, LoopStatus64, LOOP_BASENAME}; +use super::constants::{ + LoopFlags, LoopIoctl, LoopState, LoopStatus64, LOOP_BASENAME, LOOP_IO_DRAIN_CHECK_INTERVAL_US, + LOOP_IO_DRAIN_TIMEOUT_MS, +}; /// Loop 设备 KObject 类型 #[derive(Debug)] @@ -380,8 +383,7 @@ impl LoopDevice { core::mem::size_of::(), true, )?; - let mut info = LoopStatus64::default(); - reader.copy_one_from_user(&mut info, 0)?; + let info: LoopStatus64 = reader.buffer_protected(0)?.read_one(0)?; Self::validate_loop_status64_params(&info)?; let new_offset = info.lo_offset as usize; @@ -452,7 +454,7 @@ impl LoopDevice { core::mem::size_of::(), true, )?; - writer.copy_one_to_user(&info, 0)?; + writer.buffer_protected(0)?.write_one(0, &info)?; Ok(()) } @@ -586,9 +588,7 @@ impl LoopDevice { ); } drop(inner); - let timeout_ms = 30_000; - let check_interval_us = 10_000; - let max_checks = timeout_ms * 1000 / check_interval_us; + let max_checks = LOOP_IO_DRAIN_TIMEOUT_MS * 1000 / LOOP_IO_DRAIN_CHECK_INTERVAL_US; for _i in 0..max_checks { let count = self.active_io_count.load(Ordering::Acquire); @@ -792,8 +792,10 @@ impl IndexNode for LoopDevice { data: usize, _private_data: &FilePrivateData, ) -> Result { - match LoopIoctl::from_u32(cmd) { - Some(LoopIoctl::LoopSetFd) => { + let ioctl_cmd = LoopIoctl::from_u32(cmd).ok_or(SystemError::ENOSYS)?; + + match ioctl_cmd { + LoopIoctl::LoopSetFd => { let file_fd = data as i32; let fd_table = ProcessManager::current_pcb().fd_table(); let file = { @@ -812,31 +814,31 @@ impl IndexNode for LoopDevice { self.bind_file(inode, read_only)?; Ok(0) } - Some(LoopIoctl::LoopClrFd) => { + LoopIoctl::LoopClrFd => { self.clear_file()?; Ok(0) } - Some(LoopIoctl::LoopSetStatus) => { + LoopIoctl::LoopSetStatus => { self.set_status(data)?; Ok(0) } - Some(LoopIoctl::LoopGetStatus) => { + LoopIoctl::LoopGetStatus => { self.get_status(data)?; Ok(0) } - Some(LoopIoctl::LoopSetStatus64) => { + LoopIoctl::LoopSetStatus64 => { self.set_status64(data)?; Ok(0) } - Some(LoopIoctl::LoopGetStatus64) => { + LoopIoctl::LoopGetStatus64 => { self.get_status64(data)?; Ok(0) } - Some(LoopIoctl::LoopChangeFd) => { + LoopIoctl::LoopChangeFd => { self.change_fd(data as i32)?; Ok(0) } - Some(LoopIoctl::LoopSetCapacity) => { + LoopIoctl::LoopSetCapacity => { self.set_capacity(data)?; Ok(0) } From 931f4776b07da85a103c00b5e34ed602ecdca4ae Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Wed, 10 Dec 2025 16:07:12 +0800 Subject: [PATCH 35/39] - refactor: test_loop --- .../src/driver/block/loop_device/manager.rs | 3 +- user/apps/c_unitest/test_loop.c | 1385 ++++++++--------- 2 files changed, 670 insertions(+), 718 deletions(-) diff --git a/kernel/src/driver/block/loop_device/manager.rs b/kernel/src/driver/block/loop_device/manager.rs index 89217490d..bb2420e15 100644 --- a/kernel/src/driver/block/loop_device/manager.rs +++ b/kernel/src/driver/block/loop_device/manager.rs @@ -189,8 +189,7 @@ impl LoopManager { if minor >= Self::MAX_DEVICES as u32 { return Err(SystemError::EINVAL); } - - let devname = Self::format_name(id); + let devname = Self::format_name(minor as usize); let loop_dev = LoopDevice::new_empty_loop_device(devname, id, minor).ok_or(SystemError::ENOMEM)?; diff --git a/user/apps/c_unitest/test_loop.c b/user/apps/c_unitest/test_loop.c index 9acbbcadf..e5b148cfb 100644 --- a/user/apps/c_unitest/test_loop.c +++ b/user/apps/c_unitest/test_loop.c @@ -4,12 +4,76 @@ #include #include #include -#include // 用于 fstat +#include #include #include #include #include +// =================================================================== +// 测试框架定义 +// =================================================================== + +#define TEST_PASS 0 +#define TEST_FAIL 1 + +// 测试结果统计 +static int g_tests_total = 0; +static int g_tests_passed = 0; +static int g_tests_failed = 0; + +// 测试输出宏 +#define TEST_BEGIN(name) \ + do { \ + g_tests_total++; \ + printf("\n"); \ + printf("========================================\n"); \ + printf("[TEST %d] %s\n", g_tests_total, name); \ + printf("========================================\n"); \ + } while(0) + +#define TEST_END_PASS(name) \ + do { \ + g_tests_passed++; \ + printf("----------------------------------------\n"); \ + printf("[PASS] %s\n", name); \ + printf("----------------------------------------\n"); \ + } while(0) + +#define TEST_END_FAIL(name, reason) \ + do { \ + g_tests_failed++; \ + printf("----------------------------------------\n"); \ + printf("[FAIL] %s: %s\n", name, reason); \ + printf("----------------------------------------\n"); \ + } while(0) + +#define LOG_INFO(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__) +#define LOG_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__) +#define LOG_STEP(fmt, ...) printf(" -> " fmt "\n", ##__VA_ARGS__) + +// 打印最终测试汇总 +static void print_test_summary(void) { + printf("\n"); + printf("+========================================+\n"); + printf("| TEST SUMMARY |\n"); + printf("+========================================+\n"); + printf("| Total: %3d |\n", g_tests_total); + printf("| Passed: %3d |\n", g_tests_passed); + printf("| Failed: %3d |\n", g_tests_failed); + printf("+========================================+\n"); + if (g_tests_failed == 0) { + printf("| Result: ALL TESTS PASSED |\n"); + } else { + printf("| Result: SOME TESTS FAILED |\n"); + } + printf("+========================================+\n"); +} + +// =================================================================== +// Loop 设备常量定义 +// =================================================================== + // 控制命令常量 #define LOOP_CTL_ADD 0x4C80 #define LOOP_CTL_REMOVE 0x4C81 @@ -18,17 +82,18 @@ #define LOOP_CLR_FD 0x4C01 #define LOOP_SET_STATUS64 0x4C04 #define LOOP_GET_STATUS64 0x4C05 -#define LOOP_CHANGE_FD 0x4C06 // 新增 -#define LOOP_SET_CAPACITY 0x4C07 // 新增 +#define LOOP_CHANGE_FD 0x4C06 +#define LOOP_SET_CAPACITY 0x4C07 -// 与内核通信的设备路径 +// 设备路径和测试参数 #define LOOP_DEVICE_CONTROL "/dev/loop-control" #define LO_FLAGS_READ_ONLY 0x1 -#define TEST_FILE_NAME "test_image.img" -#define TEST_FILE_NAME_2 "test_image_2.img" // 第二个测试文件 -#define TEST_FILE_SIZE (1024 * 1024) // 测试镜像大小 1MB -#define TEST_FILE_SIZE_2 (512 * 1024) // 第二个测试镜像大小 512KB +#define TEST_FILE_NAME "test_image.img" +#define TEST_FILE_NAME_2 "test_image_2.img" +#define TEST_FILE_SIZE (1024 * 1024) // 1MB +#define TEST_FILE_SIZE_2 (512 * 1024) // 512KB +// Loop 状态结构体 struct loop_status64 { uint64_t lo_offset; uint64_t lo_sizelimit; @@ -36,42 +101,73 @@ struct loop_status64 { uint32_t __pad; }; +// =================================================================== +// 全局测试资源 +// =================================================================== + +static int g_control_fd = -1; +static int g_backing_fd_1 = -1; +static int g_backing_fd_2 = -1; + +// =================================================================== +// 辅助函数 +// =================================================================== + // 创建测试镜像文件 -void create_test_file(const char* filename, int size) { - printf("Creating test file: %s with size %d bytes\n", filename, size); +static int create_test_file(const char *filename, int size) { + LOG_STEP("Creating test file: %s (%d bytes)", filename, size); + int fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0644); if (fd < 0) { - perror("Failed to create test file"); - exit(EXIT_FAILURE); + LOG_ERROR("Failed to create test file: %s", strerror(errno)); + return -1; } - // 写入零填充数据以确保文件占满容量 + char zero_block[512] = {0}; for (int i = 0; i < size / 512; ++i) { if (write(fd, zero_block, 512) != 512) { - perror("Failed to write to test file"); + LOG_ERROR("Failed to write to test file: %s", strerror(errno)); close(fd); - exit(EXIT_FAILURE); + return -1; } } - printf("Test file %s created successfully.\n", filename); + close(fd); + LOG_STEP("Test file created successfully"); + return 0; } -// 获取文件大小的辅助函数 -long get_file_size(int fd) { - struct stat st; - if (fstat(fd, &st) < 0) { - perror("fstat failed"); - return -1; +// 使用重试机制创建 loop 设备 +static int create_loop_device(int control_fd, int *out_minor) { + for (int retry = 0; retry < 10; retry++) { + // LOOP_CTL_GET_FREE 通过返回值返回 free 的 minor 号 + int free_minor = ioctl(control_fd, LOOP_CTL_GET_FREE, 0); + if (free_minor < 0) { + LOG_ERROR("Failed to get free loop device: %s", strerror(errno)); + return -1; + } + + int ret = ioctl(control_fd, LOOP_CTL_ADD, free_minor); + if (ret >= 0) { + *out_minor = ret; + return 0; + } + + if (errno != EEXIST) { + LOG_ERROR("Failed to add loop device: %s", strerror(errno)); + return -1; + } + // 设备已存在,重试 } - return st.st_size; + + LOG_ERROR("Failed to create loop device after 10 retries"); + return -1; } // =================================================================== -// 资源回收测试辅助结构和函数 +// 并发测试辅助结构 // =================================================================== -// 线程参数结构,用于并发I/O测试 struct io_thread_args { char loop_dev_path[64]; int duration_seconds; @@ -80,9 +176,15 @@ struct io_thread_args { int error_count; }; -// 并发读写线程函数 -void* io_worker_thread(void* arg) { - struct io_thread_args* args = (struct io_thread_args*)arg; +struct delete_thread_args { + int control_fd; + int loop_minor; + int result; + int error_code; +}; + +static void *io_worker_thread(void *arg) { + struct io_thread_args *args = (struct io_thread_args *)arg; char buffer[512]; time_t start_time = time(NULL); @@ -90,15 +192,13 @@ void* io_worker_thread(void* arg) { int fd = open(args->loop_dev_path, O_RDWR); if (fd < 0) { if (errno == ENODEV || errno == ENOENT) { - // 设备正在删除或已删除,这是预期的 break; } args->error_count++; - usleep(10000); // 10ms + usleep(10000); continue; } - // 尝试读取 if (read(fd, buffer, sizeof(buffer)) < 0) { if (errno != ENODEV) { args->error_count++; @@ -108,25 +208,15 @@ void* io_worker_thread(void* arg) { } close(fd); - usleep(1000); // 1ms + usleep(1000); } return NULL; } -// 删除设备线程函数 -struct delete_thread_args { - int control_fd; - int loop_minor; - int result; - int error_code; -}; - -void* delete_worker_thread(void* arg) { - struct delete_thread_args* args = (struct delete_thread_args*)arg; - - // 稍微延迟以确保I/O线程已经开始 - usleep(50000); // 50ms +static void *delete_worker_thread(void *arg) { + struct delete_thread_args *args = (struct delete_thread_args *)arg; + usleep(50000); // 50ms 延迟确保 I/O 线程已启动 args->result = ioctl(args->control_fd, LOOP_CTL_REMOVE, args->loop_minor); args->error_code = errno; @@ -134,854 +224,717 @@ void* delete_worker_thread(void* arg) { return NULL; } -int main() { - int control_fd; - int loop_minor; - char loop_dev_path[64]; - int loop_fd; - int backing_fd_1 = -1; - int backing_fd_2 = -1; // 第二个后端文件描述符 - struct loop_status64 status; - memset(&status, 0, sizeof(status)); +// =================================================================== +// 测试用例 +// =================================================================== + +// 测试 1: 基本读写测试 +static int test_basic_read_write(int loop_fd, const char *loop_path, + struct loop_status64 *status) { + const char *test_name = "Basic Read/Write"; + TEST_BEGIN(test_name); + char write_buf[512] = "Hello Loop Device!"; - char write_buf_2[512] = "New Backing File Data!"; // 第二个文件写入数据 - char read_buf[512]; - char verify_buf[512]; - - create_test_file(TEST_FILE_NAME, TEST_FILE_SIZE); // 创建作为 loop 设备后端的文件 1 - create_test_file(TEST_FILE_NAME_2, TEST_FILE_SIZE_2); // 创建作为 loop 设备后端的文件 2 - - backing_fd_1 = open(TEST_FILE_NAME, O_RDWR); - if (backing_fd_1 < 0) { - perror("Failed to open backing file 1"); - exit(EXIT_FAILURE); - } - - backing_fd_2 = open(TEST_FILE_NAME_2, O_RDWR); - if (backing_fd_2 < 0) { - perror("Failed to open backing file 2"); - close(backing_fd_1); - exit(EXIT_FAILURE); - } - - // 1. 打开 loop-control 字符设备 - printf("Opening loop control device: %s\n", LOOP_DEVICE_CONTROL); - control_fd = open(LOOP_DEVICE_CONTROL, O_RDWR); - if (control_fd < 0) { - perror("Failed to open loop control device. Make sure your kernel module is loaded and /dev/loop-control exists."); - close(backing_fd_1); - close(backing_fd_2); - exit(EXIT_FAILURE); - } - printf("Loop control device opened successfully (fd=%d).\n", control_fd); - - // 2. 获取一个空闲的 loop 次设备号 - printf("Requesting a free loop device minor...\n"); - if (ioctl(control_fd, LOOP_CTL_GET_FREE, &loop_minor) < 0) { - perror("Failed to get free loop device minor"); - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); - exit(EXIT_FAILURE); - } - printf("Got free loop minor: %d\n", loop_minor); - - // 3. 请求内核以该次设备号创建新的 loop 设备 - printf("Adding loop device loop%d...\n", loop_minor); - int returned_minor = ioctl(control_fd, LOOP_CTL_ADD, loop_minor); - if (returned_minor < 0) { - perror("Failed to add loop device"); - printf("returned_minor: %d\n", returned_minor); - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); - exit(EXIT_FAILURE); - } - if (returned_minor != loop_minor) { - fprintf(stderr, "Warning: LOOP_CTL_ADD returned minor %d, expected %d\n", returned_minor, loop_minor); - } - printf("Loop device loop%d added (kernel returned minor: %d).\n", loop_minor, returned_minor); - - // 4. 打开刚创建的块设备节点 - sprintf(loop_dev_path, "/dev/loop%d", loop_minor); - printf("Attempting to open block device: %s\n", loop_dev_path); - loop_fd = open(loop_dev_path, O_RDWR); - if (loop_fd < 0) { - perror("Failed to open loop block device. This might mean the block device node wasn't created/registered correctly, or permissions."); - fprintf(stderr, "Make sure /dev/loop%d exists as a block device.\n", loop_minor); - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); - exit(EXIT_FAILURE); - } - printf("Loop block device %s opened successfully (fd=%d).\n", loop_dev_path, loop_fd); - - printf("Associating backing file %s with loop device using LOOP_SET_FD...\n", TEST_FILE_NAME); - if (ioctl(loop_fd, LOOP_SET_FD, backing_fd_1) < 0) { - perror("Failed to associate backing file with loop device"); - close(loop_fd); - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); - exit(EXIT_FAILURE); - } - printf("Backing file associated successfully.\n"); - - // 配置偏移和大小限制,使 loop 设备从文件第 512 字节开始映射 - status.lo_offset = 512; - status.lo_sizelimit = TEST_FILE_SIZE - status.lo_offset; - status.lo_flags = 0; - status.__pad = 0; - - printf("配置 loop 设备的偏移和大小限制...\n"); - if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { - perror("Failed to set loop status64"); - close(loop_fd); - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); - exit(EXIT_FAILURE); - } - - struct loop_status64 status_readback = {0}; - if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { - perror("Failed to get loop status64"); - close(loop_fd); - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); - exit(EXIT_FAILURE); - } - printf("loop 偏移: %llu, 映射字节数: %llu, 标志: 0x%x\n", - (unsigned long long)status_readback.lo_offset, - (unsigned long long)status_readback.lo_sizelimit, - status_readback.lo_flags); - - if (status_readback.lo_offset != status.lo_offset || - status_readback.lo_sizelimit != status.lo_sizelimit) { - fprintf(stderr, "Loop status mismatch after configuration.\n"); - close(loop_fd); - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); - exit(EXIT_FAILURE); - } - - status = status_readback; - - // 5. 对 loop 块设备执行读写测试 (针对第一个文件) - - printf("Writing to loop device %s (via %s)...\n", loop_dev_path, TEST_FILE_NAME); + char read_buf[512] = {0}; + char verify_buf[512] = {0}; + + // 写入测试 + LOG_STEP("Writing data to loop device..."); if (lseek(loop_fd, 0, SEEK_SET) < 0) { - perror("lseek failed before write"); - goto cleanup; + TEST_END_FAIL(test_name, "lseek failed before write"); + return TEST_FAIL; } + if (write(loop_fd, write_buf, sizeof(write_buf)) != sizeof(write_buf)) { - perror("Failed to write to loop device"); - goto cleanup; + TEST_END_FAIL(test_name, "write failed"); + return TEST_FAIL; } - printf("Successfully wrote '%s' to loop device.\n", write_buf); + LOG_STEP("Write successful: '%s'", write_buf); - // 校验后端文件对应偏移512字节的数据是否与写入内容一致 + // 验证后端文件 + LOG_STEP("Verifying backing file content..."); int verify_fd = open(TEST_FILE_NAME, O_RDONLY); if (verify_fd < 0) { - perror("Failed to reopen backing file for verification"); - goto cleanup; - } - if (lseek(verify_fd, (off_t)status.lo_offset, SEEK_SET) < 0) { - perror("Failed to seek backing file"); - close(verify_fd); - goto cleanup; + TEST_END_FAIL(test_name, "cannot open backing file for verification"); + return TEST_FAIL; } - if (read(verify_fd, verify_buf, sizeof(write_buf)) != sizeof(write_buf)) { - perror("Failed to read back from backing file"); + + if (lseek(verify_fd, (off_t)status->lo_offset, SEEK_SET) < 0 || + read(verify_fd, verify_buf, sizeof(write_buf)) != sizeof(write_buf)) { close(verify_fd); - goto cleanup; + TEST_END_FAIL(test_name, "cannot read backing file"); + return TEST_FAIL; } close(verify_fd); + if (memcmp(write_buf, verify_buf, sizeof(write_buf)) != 0) { - fprintf(stderr, "Backing file data mismatch.\n"); - goto cleanup; + TEST_END_FAIL(test_name, "backing file content mismatch"); + return TEST_FAIL; } - printf("镜像文件内容验证通过。\n"); + LOG_STEP("Backing file verification passed"); - printf("Reading from loop device %s...\n", loop_dev_path); - memset(read_buf, 0, sizeof(read_buf)); + // 读取测试 + LOG_STEP("Reading data from loop device..."); if (lseek(loop_fd, 0, SEEK_SET) < 0) { - perror("lseek failed before read"); - goto cleanup; + TEST_END_FAIL(test_name, "lseek failed before read"); + return TEST_FAIL; } + if (read(loop_fd, read_buf, sizeof(read_buf)) != sizeof(read_buf)) { - perror("Failed to read from loop device"); - goto cleanup; + TEST_END_FAIL(test_name, "read failed"); + return TEST_FAIL; } - printf("Successfully read '%s' from loop device.\n", read_buf); + LOG_STEP("Read successful: '%s'", read_buf); - if (strcmp(write_buf, read_buf) == 0) { - printf("Read/write test PASSED.\n"); - } else { - printf("Read/write test FAILED: Mismatch in data.\n"); - goto cleanup; + if (strcmp(write_buf, read_buf) != 0) { + TEST_END_FAIL(test_name, "read data mismatch"); + return TEST_FAIL; } - // 将设备切换到只读模式,验证写入被阻止 - printf("切换 loop 设备为只读模式...\n"); - status.lo_flags |= LO_FLAGS_READ_ONLY; - if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { - perror("Failed to enable read-only flag"); - goto cleanup; + TEST_END_PASS(test_name); + return TEST_PASS; +} + +// 测试 2: 只读模式测试 +static int test_read_only_mode(int loop_fd, struct loop_status64 *status) { + const char *test_name = "Read-Only Mode"; + TEST_BEGIN(test_name); + + char write_buf[512] = "Test data"; + + // 设置只读标志 + LOG_STEP("Setting read-only flag..."); + status->lo_flags |= LO_FLAGS_READ_ONLY; + if (ioctl(loop_fd, LOOP_SET_STATUS64, status) < 0) { + TEST_END_FAIL(test_name, "failed to set read-only flag"); + return TEST_FAIL; } + // 尝试写入(应该失败) + LOG_STEP("Attempting write in read-only mode (should fail)..."); errno = 0; if (lseek(loop_fd, 0, SEEK_SET) < 0) { - perror("Failed to seek loop device"); + // lseek 失败不影响测试 } + if (write(loop_fd, write_buf, sizeof(write_buf)) >= 0 || errno != EROFS) { - fprintf(stderr, "Write unexpectedly succeeded under read-only mode (errno=%d).\n", errno); - goto cleanup; - } - printf("只读模式下写入被正确阻止。\n"); - - status.lo_flags &= ~LO_FLAGS_READ_ONLY; - if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { - perror("Failed to restore writeable mode"); - goto cleanup; - } - - // ======================================================= - // 新增测试用例:LOOP_CHANGE_FD - // ======================================================= - printf("\n--- Testing LOOP_CHANGE_FD ---\n"); - printf("Changing backing file from %s to %s using LOOP_CHANGE_FD...\n", TEST_FILE_NAME, TEST_FILE_NAME_2); - if (ioctl(loop_fd, LOOP_CHANGE_FD, backing_fd_2) < 0) { - perror("Failed to change backing file via LOOP_CHANGE_FD"); - goto cleanup; - } - printf("Backing file changed successfully to %s.\n", TEST_FILE_NAME_2); - - // 验证 loop 设备现在映射到第二个文件 - status_readback = (struct loop_status64){0}; - if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { - perror("Failed to get loop status64 after LOOP_CHANGE_FD"); - goto cleanup; - } - printf("After LOOP_CHANGE_FD, loop current offset: %llu, sizelimit: %llu, flags: 0x%x\n", - (unsigned long long)status_readback.lo_offset, - (unsigned long long)status_readback.lo_sizelimit, - status_readback.lo_flags); - - // 确保偏移和大小限制保持,但实际大小应该基于新文件 - long actual_file_2_size = get_file_size(backing_fd_2); - if (actual_file_2_size < 0) goto cleanup; - - // 此时 lo_sizelimit 应该反映出 TEST_FILE_NAME_2 的大小 - // 因为 LOOP_CHANGE_FD 会调用 recalc_effective_size - // 并且默认的 sizelimit 是 0,表示不限制 - // 所以 effective_size 应该等于 file_size - offset - // 我们需要重新计算预期的 effective_size - // uint64_t expected_sizelimit_after_change = (actual_file_2_size > status_readback.lo_offset) ? (actual_file_2_size - status_readback.lo_offset) : 0; - - // 注意:内核中的 `recalc_effective_size` 会将 `inner.file_size` 更新为有效大小 - // 但是 `lo_sizelimit` 字段在 `LoopStatus64` 中是用户设定的限制,它不会自动改变 - // 这里的验证需要更精确:`lo_sizelimit` 应该和我们之前设置的相同 (即 TEST_FILE_SIZE - 512) - // 但当 `LOOP_CHANGE_FD` 成功时,其内部会重新计算 `file_size` - // 如果 `lo_sizelimit` 保持为非0值,并且大于新文件大小,则 `file_size` 会被截断 - // 让我们先简单地检查是否能对新文件进行读写。 - - // 写入新数据到 loop 设备,应该写入到 TEST_FILE_NAME_2 - printf("Writing to loop device %s (via %s)...\n", loop_dev_path, TEST_FILE_NAME_2); - if (lseek(loop_fd, 0, SEEK_SET) < 0) { - perror("lseek failed before write to new backing file"); - goto cleanup; + status->lo_flags &= ~LO_FLAGS_READ_ONLY; + ioctl(loop_fd, LOOP_SET_STATUS64, status); + TEST_END_FAIL(test_name, "write should have failed with EROFS"); + return TEST_FAIL; } - if (write(loop_fd, write_buf_2, sizeof(write_buf_2)) != sizeof(write_buf_2)) { - perror("Failed to write to loop device with new backing file"); - goto cleanup; + LOG_STEP("Write correctly rejected with EROFS"); + + // 恢复可写模式 + LOG_STEP("Restoring writable mode..."); + status->lo_flags &= ~LO_FLAGS_READ_ONLY; + if (ioctl(loop_fd, LOOP_SET_STATUS64, status) < 0) { + TEST_END_FAIL(test_name, "failed to restore writable mode"); + return TEST_FAIL; } - printf("Successfully wrote '%s' to loop device with new backing file.\n", write_buf_2); - // 校验第二个后端文件对应偏移512字节的数据是否与写入内容一致 - verify_fd = open(TEST_FILE_NAME_2, O_RDONLY); + TEST_END_PASS(test_name); + return TEST_PASS; +} + +// 测试 3: LOOP_CHANGE_FD +static int test_change_fd(int loop_fd, struct loop_status64 *status) { + const char *test_name = "LOOP_CHANGE_FD"; + TEST_BEGIN(test_name); + + char write_buf[512] = "New Backing File Data!"; + char verify_buf[512] = {0}; + + // 切换后端文件 + LOG_STEP("Changing backing file to %s...", TEST_FILE_NAME_2); + if (ioctl(loop_fd, LOOP_CHANGE_FD, g_backing_fd_2) < 0) { + TEST_END_FAIL(test_name, "LOOP_CHANGE_FD failed"); + return TEST_FAIL; + } + LOG_STEP("Backing file changed successfully"); + + // 获取新状态 + struct loop_status64 new_status = {0}; + if (ioctl(loop_fd, LOOP_GET_STATUS64, &new_status) < 0) { + TEST_END_FAIL(test_name, "failed to get status after change"); + return TEST_FAIL; + } + LOG_STEP("New status - offset: %llu, sizelimit: %llu, flags: 0x%x", + (unsigned long long)new_status.lo_offset, + (unsigned long long)new_status.lo_sizelimit, + new_status.lo_flags); + + // 写入新后端文件 + LOG_STEP("Writing to new backing file..."); + if (lseek(loop_fd, 0, SEEK_SET) < 0 || + write(loop_fd, write_buf, sizeof(write_buf)) != sizeof(write_buf)) { + TEST_END_FAIL(test_name, "write to new backing file failed"); + return TEST_FAIL; + } + LOG_STEP("Write successful: '%s'", write_buf); + + // 验证新后端文件内容 + LOG_STEP("Verifying new backing file content..."); + int verify_fd = open(TEST_FILE_NAME_2, O_RDONLY); if (verify_fd < 0) { - perror("Failed to reopen new backing file for verification"); - goto cleanup; - } - if (lseek(verify_fd, (off_t)status.lo_offset, SEEK_SET) < 0) { // 使用之前设置的偏移量 - perror("Failed to seek new backing file"); - close(verify_fd); - goto cleanup; + TEST_END_FAIL(test_name, "cannot open new backing file"); + return TEST_FAIL; } - memset(verify_buf, 0, sizeof(verify_buf)); - if (read(verify_fd, verify_buf, sizeof(write_buf_2)) != sizeof(write_buf_2)) { - perror("Failed to read back from new backing file"); + + if (lseek(verify_fd, (off_t)status->lo_offset, SEEK_SET) < 0 || + read(verify_fd, verify_buf, sizeof(write_buf)) != sizeof(write_buf)) { close(verify_fd); - goto cleanup; + TEST_END_FAIL(test_name, "cannot read new backing file"); + return TEST_FAIL; } close(verify_fd); - if (memcmp(write_buf_2, verify_buf, sizeof(write_buf_2)) != 0) { - fprintf(stderr, "New backing file data mismatch after LOOP_CHANGE_FD.\n"); - goto cleanup; + + if (memcmp(write_buf, verify_buf, sizeof(write_buf)) != 0) { + TEST_END_FAIL(test_name, "new backing file content mismatch"); + return TEST_FAIL; } - printf("New backing file content verification passed after LOOP_CHANGE_FD.\n"); - // ======================================================= - // 新增测试用例:LOOP_SET_CAPACITY - // ======================================================= - printf("\n--- Testing LOOP_SET_CAPACITY ---\n"); - // 增大 TEST_FILE_NAME_2 的大小 + TEST_END_PASS(test_name); + return TEST_PASS; +} + +// 测试 4: LOOP_SET_CAPACITY +static int test_set_capacity(int loop_fd, struct loop_status64 *status) { + const char *test_name = "LOOP_SET_CAPACITY"; + TEST_BEGIN(test_name); + + // 扩大后端文件 + LOG_STEP("Resizing backing file to %d bytes...", TEST_FILE_SIZE_2 * 2); int resize_fd = open(TEST_FILE_NAME_2, O_RDWR); if (resize_fd < 0) { - perror("Failed to open TEST_FILE_NAME_2 for resizing"); - goto cleanup; + TEST_END_FAIL(test_name, "cannot open backing file for resize"); + return TEST_FAIL; } - int new_backing_file_size = TEST_FILE_SIZE_2 * 2; // 双倍大小 - if (ftruncate(resize_fd, new_backing_file_size) < 0) { - perror("Failed to ftruncate TEST_FILE_NAME_2"); + + int new_size = TEST_FILE_SIZE_2 * 2; + if (ftruncate(resize_fd, new_size) < 0) { close(resize_fd); - goto cleanup; + TEST_END_FAIL(test_name, "ftruncate failed"); + return TEST_FAIL; } close(resize_fd); - printf("Resized %s to %d bytes.\n", TEST_FILE_NAME_2, new_backing_file_size); - - printf("Calling LOOP_SET_CAPACITY to re-evaluate loop device size...\n"); - if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0) { // 参数通常为0 - perror("Failed to set loop capacity"); - goto cleanup; - } - printf("LOOP_SET_CAPACITY called successfully.\n"); + LOG_STEP("Backing file resized successfully"); - // 获取并验证新的容量 - status_readback = (struct loop_status64){0}; - if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { - perror("Failed to get loop status64 after LOOP_SET_CAPACITY"); - goto cleanup; + // 清除 sizelimit 以便看到扩展效果 + LOG_STEP("Clearing sizelimit..."); + status->lo_sizelimit = 0; + if (ioctl(loop_fd, LOOP_SET_STATUS64, status) < 0) { + TEST_END_FAIL(test_name, "failed to clear sizelimit"); + return TEST_FAIL; } - printf("After LOOP_SET_CAPACITY, loop current offset: %llu, sizelimit: %llu, flags: 0x%x\n", - (unsigned long long)status_readback.lo_offset, - (unsigned long long)status_readback.lo_sizelimit, - status_readback.lo_flags); - - // 重新计算预期大小。由于 lo_sizelimit 仍为非零值 (TEST_FILE_SIZE - 512), - // 并且新文件大小 (new_backing_file_size) 仍然可能小于 (lo_offset + lo_sizelimit) - // 实际有效大小应为 min(new_backing_file_size - lo_offset, lo_sizelimit) - uint64_t expected_effective_size = (new_backing_file_size > status_readback.lo_offset) ? (new_backing_file_size - status_readback.lo_offset) : 0; - expected_effective_size = (status_readback.lo_sizelimit > 0) ? - expected_effective_size < status_readback.lo_sizelimit ? expected_effective_size : status_readback.lo_sizelimit : - expected_effective_size; - - - // 实际验证 read/write 是否能访问到更大的区域。 - // 由于我们之前设置了 lo_sizelimit,它会限制设备可见的大小。 - // 如果想要反映出 ftruncate 后更大的大小,需要将 lo_sizelimit 设为 0。 - // 让我们先将 lo_sizelimit 清零,再测试 LOOP_SET_CAPACITY。 - - printf("Clearing lo_sizelimit and re-testing LOOP_SET_CAPACITY...\n"); - status.lo_sizelimit = 0; // 清零,表示不限制 - if (ioctl(loop_fd, LOOP_SET_STATUS64, &status) < 0) { - perror("Failed to clear lo_sizelimit"); - goto cleanup; - } - printf("lo_sizelimit cleared. Calling LOOP_SET_CAPACITY again.\n"); + // 调用 LOOP_SET_CAPACITY + LOG_STEP("Calling LOOP_SET_CAPACITY..."); if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0) { - perror("Failed to set loop capacity after clearing sizelimit"); - goto cleanup; - } - printf("LOOP_SET_CAPACITY called successfully after clearing sizelimit.\n"); - - if (ioctl(loop_fd, LOOP_GET_STATUS64, &status_readback) < 0) { - perror("Failed to get loop status64 after LOOP_SET_CAPACITY (sizelimit cleared)"); - goto cleanup; - } - printf("After LOOP_SET_CAPACITY (sizelimit cleared), loop current offset: %llu, sizelimit: %llu, flags: 0x%x\n", - (unsigned long long)status_readback.lo_offset, - (unsigned long long)status_readback.lo_sizelimit, - status_readback.lo_flags); - - // 现在 lo_sizelimit 应该为 0,有效大小应为 (new_backing_file_size - lo_offset) - expected_effective_size = (new_backing_file_size > status_readback.lo_offset) ? (new_backing_file_size - status_readback.lo_offset) : 0; - - // 尝试写入到新扩展的区域 (假设扩展区域在原文件大小之后) - // 计算旧文件大小的最后一个块的偏移,然后写入一个块 - off_t write_offset_extended = (off_t)status_readback.lo_offset + TEST_FILE_SIZE_2; // 从原文件大小之后开始写 - char extended_write_buf[512] = "Extended Data!"; - - printf("Attempting to write to extended region at offset %lld (device offset: %lld)...\n", - (long long)write_offset_extended, (long long)(TEST_FILE_SIZE_2)); // loop 设备上的相对偏移 - if (lseek(loop_fd, TEST_FILE_SIZE_2, SEEK_SET) < 0) { // 在 loop 设备上的相对偏移 - perror("lseek to extended region failed"); - goto cleanup; - } - if (write(loop_fd, extended_write_buf, sizeof(extended_write_buf)) != sizeof(extended_write_buf)) { - perror("Failed to write to extended region of loop device"); - goto cleanup; - } - printf("Successfully wrote to extended region of loop device.\n"); - - // 校验第二个后端文件扩展区域的数据 - verify_fd = open(TEST_FILE_NAME_2, O_RDONLY); + TEST_END_FAIL(test_name, "LOOP_SET_CAPACITY failed"); + return TEST_FAIL; + } + LOG_STEP("LOOP_SET_CAPACITY successful"); + + // 获取新状态 + struct loop_status64 new_status = {0}; + if (ioctl(loop_fd, LOOP_GET_STATUS64, &new_status) < 0) { + TEST_END_FAIL(test_name, "failed to get status after capacity change"); + return TEST_FAIL; + } + LOG_STEP("New status - offset: %llu, sizelimit: %llu", + (unsigned long long)new_status.lo_offset, + (unsigned long long)new_status.lo_sizelimit); + + // 尝试写入扩展区域 + LOG_STEP("Writing to extended region..."); + char extended_buf[512] = "Extended Data!"; + if (lseek(loop_fd, TEST_FILE_SIZE_2, SEEK_SET) < 0 || + write(loop_fd, extended_buf, sizeof(extended_buf)) != sizeof(extended_buf)) { + TEST_END_FAIL(test_name, "write to extended region failed"); + return TEST_FAIL; + } + LOG_STEP("Write to extended region successful"); + + // 验证扩展区域内容 + LOG_STEP("Verifying extended region content..."); + char verify_buf[512] = {0}; + int verify_fd = open(TEST_FILE_NAME_2, O_RDONLY); if (verify_fd < 0) { - perror("Failed to reopen new backing file for extended verification"); - goto cleanup; - } - if (lseek(verify_fd, write_offset_extended, SEEK_SET) < 0) { - perror("Failed to seek new backing file for extended verification"); - close(verify_fd); - goto cleanup; + TEST_END_FAIL(test_name, "cannot open backing file for verification"); + return TEST_FAIL; } - memset(verify_buf, 0, sizeof(verify_buf)); - if (read(verify_fd, verify_buf, sizeof(extended_write_buf)) != sizeof(extended_write_buf)) { - perror("Failed to read back from new backing file extended region"); + + off_t verify_offset = (off_t)status->lo_offset + TEST_FILE_SIZE_2; + if (lseek(verify_fd, verify_offset, SEEK_SET) < 0 || + read(verify_fd, verify_buf, sizeof(extended_buf)) != sizeof(extended_buf)) { close(verify_fd); - goto cleanup; + TEST_END_FAIL(test_name, "cannot read extended region"); + return TEST_FAIL; } close(verify_fd); - if (memcmp(extended_write_buf, verify_buf, sizeof(extended_write_buf)) != 0) { - fprintf(stderr, "New backing file extended data mismatch after LOOP_SET_CAPACITY.\n"); - goto cleanup; + + if (memcmp(extended_buf, verify_buf, sizeof(extended_buf)) != 0) { + TEST_END_FAIL(test_name, "extended region content mismatch"); + return TEST_FAIL; } - printf("New backing file extended content verification passed.\n"); - // ======================================================= - // 资源回收测试 1: 并发I/O期间删除设备 - // ======================================================= - printf("\n--- Testing Resource Reclamation: Concurrent I/O During Deletion ---\n"); + TEST_END_PASS(test_name); + return TEST_PASS; +} - // 创建新的loop设备用于此测试,使用重试机制处理可能的竞态条件 - int test_minor = -1; - int returned_minor_test = -1; - for (int retry = 0; retry < 10; retry++) { - if (ioctl(control_fd, LOOP_CTL_GET_FREE, &test_minor) < 0) { - perror("Failed to get free loop device for reclamation test"); - goto cleanup; - } +// 测试 5: 并发 I/O 期间删除设备 +static int test_concurrent_io_deletion(void) { + const char *test_name = "Concurrent I/O During Deletion"; + TEST_BEGIN(test_name); - returned_minor_test = ioctl(control_fd, LOOP_CTL_ADD, test_minor); - if (returned_minor_test >= 0) { - test_minor = returned_minor_test; - break; - } + #define NUM_IO_THREADS 4 - if (errno != EEXIST) { - perror("Failed to add loop device for reclamation test"); - goto cleanup; - } - // 如果设备已存在,重试获取新的minor号 - printf("Device loop%d already exists, retrying...\n", test_minor); + // 创建测试用 loop 设备 + int test_minor; + if (create_loop_device(g_control_fd, &test_minor) < 0) { + TEST_END_FAIL(test_name, "failed to create test loop device"); + return TEST_FAIL; } + LOG_STEP("Created loop device loop%d", test_minor); - if (returned_minor_test < 0) { - fprintf(stderr, "Failed to create loop device after 10 retries\n"); - goto cleanup; - } + char test_path[64]; + sprintf(test_path, "/dev/loop%d", test_minor); - char test_loop_path[64]; - sprintf(test_loop_path, "/dev/loop%d", test_minor); - int test_loop_fd = open(test_loop_path, O_RDWR); - if (test_loop_fd < 0) { - perror("Failed to open test loop device"); - ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); - goto cleanup; + int test_fd = open(test_path, O_RDWR); + if (test_fd < 0) { + ioctl(g_control_fd, LOOP_CTL_REMOVE, test_minor); + TEST_END_FAIL(test_name, "failed to open test loop device"); + return TEST_FAIL; } - // 绑定到测试文件 - if (ioctl(test_loop_fd, LOOP_SET_FD, backing_fd_1) < 0) { - perror("Failed to bind test loop device"); - close(test_loop_fd); - ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); - goto cleanup; + if (ioctl(test_fd, LOOP_SET_FD, g_backing_fd_1) < 0) { + close(test_fd); + ioctl(g_control_fd, LOOP_CTL_REMOVE, test_minor); + TEST_END_FAIL(test_name, "failed to bind test loop device"); + return TEST_FAIL; } - printf("Created test loop device loop%d for concurrent I/O test.\n", test_minor); + LOG_STEP("Bound backing file to test device"); - // 启动多个I/O线程 - #define NUM_IO_THREADS 4 + // 启动 I/O 线程 pthread_t io_threads[NUM_IO_THREADS]; struct io_thread_args io_args[NUM_IO_THREADS]; + LOG_STEP("Starting %d I/O threads...", NUM_IO_THREADS); for (int i = 0; i < NUM_IO_THREADS; i++) { - strcpy(io_args[i].loop_dev_path, test_loop_path); + strcpy(io_args[i].loop_dev_path, test_path); io_args[i].duration_seconds = 5; io_args[i].should_stop = 0; io_args[i].io_count = 0; io_args[i].error_count = 0; if (pthread_create(&io_threads[i], NULL, io_worker_thread, &io_args[i]) != 0) { - perror("Failed to create I/O thread"); - // 清理已创建的线程 for (int j = 0; j < i; j++) { io_args[j].should_stop = 1; pthread_join(io_threads[j], NULL); } - close(test_loop_fd); - ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); - goto cleanup; + close(test_fd); + ioctl(g_control_fd, LOOP_CTL_REMOVE, test_minor); + TEST_END_FAIL(test_name, "failed to create I/O thread"); + return TEST_FAIL; } } - printf("Started %d concurrent I/O threads.\n", NUM_IO_THREADS); - // 关闭主文件描述符,避免在删除时引用计数不为0 - // I/O线程会重新打开设备进行操作 - close(test_loop_fd); - printf("Closed main loop device file descriptor.\n"); + close(test_fd); // 关闭主 fd // 启动删除线程 + LOG_STEP("Starting deletion thread..."); pthread_t delete_thread; - struct delete_thread_args delete_args; - delete_args.control_fd = control_fd; - delete_args.loop_minor = test_minor; - delete_args.result = 0; - delete_args.error_code = 0; - //创建失败回退删除所有线程 + struct delete_thread_args delete_args = { + .control_fd = g_control_fd, + .loop_minor = test_minor, + .result = 0, + .error_code = 0 + }; + if (pthread_create(&delete_thread, NULL, delete_worker_thread, &delete_args) != 0) { - perror("Failed to create delete thread"); for (int i = 0; i < NUM_IO_THREADS; i++) { io_args[i].should_stop = 1; pthread_join(io_threads[i], NULL); } - close(test_loop_fd); - ioctl(control_fd, LOOP_CTL_REMOVE, test_minor); - goto cleanup; + ioctl(g_control_fd, LOOP_CTL_REMOVE, test_minor); + TEST_END_FAIL(test_name, "failed to create delete thread"); + return TEST_FAIL; } - printf("Started deletion thread.\n"); // 等待删除完成 pthread_join(delete_thread, NULL); - printf("Deletion thread completed with result: %d (errno: %d)\n", - delete_args.result, delete_args.error_code); + LOG_STEP("Deletion completed with result: %d (errno: %d)", + delete_args.result, delete_args.error_code); - // 停止I/O线程 + // 停止并等待 I/O 线程 for (int i = 0; i < NUM_IO_THREADS; i++) { io_args[i].should_stop = 1; } - // 等待所有I/O线程完成 - int total_io_count = 0; - int total_error_count = 0; + int total_io = 0, total_errors = 0; for (int i = 0; i < NUM_IO_THREADS; i++) { pthread_join(io_threads[i], NULL); - total_io_count += io_args[i].io_count; - total_error_count += io_args[i].error_count; - printf("I/O thread %d: %d successful ops, %d errors\n", - i, io_args[i].io_count, io_args[i].error_count); + total_io += io_args[i].io_count; + total_errors += io_args[i].error_count; } - printf("Total I/O operations: %d successful, %d errors\n", - total_io_count, total_error_count); - - // test_loop_fd 已经在删除前关闭了 + LOG_STEP("I/O statistics: %d successful, %d errors", total_io, total_errors); - if (delete_args.result == 0) { - printf("✓ Concurrent I/O deletion test PASSED: Device deleted successfully while I/O was active.\n"); - } else { - printf("✗ Concurrent I/O deletion test FAILED: Deletion returned %d (errno: %d)\n", - delete_args.result, delete_args.error_code); + // 验证设备已删除 + int verify_fd = open(test_path, O_RDWR); + if (verify_fd >= 0) { + close(verify_fd); + TEST_END_FAIL(test_name, "device still accessible after deletion"); + return TEST_FAIL; } - // 验证设备已被删除 - int verify_test_fd = open(test_loop_path, O_RDWR); - if (verify_test_fd < 0 && (errno == ENOENT || errno == ENODEV)) { - printf("✓ Device %s is correctly inaccessible after deletion.\n", test_loop_path); - } else { - if (verify_test_fd >= 0) { - printf("✗ FAILED: Device %s still accessible after deletion!\n", test_loop_path); - close(verify_test_fd); - } + if (delete_args.result != 0) { + TEST_END_FAIL(test_name, "deletion failed"); + return TEST_FAIL; } - // ======================================================= - // 资源回收测试 2: 删除未绑定的设备 - // ======================================================= - printf("\n--- Testing Resource Reclamation: Deleting Unbound Device ---\n"); - - int unbound_minor = -1; - int ret_unbound = -1; - for (int retry = 0; retry < 10; retry++) { - if (ioctl(control_fd, LOOP_CTL_GET_FREE, &unbound_minor) < 0) { - perror("Failed to get free loop device for unbound test"); - goto cleanup; - } + TEST_END_PASS(test_name); + return TEST_PASS; - ret_unbound = ioctl(control_fd, LOOP_CTL_ADD, unbound_minor); - if (ret_unbound >= 0) { - unbound_minor = ret_unbound; - break; - } + #undef NUM_IO_THREADS +} - if (errno != EEXIST) { - perror("Failed to add loop device for unbound test"); - goto cleanup; - } - } +// 测试 6: 删除未绑定的设备 +static int test_delete_unbound_device(void) { + const char *test_name = "Delete Unbound Device"; + TEST_BEGIN(test_name); - if (ret_unbound < 0) { - fprintf(stderr, "Failed to create unbound loop device after retries\n"); - goto cleanup; + int minor; + if (create_loop_device(g_control_fd, &minor) < 0) { + TEST_END_FAIL(test_name, "failed to create loop device"); + return TEST_FAIL; } - printf("Created unbound loop device loop%d.\n", unbound_minor); + LOG_STEP("Created unbound loop device loop%d", minor); - // 立即删除未绑定的设备 - if (ioctl(control_fd, LOOP_CTL_REMOVE, unbound_minor) < 0) { - perror("Failed to remove unbound loop device"); - printf("✗ Unbound device deletion test FAILED.\n"); - } else { - printf("✓ Unbound device deletion test PASSED: Successfully deleted loop%d.\n", unbound_minor); + // 立即删除 + LOG_STEP("Deleting unbound device..."); + if (ioctl(g_control_fd, LOOP_CTL_REMOVE, minor) < 0) { + TEST_END_FAIL(test_name, "failed to delete unbound device"); + return TEST_FAIL; } - // ======================================================= - // 资源回收测试 3: 重复删除同一设备 - // ======================================================= - printf("\n--- Testing Resource Reclamation: Duplicate Deletion ---\n"); - - int dup_minor = -1; - int ret_dup = -1; - for (int retry = 0; retry < 10; retry++) { - if (ioctl(control_fd, LOOP_CTL_GET_FREE, &dup_minor) < 0) { - perror("Failed to get free loop device for duplicate deletion test"); - goto cleanup; - } - - ret_dup = ioctl(control_fd, LOOP_CTL_ADD, dup_minor); - if (ret_dup >= 0) { - dup_minor = ret_dup; - break; - } + TEST_END_PASS(test_name); + return TEST_PASS; +} - if (errno != EEXIST) { - perror("Failed to add loop device for duplicate deletion test"); - goto cleanup; - } - } +// 测试 7: 重复删除设备 +static int test_duplicate_deletion(void) { + const char *test_name = "Duplicate Deletion"; + TEST_BEGIN(test_name); - if (ret_dup < 0) { - fprintf(stderr, "Failed to create loop device for duplicate deletion test after retries\n"); - goto cleanup; + int minor; + if (create_loop_device(g_control_fd, &minor) < 0) { + TEST_END_FAIL(test_name, "failed to create loop device"); + return TEST_FAIL; } - printf("Created loop device loop%d for duplicate deletion test.\n", dup_minor); + LOG_STEP("Created loop device loop%d", minor); // 第一次删除 - if (ioctl(control_fd, LOOP_CTL_REMOVE, dup_minor) < 0) { - perror("First deletion failed"); - printf("✗ Duplicate deletion test FAILED: First deletion failed.\n"); - goto cleanup; + LOG_STEP("First deletion..."); + if (ioctl(g_control_fd, LOOP_CTL_REMOVE, minor) < 0) { + TEST_END_FAIL(test_name, "first deletion failed"); + return TEST_FAIL; } - printf("First deletion of loop%d succeeded.\n", dup_minor); + LOG_STEP("First deletion successful"); // 第二次删除(应该失败) + LOG_STEP("Second deletion (should fail)..."); errno = 0; - int second_delete = ioctl(control_fd, LOOP_CTL_REMOVE, dup_minor); - if (second_delete < 0 && (errno == ENODEV || errno == EINVAL)) { - printf("✓ Duplicate deletion test PASSED: Second deletion correctly failed with errno %d.\n", errno); - } else { - printf("✗ Duplicate deletion test FAILED: Second deletion returned %d (errno: %d), expected failure.\n", - second_delete, errno); + int ret = ioctl(g_control_fd, LOOP_CTL_REMOVE, minor); + if (ret >= 0) { + TEST_END_FAIL(test_name, "second deletion should have failed"); + return TEST_FAIL; + } + + if (errno != ENODEV && errno != EINVAL) { + char msg[64]; + snprintf(msg, sizeof(msg), "unexpected errno: %d", errno); + TEST_END_FAIL(test_name, msg); + return TEST_FAIL; } + LOG_STEP("Second deletion correctly failed with errno %d", errno); + + TEST_END_PASS(test_name); + return TEST_PASS; +} - // ======================================================= - // 资源回收测试 4: 文件描述符泄漏检测 - // ======================================================= - printf("\n--- Testing Resource Reclamation: File Descriptor Leak Detection ---\n"); +// 测试 8: 文件描述符泄漏检测 +static int test_fd_leak_detection(void) { + const char *test_name = "FD Leak Detection"; + TEST_BEGIN(test_name); - // 创建多个loop设备并快速删除,检查是否有FD泄漏 #define LEAK_TEST_COUNT 10 - int leak_test_minors[LEAK_TEST_COUNT]; - int leak_test_fds[LEAK_TEST_COUNT]; - printf("Creating and deleting %d loop devices to test for FD leaks...\n", LEAK_TEST_COUNT); + int minors[LEAK_TEST_COUNT]; + int fds[LEAK_TEST_COUNT]; + LOG_STEP("Creating %d loop devices...", LEAK_TEST_COUNT); for (int i = 0; i < LEAK_TEST_COUNT; i++) { - leak_test_minors[i] = -1; - leak_test_fds[i] = -1; - - // 使用重试机制创建设备 - for (int retry = 0; retry < 10; retry++) { - int free_minor; - if (ioctl(control_fd, LOOP_CTL_GET_FREE, &free_minor) < 0) { - perror("Failed to get free loop device for leak test"); - // 清理已创建的设备 - for (int j = 0; j < i; j++) { - if (leak_test_minors[j] >= 0) { - ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); - } - } - goto cleanup; - } - - int ret_leak = ioctl(control_fd, LOOP_CTL_ADD, free_minor); - if (ret_leak >= 0) { - leak_test_minors[i] = ret_leak; - break; - } + minors[i] = -1; + fds[i] = -1; - if (errno != EEXIST) { - perror("Failed to add loop device for leak test"); - for (int j = 0; j < i; j++) { - if (leak_test_minors[j] >= 0) { - ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); - } + if (create_loop_device(g_control_fd, &minors[i]) < 0) { + // 清理已创建的设备 + for (int j = 0; j < i; j++) { + if (fds[j] >= 0) { + ioctl(fds[j], LOOP_CLR_FD, 0); + close(fds[j]); } - goto cleanup; + if (minors[j] >= 0) ioctl(g_control_fd, LOOP_CTL_REMOVE, minors[j]); } + TEST_END_FAIL(test_name, "failed to create loop device"); + return TEST_FAIL; } - if (leak_test_minors[i] < 0) { - fprintf(stderr, "Failed to create loop device %d for leak test\n", i); + char path[64]; + sprintf(path, "/dev/loop%d", minors[i]); + fds[i] = open(path, O_RDWR); + if (fds[i] < 0) { + // 清理已创建的设备 for (int j = 0; j < i; j++) { - if (leak_test_minors[j] >= 0) { - ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[j]); + if (fds[j] >= 0) { + ioctl(fds[j], LOOP_CLR_FD, 0); + close(fds[j]); } + if (minors[j] >= 0) ioctl(g_control_fd, LOOP_CTL_REMOVE, minors[j]); } - goto cleanup; + ioctl(g_control_fd, LOOP_CTL_REMOVE, minors[i]); + TEST_END_FAIL(test_name, "failed to open loop device"); + return TEST_FAIL; } - // 打开并绑定设备 - char leak_path[64]; - sprintf(leak_path, "/dev/loop%d", leak_test_minors[i]); - leak_test_fds[i] = open(leak_path, O_RDWR); - if (leak_test_fds[i] >= 0) { - ioctl(leak_test_fds[i], LOOP_SET_FD, backing_fd_1); + // 立即绑定后端文件,这样下次 GET_FREE 会返回不同的 minor + if (ioctl(fds[i], LOOP_SET_FD, g_backing_fd_1) < 0) { + // 清理已创建的设备 + for (int j = 0; j <= i; j++) { + if (fds[j] >= 0) { + ioctl(fds[j], LOOP_CLR_FD, 0); + close(fds[j]); + } + if (minors[j] >= 0) ioctl(g_control_fd, LOOP_CTL_REMOVE, minors[j]); + } + TEST_END_FAIL(test_name, "failed to bind loop device"); + return TEST_FAIL; } } + LOG_STEP("Created %d devices successfully", LEAK_TEST_COUNT); // 删除所有设备 - int leak_delete_success = 0; + LOG_STEP("Deleting all devices..."); + int success_count = 0; for (int i = 0; i < LEAK_TEST_COUNT; i++) { - if (leak_test_fds[i] >= 0) { - ioctl(leak_test_fds[i], LOOP_CLR_FD, 0); - close(leak_test_fds[i]); + if (fds[i] >= 0) { + ioctl(fds[i], LOOP_CLR_FD, 0); + close(fds[i]); } - - if (ioctl(control_fd, LOOP_CTL_REMOVE, leak_test_minors[i]) == 0) { - leak_delete_success++; + if (ioctl(g_control_fd, LOOP_CTL_REMOVE, minors[i]) == 0) { + success_count++; } } - printf("Successfully deleted %d out of %d devices.\n", leak_delete_success, LEAK_TEST_COUNT); - if (leak_delete_success == LEAK_TEST_COUNT) { - printf("✓ FD leak test PASSED: All devices deleted successfully.\n"); - } else { - printf("⚠ FD leak test: %d devices failed to delete.\n", LEAK_TEST_COUNT - leak_delete_success); + LOG_STEP("Deleted %d/%d devices", success_count, LEAK_TEST_COUNT); + + if (success_count != LEAK_TEST_COUNT) { + TEST_END_FAIL(test_name, "not all devices deleted"); + return TEST_FAIL; } - // ======================================================= - // 资源回收测试 5: 删除后设备不可访问 - // ======================================================= - printf("\n--- Testing Resource Reclamation: Device Inaccessibility After Deletion ---\n"); + TEST_END_PASS(test_name); + return TEST_PASS; - int reject_minor = -1; - int ret_reject = -1; - for (int retry = 0; retry < 10; retry++) { - if (ioctl(control_fd, LOOP_CTL_GET_FREE, &reject_minor) < 0) { - perror("Failed to get free loop device for I/O rejection test"); - goto cleanup; - } + #undef LEAK_TEST_COUNT +} - ret_reject = ioctl(control_fd, LOOP_CTL_ADD, reject_minor); - if (ret_reject >= 0) { - reject_minor = ret_reject; - break; - } +// 测试 9: 删除后设备不可访问 +static int test_device_inaccessible_after_deletion(void) { + const char *test_name = "Device Inaccessible After Deletion"; + TEST_BEGIN(test_name); - if (errno != EEXIST) { - perror("Failed to add loop device for I/O rejection test"); - goto cleanup; - } + int minor; + if (create_loop_device(g_control_fd, &minor) < 0) { + TEST_END_FAIL(test_name, "failed to create loop device"); + return TEST_FAIL; } - if (ret_reject < 0) { - fprintf(stderr, "Failed to create loop device for I/O rejection test after retries\n"); - goto cleanup; - } + char path[64]; + sprintf(path, "/dev/loop%d", minor); + LOG_STEP("Created loop device %s", path); - char reject_path[64]; - sprintf(reject_path, "/dev/loop%d", reject_minor); - int reject_fd = open(reject_path, O_RDWR); - if (reject_fd < 0) { - perror("Failed to open loop device for I/O rejection test"); - ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor); - goto cleanup; + int fd = open(path, O_RDWR); + if (fd < 0) { + ioctl(g_control_fd, LOOP_CTL_REMOVE, minor); + TEST_END_FAIL(test_name, "failed to open loop device"); + return TEST_FAIL; } - if (ioctl(reject_fd, LOOP_SET_FD, backing_fd_1) < 0) { - perror("Failed to bind loop device for I/O rejection test"); - close(reject_fd); - ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor); - goto cleanup; + if (ioctl(fd, LOOP_SET_FD, g_backing_fd_1) < 0) { + close(fd); + ioctl(g_control_fd, LOOP_CTL_REMOVE, minor); + TEST_END_FAIL(test_name, "failed to bind loop device"); + return TEST_FAIL; } - printf("Created and bound loop device loop%d for I/O rejection test.\n", reject_minor); + LOG_STEP("Bound backing file"); - // 执行一次成功的I/O操作 - char reject_buf[512] = "Test data"; - if (write(reject_fd, reject_buf, sizeof(reject_buf)) != sizeof(reject_buf)) { - perror("Initial write failed"); - } else { - printf("Initial write succeeded (expected).\n"); + // 执行一次成功的 I/O + char buf[512] = "Test data"; + if (write(fd, buf, sizeof(buf)) != sizeof(buf)) { + close(fd); + ioctl(g_control_fd, LOOP_CTL_REMOVE, minor); + TEST_END_FAIL(test_name, "initial write failed"); + return TEST_FAIL; } + LOG_STEP("Initial I/O successful"); - // 关闭文件描述符,准备删除 - close(reject_fd); - printf("Closed device file descriptor.\n"); + close(fd); - // 触发删除 - printf("Triggering device deletion...\n"); - if (ioctl(control_fd, LOOP_CTL_REMOVE, reject_minor) < 0) { - perror("Failed to trigger deletion for I/O rejection test"); - goto cleanup; + // 删除设备 + LOG_STEP("Deleting device..."); + if (ioctl(g_control_fd, LOOP_CTL_REMOVE, minor) < 0) { + TEST_END_FAIL(test_name, "deletion failed"); + return TEST_FAIL; } - printf("Deletion triggered successfully.\n"); - // 尝试重新打开设备(应该失败) + // 尝试重新打开 + LOG_STEP("Attempting to reopen deleted device..."); errno = 0; - int reopen_reject_fd = open(reject_path, O_RDWR); - if (reopen_reject_fd < 0 && (errno == ENODEV || errno == ENOENT)) { - printf("✓ I/O rejection test PASSED: Device correctly inaccessible after deletion (errno: %d).\n", errno); - } else { - if (reopen_reject_fd >= 0) { - printf("✗ I/O rejection test FAILED: Device still accessible after deletion.\n"); - close(reopen_reject_fd); - } else { - printf("✗ I/O rejection test FAILED: Unexpected errno %d (expected ENODEV or ENOENT).\n", errno); - } + int reopen_fd = open(path, O_RDWR); + if (reopen_fd >= 0) { + close(reopen_fd); + TEST_END_FAIL(test_name, "device still accessible after deletion"); + return TEST_FAIL; + } + + if (errno != ENODEV && errno != ENOENT) { + char msg[64]; + snprintf(msg, sizeof(msg), "unexpected errno: %d", errno); + TEST_END_FAIL(test_name, msg); + return TEST_FAIL; } + LOG_STEP("Device correctly inaccessible (errno: %d)", errno); + + TEST_END_PASS(test_name); + return TEST_PASS; +} + +// =================================================================== +// 主函数 +// =================================================================== - printf("\n=== All Resource Reclamation Tests Completed ===\n"); +int main(void) { + printf("+========================================+\n"); + printf("| Loop Device Test Suite |\n"); + printf("+========================================+\n"); + // 初始化测试环境 + LOG_INFO("Initializing test environment..."); -cleanup: - // 6. 清理并删除 loop 设备 - printf("\n--- Cleaning up ---\n"); - printf("Clearing loop device loop%d backing file...\n", loop_minor); - if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) { - perror("Failed to clear loop device backing file"); + if (create_test_file(TEST_FILE_NAME, TEST_FILE_SIZE) < 0 || + create_test_file(TEST_FILE_NAME_2, TEST_FILE_SIZE_2) < 0) { + LOG_ERROR("Failed to create test files"); + return EXIT_FAILURE; } - // 在删除设备前先关闭文件描述符,避免引用计数问题 - close(loop_fd); - printf("Closed loop device file descriptor.\n"); + g_backing_fd_1 = open(TEST_FILE_NAME, O_RDWR); + g_backing_fd_2 = open(TEST_FILE_NAME_2, O_RDWR); + if (g_backing_fd_1 < 0 || g_backing_fd_2 < 0) { + LOG_ERROR("Failed to open backing files"); + goto cleanup_files; + } - printf("Removing loop device loop%d...\n", loop_minor); - if (ioctl(control_fd, LOOP_CTL_REMOVE, loop_minor) < 0) { - perror("Failed to remove loop device"); - // 即使删除失败也继续清理 - } else { - printf("Loop device loop%d removed successfully.\n", loop_minor); + g_control_fd = open(LOOP_DEVICE_CONTROL, O_RDWR); + if (g_control_fd < 0) { + LOG_ERROR("Failed to open loop control device: %s", strerror(errno)); + goto cleanup_backing; } + LOG_INFO("Test environment initialized"); - // 释放资源并删除测试文件 - close(backing_fd_1); - close(backing_fd_2); - close(control_fd); + // 创建主测试 loop 设备 + int main_minor; + if (create_loop_device(g_control_fd, &main_minor) < 0) { + LOG_ERROR("Failed to create main loop device"); + goto cleanup_control; + } + + char main_loop_path[64]; + sprintf(main_loop_path, "/dev/loop%d", main_minor); + LOG_INFO("Created main loop device: %s", main_loop_path); + + int main_loop_fd = open(main_loop_path, O_RDWR); + if (main_loop_fd < 0) { + LOG_ERROR("Failed to open main loop device"); + ioctl(g_control_fd, LOOP_CTL_REMOVE, main_minor); + goto cleanup_control; + } + + if (ioctl(main_loop_fd, LOOP_SET_FD, g_backing_fd_1) < 0) { + LOG_ERROR("Failed to bind main loop device"); + close(main_loop_fd); + ioctl(g_control_fd, LOOP_CTL_REMOVE, main_minor); + goto cleanup_control; + } + + // 配置偏移和大小限制 + struct loop_status64 status = { + .lo_offset = 512, + .lo_sizelimit = TEST_FILE_SIZE - 512, + .lo_flags = 0, + .__pad = 0 + }; + + if (ioctl(main_loop_fd, LOOP_SET_STATUS64, &status) < 0) { + LOG_ERROR("Failed to configure main loop device"); + close(main_loop_fd); + ioctl(g_control_fd, LOOP_CTL_REMOVE, main_minor); + goto cleanup_control; + } + LOG_INFO("Main loop device configured (offset: %llu, sizelimit: %llu)", + (unsigned long long)status.lo_offset, + (unsigned long long)status.lo_sizelimit); + + // =================================================================== + // 运行测试用例 + // =================================================================== + + // 基本功能测试 + test_basic_read_write(main_loop_fd, main_loop_path, &status); + test_read_only_mode(main_loop_fd, &status); + test_change_fd(main_loop_fd, &status); + test_set_capacity(main_loop_fd, &status); + + // 资源回收测试 + test_concurrent_io_deletion(); + test_delete_unbound_device(); + test_duplicate_deletion(); + test_fd_leak_detection(); + test_device_inaccessible_after_deletion(); + + // =================================================================== + // 清理 + // =================================================================== + + LOG_INFO("Cleaning up main loop device..."); + ioctl(main_loop_fd, LOOP_CLR_FD, 0); + close(main_loop_fd); + ioctl(g_control_fd, LOOP_CTL_REMOVE, main_minor); + +cleanup_control: + if (g_control_fd >= 0) close(g_control_fd); + +cleanup_backing: + if (g_backing_fd_1 >= 0) close(g_backing_fd_1); + if (g_backing_fd_2 >= 0) close(g_backing_fd_2); + +cleanup_files: unlink(TEST_FILE_NAME); unlink(TEST_FILE_NAME_2); - printf("All tests completed. Cleaned up.\n"); - // 校验设备删除后不可再次打开 - int reopen_fd = open(loop_dev_path, O_RDWR); - if (reopen_fd >= 0) { - printf("Unexpectedly reopened %s after removal (fd=%d).\n", loop_dev_path, reopen_fd); - close(reopen_fd); - return EXIT_FAILURE; - } else { - printf("Confirmed %s is inaccessible after removal (errno=%d).\n", loop_dev_path, errno); - } + // 打印测试汇总 + print_test_summary(); - return 0; -} \ No newline at end of file + return (g_tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} From 4137d56e0d7d9cb8b372c4f9f0dbc9a713e78164 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 11 Dec 2025 14:42:19 +0800 Subject: [PATCH 36/39] cargo fmt --- kernel/src/driver/block/loop_device/loop_device.rs | 2 +- kernel/src/driver/block/loop_device/mod.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/src/driver/block/loop_device/loop_device.rs b/kernel/src/driver/block/loop_device/loop_device.rs index a3bb242b2..1e6aacb6e 100644 --- a/kernel/src/driver/block/loop_device/loop_device.rs +++ b/kernel/src/driver/block/loop_device/loop_device.rs @@ -357,7 +357,7 @@ impl LoopDevice { if info.lo_sizelimit != 0 && !info.lo_sizelimit.is_multiple_of(LBA_SIZE as u64) { return Err(SystemError::EINVAL); } - if !LoopFlags::from_bits(info.lo_flags).is_some() { + if LoopFlags::from_bits(info.lo_flags).is_none() { return Err(SystemError::EINVAL); } Ok(()) diff --git a/kernel/src/driver/block/loop_device/mod.rs b/kernel/src/driver/block/loop_device/mod.rs index bd8e31a96..9dabe725d 100644 --- a/kernel/src/driver/block/loop_device/mod.rs +++ b/kernel/src/driver/block/loop_device/mod.rs @@ -14,6 +14,7 @@ mod constants; mod driver; mod loop_control; +#[allow(clippy::module_inception)] mod loop_device; mod manager; From a1c83a42ce2a905202cfea255e0b5bdb43e5e89e Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 11 Dec 2025 20:59:16 +0800 Subject: [PATCH 37/39] =?UTF-8?q?-=20fix=20=EF=BC=9A=E5=A2=9E=E5=A4=A7?= =?UTF-8?q?=E8=B6=85=E6=97=B6=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- user/apps/tests/syscall/gvisor/monitor_test_results.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/apps/tests/syscall/gvisor/monitor_test_results.sh b/user/apps/tests/syscall/gvisor/monitor_test_results.sh index 765c5e4c8..eecd941d3 100755 --- a/user/apps/tests/syscall/gvisor/monitor_test_results.sh +++ b/user/apps/tests/syscall/gvisor/monitor_test_results.sh @@ -9,7 +9,7 @@ BOOT_TIMEOUT=300 # DragonOS开机超时(5分钟) TEST_START_TIMEOUT=600 # 测试程序启动超时(10分钟) TEST_TIMEOUT=1800 # 整个测试超时(30分钟) IDLE_TIMEOUT=120 # 无输出超时(5分钟) -SINGLE_TEST_TIMEOUT=60 # 单个测试用例超时(1分钟) +SINGLE_TEST_TIMEOUT=120 # 单个测试用例超时(2分钟) # QEMU进程查找条件 QEMU_SEARCH_PATTERN=${QEMU_SEARCH_PATTERN:-"qemu-system-x86_64.*AUTO_TEST=syscall"} From 0d6beae2eec22ea4240ec253918f97e866a8c346 Mon Sep 17 00:00:00 2001 From: longjin Date: Wed, 17 Dec 2025 14:32:39 +0800 Subject: [PATCH 38/39] =?UTF-8?q?feat(ida):=20=E6=96=B0=E5=A2=9Ealloc=5Fsp?= =?UTF-8?q?ecific=E6=96=B9=E6=B3=95=E6=94=AF=E6=8C=81=E6=8C=89=E6=8C=87?= =?UTF-8?q?=E5=AE=9AID=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在IdAllocator中新增alloc_specific方法,允许按用户指定的ID进行分配 - 重构LoopManager,移除next_free_minor字段,简化minor号管理逻辑 - 修改设备查找和创建逻辑,直接使用ID作为minor号,提高代码简洁性 Signed-off-by: longjin --- kernel/crates/ida/src/lib.rs | 29 +++++++ .../src/driver/block/loop_device/manager.rs | 78 ++++++------------- 2 files changed, 54 insertions(+), 53 deletions(-) diff --git a/kernel/crates/ida/src/lib.rs b/kernel/crates/ida/src/lib.rs index 29c89e159..28149f864 100644 --- a/kernel/crates/ida/src/lib.rs +++ b/kernel/crates/ida/src/lib.rs @@ -105,6 +105,35 @@ impl IdAllocator { return None; } + /// 按指定的id分配(预占)一个id + /// + /// 主要用于“用户请求指定编号”的场景 + /// + /// ## 返回 + /// + /// - `Some(id)`: 分配成功 + /// - `None`: id 越界、已被占用或无可用 id + pub fn alloc_specific(&mut self, id: usize) -> Option { + if unlikely(self.available() == 0) { + return None; + } + + if id < self.min_id || id >= self.max_id { + return None; + } + + if self.exists(id) { + return None; + } + + self.xarray.store(id as u64, EmptyIdaItem); + self.used += 1; + + // 为了让后续的 alloc() 更均匀地分配,尽量从下一个位置开始搜索 + self.current_id = (id + 1).min(self.max_id.saturating_sub(1)); + Some(id) + } + /// 检查id是否存在 /// /// ## 参数 diff --git a/kernel/src/driver/block/loop_device/manager.rs b/kernel/src/driver/block/loop_device/manager.rs index bb2420e15..c48aa8361 100644 --- a/kernel/src/driver/block/loop_device/manager.rs +++ b/kernel/src/driver/block/loop_device/manager.rs @@ -24,7 +24,6 @@ pub struct LoopManager { pub struct LoopManagerInner { devices: [Option>; LoopManager::MAX_DEVICES], id_alloc: IdAllocator, - next_free_minor: u32, } impl LoopManager { @@ -39,7 +38,6 @@ impl LoopManager { devices: [const { None }; Self::MAX_DEVICES], id_alloc: IdAllocator::new(0, Self::MAX_DEVICES) .expect("create IdAllocator failed"), - next_free_minor: 0, }), } } @@ -53,6 +51,11 @@ impl LoopManager { inner.id_alloc.alloc() } + #[inline] + fn alloc_specific_id_locked(inner: &mut LoopManagerInner, id: usize) -> Option { + inner.id_alloc.alloc_specific(id) + } + #[inline] fn free_id_locked(inner: &mut LoopManagerInner, id: usize) { if id < Self::MAX_DEVICES && inner.id_alloc.exists(id) { @@ -69,30 +72,10 @@ impl LoopManager { inner: &LoopManagerInner, minor: u32, ) -> Option> { - inner - .devices - .iter() - .flatten() - .find(|device| device.minor() == minor) - .map(Arc::clone) - } - - fn find_unused_minor_locked(inner: &LoopManagerInner) -> Option { - let mut candidate = inner.next_free_minor; - for _ in 0..Self::MAX_DEVICES as u32 { - let mut used = false; - for dev in inner.devices.iter().flatten() { - if dev.minor() == candidate { - used = true; - break; - } - } - if !used { - return Some(candidate); - } - candidate = (candidate + 1) % Self::MAX_DEVICES as u32; + if minor >= Self::MAX_DEVICES as u32 { + return None; } - None + inner.devices[minor as usize].clone() } /// # 功能 @@ -142,8 +125,9 @@ impl LoopManager { return Ok(device); } - let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; - match self.create_and_register_device_locked(inner, id, minor) { + let id = + Self::alloc_specific_id_locked(inner, minor as usize).ok_or(SystemError::ENOSPC)?; + match self.create_and_register_device_locked(inner, id) { Ok(device) => Ok(device), Err(e) => { Self::free_id_locked(inner, id); @@ -166,14 +150,7 @@ impl LoopManager { } let id = Self::alloc_id_locked(inner).ok_or(SystemError::ENOSPC)?; - let minor = match Self::find_unused_minor_locked(inner) { - Some(minor) => minor, - None => { - Self::free_id_locked(inner, id); - return Err(SystemError::ENOSPC); - } - }; - let result = self.create_and_register_device_locked(inner, id, minor); + let result = self.create_and_register_device_locked(inner, id); if result.is_err() { Self::free_id_locked(inner, id); } @@ -184,12 +161,12 @@ impl LoopManager { &self, inner: &mut LoopManagerInner, id: usize, - minor: u32, ) -> Result, SystemError> { - if minor >= Self::MAX_DEVICES as u32 { + if id >= Self::MAX_DEVICES { return Err(SystemError::EINVAL); } - let devname = Self::format_name(minor as usize); + let minor = id as u32; + let devname = Self::format_name(id); let loop_dev = LoopDevice::new_empty_loop_device(devname, id, minor).ok_or(SystemError::ENOMEM)?; @@ -203,7 +180,6 @@ impl LoopManager { } inner.devices[id] = Some(loop_dev.clone()); - inner.next_free_minor = (minor + 1) % Self::MAX_DEVICES as u32; log::info!( "Loop device id {} (minor {}) added successfully.", id, @@ -254,9 +230,8 @@ impl LoopManager { { let mut inner = self.inner(); - inner.devices[id] = None; - Self::free_id_locked(&mut inner, id); - inner.next_free_minor = minor; + inner.devices[minor as usize] = None; + Self::free_id_locked(&mut inner, minor as usize); } info!( "Loop device id {} (minor {}) removed successfully.", @@ -267,16 +242,12 @@ impl LoopManager { pub fn find_free_minor(&self) -> Option { let inner = self.inner(); - 'outer: for minor in 0..Self::MAX_DEVICES as u32 { - for dev in inner.devices.iter().flatten() { - if dev.minor() == minor { - if !dev.is_bound() { - return Some(minor); - } - continue 'outer; - } + for minor in 0..Self::MAX_DEVICES as u32 { + match &inner.devices[minor as usize] { + Some(dev) if !dev.is_bound() => return Some(minor), + Some(_) => continue, + None => return Some(minor), } - return Some(minor); } None } @@ -288,8 +259,9 @@ impl LoopManager { if Self::find_device_by_minor_locked(&inner, minor_u32).is_some() { continue; } - let id = Self::alloc_id_locked(&mut inner).ok_or(SystemError::ENOSPC)?; - if let Err(e) = self.create_and_register_device_locked(&mut inner, id, minor_u32) { + let id = + Self::alloc_specific_id_locked(&mut inner, minor).ok_or(SystemError::ENOSPC)?; + if let Err(e) = self.create_and_register_device_locked(&mut inner, id) { Self::free_id_locked(&mut inner, id); return Err(e); } From c9dc564d93ccf12f4cb9f14d3bb502f029ed1d98 Mon Sep 17 00:00:00 2001 From: longjin Date: Wed, 17 Dec 2025 20:08:52 +0800 Subject: [PATCH 39/39] 1 --- user/apps/tests/syscall/gvisor/monitor_test_results.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user/apps/tests/syscall/gvisor/monitor_test_results.sh b/user/apps/tests/syscall/gvisor/monitor_test_results.sh index eecd941d3..765c5e4c8 100755 --- a/user/apps/tests/syscall/gvisor/monitor_test_results.sh +++ b/user/apps/tests/syscall/gvisor/monitor_test_results.sh @@ -9,7 +9,7 @@ BOOT_TIMEOUT=300 # DragonOS开机超时(5分钟) TEST_START_TIMEOUT=600 # 测试程序启动超时(10分钟) TEST_TIMEOUT=1800 # 整个测试超时(30分钟) IDLE_TIMEOUT=120 # 无输出超时(5分钟) -SINGLE_TEST_TIMEOUT=120 # 单个测试用例超时(2分钟) +SINGLE_TEST_TIMEOUT=60 # 单个测试用例超时(1分钟) # QEMU进程查找条件 QEMU_SEARCH_PATTERN=${QEMU_SEARCH_PATTERN:-"qemu-system-x86_64.*AUTO_TEST=syscall"}