diag: targeted EINVAL tracing

This commit is contained in:
2026-07-12 06:08:17 +03:00
parent 66a5243f18
commit b2a9228783
4 changed files with 81 additions and 25 deletions
+40 -14
View File
@@ -776,24 +776,33 @@ impl FdTbl {
let tag = min & UPPER_FDTBL_TAG; let tag = min & UPPER_FDTBL_TAG;
let (fdtbl, min) = self.select_fdtbl_mut(min); let found_pos = {
let (fdtbl, min_val) = self.select_fdtbl_mut(min);
// Find the first empty slot in the posix_fdtbl starting from `min`. fdtbl.iter().enumerate().skip(min_val).find(|(_, slot)| slot.is_none()).map(|(pos, _)| pos)
if let Some((pos, slot)) = fdtbl
.iter_mut()
.enumerate()
.skip(min)
.find(|(_, slot)| slot.is_none())
{
*slot = Some(file);
self.active_count += 1;
return Some(FileHandle::from(pos | tag));
}; };
let len = fdtbl.len(); if let Some(pos) = found_pos {
if tag == 0 && pos <= 5 {
crate::info!("ADDFILE_MIN: pos={}", pos);
}
let (fdtbl, _) = self.select_fdtbl_mut(min | tag);
if let Some(slot) = fdtbl.get_mut(pos) {
*slot = Some(file);
}
self.active_count += 1;
return Some(FileHandle::from(pos | tag));
}
let len = {
let (fdtbl, _) = self.select_fdtbl_mut(min);
fdtbl.len()
};
// If no empty slot was found, we need to allocate a new slot.
if len >= min { if len >= min {
if tag == 0 {
crate::info!("ADDFILE_APPEND: pos={}", len);
}
let (fdtbl, _) = self.select_fdtbl_mut(min | tag);
fdtbl.push(Some(file)); fdtbl.push(Some(file));
self.active_count += 1; self.active_count += 1;
Some(FileHandle::from(len | tag)) Some(FileHandle::from(len | tag))
@@ -835,6 +844,18 @@ impl FdTbl {
return None; return None;
} }
let index = i.get(); let index = i.get();
let is_posix = index & UPPER_FDTBL_TAG == 0;
if is_posix {
let real_index = Self::strip_tags(index);
if real_index >= super::CONTEXT_MAX_FILES {
return None;
}
if real_index <= 5 {
crate::info!("INSERT_FILE: posix_fd={}", real_index);
}
}
let (fdtbl, real_index) = self.select_fdtbl_mut(index); let (fdtbl, real_index) = self.select_fdtbl_mut(index);
if real_index >= super::CONTEXT_MAX_FILES { if real_index >= super::CONTEXT_MAX_FILES {
@@ -960,8 +981,13 @@ impl FdTbl {
fn remove_file(&mut self, i: FileHandle) -> Option<FileDescriptor> { fn remove_file(&mut self, i: FileHandle) -> Option<FileDescriptor> {
let index = i.get(); let index = i.get();
let is_posix = index & UPPER_FDTBL_TAG == 0;
let (fdtbl, real_index) = self.select_fdtbl_mut(index); let (fdtbl, real_index) = self.select_fdtbl_mut(index);
if is_posix && real_index <= 5 {
crate::info!("REMOVE_FILE: posix_fd={}", real_index);
}
let removed_file_opt = fdtbl.get_mut(real_index).and_then(|opt| opt.take()); let removed_file_opt = fdtbl.get_mut(real_index).and_then(|opt| opt.take());
if removed_file_opt.is_some() { if removed_file_opt.is_some() {
self.active_count -= 1; self.active_count -= 1;
+4 -1
View File
@@ -384,7 +384,10 @@ impl KernelScheme for SchemeList {
) -> Result<usize> { ) -> Result<usize> {
match self.get_user_inner(id, token) { match self.get_user_inner(id, token) {
Some(inner) => inner.write(buf, token), Some(inner) => inner.write(buf, token),
None => Err(Error::new(EBADF)), None => {
error!("KWRITE: scheme {} not found", id);
Err(Error::new(EBADF))
}
} }
} }
+25 -9
View File
@@ -167,7 +167,9 @@ impl UserInner {
fn next_id(&self, token: &mut CleanLockToken) -> Result<u32> { fn next_id(&self, token: &mut CleanLockToken) -> Result<u32> {
let idx = { let idx = {
let mut states = self.states.lock(token.token()); let mut states = self.states.lock(token.token());
states.insert(State::Placeholder) let idx = states.insert(State::Placeholder);
info!("TAG_ALLOC: scheme={} tag={}", self.scheme_id.get(), idx);
idx
}; };
// TODO: implement blocking? // TODO: implement blocking?
@@ -721,9 +723,12 @@ impl UserInner {
} }
pub fn write(&self, buf: UserSliceRo, token: &mut CleanLockToken) -> Result<usize> { pub fn write(&self, buf: UserSliceRo, token: &mut CleanLockToken) -> Result<usize> {
info!("WRITE_ENTRY: scheme={} buf_len={}", self.scheme_id.get(), buf.len());
let mut bytes_read = 0; let mut bytes_read = 0;
for chunk in buf.in_exact_chunks(size_of::<Cqe>()) { for chunk in buf.in_exact_chunks(size_of::<Cqe>()) {
match ParsedCqe::parse_cqe(&unsafe { chunk.read_exact::<Cqe>()? }) let cqe = unsafe { chunk.read_exact::<Cqe>()? };
info!("CQE_RECV: scheme={} opcode={} tag={} result={}", self.scheme_id.get(), cqe.flags & 0b111, cqe.tag, cqe.result);
match ParsedCqe::parse_cqe(&cqe)
.and_then(|p| self.handle_parsed(&p, token)) .and_then(|p| self.handle_parsed(&p, token))
{ {
Ok(()) => bytes_read += size_of::<Cqe>(), Ok(()) => bytes_read += size_of::<Cqe>(),
@@ -741,8 +746,6 @@ impl UserInner {
flags: MapFlags, flags: MapFlags,
token: &mut CleanLockToken, token: &mut CleanLockToken,
) -> Result<()> { ) -> Result<()> {
info!("REQUEST FMAP");
let tag = self.next_id(token)?; let tag = self.next_id(token)?;
{ {
let mut states = self.states.lock(token.token()); let mut states = self.states.lock(token.token());
@@ -779,20 +782,28 @@ impl UserInner {
ParsedCqe::RespondAndNotifyOnDetach { tag, res, extra0 } => { ParsedCqe::RespondAndNotifyOnDetach { tag, res, extra0 } => {
self.respond(tag, Response::Regular(res, extra0, true), token)? self.respond(tag, Response::Regular(res, extra0, true), token)?
} }
ParsedCqe::ResponseWithFd { tag, fd } => self.respond( ParsedCqe::ResponseWithFd { tag, fd } => {
info!("RESPOND_WITH_FD: tag={} fd={}", tag, fd);
self.respond(
tag, tag,
Response::Fd({ Response::Fd({
{ let removed = {
let current_lock = context::current(); let current_lock = context::current();
let mut current = current_lock.read(token.token()); let mut current = current_lock.read(token.token());
let (context, mut token) = current.token_split(); let (context, mut token) = current.token_split();
context.remove_file(FileHandle::from(fd), &mut token) context.remove_file(FileHandle::from(fd), &mut token)
};
match removed {
Some(desc) => desc.description,
None => {
error!("EINVAL ResponseWithFd: tag={} fd={} not in procmgr fd table", tag, fd);
return Err(Error::new(EINVAL));
}
} }
.ok_or(Error::new(EINVAL))?
.description
}), }),
token, token,
)?, )?;
},
ParsedCqe::ResponseWithMultipleFds { tag, num_fds: _ } => { ParsedCqe::ResponseWithMultipleFds { tag, num_fds: _ } => {
self.respond(tag, Response::MultipleFds(None), token)?; self.respond(tag, Response::MultipleFds(None), token)?;
} }
@@ -931,6 +942,11 @@ impl UserInner {
State::Placeholder => return Err(Error::new(EBADFD)), State::Placeholder => return Err(Error::new(EBADFD)),
// invalid scheme to kernel call // invalid scheme to kernel call
old_state @ (State::Responded(_) | State::Fmap(_)) => { old_state @ (State::Responded(_) | State::Fmap(_)) => {
error!("EINVAL respond: tag={} state={:?}", tag, match &old_state {
State::Responded(_) => "Responded",
State::Fmap(_) => "Fmap",
_ => unreachable!(),
});
*o = old_state; *o = old_state;
return Err(Error::new(EINVAL)); return Err(Error::new(EINVAL));
} }
+12 -1
View File
@@ -45,6 +45,12 @@ pub fn file_op_generic_ext<T>(
(file, desc) (file, desc)
}; };
// Debug: trace fd=3 to catch corruption
if fd.get() == 3 && fd.get() & syscall::UPPER_FDTBL_TAG == 0 {
let pid = context::current().read(token.token()).pid;
info!("FD3_TRACE: pid={} scheme={} number={}", pid, desc.scheme.get(), desc.number);
}
let scheme = scheme::get_scheme(token.token(), desc.scheme)?; let scheme = scheme::get_scheme(token.token(), desc.scheme)?;
op(&*scheme, file.description, desc, token) op(&*scheme, file.description, desc, token)
@@ -848,8 +854,13 @@ pub fn sys_write(fd: FileHandle, buf: UserSliceRo, token: &mut CleanLockToken) -
} else { } else {
0 0
}; };
let res = scheme.kwriteoff(desc.number, buf, offset, desc.flags, desc.flags, token);
if res.is_err() {
let pid = context::current().read(token.token()).pid;
error!("SYS_WRITE_ERR: pid={} fd={} scheme={} number={} offset={} err={:?}", pid, fd.get(), desc.scheme.get(), desc.number, offset, res.as_ref().err());
}
Ok(( Ok((
scheme.kwriteoff(desc.number, buf, offset, desc.flags, desc.flags, token)?, res?,
desc_arc, desc_arc,
desc, desc,
)) ))