Skip to content

Commit 2d48f12

Browse files
authored
feat(pipe): 修复&完善pipe的行为,并且在procfs新增fd相关支持。 (#1426)
* feat(pipe): 改进管道实现,支持命名管道和符合POSIX的行为 - 新增管道文件系统(PipeFS)并注册PIPEFS_MAGIC - 扩展管道缓冲区至65536字节,支持原子写入 - 实现命名管道(FIFO)支持,允许O_RDWR模式打开 - 改进fcntl的F_SETFL实现,仅允许修改特定标志位 - 修复写入只读文件描述符的错误码为EBADF - 为命名管道自动添加O_LARGEFILE标志 - 优化管道读写逻辑,支持循环写入和部分写入 Signed-off-by: longjin <[email protected]> * fix(vfs): 在preadv/pwrite64/pwritev系统调用中增加对管道、Socket和字符设备的ESPIPE错误检查 Signed-off-by: longjin <[email protected]> * feat(vfs): 为fcntl系统调用添加管道缓冲区大小查询功能 - 实现F_GETPIPE_SZ和F_SETPIPE_SZ命令,支持获取和设置管道缓冲区大小 - 优化管道关闭逻辑,避免潜在死锁问题 - 公开PIPE_BUFF_SIZE常量供系统调用使用 Signed-off-by: longjin <[email protected]> * feat(procfs): 支持/proc/self/fd/N魔法链接并实现管道FIONREAD - 为procfs的InodeInfo添加target_inode字段,用于存储魔法链接的原始文件inode - 实现IndexNode::special_node方法,使/proc/self/fd/N能返回原始文件的引用 - 在VFS中处理SpecialNodeData::Reference,支持魔法链接的路径解析 - 为管道文件实现ioctl的FIONREAD命令,获取可读字节数 Signed-off-by: longjin <[email protected]> * feat(procfs): 添加/proc/<pid>/fdinfo目录支持并实现管道缓冲区动态调整 - 新增ProcFdInfoDir和ProcFdInfoFile枚举类型,支持/proc/<pid>/fdinfo目录和文件 - 实现fdinfo目录的动态查找和列表功能,与fd目录共享文件描述符列表逻辑 - 重构fcntl系统调用,支持F_GETPIPE_SZ和F_SETPIPE_SZ命令的动态管道缓冲区管理 - 修改管道实现,使用动态分配的Vec缓冲区替代固定大小数组,支持运行时调整大小 - 添加管道缓冲区大小验证和迁移逻辑,确保数据完整性 Signed-off-by: longjin <[email protected]> * feat(filesystem): 提升文件描述符表最大容量并优化分配策略 - 将文件描述符表最大容量从65536提升至1048576 - 优化文件描述符分配算法,支持动态扩容 - 更新进程资源限制以匹配新的最大容量 Signed-off-by: longjin <[email protected]> * perf(pipe): 实现管道缓冲区延迟分配以优化内存使用 - 修改管道缓冲区初始化逻辑,从立即分配改为首次写入时分配 - 优化缓冲区大小调整逻辑,避免不必要的内存分配 - 更新管道元数据返回逻辑,移除冗余计算 - 添加管道测试黑名单文件以排除已知卡死问题 Signed-off-by: longjin <[email protected]> * perf(filesystem): 优化文件描述符分配性能 Signed-off-by: longjin <[email protected]> --------- Signed-off-by: longjin <[email protected]>
1 parent c0122b5 commit 2d48f12

File tree

12 files changed

+622
-105
lines changed

12 files changed

+622
-105
lines changed

kernel/src/filesystem/procfs/mod.rs

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ pub enum ProcFileType {
7171
ProcSelf,
7272
ProcFdDir,
7373
ProcFdFile,
74+
/// /proc/<pid>/fdinfo 目录
75+
ProcFdInfoDir,
76+
/// /proc/<pid>/fdinfo/<fd> 文件
77+
ProcFdInfoFile,
7478
ProcMounts,
7579
/// /proc/version
7680
ProcVersion,
@@ -169,17 +173,29 @@ impl<'a> ProcFileCreationParamsBuilder<'a> {
169173

170174
/// @brief 节点私有信息结构体
171175
/// @usage 用于传入各类文件所需的信息
172-
#[derive(Debug)]
173176
pub struct InodeInfo {
174177
///进程的pid
175178
pid: Option<RawPid>,
176179
///文件类型
177180
ftype: ProcFileType,
178181
/// 文件描述符
179182
fd: i32,
183+
/// 对于 /proc/self/fd/N 这种魔法链接,存储原始文件的 inode
184+
target_inode: Option<Arc<dyn IndexNode>>,
180185
// 其他需要传入的信息在此定义
181186
}
182187

188+
impl core::fmt::Debug for InodeInfo {
189+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
190+
f.debug_struct("InodeInfo")
191+
.field("pid", &self.pid)
192+
.field("ftype", &self.ftype)
193+
.field("fd", &self.fd)
194+
.field("target_inode", &self.target_inode.is_some())
195+
.finish()
196+
}
197+
}
198+
183199
/// @brief procfs的inode名称的最大长度
184200
const PROCFS_MAX_NAMELEN: usize = 64;
185201
const PROCFS_BLOCK_SIZE: u64 = 512;
@@ -573,6 +589,7 @@ impl ProcFS {
573589
pid: None,
574590
ftype: ProcFileType::Default,
575591
fd: -1,
592+
target_inode: None,
576593
},
577594
dname: DName::default(),
578595
})));
@@ -634,6 +651,18 @@ impl ProcFS {
634651
let fd = pid_dir.create("fd", FileType::Dir, InodeMode::from_bits_truncate(0o555))?;
635652
let fd = fd.as_any_ref().downcast_ref::<LockedProcFSInode>().unwrap();
636653
fd.0.lock().fdata.ftype = ProcFileType::ProcFdDir;
654+
655+
// fdinfo dir
656+
let fdinfo = pid_dir.create(
657+
"fdinfo",
658+
FileType::Dir,
659+
InodeMode::from_bits_truncate(0o555),
660+
)?;
661+
let fdinfo = fdinfo
662+
.as_any_ref()
663+
.downcast_ref::<LockedProcFSInode>()
664+
.unwrap();
665+
fdinfo.0.lock().fdata.ftype = ProcFileType::ProcFdInfoDir;
637666
//todo: 创建其他文件
638667

639668
return Ok(());
@@ -650,6 +679,7 @@ impl ProcFS {
650679
pid_dir.unlink("status")?;
651680
pid_dir.unlink("exe")?;
652681
pid_dir.rmdir("fd")?;
682+
pid_dir.rmdir("fdinfo")?;
653683

654684
// 查看进程文件是否还存在
655685
// let pf= pid_dir.find("status").expect("Cannot find status");
@@ -714,15 +744,23 @@ impl LockedProcFSInode {
714744
let fd_table = pcb.fd_table();
715745
let fd_table = fd_table.read();
716746
let file = fd_table.get_file_by_fd(fd);
717-
if file.is_some() {
747+
if let Some(file) = file {
748+
// 获取原始文件的 inode
749+
let target_inode = file.inode();
750+
drop(fd_table);
751+
718752
let _ = self.unlink(&fd.to_string());
719753
let fd_file = self.create(&fd.to_string(), FileType::SymLink, InodeMode::S_IRUGO)?;
720754
let fd_file_proc = fd_file
721755
.as_any_ref()
722756
.downcast_ref::<LockedProcFSInode>()
723757
.unwrap();
724-
fd_file_proc.0.lock().fdata.fd = fd;
725-
fd_file_proc.0.lock().fdata.ftype = ProcFileType::ProcFdFile;
758+
let mut guard = fd_file_proc.0.lock();
759+
guard.fdata.fd = fd;
760+
guard.fdata.ftype = ProcFileType::ProcFdFile;
761+
// 存储原始文件的 inode,用于魔法链接
762+
guard.fdata.target_inode = Some(target_inode);
763+
drop(guard);
726764
return Ok(fd_file);
727765
} else {
728766
return Err(SystemError::ENOENT);
@@ -737,6 +775,42 @@ impl LockedProcFSInode {
737775
let res = fd_table.iter().map(|(fd, _)| fd.to_string()).collect();
738776
return Ok(res);
739777
}
778+
779+
fn dynamical_find_fdinfo(&self, fd: &str) -> Result<Arc<dyn IndexNode>, SystemError> {
780+
let fd_num = fd.parse::<i32>().map_err(|_| SystemError::EINVAL)?;
781+
let pcb = ProcessManager::current_pcb();
782+
let fd_table = pcb.fd_table();
783+
let fd_table = fd_table.read();
784+
let file = fd_table.get_file_by_fd(fd_num);
785+
if file.is_some() {
786+
drop(fd_table);
787+
788+
let _ = self.unlink(&fd_num.to_string());
789+
// fdinfo 文件是普通文件,不是符号链接
790+
let fdinfo_file =
791+
self.create(&fd_num.to_string(), FileType::File, InodeMode::S_IRUGO)?;
792+
let fdinfo_file_proc = fdinfo_file
793+
.as_any_ref()
794+
.downcast_ref::<LockedProcFSInode>()
795+
.unwrap();
796+
let mut guard = fdinfo_file_proc.0.lock();
797+
guard.fdata.fd = fd_num;
798+
guard.fdata.ftype = ProcFileType::ProcFdInfoFile;
799+
drop(guard);
800+
return Ok(fdinfo_file);
801+
} else {
802+
return Err(SystemError::ENOENT);
803+
}
804+
}
805+
806+
fn dynamical_list_fdinfo(&self) -> Result<Vec<String>, SystemError> {
807+
// 与 fd 目录共享相同的列表逻辑
808+
let pcb = ProcessManager::current_pcb();
809+
let fd_table = pcb.fd_table();
810+
let fd_table = fd_table.read();
811+
let res = fd_table.iter().map(|(fd, _)| fd.to_string()).collect();
812+
return Ok(res);
813+
}
740814
}
741815

742816
/// 为 `/proc/thread-self/ns/*` 节点构造 namespace fd 绑定的私有数据。
@@ -797,6 +871,8 @@ impl IndexNode for LockedProcFSInode {
797871
ProcFileType::ProcKmsg
798872
| ProcFileType::ProcFdDir
799873
| ProcFileType::ProcFdFile
874+
| ProcFileType::ProcFdInfoDir
875+
| ProcFileType::ProcFdInfoFile
800876
| ProcFileType::ProcThreadSelfNsRoot
801877
| ProcFileType::ProcSysKernelPrintk => 0,
802878
};
@@ -1031,6 +1107,7 @@ impl IndexNode for LockedProcFSInode {
10311107
pid: None,
10321108
ftype: ProcFileType::Default,
10331109
fd: -1,
1110+
target_inode: None,
10341111
},
10351112
dname: dname.clone(),
10361113
})));
@@ -1148,6 +1225,9 @@ impl IndexNode for LockedProcFSInode {
11481225
ProcFileType::ProcFdDir => {
11491226
return self.dynamical_find_fd(name);
11501227
}
1228+
ProcFileType::ProcFdInfoDir => {
1229+
return self.dynamical_find_fdinfo(name);
1230+
}
11511231
ProcFileType::ProcThreadSelfNsRoot => {
11521232
return self.dynamical_find_thread_self_ns(name);
11531233
}
@@ -1229,6 +1309,11 @@ impl IndexNode for LockedProcFSInode {
12291309
keys.append(&mut fd_list);
12301310
return Ok(keys);
12311311
}
1312+
ProcFileType::ProcFdInfoDir => {
1313+
let mut fdinfo_list = self.dynamical_list_fdinfo()?;
1314+
keys.append(&mut fdinfo_list);
1315+
return Ok(keys);
1316+
}
12321317
ProcFileType::ProcThreadSelfNsRoot => {
12331318
keys.extend(ThreadSelfNsFileType::ALL_NAME.iter().map(|s| s.to_string()));
12341319

@@ -1253,6 +1338,17 @@ impl IndexNode for LockedProcFSInode {
12531338
fn dname(&self) -> Result<DName, SystemError> {
12541339
Ok(self.0.lock().dname.clone())
12551340
}
1341+
1342+
fn special_node(&self) -> Option<super::vfs::SpecialNodeData> {
1343+
let guard = self.0.lock();
1344+
// 对于 /proc/self/fd/N 这种魔法链接,返回原始文件的 inode
1345+
if guard.fdata.ftype == ProcFileType::ProcFdFile {
1346+
if let Some(target_inode) = &guard.fdata.target_inode {
1347+
return Some(super::vfs::SpecialNodeData::Reference(target_inode.clone()));
1348+
}
1349+
}
1350+
None
1351+
}
12561352
}
12571353

12581354
/// @brief 向procfs注册进程

kernel/src/filesystem/vfs/file.rs

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -182,26 +182,26 @@ impl FileFlags {
182182
///
183183
/// 这是正确提取访问模式的方法,因为O_RDONLY=0不能用contains()检查
184184
#[inline]
185-
pub fn access_flags(&self) -> u32 {
186-
self.bits() & Self::O_ACCMODE.bits()
185+
pub fn access_flags(&self) -> FileFlags {
186+
*self & Self::O_ACCMODE
187187
}
188188

189189
/// @brief 检查是否是只读模式
190190
#[inline]
191191
pub fn is_read_only(&self) -> bool {
192-
self.access_flags() == Self::O_RDONLY.bits()
192+
self.access_flags() == Self::O_RDONLY
193193
}
194194

195195
/// @brief 检查是否是只写模式
196196
#[inline]
197197
pub fn is_write_only(&self) -> bool {
198-
self.access_flags() == Self::O_WRONLY.bits()
198+
self.access_flags() == Self::O_WRONLY
199199
}
200200

201201
/// @brief 检查是否是读写模式
202202
#[inline]
203203
pub fn is_rdwr(&self) -> bool {
204-
self.access_flags() == Self::O_RDWR.bits()
204+
self.access_flags() == Self::O_RDWR
205205
}
206206

207207
/// 检查是否设置了 FASYNC 标志
@@ -311,7 +311,7 @@ impl FileMode {
311311
/// - 以及对于抑制fsnotify/fanotify机制触发通知的标志FMODE_NONOTIFY
312312
pub fn open_fmode(flags: FileFlags) -> Self {
313313
let fmode = flags.bits() & FileMode::FMODE_NONOTIFY.bits()
314-
| (flags.access_flags() + 1) & FileFlags::O_ACCMODE.bits();
314+
| (flags.access_flags().bits + 1) & FileFlags::O_ACCMODE.bits();
315315

316316
// 初始只设置访问模式,其他能力在后续设置
317317
FileMode::from_bits_truncate(fmode)
@@ -375,10 +375,21 @@ impl File {
375375
pub fn new(inode: Arc<dyn IndexNode>, mut flags: FileFlags) -> Result<Self, SystemError> {
376376
let mut inode = inode;
377377
let file_type = inode.metadata()?.file_type;
378-
if file_type == FileType::Pipe {
378+
// 检查是否为命名管道(FIFO)
379+
let is_named_pipe = if file_type == FileType::Pipe {
379380
if let Some(SpecialNodeData::Pipe(pipe_inode)) = inode.special_node() {
380381
inode = pipe_inode;
382+
true
383+
} else {
384+
false
381385
}
386+
} else {
387+
false
388+
};
389+
390+
// 对于命名管道,自动添加 O_LARGEFILE 标志(符合 Linux 行为)
391+
if is_named_pipe {
392+
flags.insert(FileFlags::O_LARGEFILE);
382393
}
383394

384395
let metadata = inode.metadata()?;
@@ -1047,6 +1058,9 @@ impl Drop for File {
10471058
pub struct FileDescriptorVec {
10481059
/// 当前进程打开的文件描述符
10491060
fds: Vec<Option<Arc<File>>>,
1061+
/// 下一个可能空闲的文件描述符号(用于优化分配,避免O(n²)扫描)
1062+
/// 类似于 Linux 的 fd_next_fd
1063+
next_fd: usize,
10501064
}
10511065
impl Default for FileDescriptorVec {
10521066
fn default() -> Self {
@@ -1057,15 +1071,18 @@ impl FileDescriptorVec {
10571071
/// 文件描述符表的初始容量
10581072
pub const INITIAL_CAPACITY: usize = 1024;
10591073
/// 文件描述符表的最大容量限制(防止无限扩容)
1060-
pub const MAX_CAPACITY: usize = 65536;
1074+
pub const MAX_CAPACITY: usize = 1048576;
10611075

10621076
#[inline(never)]
10631077
pub fn new() -> FileDescriptorVec {
10641078
let mut data = Vec::with_capacity(FileDescriptorVec::INITIAL_CAPACITY);
10651079
data.resize(FileDescriptorVec::INITIAL_CAPACITY, None);
10661080

10671081
// 初始化文件描述符数组结构体
1068-
return FileDescriptorVec { fds: data };
1082+
return FileDescriptorVec {
1083+
fds: data,
1084+
next_fd: 0,
1085+
};
10691086
}
10701087

10711088
/// @brief 克隆一个文件描述符数组
@@ -1081,6 +1098,8 @@ impl FileDescriptorVec {
10811098
res.fds[i] = Some(file.clone());
10821099
}
10831100
}
1101+
// 复制 next_fd 以保持相同的分配状态
1102+
res.next_fd = self.next_fd;
10841103
return res;
10851104
}
10861105

@@ -1119,6 +1138,10 @@ impl FileDescriptorVec {
11191138
let target = core::cmp::max(new_capacity, floor);
11201139
if target < current_len {
11211140
self.fds.truncate(target);
1141+
// 确保 next_fd 不超过新的容量
1142+
if self.next_fd > target {
1143+
self.next_fd = target;
1144+
}
11221145
}
11231146
}
11241147
Ok(())
@@ -1176,19 +1199,48 @@ impl FileDescriptorVec {
11761199
let x = &mut self.fds[new_fd as usize];
11771200
if x.is_none() {
11781201
*x = Some(Arc::new(file));
1202+
// 更新 next_fd:如果分配的是 next_fd 位置,则推进到下一个
1203+
if new_fd as usize == self.next_fd {
1204+
self.next_fd = new_fd as usize + 1;
1205+
}
11791206
return Ok(new_fd);
11801207
} else {
11811208
return Err(SystemError::EBADF);
11821209
}
11831210
} else {
1184-
// 没有指定要申请的文件描述符编号,在有效范围内查找空位
1211+
// 没有指定要申请的文件描述符编号
1212+
// 使用 next_fd 作为起始搜索位置,避免每次都从0开始扫描 (O(n²) -> O(n))
11851213
let max_search = core::cmp::min(self.fds.len(), nofile_limit);
1186-
for i in 0..max_search {
1214+
1215+
// 从 next_fd 开始查找空位
1216+
for i in self.next_fd..max_search {
11871217
if self.fds[i].is_none() {
11881218
self.fds[i] = Some(Arc::new(file));
1219+
// 更新 next_fd 为下一个位置
1220+
self.next_fd = i + 1;
11891221
return Ok(i as i32);
11901222
}
11911223
}
1224+
1225+
// 当前容量内没有空位,尝试扩容
1226+
// 计算新的容量:当前容量翻倍,但不超过 nofile_limit
1227+
let current_len = self.fds.len();
1228+
if current_len < nofile_limit {
1229+
// 扩容策略:翻倍或增加到 nofile_limit,取较小值
1230+
let new_capacity = core::cmp::min(
1231+
core::cmp::max(current_len * 2, current_len + 1),
1232+
nofile_limit,
1233+
);
1234+
self.resize_to_capacity(new_capacity)?;
1235+
1236+
// 扩容后,第一个新位置就是空的
1237+
let new_fd = current_len;
1238+
self.fds[new_fd] = Some(Arc::new(file));
1239+
// 更新 next_fd
1240+
self.next_fd = new_fd + 1;
1241+
return Ok(new_fd as i32);
1242+
}
1243+
11921244
return Err(SystemError::EMFILE);
11931245
}
11941246
}
@@ -1240,6 +1292,14 @@ impl FileDescriptorVec {
12401292

12411293
// 把文件描述符数组对应位置设置为空
12421294
let file = self.fds[fd as usize].take().unwrap();
1295+
1296+
// 更新 next_fd:如果释放的fd比当前next_fd小,则更新next_fd
1297+
// 这确保下次分配时可以复用较小的fd号,符合POSIX语义
1298+
// (POSIX要求分配最小可用的fd号)
1299+
if (fd as usize) < self.next_fd {
1300+
self.next_fd = fd as usize;
1301+
}
1302+
12431303
return Ok(file);
12441304
}
12451305

0 commit comments

Comments
 (0)