fix: open() uses single SYS_OPENAT call — eliminates OtherScheme EOPNOTSUPP
The two-step pattern (open full path as scheme root, then open reference relative to root_fd) failed for namespace-internal paths like /scheme/namespace/scheme-creation-cap. The namespace scheme resolves the full path and returns OtherScheme pointing to SchemeList (a kernel scheme that does not implement kopenat). The second call then hits SchemeList.kopenat() → EOPNOTSUPP. The namespace scheme already handles reference resolution internally via open_scheme_resource(), so a single SYS_OPENAT call with the full path resolves everything. This also bypasses FILETABLE.insert_upper (which previously collided with the untracked ns_fd at UPPER index 0).
This commit is contained in:
+7
-19
@@ -589,32 +589,20 @@ pub fn getns() -> Result<usize> {
|
||||
|
||||
pub fn open<T: AsRef<str>>(path: T, flags: usize) -> Result<usize> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let fcntl_flags = flags & syscall::O_FCNTL_MASK;
|
||||
let redox_path = RedoxPath::from_absolute(path.as_ref()).ok_or(Error::new(EINVAL))?;
|
||||
let (_, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let ns_fd = crate::current_namespace_fd()?;
|
||||
|
||||
// Open the scheme root using raw SYS_OPENAT (auto-assigned POSIX fd).
|
||||
// This bypasses FILETABLE.insert_upper, which could collide with the
|
||||
// namespace fd (ns_fd) that is not always tracked in the UPPER table.
|
||||
let root_fd = syscall::openat(
|
||||
// Single SYS_OPENAT call: the kernel resolves the full path through the
|
||||
// namespace scheme, which handles OtherScheme redirection internally.
|
||||
// The previous two-step approach (open scheme root, then open reference)
|
||||
// failed when the namespace returned OtherScheme, because the target
|
||||
// scheme did not implement kopenat for the reference path.
|
||||
let posix_fd = syscall::openat(
|
||||
ns_fd,
|
||||
path.as_ref(),
|
||||
syscall::O_DIRECTORY | O_CLOEXEC,
|
||||
flags,
|
||||
0,
|
||||
)?;
|
||||
register_external_fd(root_fd)?;
|
||||
|
||||
let posix_fd = syscall::openat(
|
||||
root_fd,
|
||||
reference.as_ref(),
|
||||
flags,
|
||||
fcntl_flags,
|
||||
)?;
|
||||
|
||||
// Close root_fd and remove from FILETABLE, then register posix_fd.
|
||||
close(root_fd)?;
|
||||
register_external_fd(posix_fd)?;
|
||||
|
||||
Ok(posix_fd)
|
||||
|
||||
Reference in New Issue
Block a user