Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kernel/src/arch/x86_64/filesystem/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl TryFrom<KStat> for PosixStat {
tmp.st_uid = kstat.uid;
tmp.st_gid = kstat.gid;

tmp.st_rdev = kstat.rdev.data() as usize;
tmp.st_rdev = kstat.rdev.new_encode_dev() as usize;
tmp.st_size = kstat.size as isize;

tmp.st_atime = kstat.atime.tv_sec as usize;
Expand Down
26 changes: 2 additions & 24 deletions kernel/src/driver/tty/pty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
use alloc::{
string::{String, ToString},
sync::Arc,
};
use alloc::sync::Arc;
use system_error::SystemError;
use unified_init::macros::unified_init;

use crate::{
driver::base::device::{
device_number::{DeviceNumber, Major},
device_register, IdTable,
},
filesystem::devfs::devfs_register,
driver::base::device::device_number::Major,
init::initcall::INITCALL_DEVICE,
libs::lazy_init::Lazy,
mm::VirtAddr,
Expand All @@ -22,7 +15,6 @@ use self::unix98pty::{Unix98PtyDriverInner, NR_UNIX98_PTY_MAX};
use super::{
termios::{ControlMode, InputMode, LocalMode, OutputMode, TTY_STD_TERMIOS},
tty_core::{TtyCore, TtyCoreData, TtyFlag, TtyPacketStatus},
tty_device::{TtyDevice, TtyType},
tty_driver::{TtyDriver, TtyDriverManager, TtyDriverSubType, TtyDriverType, TTY_DRIVERS},
tty_port::{DefaultTtyPort, TtyPort},
};
Expand Down Expand Up @@ -165,20 +157,6 @@ impl PtyCommon {
ptm_driver.set_other_pty_driver(Arc::downgrade(&pts_driver));
pts_driver.set_other_pty_driver(Arc::downgrade(&ptm_driver));

let idt = IdTable::new(
String::from("ptmx"),
Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 2)),
);
let ptmx_dev = TtyDevice::new(
"ptmx".to_string(),
idt.clone(),
TtyType::Pty(super::tty_device::PtyType::Ptm),
);

ptmx_dev.inner_write().metadata_mut().raw_dev = idt.device_number();
device_register(ptmx_dev.clone())?;
devfs_register("ptmx", ptmx_dev)?;

TTY_DRIVERS.lock().push(ptm_driver);
TTY_DRIVERS.lock().push(pts_driver);

Expand Down
152 changes: 128 additions & 24 deletions kernel/src/driver/tty/pty/unix98pty.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,110 @@
use alloc::{string::ToString, sync::Arc};
use alloc::{
string::ToString,
sync::{Arc, Weak},
};
use core::sync::atomic::{AtomicBool, Ordering};
use system_error::SystemError;

use crate::{
driver::tty::{
termios::{ControlCharIndex, ControlMode, InputMode, LocalMode, Termios},
tty_core::{TtyCore, TtyCoreData, TtyFlag, TtyIoctlCmd, TtyPacketStatus},
tty_device::TtyFilePrivateData,
tty_device::{TtyDevice, TtyFilePrivateData},
tty_driver::{TtyDriver, TtyDriverPrivateData, TtyDriverSubType, TtyOperation},
},
filesystem::{
devpts::DevPtsFs,
epoll::{event_poll::EventPoll, EPollEventType},
vfs::{
file::FileFlags, FilePrivateData, FileType, InodeMode, MountFS,
VFS_MAX_FOLLOW_SYMLINK_TIMES,
},
vfs::{file::FileFlags, FilePrivateData, FileSystem, FileType, IndexNode, InodeMode},
},
libs::spinlock::SpinLockGuard,
libs::{casting::DowncastArc, spinlock::SpinLockGuard},
mm::VirtAddr,
process::ProcessManager,
syscall::user_access::UserBufferWriter,
};

use super::{ptm_driver, pts_driver, PtyCommon};

pub const NR_UNIX98_PTY_MAX: u32 = 128;

#[derive(Debug)]
struct PtyDevPtsLink {
/// devpts 挂载点根目录(/dev/pts 的 inode),用于精确 unlink 目录项
pts_root: Weak<dyn IndexNode>,
/// devpts 文件系统本体,用于精确回收索引(避免再去 downcast/全局路径查找)
devpts: Weak<DevPtsFs>,
index: usize,
/// master 侧(ptmx)最后一个 fd 已关闭
master_closed: AtomicBool,
/// slave 侧(/dev/pts/N)最后一个 fd 已关闭
slave_closed: AtomicBool,
/// 目录项是否已经 unlink(通常在 master close 时执行)
unlinked: AtomicBool,
/// 索引是否已经归还(仅在 master+slave 都关闭后才允许归还)
index_freed: AtomicBool,
}

impl crate::driver::tty::tty_driver::TtyCorePrivateField for PtyDevPtsLink {
fn as_any(&self) -> &dyn core::any::Any {
self
}
}

impl PtyDevPtsLink {
fn new(pts_root: Weak<dyn IndexNode>, devpts: Weak<DevPtsFs>, index: usize) -> Self {
Self {
pts_root,
devpts,
index,
master_closed: AtomicBool::new(false),
slave_closed: AtomicBool::new(false),
unlinked: AtomicBool::new(false),
index_freed: AtomicBool::new(false),
}
}

fn on_close(&self, subtype: TtyDriverSubType) {
match subtype {
TtyDriverSubType::PtyMaster => {
self.master_closed.store(true, Ordering::SeqCst);
// Linux 语义:master 关闭后,/dev/pts/N 目录项应从 devpts 中消失;
// 但索引不能立即复用(slave 可能仍持有打开的 fd),因此 unlink 与 free_index 分离。
self.try_unlink_once();
}
TtyDriverSubType::PtySlave => {
self.slave_closed.store(true, Ordering::SeqCst);
}
_ => {}
}

self.try_free_index_when_fully_closed();
}

fn try_unlink_once(&self) {
if self.unlinked.swap(true, Ordering::SeqCst) {
return;
}
if let Some(root) = self.pts_root.upgrade() {
let _ = root.unlink(&self.index.to_string());
}
}

fn try_free_index_when_fully_closed(&self) {
if !(self.master_closed.load(Ordering::SeqCst) && self.slave_closed.load(Ordering::SeqCst))
{
return;
}
if self.index_freed.swap(true, Ordering::SeqCst) {
return;
}

// 兜底:如果 master 未触发 unlink(异常路径),在最终回收时再尝试一次。
self.try_unlink_once();
if let Some(devpts) = self.devpts.upgrade() {
devpts.free_index(self.index);
}
}
}

#[derive(Debug)]
pub struct Unix98PtyDriverInner;

Expand Down Expand Up @@ -220,12 +299,15 @@ impl TtyOperation for Unix98PtyDriverInner {

fn close(&self, tty: Arc<TtyCore>) -> Result<(), SystemError> {
let driver = tty.core().driver();
let root_inode = ProcessManager::current_mntns().root_inode();
if tty.core().driver().tty_driver_sub_type() == TtyDriverSubType::PtySlave {
// 通过 hook 精确管理 devpts 目录项与索引生命周期
if let Some(hook_arc) = tty.private_fields() {
if let Some(hook) = hook_arc.as_any().downcast_ref::<PtyDevPtsLink>() {
hook.on_close(driver.tty_driver_sub_type());
}
}

if driver.tty_driver_sub_type() == TtyDriverSubType::PtySlave {
driver.ttys().remove(&tty.core().index());
let pts_root_inode =
root_inode.lookup_follow_symlink("/dev/pts", VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
let _ = pts_root_inode.unlink(&tty.core().index().to_string());
if let Some(link) = tty.core().link() {
let link_core = link.core();
// set OTHER_CLOSED flag to tell master side that the slave side is closed
Expand All @@ -237,6 +319,17 @@ impl TtyOperation for Unix98PtyDriverInner {
let epitems = link_core.epitems();
let _ = EventPoll::wakeup_epoll(epitems, EPollEventType::EPOLLHUP);
}
} else if driver.tty_driver_sub_type() == TtyDriverSubType::PtyMaster {
// master 侧最后关闭:从 driver 表移除自身(避免泄漏);devpts 的释放由 hook 统一处理
driver.ttys().remove(&tty.core().index());
if let Some(link) = tty.core().link() {
let link_core = link.core();
link_core.flags_write().insert(TtyFlag::OTHER_CLOSED);
link_core.read_wq().wakeup_all();
link_core.write_wq().wakeup_all();
let epitems = link_core.epitems();
let _ = EventPoll::wakeup_epoll(epitems, EPollEventType::EPOLLHUP);
}
}

Ok(())
Expand All @@ -262,6 +355,7 @@ impl TtyOperation for Unix98PtyDriverInner {
}

pub fn ptmx_open(
this: &TtyDevice,
mut data: SpinLockGuard<FilePrivateData>,
flags: &FileFlags,
) -> Result<(), SystemError> {
Expand All @@ -271,17 +365,14 @@ pub fn ptmx_open(
tty.core().add_count();
return Ok(());
}
let root_inode = ProcessManager::current_mntns().root_inode();
let pts_root_inode =
root_inode.lookup_follow_symlink("/dev/pts", VFS_MAX_FOLLOW_SYMLINK_TIMES)?;

let fs = pts_root_inode
.fs()
.as_any_ref()
.downcast_ref::<MountFS>()
.unwrap()
.inner_filesystem();
let fsinfo = fs.as_any_ref().downcast_ref::<DevPtsFs>().unwrap();
// 根据当前节点所属的文件系统决定 devpts 根
let (pts_root_inode, fsinfo) =
if let Some(devpts) = this.fs().clone().downcast_arc::<DevPtsFs>() {
let root_inode = devpts.root_inode();
(root_inode, devpts)
} else {
return Err(SystemError::ENODEV);
};

let index = fsinfo.alloc_index()?;

Expand All @@ -302,6 +393,19 @@ pub fn ptmx_open(
InodeMode::from_bits_truncate(0x666),
)?;

// 在 master/slave 两端记录 devpts 根目录与 fs,用于精确清理:
// - master close: unlink /dev/pts/N
// - master+slave 都 close: free_index(N)
let hook = Arc::new(PtyDevPtsLink::new(
Arc::downgrade(&pts_root_inode),
Arc::downgrade(&fsinfo),
index,
));
tty.set_private_fields(hook.clone());
if let Some(slave) = tty.core().link() {
slave.set_private_fields(hook);
}

ptm_driver().driver_funcs().open(core)?;

Ok(())
Expand Down
7 changes: 4 additions & 3 deletions kernel/src/driver/tty/tty_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,9 +652,10 @@ impl TtyOperation for TtyCore {
self.core().dec_count();
let cnt = self.core().count();
// TODO: fix pty slave close issue
let is_pty_slave_last =
cnt == 1 && tty.core().driver().tty_driver_sub_type() == TtyDriverSubType::PtySlave;
if !self.core().count_valid() || is_pty_slave_last {
let subtype = tty.core().driver().tty_driver_sub_type();
let is_pty_slave_last = cnt == 1 && subtype == TtyDriverSubType::PtySlave;
let is_pty_master_last = cnt == 1 && subtype == TtyDriverSubType::PtyMaster;
if !self.core().count_valid() || is_pty_slave_last || is_pty_master_last {
// log::debug!(
// "TtyCore close: ref count: {}, tty: {}",
// cnt,
Expand Down
34 changes: 24 additions & 10 deletions kernel/src/driver/tty/tty_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,16 @@ impl InnerTtyDevice {
inode: None,
driver: None,
can_match: false,
metadata: Metadata::new(FileType::CharDevice, InodeMode::from_bits_truncate(0o755)),
metadata: {
let mut md =
Metadata::new(FileType::CharDevice, InodeMode::from_bits_truncate(0o755));
// 对于字符设备,选择与 Linux devpts/devfs 一致的首选 I/O 块大小。
// 1024 满足测试期望 (允许 1024 或 4096)。
md.blk_size = 1024;
md
},
}
}

pub fn metadata_mut(&mut self) -> &mut Metadata {
&mut self.metadata
}
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -225,15 +228,28 @@ impl IndexNode for TtyDevice {
mode: &crate::filesystem::vfs::file::FileFlags,
) -> Result<(), SystemError> {
if self.tty_type == TtyType::Pty(PtyType::Ptm) {
return ptmx_open(data, mode);
return ptmx_open(self, data, mode);
}
let dev_num = self.metadata()?.raw_dev;
// /dev/tty 仅在已有控制终端时才能打开;否则返回 ENXIO
let mut tty = if dev_num == DeviceNumber::new(Major::TTYAUX_MAJOR, 0) {
if let Some(current) = self.open_current_tty(dev_num, &mut data) {
Some(current)
} else {
return Err(SystemError::ENXIO);
}
} else {
None
};

// log::debug!(
// "TtyDevice::open: dev_num: {}, current pid: {}",
// dev_num,
// ProcessManager::current_pid()
// );
let mut tty = self.open_current_tty(dev_num, &mut data);
if tty.is_none() {
tty = self.open_current_tty(dev_num, &mut data);
}
if tty.is_none() {
let (index, driver) =
TtyDriverManager::lookup_tty_driver(dev_num).ok_or(SystemError::ENODEV)?;
Expand All @@ -260,10 +276,8 @@ impl IndexNode for TtyDevice {
}

let driver = tty.core().driver();
// 考虑noctty(当前tty)
// 考虑 O_NOCTTY:显式指定则不设置控制终端;pty master 也不会成为控制终端。
if !(mode.contains(FileFlags::O_NOCTTY)
&& dev_num == DeviceNumber::new(Major::TTY_MAJOR, 0)
|| dev_num == DeviceNumber::new(Major::TTYAUX_MAJOR, 1)
|| (driver.tty_driver_type() == TtyDriverType::Pty
&& driver.tty_driver_sub_type() == TtyDriverSubType::PtyMaster))
{
Expand Down
13 changes: 10 additions & 3 deletions kernel/src/driver/tty/tty_driver.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::fmt::Debug;
use core::{any::Any, fmt::Debug};

use alloc::{
string::{String, ToString},
Expand Down Expand Up @@ -102,7 +102,9 @@ impl TtyDriverManager {

/// tty 驱动程序的与设备相关的数据
pub trait TtyDriverPrivateField: Debug + Send + Sync {}
pub trait TtyCorePrivateField: Debug + Send + Sync {}
pub trait TtyCorePrivateField: Debug + Send + Sync + Any {
fn as_any(&self) -> &dyn Any;
}

#[allow(dead_code)]
#[derive(Debug)]
Expand Down Expand Up @@ -336,8 +338,13 @@ impl TtyDriver {
// log::debug!("init_tty_device: to ldisc_setup");
TtyLdiscManager::ldisc_setup(tty.clone(), tty.core().link())?;

// 在devfs创建对应的文件
// 对 PTY 来说,用户可见的设备节点由 devpts 挂载点下的动态节点提供,
// 不应再向全局 devfs 注册(否则在新实例复用索引时会因已有的 ptm/ptsX 节点返回 EEXIST)。
if self.tty_driver_type == TtyDriverType::Pty {
return Ok(tty);
}

// 在devfs创建对应的文件
// log::debug!("init_tty_device: to new tty device");
let device = TtyDevice::new(
core.name().clone(),
Expand Down
Loading
Loading