[dfs][posix] Extend Smart POSIX filesystem and syscall compatibility - #11732
[dfs][posix] Extend Smart POSIX filesystem and syscall compatibility#11732BernardXiong wants to merge 8 commits into
Conversation
为 DFS v2 增加 POSIX 记录锁、fchmod,以及 tmpfs 的权限和时间元数据。 进程退出时通过 dfs_fdtable_drop_fd 释放文件描述符和记录锁。
补齐 procfs 中 cpuinfo、stat、uptime、loadavg、meminfo、mounts 和进程目录文件。 按架构和 SMP 配置隔离仅在对应平台有效的字段,避免非 AArch64/非 SMP 构建告警。
修复 epoll waiter 生命周期,避免等待队列节点在回调后失效。 整理 LWP POSIX syscall 的用户空间拷贝和错误返回路径。
将 VirtIO Net 的依赖从 RT_USING_ETHERNET 调整为 RT_USING_LWIP。 避免 SMART QEMU 在未启用以太网抽象时无法选择网卡。
|
👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread! 为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。 🛠 操作步骤 | Steps
完成后,提交将自动更新至 如有问题欢迎联系我们,再次感谢您的贡献!💐 |
📌 Code Review Assignment🏷️ Tag: componentsReviewers: @Maihuanyi Changed Files (Click to expand)
🏷️ Tag: components_libcReviewers: @GorrayLi @mysterywolf Changed Files (Click to expand)
🏷️ Tag: components_lwpReviewers: @xu18838022837 Changed Files (Click to expand)
📊 Current Review Status (Last Updated: 2026-08-23 10:14 CST)
📝 Review Instructions
|
|
There was a problem hiding this comment.
Pull request overview
English: This PR improves RT-Smart POSIX compatibility across DFSv2, tmpfs, procfs, epoll, and LWP syscalls to better support Linux-compatible user-space applications on RT-Thread.
中文:本 PR 面向 RT-Smart 用户态应用的 Linux/POSIX 兼容需求,对 DFSv2、tmpfs、procfs、epoll 以及 LWP syscall 行为进行了补全与对齐。
Changes / 变更点:
- Add DFSv2 POSIX advisory record locking +
fchmod()support, including lock cleanup on close/dup paths.
增加 DFSv2 POSIX 建议锁(record locking)与fchmod()支持,并在 close/dup 等路径做锁清理。 - Improve tmpfs metadata semantics (mode/link count) and add path component length validation with utests.
完善 tmpfs 元数据语义(mode/nlink),并增加路径分量长度校验与单元测试覆盖。 - Provide richer Linux-style procfs data and improve epoll waiter tracking + LWP socket syscall user-buffer handling.
增强 procfs 的 Linux 风格数据输出,并改进 epoll 等待队列跟踪及 LWP socket syscall 的用户缓冲区处理。
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| components/lwp/lwp_syscall.c | LWP syscalls: adjust read behavior for zero-length and add ioctl flock copy-in/out; refine send/recv msg error handling / LWP 系统调用兼容性补全 |
| components/lwp/lwp_pid.c | Use dfs_fdtable_drop_fd() for file cleanup on exit / 退出时 FD 清理路径统一 |
| components/libc/posix/io/epoll/epoll.c | Track epoll waiters per wqueue and update polling thread / epoll 等待节点管理改进 |
| components/drivers/virtio/Kconfig | Fix VirtIO Net dependency to RT_USING_LWIP / 修正 VirtIO 网卡依赖 |
| components/dfs/dfs_v2/src/dfs.c | Initialize record-lock subsystem during DFS init / DFS 初始化增加记录锁初始化 |
| components/dfs/dfs_v2/src/dfs_vnode.c | Initialize vnode nlink / vnode 增加 nlink 初值 |
| components/dfs/dfs_v2/src/dfs_record_lock.c | New DFSv2 POSIX advisory record lock implementation / 新增 POSIX 建议锁实现 |
| components/dfs/dfs_v2/src/dfs_posix.c | Use fdtable drop on close, add fchmod, adjust fcntl handling / POSIX 接口增强 |
| components/dfs/dfs_v2/src/dfs_file.c | Map permission errors to -EACCES, add fsetattr, expose nlink fallback, implement record lock fcntl / DFS 文件层增强 |
| components/dfs/dfs_v2/include/dfs_file.h | Add prototypes for fsetattr + record lock APIs / 新增接口声明 |
| components/dfs/dfs_v2/filesystems/tmpfs/utest/tmpfs.c | Add tmpfs tests: long names, ENAMETOOLONG reject, fchmod/mode change / tmpfs 测试增强 |
| components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h | Expand tmpfs NAME_MAX and store mode/nlink / tmpfs 元数据扩展 |
| components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c | Validate path lengths; preserve mode/nlink; implement setattr; strengthen rename/unlink behavior / tmpfs 行为对齐与健壮性提升 |
| components/dfs/dfs_v2/filesystems/procfs/proc_uptime.c | Linux-like uptime/idle formatting with SMP handling / uptime 输出兼容增强 |
| components/dfs/dfs_v2/filesystems/procfs/proc_stat.c | Add process counts (Smart) and improve formatting / stat 输出增强 |
| components/dfs/dfs_v2/filesystems/procfs/proc_pid.c | Add /proc/<pid>/{status,statm,maps,smaps} and safer PID-based lookups / proc pid 目录与内容扩展 |
| components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c | Escape mount strings and use ro/rw flags / mounts 输出更贴近 Linux |
| components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c | Expand meminfo fields and normalize kB formatting / meminfo 输出扩展 |
| components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c | Smart-aware runnable/total process reporting / loadavg 输出增强 |
| components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c | Provide per-CPU entries with arch-specific details / cpuinfo 输出增强 |
Suppressed comments (1)
components/dfs/dfs_v2/src/dfs_posix.c:394
- [bug]:
write()returns the wrong errno whenbuf == NULL.
English: buf being NULL should report -EFAULT (bad address). Using -EBADF makes callers mis-handle the error and diverges from Linux/POSIX.
中文:buf 为 NULL 应返回 -EFAULT(非法地址)。使用 -EBADF 会导致调用方误判错误原因,且与 Linux/POSIX 行为不一致。
if (buf == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (buf == NULL) | ||
| { | ||
| rt_set_errno(-EBADF); | ||
| return -1; | ||
| } |
There was a problem hiding this comment.
Fixed: read()/write() now set -EFAULT when buf == NULL.
| fd = open(path, O_CREAT | O_RDWR, 0); | ||
| uassert_int_equal(fd, -1); | ||
|
|
There was a problem hiding this comment.
Fixed: the too-long-name open() path now also asserts errno == -ENAMETOOLONG.
| address = entry->start; | ||
| end = entry->end; | ||
| while (address < end) | ||
| { | ||
| if (rt_hw_mmu_v2p(varea->aspace, (void *)address) != ARCH_MAP_FAILED) | ||
| { | ||
| entry->resident_pages++; | ||
| } | ||
| address += ARCH_PAGE_SIZE; | ||
| } |
There was a problem hiding this comment.
Fixed: proc_map_collect() only walks pages when generating smaps/RSS; /proc/<pid>/maps no longer does an O(pages) scan.
| waiter = (struct rt_epoll_waiter *)rt_calloc(1, sizeof(*waiter)); | ||
| if (waiter == RT_NULL) | ||
| { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Fixed: waiter allocation failure now marks the fd with POLLERR and wakes epoll_wait() instead of silently dropping the watch.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated 12 comments.
Suppressed comments (1)
components/libc/posix/io/epoll/epoll.c:309
- [Operational Implications/运行影响]: Allocation failure silently drops event registration / 分配失败会静默丢失事件注册
English: If this per-queue allocation fails, the poll callback returns without registering a waiter or reporting an error. epoll_wait() can then sleep until timeout even when the watched descriptor becomes ready. Preallocate the waiter or propagate a registration failure so the wait does not block on an incomplete watch set.
中文:如果此逐队列分配失败,poll 回调会直接返回,既不注册等待节点也不报告错误。随后即使被监控描述符就绪,epoll_wait() 也可能一直睡眠到超时。请预分配等待节点,或向上传递注册失败,避免在不完整的监控集合上阻塞。
waiter = (struct rt_epoll_waiter *)rt_calloc(1, sizeof(*waiter));
if (waiter == RT_NULL)
{
return;
| RT_IPC_FLAG_FIFO); | ||
| } | ||
|
|
||
| int dfs_record_lock_fcntl(struct dfs_file *file, int cmd, struct flock *flock) |
There was a problem hiding this comment.
Added tmpfs-backed record-lock utest covering positive/negative l_len, overlapping GETLK conflicts, interrupted F_SETLKW, split/merge, and close/dup2 release.
| if (attr->ia_valid & ATTR_MODE_SET) | ||
| { | ||
| mode_t permissions = attr->st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); | ||
|
|
||
| rt_spin_lock(&superblock->lock); | ||
| d_file->mode = (d_file->mode & S_IFMT) | permissions; |
There was a problem hiding this comment.
Fixed: tmpfs chmod/fchmod now keep S_ISUID|S_ISGID|S_ISVTX while preserving the existing file-type bits.
| superblock = (struct tmpfs_sb *)dentry->mnt->data; | ||
| d_file = dfs_tmpfs_lookup(superblock, dentry->pathname, &size); | ||
| if (d_file == RT_NULL) | ||
| { | ||
| st->st_mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO); | ||
| return -ENOENT; |
There was a problem hiding this comment.
Fixed: setattr/stat now use the vnode-backed tmpfs object, so fchmod() continues to work after unlink.
| if (context->count >= PROC_MAP_MAX || !varea || varea->size == 0) | ||
| { | ||
| return 0; |
There was a problem hiding this comment.
Fixed: maps/smaps storage grows from the actual VMA count instead of a silent 256-entry cap.
| state = lwp->terminated ? 'Z' : 'S'; | ||
| dfs_seq_printf(seq, "Name:\t%s\n", lwp->cmd); | ||
| dfs_seq_printf(seq, "State:\t%c (sleeping)\n", state); |
There was a problem hiding this comment.
Fixed: /proc/<pid>/status now derives both the state code and description from the thread/process state.
| dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemMaxUsed:", (unsigned long)(max_used / 1024)); | ||
| dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemAvailable:", (unsigned long)((total - used) / 1024)); |
There was a problem hiding this comment.
Fixed: MemAvailable is emitted after page-pool free pages are included, matching MemFree.
| lwp_pid_for_each(loadavg_count_pid, &count); | ||
| dfs_seq_printf(seq, "0.00 0.00 0.00 %d/%d 0\n", count.runnable, count.total); | ||
| #else | ||
| dfs_seq_puts(seq, "0.00 0.00 0.00 0/0 0\n"); |
There was a problem hiding this comment.
Fixed: /proc/loadavg now maintains 1/5/15-minute averages and reports the last created PID.
| struct stat_process_count process_count = { 0, 0 }; | ||
| lwp_pid_for_each(stat_process_count, &process_count); | ||
| dfs_seq_printf(seq, "processes %d\n", process_count.total); | ||
| dfs_seq_printf(seq, "procs_running %d\n", process_count.running); |
There was a problem hiding this comment.
Fixed: /proc/stat processes now uses a cumulative LWP create counter.
| #elif defined(__riscv) | ||
| dfs_seq_puts(seq, "model name\t: RISC-V Generic\n"); | ||
| dfs_seq_puts(seq, "isa\t\t: rv64\n"); | ||
| #else |
There was a problem hiding this comment.
Fixed: RISC-V cpuinfo uses __riscv_xlen to report rv32 or rv64.
| return; | ||
| } | ||
|
|
||
| while (*cursor != '\0' && offset + 4 < target_size) |
There was a problem hiding this comment.
Fixed: mount-path escaping now reserves 1 or 4 bytes per character instead of always 4.
NULL read/write buffers now return -EFAULT. tmpfs setattr uses the vnode-backed object after unlink, keeps S_ISUID/S_ISGID/S_ISVTX, and the tmpfs utest checks ENAMETOOLONG plus post-unlink fchmod.
If waiter allocation fails, mark the fd with POLLERR and wake epoll_wait() instead of silently dropping the watch.
Grow maps without a 256 VMA cap, skip RSS walks for maps, report matching status text, real RSS/statm, MemAvailable after page-pool free pages, load averages plus last PID, cumulative processes, RV32 cpuinfo, and per-character mount escaping.
Cover positive/negative l_len, overlapping GETLK conflicts, interrupted F_SETLKW, split/merge, and close/dup2 lock release on tmpfs.
|
Addressed the Copilot review comments in follow-up commits:
Local QEMU SMART ( |
为什么提交这份PR (why to submit this PR)
RT-Smart user-space applications require more complete POSIX filesystem, procfs, locking, and syscall behavior. DFS v2 still lacks several interfaces and compatibility details required by Linux-compatible user-space components.
This PR extends Smart POSIX compatibility on current upstream master. musl libc enablement remains toolchain-driven through
GetMuslVersion(rtconfig)incomponents/libc/compilers/musl/SConscript. CI workflow, Smart test configs, and QEMU attachconfig files are unchanged.你的解决方案是什么 (what is your solution)
fchmod()support to DFS v2, including lock cleanup on descriptor close and replacement.RT_USING_LWIP.请提供验证的bsp和config (provide the config and bsp)
bsp/qemu-vexpress-a9RT_USING_SMART,RT_USING_MEMHEAP,RT_USING_DFS_V2,RT_USING_DFS_PROCFS,RT_USING_DFS_TMPFSsconswitharm-none-eabidefault config passed; QEMU reachedmsh />.arm-linux-musleabipassed (GetMuslVersionselected musl libc). QEMU Smart kernel reachedmsh />. Aftermount none /proc procfsandmount none /tmp tmp,/proc/{version,uptime,meminfo,stat,cpuinfo,loadavg,mounts}and tmpfsecho/cat/chmodworked.当前拉取/合并请求的状态 Intent for your PR
必须选择一项 Choose one (Mandatory):
代码质量 Code Quality:
我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:
#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up