From 80e605557204fa3fd90e46a5e18ebf77eeb3963b Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 4 Dec 2025 22:10:03 +0800 Subject: [PATCH 1/5] - fix NonBlockingEventPOLLHUP - fix BlockingEventPOLLHUP --- kernel/src/filesystem/epoll/event_poll.rs | 7 ++++--- kernel/src/filesystem/poll.rs | 3 ++- kernel/src/ipc/pipe.rs | 6 ++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/kernel/src/filesystem/epoll/event_poll.rs b/kernel/src/filesystem/epoll/event_poll.rs index 05abf7bde..4e141fd4f 100644 --- a/kernel/src/filesystem/epoll/event_poll.rs +++ b/kernel/src/filesystem/epoll/event_poll.rs @@ -456,14 +456,15 @@ impl EventPoll { push_back.push(epitem); break; } - let mut ep_events = EPollEventType::from_bits_truncate(epitem.event.read().events); - // 再次poll获取事件(为了防止水平触发一直加入队列) + let mut ep_events = EPollEventType::empty(); let revents = epitem.ep_item_poll(); + let priv_bits = EPollEventType::from_bits_truncate(epitem.event.read().events) + .intersection(EPollEventType::EP_PRIVATE_BITS); if revents.is_empty() { // TODO: one-shot event will be lost here // continue; } - ep_events |= revents; + ep_events |= revents | priv_bits; // 构建触发事件结构体 let event = EPollEvent { events: ep_events.bits, diff --git a/kernel/src/filesystem/poll.rs b/kernel/src/filesystem/poll.rs index 88c351e63..508a64cd6 100644 --- a/kernel/src/filesystem/poll.rs +++ b/kernel/src/filesystem/poll.rs @@ -43,7 +43,8 @@ impl<'a> PollAdapter<'a> { continue; } let mut epoll_event = EPollEvent::default(); - let poll_flags = PollFlags::from_bits_truncate(pollfd.events); + let mut poll_flags = PollFlags::from_bits_truncate(pollfd.events); + poll_flags |= PollFlags::POLLERR | PollFlags::POLLHUP; let ep_events: EPollEventType = poll_flags.into(); epoll_event.set_events(ep_events.bits()); epoll_event.set_data(i as u64); diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 3b4f88c6a..18ed04606 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -490,9 +490,15 @@ impl IndexNode for LockedPipeInode { guard.writer -= 1; // 如果已经没有写端了,则唤醒读端 if guard.writer == 0 { + // 写端耗尽意味着读端应收到 POLLHUP,唤醒等待者与 epoll + let poll_data = FilePrivateData::Pipefs(PipeFsPrivateData { flags }); + let pollflag = + EPollEventType::from_bits_truncate(guard.poll(&poll_data)? as u32); drop(guard); // 先释放 inner 锁,避免潜在的死锁 self.read_wait_queue .wakeup_all(Some(ProcessState::Blocked(true))); + // 唤醒所有依赖 epoll 的等待者,确保 HUP 事件可见 + EventPoll::wakeup_epoll(&self.epitems, pollflag)?; return Ok(()); } } From 465c6c1a765483d102c1ffd09284ec2bcb6f295b Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 18 Dec 2025 19:14:45 +0800 Subject: [PATCH 2/5] - failed PollTest.Nfds,PollTest.UnpollableFile --- kernel/src/filesystem/poll.rs | 163 +++++++++++++++++++++-- kernel/src/net/socket/unix/stream/mod.rs | 19 ++- 2 files changed, 167 insertions(+), 15 deletions(-) diff --git a/kernel/src/filesystem/poll.rs b/kernel/src/filesystem/poll.rs index 508a64cd6..560e431c4 100644 --- a/kernel/src/filesystem/poll.rs +++ b/kernel/src/filesystem/poll.rs @@ -17,6 +17,7 @@ use crate::{ use super::vfs::file::{File, FileFlags}; use alloc::sync::Arc; +use crate::process::resource::RLimitID; use system_error::SystemError; #[repr(C)] @@ -92,13 +93,42 @@ impl Syscall { /// https://code.dragonos.org.cn/xref/linux-6.6.21/fs/select.c#1068 #[inline(never)] pub fn poll(pollfd_ptr: usize, nfds: u32, timeout_ms: i32) -> Result { + // 检查 nfds 是否超过 RLIMIT_NOFILE + let rlimit_nofile = ProcessManager::current_pcb() + .get_rlimit(RLimitID::Nofile) + .rlim_cur as u32; + if nfds > rlimit_nofile { + return Err(SystemError::EINVAL); + } + + // 检查长度溢出 + let len = (nfds as usize) + .checked_mul(core::mem::size_of::()) + .ok_or(SystemError::EINVAL)?; + + // 当 nfds > 0 但 pollfd_ptr 为空指针时,返回 EFAULT + if nfds > 0 && pollfd_ptr == 0 { + return Err(SystemError::EFAULT); + } + let pollfd_ptr = VirtAddr::new(pollfd_ptr); - let len = nfds as usize * core::mem::size_of::(); let mut timeout: Option = None; if timeout_ms >= 0 { timeout = poll_select_set_timeout(timeout_ms as u64); } + + // nfds == 0 时,直接进入等待逻辑,不需要用户缓冲区 + if nfds == 0 { + let mut r = do_sys_poll(&mut [], timeout); + if let Err(SystemError::ERESTARTNOHAND) = r { + let restart_block_data = RestartBlockData::new_poll(pollfd_ptr, nfds, timeout); + let restart_block = RestartBlock::new(&RestartFnPoll, restart_block_data); + r = ProcessManager::current_pcb().set_restart_fn(Some(restart_block)); + } + return r; + } + let mut poll_fds_writer = UserBufferWriter::new(pollfd_ptr.as_ptr::(), len, true)?; let mut r = do_sys_poll(poll_fds_writer.buffer(0)?, timeout); if let Err(SystemError::ERESTARTNOHAND) = r { @@ -118,13 +148,28 @@ impl Syscall { timespec_ptr: usize, sigmask_ptr: usize, ) -> Result { + // 检查 nfds 是否超过 RLIMIT_NOFILE + let rlimit_nofile = ProcessManager::current_pcb() + .get_rlimit(RLimitID::Nofile) + .rlim_cur as u32; + if nfds > rlimit_nofile { + return Err(SystemError::EINVAL); + } + + // 检查长度溢出 + let pollfds_len = (nfds as usize) + .checked_mul(core::mem::size_of::()) + .ok_or(SystemError::EINVAL)?; + + // 当 nfds > 0 但 pollfd_ptr 为空指针时,返回 EFAULT + if nfds > 0 && pollfd_ptr == 0 { + return Err(SystemError::EFAULT); + } + let mut timeout_ts: Option = None; let mut sigmask: Option = None; let pollfd_ptr = VirtAddr::new(pollfd_ptr); - let pollfds_len = nfds as usize * core::mem::size_of::(); - let mut poll_fds_writer = - UserBufferWriter::new(pollfd_ptr.as_ptr::(), pollfds_len, true)?; - let poll_fds = poll_fds_writer.buffer(0)?; + if sigmask_ptr != 0 { let sigmask_reader = UserBufferReader::new(sigmask_ptr as *const SigSet, size_of::(), true)?; @@ -149,15 +194,16 @@ impl Syscall { if let Some(mut sigmask) = sigmask { set_user_sigmask(&mut sigmask); } - // log::debug!( - // "ppoll: poll_fds: {:?}, nfds: {}, timeout_ts: {:?},sigmask: {:?}", - // poll_fds, - // nfds, - // timeout_ts, - // sigmask - // ); - let r: Result = do_sys_poll(poll_fds, timeout_ts); + // nfds == 0 时,直接进入等待逻辑,不需要用户缓冲区 + let r: Result = if nfds == 0 { + do_sys_poll(&mut [], timeout_ts) + } else { + let mut poll_fds_writer = + UserBufferWriter::new(pollfd_ptr.as_ptr::(), pollfds_len, true)?; + let poll_fds = poll_fds_writer.buffer(0)?; + do_sys_poll(poll_fds, timeout_ts) + }; return poll_select_finish(timeout_ts, timespec_ptr, PollTimeType::TimeSpec, r); } @@ -167,6 +213,12 @@ pub fn do_sys_poll( poll_fds: &mut [PollFd], timeout: Option, ) -> Result { + // 特殊处理: nfds=0 时,直接进入可中断等待 + // 这种情况下只等待超时或信号,不需要创建 epoll + if poll_fds.is_empty() { + return poll_wait_timeout_only(timeout); + } + let ep_file = EventPoll::create_epoll_file(FileFlags::empty())?; let ep_file = Arc::new(ep_file); @@ -178,6 +230,91 @@ pub fn do_sys_poll( Ok(nevents) } +/// 处理 nfds=0 的情况:纯等待超时或信号 +/// +/// 根据 Linux 语义: +/// - 如果 timeout=0,立即返回 0 +/// - 如果 timeout>0,等待指定时间后返回 0 +/// - 如果 timeout=-1(None),无限等待直到被信号中断,返回 ERESTARTNOHAND +fn poll_wait_timeout_only(timeout: Option) -> Result { + use crate::arch::ipc::signal::Signal; + use crate::time::timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper}; + use crate::arch::CurrentIrqArch; + use crate::exception::InterruptArch; + use crate::sched::{schedule, SchedMode}; + use alloc::boxed::Box; + + // 如果有超时时间且已过期,直接返回 + if let Some(end_time) = timeout { + if Instant::now() >= end_time { + return Ok(0); + } + } + + loop { + // 检查是否有待处理的信号 + let current_pcb = ProcessManager::current_pcb(); + if current_pcb.has_pending_signal_fast() + && Signal::signal_pending_state(true, false, ¤t_pcb) + { + return Err(SystemError::ERESTARTNOHAND); + } + + // 检查超时 + if let Some(end_time) = timeout { + if Instant::now() >= end_time { + return Ok(0); + } + } + + // 计算剩余等待时间 + let sleep_duration = if let Some(end_time) = timeout { + let remain = end_time.duration_since(Instant::now()).unwrap_or(Duration::ZERO); + if remain == Duration::ZERO { + return Ok(0); + } + remain + } else { + // 无限等待时,设置一个较长的时间(比如1秒),然后循环检查信号 + Duration::from_secs(1) + }; + + // 创建定时器唤醒 + let handler: Box = WakeUpHelper::new(ProcessManager::current_pcb()); + let sleep_us = sleep_duration.total_micros(); + let timer: Arc = Timer::new(handler, next_n_us_timer_jiffies(sleep_us)); + + // 使用直接的可中断睡眠 + let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; + ProcessManager::mark_sleep(true).ok(); + timer.activate(); + drop(irq_guard); + + schedule(SchedMode::SM_NONE); + + // 醒来后检查原因 + let was_timeout = timer.timeout(); + if !was_timeout { + timer.cancel(); + } + + // 检查是否因信号而醒来 + let current_pcb = ProcessManager::current_pcb(); + if current_pcb.has_pending_signal_fast() + && Signal::signal_pending_state(true, false, ¤t_pcb) + { + return Err(SystemError::ERESTARTNOHAND); + } + + // 如果超时且有超时设置,返回 0 + if was_timeout && timeout.is_some() { + return Ok(0); + } + + // 无限等待时继续循环(重新检查信号) + } +} + /// 计算超时的时刻 pub fn poll_select_set_timeout(timeout_ms: u64) -> Option { Some(Instant::now() + Duration::from_millis(timeout_ms)) diff --git a/kernel/src/net/socket/unix/stream/mod.rs b/kernel/src/net/socket/unix/stream/mod.rs index 1cd210e80..14ff5d737 100644 --- a/kernel/src/net/socket/unix/stream/mod.rs +++ b/kernel/src/net/socket/unix/stream/mod.rs @@ -281,11 +281,26 @@ impl Socket for UnixStreamSocket { fn recv_from( &self, - _buffer: &mut [u8], + buffer: &mut [u8], _flags: socket::PMSG, _address: Option, ) -> Result<(usize, Endpoint), SystemError> { - todo!() + // 对于流式 Unix Socket,recv_from 与 recv 类似 + // 直接调用 try_recv 并返回对端地址 + let recv_len = self.try_recv(buffer)?; + + // 获取对端地址 + let peer_endpoint = match self + .inner + .read() + .as_ref() + .expect("UnixStreamSocket inner is None") + { + Inner::Connected(connected) => connected.peer_endpoint(), + _ => return Err(SystemError::ENOTCONN), + }; + + Ok((recv_len, peer_endpoint.into())) // if flags.contains(PMSG::OOB) { // return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); From d47c733793e3c45310d3a2e1472043be92dd5112 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Thu, 18 Dec 2025 22:01:48 +0800 Subject: [PATCH 3/5] fix nfds && unpollablefile --- kernel/src/filesystem/poll.rs | 109 +++++++++++++++---- kernel/src/ipc/pipe.rs | 3 +- user/apps/tests/syscall/gvisor/whitelist.txt | 1 + 3 files changed, 91 insertions(+), 22 deletions(-) diff --git a/kernel/src/filesystem/poll.rs b/kernel/src/filesystem/poll.rs index 560e431c4..5f3232ee5 100644 --- a/kernel/src/filesystem/poll.rs +++ b/kernel/src/filesystem/poll.rs @@ -16,8 +16,8 @@ use crate::{ }; use super::vfs::file::{File, FileFlags}; -use alloc::sync::Arc; use crate::process::resource::RLimitID; +use alloc::sync::Arc; use system_error::SystemError; #[repr(C)] @@ -31,40 +31,90 @@ pub struct PollFd { struct PollAdapter<'a> { ep_file: Arc, poll_fds: &'a mut [PollFd], + /// 记录已添加到 epoll 的 fd 以及合并后的事件掩码 + added_fds: alloc::collections::BTreeMap, } impl<'a> PollAdapter<'a> { pub fn new(ep_file: Arc, poll_fds: &'a mut [PollFd]) -> Self { - Self { ep_file, poll_fds } + Self { + ep_file, + poll_fds, + added_fds: alloc::collections::BTreeMap::new(), + } } - fn add_pollfds(&self) -> Result<(), SystemError> { - for (i, pollfd) in self.poll_fds.iter().enumerate() { + fn add_pollfds(&mut self) -> Result<(), SystemError> { + // 首先清除所有 revents(revents 是 output-only 字段) + // 这确保每次 poll 调用都从干净状态开始,不受之前调用的影响 + for pollfd in self.poll_fds.iter_mut() { + pollfd.revents = 0; + } + + // 第一遍:收集每个唯一 fd 的合并事件掩码 + for i in 0..self.poll_fds.len() { + let pollfd = &self.poll_fds[i]; if pollfd.fd < 0 { continue; } + + // 合并同一 fd 的所有事件 + let entry = self.added_fds.entry(pollfd.fd).or_insert(0); + *entry |= pollfd.events; + } + + // 第二遍:将每个唯一 fd 添加到 epoll + let fds_to_add: alloc::vec::Vec<_> = self + .added_fds + .iter() + .map(|(&fd, &events)| (fd, events)) + .collect(); + + for (fd, merged_events) in fds_to_add { let mut epoll_event = EPollEvent::default(); - let mut poll_flags = PollFlags::from_bits_truncate(pollfd.events); + let mut poll_flags = PollFlags::from_bits_truncate(merged_events); poll_flags |= PollFlags::POLLERR | PollFlags::POLLHUP; let ep_events: EPollEventType = poll_flags.into(); epoll_event.set_events(ep_events.bits()); - epoll_event.set_data(i as u64); + epoll_event.set_data(fd as u64); - EventPoll::epoll_ctl_with_epfile( + let result = EventPoll::epoll_ctl_with_epfile( self.ep_file.clone(), EPollCtlOption::Add, - pollfd.fd, + fd, epoll_event, false, - ) - .map(|_| ())?; + ); + + match result { + Ok(_) => {} + Err(SystemError::ENOSYS) | Err(SystemError::EOPNOTSUPP_OR_ENOTSUP) => { + // 文件不支持 poll,标记所有对应的 pollfd 为立即就绪 + for pollfd in self.poll_fds.iter_mut() { + if pollfd.fd == fd { + pollfd.revents = (PollFlags::POLLIN | PollFlags::POLLOUT).bits(); + } + } + // 从 added_fds 中移除,因为它没有被添加到 epoll + self.added_fds.remove(&fd); + } + Err(e) => return Err(e), + } } Ok(()) } fn poll_all_fds(&mut self, timeout: Option) -> Result { - let mut epoll_events = vec![EPollEvent::default(); self.poll_fds.len()]; + // 首先计算已经有 revents 的条目数量(不可 poll 的文件) + let mut count = self.poll_fds.iter().filter(|pfd| pfd.revents != 0).count(); + + // 如果已经有就绪的事件,或者没有添加任何 fd 到 epoll,直接返回 + if count > 0 || self.added_fds.is_empty() { + return Ok(count); + } + + let mut epoll_events = vec![EPollEvent::default(); self.added_fds.len()]; let len = epoll_events.len() as i32; let remain_timeout = timeout.map(|t| { t.duration_since(Instant::now()) @@ -77,15 +127,31 @@ impl<'a> PollAdapter<'a> { len, remain_timeout, )?; + + // 处理返回的事件,将它们映射回所有相关的 pollfd 条目 for event in epoll_events.iter().take(events) { - let index = event.data() as usize; - if index >= self.poll_fds.len() { - log::warn!("poll_all_fds: Invalid index in epoll event: {}", index); - continue; + let event_fd = event.data() as i32; + let revents = event.events(); + + // 找到所有匹配这个 fd 的 pollfd 条目 + for pollfd in self.poll_fds.iter_mut() { + if pollfd.fd == event_fd { + // 只设置用户请求的事件 + 强制事件 + let requested = (pollfd.events as u32) + | PollFlags::POLLERR.bits() as u32 + | PollFlags::POLLHUP.bits() as u32 + | PollFlags::POLLNVAL.bits() as u32; + let filtered_revents = revents & requested; + if filtered_revents != 0 { + pollfd.revents = (filtered_revents & 0xffff) as u16; + } + } } - self.poll_fds[index].revents = (event.events() & 0xffff) as u16; } - Ok(events) + + // 计算有事件的 pollfd 数量 + count = self.poll_fds.iter().filter(|pfd| pfd.revents != 0).count(); + Ok(count) } } @@ -238,10 +304,10 @@ pub fn do_sys_poll( /// - 如果 timeout=-1(None),无限等待直到被信号中断,返回 ERESTARTNOHAND fn poll_wait_timeout_only(timeout: Option) -> Result { use crate::arch::ipc::signal::Signal; - use crate::time::timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper}; use crate::arch::CurrentIrqArch; use crate::exception::InterruptArch; use crate::sched::{schedule, SchedMode}; + use crate::time::timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper}; use alloc::boxed::Box; // 如果有超时时间且已过期,直接返回 @@ -269,7 +335,9 @@ fn poll_wait_timeout_only(timeout: Option) -> Result) -> Result = WakeUpHelper::new(ProcessManager::current_pcb()); let sleep_us = sleep_duration.total_micros(); - let timer: Arc = Timer::new(handler, next_n_us_timer_jiffies(sleep_us)); + let timer: Arc = + Timer::new(handler, next_n_us_timer_jiffies(sleep_us)); // 使用直接的可中断睡眠 let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 2303d468f..3b05f0fd9 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -603,8 +603,7 @@ impl IndexNode for LockedPipeInode { if guard.writer == 0 { // 写端耗尽意味着读端应收到 POLLHUP,唤醒等待者与 epoll let poll_data = FilePrivateData::Pipefs(PipeFsPrivateData { flags }); - let pollflag = - EPollEventType::from_bits_truncate(guard.poll(&poll_data)? as u32); + let pollflag = EPollEventType::from_bits_truncate(guard.poll(&poll_data)? as u32); drop(guard); // 先释放 inner 锁,避免潜在的死锁 self.read_wait_queue .wakeup_all(Some(ProcessState::Blocked(true))); diff --git a/user/apps/tests/syscall/gvisor/whitelist.txt b/user/apps/tests/syscall/gvisor/whitelist.txt index 7b39e6dbe..634354d51 100644 --- a/user/apps/tests/syscall/gvisor/whitelist.txt +++ b/user/apps/tests/syscall/gvisor/whitelist.txt @@ -55,6 +55,7 @@ prctl_test exit_test setns_test eventfd_test +poll_test # 内存管理测试 mmap_test From fcbb7d3b5a8eab132f042cf28fd78afdbce38e04 Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sat, 20 Dec 2025 14:59:08 +0800 Subject: [PATCH 4/5] =?UTF-8?q?fix(net):=20=E4=BC=98=E5=85=88=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=20loopback=20=E6=8E=A5=E5=8F=A3=E4=BB=A5=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20SIOCGIFCONF=20ioctl=20=20=20=E5=9C=A8=20handle=5Fsi?= =?UTF-8?q?ocgifconf=20=E4=B8=AD=EF=BC=8C=E5=B0=86=20loopback=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E4=BC=98=E5=85=88=E6=B7=BB=E5=8A=A0=E5=88=B0=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=88=97=E8=A1=A8=E5=BC=80=E5=A4=B4=EF=BC=8C=20=20=20?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E5=BD=93=E7=94=A8=E6=88=B7=E7=BC=93=E5=86=B2?= =?UTF-8?q?=E5=8C=BA=E5=AE=B9=E9=87=8F=E6=9C=89=E9=99=90=E6=97=B6=EF=BC=8C?= =?UTF-8?q?loopback=20=E6=8E=A5=E5=8F=A3=E8=83=BD=E8=A2=AB=E4=BC=98?= =?UTF-8?q?=E5=85=88=E8=BF=94=E5=9B=9E=E3=80=82=20=20=20=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=8E=9F=E5=9B=A0=EF=BC=9A=E5=BD=93=E7=B3=BB=E7=BB=9F=E6=9C=89?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E7=BD=91=E7=BB=9C=E6=8E=A5=E5=8F=A3=E6=97=B6?= =?UTF-8?q?=EF=BC=8Cloopback=20"lo"=20=E5=8F=AF=E8=83=BD=E6=8E=92=E5=9C=A8?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=9C=AB=E5=B0=BE=EF=BC=8C=20=20=20=E8=B6=85?= =?UTF-8?q?=E5=87=BA=E7=94=A8=E6=88=B7=E7=BC=93=E5=86=B2=E5=8C=BA=E5=AE=B9?= =?UTF-8?q?=E9=87=8F=E5=AF=BC=E8=87=B4=E6=97=A0=E6=B3=95=E8=A2=AB=E8=BF=94?= =?UTF-8?q?=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/net/loopback.rs | 18 +++++++ kernel/src/net/socket/inode.rs | 80 +++++++++++++++++++------------ 2 files changed, 67 insertions(+), 31 deletions(-) diff --git a/kernel/src/driver/net/loopback.rs b/kernel/src/driver/net/loopback.rs index 26e0136bf..43fe2357e 100644 --- a/kernel/src/driver/net/loopback.rs +++ b/kernel/src/driver/net/loopback.rs @@ -552,16 +552,34 @@ pub fn loopback_probe() { pub fn loopback_driver_init() { static INIT: Once = Once::new(); INIT.call_once(|| { + log::info!("[loopback_driver_init] Starting loopback initialization..."); + // If already initialized (e.g., by earlier init path), do nothing. if INIT_NET_NAMESPACE.loopback_iface().is_some() { + log::info!("[loopback_driver_init] Loopback already exists, skipping."); return; } let iface = generate_loopback_iface_default(); + log::info!( + "[loopback_driver_init] Created loopback iface with nic_id={}", + iface.nic_id() + ); INIT_NET_NAMESPACE.add_device(iface.clone()); + log::info!( + "[loopback_driver_init] Added to device_list, device_list.len()={}", + INIT_NET_NAMESPACE.device_list().len() + ); + INIT_NET_NAMESPACE.set_loopback_iface(iface.clone()); + log::info!( + "[loopback_driver_init] Set loopback_iface, is_some={}", + INIT_NET_NAMESPACE.loopback_iface().is_some() + ); + iface.common.set_net_namespace(INIT_NET_NAMESPACE.clone()); + log::info!("[loopback_driver_init] Loopback initialization complete!"); }); } diff --git a/kernel/src/net/socket/inode.rs b/kernel/src/net/socket/inode.rs index af9ffc8d8..77002aa5e 100644 --- a/kernel/src/net/socket/inode.rs +++ b/kernel/src/net/socket/inode.rs @@ -77,6 +77,12 @@ fn handle_siocgifconf(data: usize) -> Result { // Get current network namespace and enumerate interfaces let netns = ProcessManager::current_netns(); + + log::debug!( + "[handle_siocgifconf] Processing SIOCGIFCONF, device_list.len()={}", + netns.device_list().len() + ); + let device_list = netns.device_list(); // Calculate how many ifreq structures we can fit @@ -85,10 +91,42 @@ fn handle_siocgifconf(data: usize) -> Result { // Collect interface information let mut ifreqs: Vec = Vec::new(); + // First, add loopback interface to ensure it's at the front of the list + // This is important because user buffers may be limited and we want to + // ensure loopback is always returned. + if let Some(loopback) = netns.loopback_iface() { + let lo_iface: &dyn Iface = loopback.as_ref(); + let lo_name = lo_iface.iface_name(); + let ipv4_addr = lo_iface + .common() + .ipv4_addr() + .unwrap_or(core::net::Ipv4Addr::new(127, 0, 0, 1)); + + let mut ifreq = IfReq::default(); + let name_bytes = lo_name.as_bytes(); + let copy_len = core::cmp::min(name_bytes.len(), IFNAMSIZ - 1); + ifreq.ifr_name[..copy_len].copy_from_slice(&name_bytes[..copy_len]); + + let addr = SockAddrIn { + sin_family: 2, // AF_INET + sin_port: 0, + sin_addr: u32::from_ne_bytes(ipv4_addr.octets()), + sin_zero: [0u8; 8], + }; + ifreq.set_sockaddr_in(&addr); + ifreqs.push(ifreq); + } + + // Then add other interfaces from device_list for (_, iface) in device_list.iter() { // Get interface name let iface_name = iface.iface_name(); + // Skip loopback since we already added it + if iface_name == "lo" { + continue; + } + // Get IPv4 address if available if let Some(ipv4_addr) = iface.common().ipv4_addr() { let mut ifreq = IfReq::default(); @@ -111,37 +149,17 @@ fn handle_siocgifconf(data: usize) -> Result { } } - // Also check loopback interface explicitly. - if let Some(loopback) = netns.loopback_iface() { - // Check if loopback already added. - let lo_name = "lo"; - let already_added = ifreqs.iter().any(|req| { - let name_str = core::str::from_utf8(&req.ifr_name) - .unwrap_or("") - .trim_end_matches('\0'); - name_str == lo_name - }); - - if !already_added { - // Try to get loopback's IPv4 address. - let lo_iface: &dyn Iface = loopback.as_ref(); - let ipv4_addr = lo_iface - .common() - .ipv4_addr() - .unwrap_or(core::net::Ipv4Addr::new(127, 0, 0, 1)); - - let mut ifreq = IfReq::default(); - ifreq.ifr_name[..2].copy_from_slice(lo_name.as_bytes()); - - let addr = SockAddrIn { - sin_family: 2, // AF_INET - sin_port: 0, - sin_addr: u32::from_ne_bytes(ipv4_addr.octets()), - sin_zero: [0u8; 8], - }; - ifreq.set_sockaddr_in(&addr); - ifreqs.push(ifreq); - } + log::debug!( + "[handle_siocgifconf] Final result: returning {} interfaces", + ifreqs.len() + ); + + // Debug: print all interface names + for (i, req) in ifreqs.iter().enumerate() { + let name_str = core::str::from_utf8(&req.ifr_name) + .unwrap_or("") + .trim_end_matches('\0'); + log::debug!("[handle_siocgifconf] Interface {}: name='{}'", i, name_str); } // If ifc_buf is NULL (0), just return the total size needed From c5f25d88730c745eec74bf721971057cfbc52dba Mon Sep 17 00:00:00 2001 From: Vitus213 Date: Sat, 20 Dec 2025 17:46:17 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=B8=85=E7=90=86=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/src/driver/net/loopback.rs | 18 ------------------ kernel/src/net/socket/inode.rs | 19 ------------------- 2 files changed, 37 deletions(-) diff --git a/kernel/src/driver/net/loopback.rs b/kernel/src/driver/net/loopback.rs index 43fe2357e..26e0136bf 100644 --- a/kernel/src/driver/net/loopback.rs +++ b/kernel/src/driver/net/loopback.rs @@ -552,34 +552,16 @@ pub fn loopback_probe() { pub fn loopback_driver_init() { static INIT: Once = Once::new(); INIT.call_once(|| { - log::info!("[loopback_driver_init] Starting loopback initialization..."); - // If already initialized (e.g., by earlier init path), do nothing. if INIT_NET_NAMESPACE.loopback_iface().is_some() { - log::info!("[loopback_driver_init] Loopback already exists, skipping."); return; } let iface = generate_loopback_iface_default(); - log::info!( - "[loopback_driver_init] Created loopback iface with nic_id={}", - iface.nic_id() - ); INIT_NET_NAMESPACE.add_device(iface.clone()); - log::info!( - "[loopback_driver_init] Added to device_list, device_list.len()={}", - INIT_NET_NAMESPACE.device_list().len() - ); - INIT_NET_NAMESPACE.set_loopback_iface(iface.clone()); - log::info!( - "[loopback_driver_init] Set loopback_iface, is_some={}", - INIT_NET_NAMESPACE.loopback_iface().is_some() - ); - iface.common.set_net_namespace(INIT_NET_NAMESPACE.clone()); - log::info!("[loopback_driver_init] Loopback initialization complete!"); }); } diff --git a/kernel/src/net/socket/inode.rs b/kernel/src/net/socket/inode.rs index 77002aa5e..477a849e6 100644 --- a/kernel/src/net/socket/inode.rs +++ b/kernel/src/net/socket/inode.rs @@ -77,12 +77,6 @@ fn handle_siocgifconf(data: usize) -> Result { // Get current network namespace and enumerate interfaces let netns = ProcessManager::current_netns(); - - log::debug!( - "[handle_siocgifconf] Processing SIOCGIFCONF, device_list.len()={}", - netns.device_list().len() - ); - let device_list = netns.device_list(); // Calculate how many ifreq structures we can fit @@ -149,19 +143,6 @@ fn handle_siocgifconf(data: usize) -> Result { } } - log::debug!( - "[handle_siocgifconf] Final result: returning {} interfaces", - ifreqs.len() - ); - - // Debug: print all interface names - for (i, req) in ifreqs.iter().enumerate() { - let name_str = core::str::from_utf8(&req.ifr_name) - .unwrap_or("") - .trim_end_matches('\0'); - log::debug!("[handle_siocgifconf] Interface {}: name='{}'", i, name_str); - } - // If ifc_buf is NULL (0), just return the total size needed if ifc_buf == 0 { let total_size = ifreqs.len() * ifreq_size;