diag: targeted EINVAL tracing
This commit is contained in:
+40
-14
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||||
))
|
))
|
||||||
|
|||||||
Reference in New Issue
Block a user