fix(repo): migrate spin usage to ax-kspin#861
Conversation
fa7af28 to
9064a1f
Compare
There was a problem hiding this comment.
Review 总结
本 PR 完成了将仓库内 spin::Mutex 用法迁移到 ax_kspin::SpinNoIrq 的工作,同时将外部 spin crate vendor 到 components/spin/ 以保留 RwLock/Once/Lazy 等尚不需要迁移的原语,并通过 [patch.crates-io] 替换构建图中的外部版本。
变更范围(128 个文件,+6859 / -281)
- 供应链解耦:vendor
spin 0.10.0,移除spin 0.9.8,统一为本地版本;默认 feature 精简为rwlock/once/lazy,不再暴露Mutex。 spin::Mutex → ax_kspin::SpinNoIrq:覆盖 VFS 层(axfs-ng-vfs)、ArceOS 文件系统模块(axfsFAT/ext4)、网络模块(axnet-ngraw/unix)、设备层(arm_vgic/riscv_vplic/dma-api/axdevice)、Axvisor 全局锁、axplat-dyn驱动、各类 USB/NVMe/串口/SoC 驱动。SpinNoPreempt → SpinNoIrq:epoll ready queue/interests、loop device cache、StarryOS timer/netlink/usbfs/camera 锁,修正了 IRQ 未禁用时的同 CPU 重入死锁风险。lazy_static → spin::Lazy:netlink socket 注册表、unix abstract bind、PWM sysfs state、axvisor shell command tree、axnet-ng unix socket 等。- USBFS 睡眠安全:将
LiveDeviceState::device和UsbFsManager::open_lock从 spin lock 改为ax_sync::Mutex(可睡眠),避免在 spin lock 保护区内调用可能阻塞的 USB 操作。 - Lockdep 测试:新增
vfs-cache-single测试用例,验证axfs-ng-vfsdentry user_data/cache 的 ABBA 检测。 - 审计文档:
reports/external-spin-audit.md、reports/external-spin-migration-plan.md、reports/spin-no-preempt-audit.md详细记录了当前状态和后续迁移策略。
验证
cargo fmt --check✅cargo clippy --package {axdevice,dma-api,axfs-ng-vfs,rsext4,spin}全部通过,无 warning ✅- CI 状态:pending(无已完成的 check),本地已做针对性的 clippy 验证
重复/重叠分析
- 搜索了所有 open PR(#868 socket syscall 测试、#853 procfs/procps、#831 等),均与本 PR 的 spin 迁移无重叠。
- base 分支上已无未被迁移的
spin::Mutex直接使用(仅剩spin::RwLock/Once/Lazy按计划保留)。
评估
整体变更方向正确:
- 将 Mutex 类锁迁移到
ax_kspin::SpinNoIrq解决了 lockdep 盲区和 IRQ 重入问题。 - USBFS 中 spin →
ax_sync::Mutex的变更是合理的,因为 USB 操作可能睡眠/等待事件。 - epoll
ready_queue注释已明确指出VecDeque::push_back可能在 IRQ 上下文中分配的 follow-up。 - Unix socket
with_slot/with_slot_or_insert中的 SpinNoIrq guard drop-before-transport 逻辑正确避免了嵌套锁问题。
未发现阻塞性问题,予以批准。 后续建议关注 audit 中列出的中长期锁策略优化。
Powered by glm-5.1
| if interest.try_mark_in_queue() { | ||
| // The queue lock must disable IRQs because wakers may be invoked | ||
| // from IRQ wake paths. `VecDeque::push_back` can still allocate | ||
| // when capacity is exhausted; if this path is proven to run in IRQ |
There was a problem hiding this comment.
这个注释清楚地标记了 VecDeque::push_back 在 IRQ 上下文可能分配的风险。后续如果确认 waker 会从硬中断上下文调用,建议替换为 bounded ring buffer 或 deferred work 设计。当前的 conservative SpinNoIrq 是正确的短期修复。
| .ok_or(AxError::ConnectionRefused)? | ||
| .as_ref()) | ||
| let slot = { | ||
| // `DirEntry::user_data()` is protected by a SpinNoIrq guard. |
There was a problem hiding this comment.
好的做法——先 clone BindSlot 的 Arc 引用再释放 user_data() 的 SpinNoIrq guard,避免了在 spin lock 保护区内调用可能睡眠的 socket transport 代码。
fc89bff to
d14e327
Compare
There was a problem hiding this comment.
Review 总结
本 PR 完成了将仓库内 spin::Mutex 用法迁移到 ax_kspin::SpinNoIrq 的工作,同时将外部 spin crate vendor 到 components/spin/ 以保留 RwLock/Once/Lazy 等尚不需要迁移的原语,并通过 [patch.crates-io] 替换构建图中的外部版本。
变更范围(128 个文件,+6815 / -225)
- 供应链解耦:vendor
spin 0.10.0到本地,移除spin 0.9.8双版本共存;默认 feature 精简为rwlock/once/lazy,不再暴露Mutex。 spin::Mutex → ax_kspin::SpinNoIrq:覆盖 VFS 层、ArceOS 文件系统模块、网络模块、设备层、Axvisor 全局锁、驱动层等所有 lockdep 相关锁。SpinNoPreempt → SpinNoIrq:epoll ready_queue/interests、loop device cache、StarryOS timer/netlink/usbfs/camera 锁,修正了 IRQ 未禁用时的同 CPU 重入死锁风险。lazy_static → spin::Lazy:netlink socket 注册表、unix abstract bind、timer alarm_list、axvisor shell command tree 等。- USBFS 睡眠安全:
LiveDeviceState::device和UsbFsManager::open_lock从 spin lock 改为ax_sync::Mutex(可睡眠),避免在 spin lock 保护区内调用可能阻塞的 USB 操作。 - Netlink
read_one改进:先pop_front再write,避免在持锁期间进行用户态拷贝。 - Lockdep 测试:新增
vfs-cache-single测试用例,验证axfs-ng-vfsdentry user_data/cache 的 ABBA 检测。 - 审计文档:三份详细的审计和迁移计划文档,记录了当前状态和后续迁移策略。
验证
- 所有
spin::Mutex直接使用已从源码中移除(仅剩spin::RwLock/Once/Lazy,按计划保留)。 SpinNoPreempt使用也已全部迁移到SpinNoIrq。- Vendored spin 的
Cargo.toml正确配置了[patch.crates-io]和精简的默认 feature。 - Unix socket 的 SpinNoIrq guard 提前释放逻辑正确,避免了在 spin lock 内调用可睡眠的 transport 代码。
评估
整体变更方向正确、执行到位:
- 将 Mutex 类锁迁移到
ax_kspin::SpinNoIrq解决了 lockdep 盲区和 IRQ 重入问题。 - USBFS 中 spin →
ax_sync::Mutex的变更是合理的。 - Unix socket
with_slot/with_slot_or_insert中的 guard drop-before-transport 逻辑正确。 - epoll
ready_queue注释已明确指出VecDeque::push_back在 IRQ 上下文中可能的分配风险。 - FAT/ext4 的 lock 注释正确说明了短期使用
SpinNoIrq的原因和后续优化方向。 - 三份审计报告详尽记录了决策过程和后续计划,方便后续维护。
未发现阻塞性问题,予以批准。 后续建议关注 audit 中列出的中长期锁策略优化。
Powered by glm-5.1
| // Cap at the message length; netlink datagrams are not coalesced. | ||
| let n = dst.write(msg)?; | ||
| queue.pop_front(); | ||
| let n = dst.write(&msg)?; |
There was a problem hiding this comment.
好的改动。pop_front 先取出消息再释放锁,然后在锁外进行 dst.write(),避免了在持自旋锁期间进行用户态内存拷贝。
| /// current rootfs setup can also run in early atomic contexts where a | ||
| /// blocking mutex trips `might_sleep()`, so use `SpinNoIrq` instead of the | ||
| /// older `SpinNoPreempt` to close same-CPU IRQ reentry without changing the | ||
| /// boot-time calling contract. |
There was a problem hiding this comment.
注释清楚地记录了设计选择和权衡:短期内使用 SpinNoIrq 关闭 IRQ 重入,后续需要缩短临界区或改为阻塞锁。类似的注释也出现在 rsext4/fs.rs 和 lwext4/fs.rs,保持了一致性。
| # Enables `SpinMutex` and the default spin mutex implementation for `Mutex`. | ||
| spin_mutex = ["mutex"] | ||
|
|
||
| # Enables `TicketMutex`. |
There was a problem hiding this comment.
vendor 的 spin crate 默认 feature 精简得当——只保留 rwlock、once、lazy,移除了 mutex。配合根 Cargo.toml 的 [patch.crates-io] 确保整个 workspace 统一使用本地版本。
buddy-slab-allocator depends on spin::Mutex but the mutex feature was removed from spin's default features. Enable it to maintain compatibility with external crates.
There was a problem hiding this comment.
Review 总结
本 PR 将仓库内所有 spin::Mutex 直接使用迁移到 ax_kspin::SpinNoIrq,同时将外部 spin crate vendor 到 components/spin/ 以保留 RwLock/Once/Lazy,并通过 [patch.crates-io] 统一构建图。共 128 文件,43 个 commit,+6861 / -281。
变更分类
- 供应链解耦:vendor
spin 0.10.0,移除spin 0.9.8双版本,默认 feature 精简为rwlock/once/lazy/mutex(mutex 保留给buddy-slab-allocator等外部 crate)。 spin::Mutex → ax_kspin::SpinNoIrq:覆盖 VFS、FAT/ext4 文件系统、网络模块、设备层(arm_vgic/riscv_vplic/dma-api/axdevice)、Axvisor、驱动层等全部 lockdep 相关锁。SpinNoPreempt → SpinNoIrq:epoll、loop device cache、timer、netlink、usbfs、camera、pty/terminal 锁,修正 IRQ 重入死锁风险。lazy_static → spin::Lazy:netlink socket 注册表、unix abstract bind、timer alarm_list、PWM sysfs、axvisor shell command tree 等。- USBFS 睡眠安全:
LiveDeviceState::device和UsbFsManager::open_lock从 spin lock 改为ax_sync::Mutex(可睡眠),避免 spin lock 内调用可能阻塞的 USB 操作。 - 锁作用域优化:netlink
read_one和 packet socket 先取出数据再释放锁,避免 spin lock 内进行用户态拷贝。 - tmpfs 锁变更:目录 entries 从
ax_sync::Mutex改为SpinNoIrq,因 VFS dentry-cache 操作在 SpinNoIrq 保护下回调后端。 - Lockdep 测试:新增
vfs-cache-single用例,验证 axfs-ng-vfs dentry user_data/cache 的 ABBA 检测。 - axbuild 特性规范化:std 构建时自动将特性映射到
arceos-rust/前缀,支持lockdep等新特性。 - 审计文档:三份报告详细记录了当前 spin 使用状况和后续迁移策略。
验证
- 本地
cargo fmt --check通过 - 源码扫描确认无残留
spin::Mutex直接使用(仅剩spin::RwLock/Once/Lazy,按计划保留) SpinNoPreempt直接使用也已全部迁移(仅出现在注释中)- vendored spin 的
[patch.crates-io]配置正确 - lockdep test 新增用例的
build-vfs-cache-x86_64-unknown-none.toml配置完整
已知权衡(非阻塞)
- tmpfs
HashMap和 epollVecDeque在SpinNoIrq下可触发分配,已在注释和 audit 文档中标为后续优化项 - tmpfs 移除了 lockdep subclass 注释(
lock_tmpfs_nested),因 VFS 层 SpinNoIrq 回调使阻塞 mutex 不可行;lockdep false positive 风险可接受 - FAT/ext4 大锁改为
SpinNoIrq是短期方案,后续需缩短临界区或改为阻塞锁
重复/重叠分析
搜索了当前所有 open PR,未发现与 spin 迁移重叠的 PR。base 分支上已无未迁移的 spin::Mutex 直接使用。
评估
变更方向正确,执行到位,权衡均有记录。未发现阻塞性问题,予以批准。
Powered by glm-5.1
| nested_dir_entries: bool, | ||
| ) -> Arc<Inode> { | ||
| let mut inodes = fs.inodes.lock(); | ||
| let entry = inodes.vacant_entry(); |
There was a problem hiding this comment.
好的做法:tmpfs entries 从 ax_sync::Mutex 改为 SpinNoIrq 是必要的,因为 VFS dentry-cache 操作在 SpinNoIrq 保护下回调后端,使用阻塞 mutex 会死锁。
需要注意的是 HashMap::insert 在容量不足时会分配内存,此时 IRQ 被禁用。如果 tmpfs 目录条目数量可能很大,后续可考虑预分配容量或改用固定大小数据结构。当前对于典型 OS 使用场景是可接受的。
| .unwrap_or_else(|| normalized.clone()), | ||
| feature if feature.starts_with("arceos-rust/") => normalized, | ||
| feature => format!("arceos-rust/{feature}"), | ||
| } |
There was a problem hiding this comment.
lockdep 特性正确地透传到了 arceos-rust。axbuild 的 normalize_std_feature 将裸特性名(如 lockdep)映射为 arceos-rust/lockdep,确保 std 构建时特性能正确传递到最终的用户 crate。测试覆盖了 ax-std/、arceos-rust/ 和裸特性名三种情况。
| @@ -258,6 +431,7 @@ fn run_case(case: &str) { | |||
| "mixed-two-task" => mixed_two_task_abba(), | |||
There was a problem hiding this comment.
VFS 层的 lockdep 测试用例设计良好:通过 user_data() 获取 SpinNoIrq guard,然后在 guard 持有期间调用 lookup(也会获取 SpinNoIrq guard),形成 dentry user_data → dir cache 的锁序。后续的 rename 操作反过来获取 cache → user_data,触发 ABBA 检测。
这验证了 ax-kspin lockdep 对 VFS 层嵌套锁的可见性。
Background
The repository had multiple direct usages of the external
spin/lazy_staticlocking primitives. SomeSpinNoPreemptusageswere in contexts where IRQs were not disabled, which could lead to interrupt reentry deadlocks or lockdep/might_sleep failures.
Changes
spincrate into the repository as a controlled local dependency.ax-kspinlock types.spin::Mutexby default to reduce accidental future misuse.contexts.
axaddrspace.spinandSpinNoPreemptusage, including handled cases and follow-up locking design notes.Notes
Some
Mutex -> SpinNoIrqchanges are conservative short-term fixes intended to remove current runtime hazards. Longer term, somecall paths should be revisited by narrowing lock ranges, restructuring call flows, and returning to blocking mutexes where
appropriate.