refactor: Allow refreshing filetable data using dup2 to fix O_CLOEXEC

This commit is contained in:
Ibuki Omatsu
2026-07-18 01:49:20 +00:00
committed by Jeremy Soller
parent e100dd5a71
commit 37ffa2e29e
2 changed files with 80 additions and 29 deletions
+51 -17
View File
@@ -771,25 +771,59 @@ impl KernelScheme for ProcScheme {
} => { } => {
// TODO: Maybe allow userspace to either copy or transfer recently dupped file // TODO: Maybe allow userspace to either copy or transfer recently dupped file
// descriptors between file tables. // descriptors between file tables.
if buf != b"copy" { let new_handle = match buf {
return Err(Error::new(EINVAL)); b"copy" => {
} let filetable = filetable.upgrade().ok_or(Error::new(EOWNERDEAD))?;
let filetable = filetable.upgrade().ok_or(Error::new(EOWNERDEAD))?;
let new_filetable = let new_filetable =
Arc::new(RwLock::new(filetable.read(token.token()).clone())); Arc::new(RwLock::new(filetable.read(token.token()).clone()));
handle( Handle {
Handle { kind: ContextHandle::NewFiletable {
kind: ContextHandle::NewFiletable { filetable: new_filetable,
filetable: new_filetable, binary_format,
binary_format, data: data.clone(),
data: data.clone(), },
}, context,
context, }
}, }
true, b"refresh" => {
) let filetable = filetable.upgrade().ok_or(Error::new(EOWNERDEAD))?;
let new_data = if binary_format {
let mut data = Vec::new();
for index in filetable
.read(token.token())
.enumerate()
.filter_map(|(idx, val)| val.as_ref().map(|_| idx))
{
data.extend((index as u64).to_le_bytes());
}
data.into_boxed_slice()
} else {
use core::fmt::Write;
let mut data = String::new();
for index in filetable
.read(token.token())
.enumerate()
.filter_map(|(idx, val)| val.as_ref().map(|_| idx))
{
writeln!(data, "{}", index).unwrap();
}
data.into_bytes().into_boxed_slice()
};
Handle {
kind: ContextHandle::Filetable {
filetable: Arc::downgrade(&filetable),
binary_format,
data: new_data,
},
context,
}
}
_ => return Err(Error::new(EINVAL)),
};
handle(new_handle, true)
} }
Handle { Handle {
kind: ContextHandle::AddrSpace { ref addrspace }, kind: ContextHandle::AddrSpace { ref addrspace },
+29 -12
View File
@@ -235,19 +235,36 @@ pub fn dup2(
buf: UserSliceRo, buf: UserSliceRo,
token: &mut CleanLockToken, token: &mut CleanLockToken,
) -> Result<FileHandle> { ) -> Result<FileHandle> {
if fd == new_fd { if fd == new_fd && buf.is_empty() {
Ok(new_fd) return Ok(new_fd);
} else {
let _ = close(new_fd, token);
let new_file = duplicate_file(fd, buf, token)?;
let current_lock = context::current();
let mut current = current_lock.read(token.token());
let (context, mut token) = current.token_split();
context
.insert_file(new_fd, new_file, &mut token)
.ok_or(Error::new(EMFILE))
} }
let new_file = duplicate_file(fd, buf, token)?;
let old_file = {
let current_lock = context::current();
let mut current = current_lock.write(token.token());
let (context, mut split_token) = current.token_split();
let old_file = context.remove_file(new_fd, &mut split_token.token());
if context
.insert_file(new_fd, new_file, &mut split_token.token())
.is_none()
{
if let Some(old) = old_file {
context.insert_file(new_fd, old, &mut split_token.token());
}
return Err(Error::new(EMFILE));
}
old_file
};
if let Some(old) = old_file {
let _ = old.close(token);
}
Ok(new_fd)
} }
pub fn call( pub fn call(
fds: &[usize], fds: &[usize],