Merge branch 'shm-handling' into 'main'

Fixes for shm handling

See merge request redox-os/base!31
This commit is contained in:
Jeremy Soller
2025-10-17 15:02:45 -06:00
+121 -9
View File
@@ -5,13 +5,15 @@ use std::{
rc::Rc,
};
use syscall::{
error::*, schemev2::NewFdFlags, Error, Map, MapFlags, Result, MAP_PRIVATE, PAGE_SIZE,
error::*, schemev2::NewFdFlags, Error, Map, MapFlags, Result, MAP_PRIVATE, MAP_SHARED,
PAGE_SIZE, PROT_READ, PROT_WRITE,
};
#[derive(Default)]
pub struct ShmHandle {
buffer: Option<MmapGuard>,
refs: usize,
unlinked: bool,
}
pub struct ShmScheme {
maps: HashMap<Rc<str>, ShmHandle>,
@@ -29,12 +31,23 @@ impl ShmScheme {
}
impl SchemeSync for ShmScheme {
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
//FIXME: Handle O_RDONLY/O_WRONLY/O_RDWR
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
let path = Rc::from(path);
let entry = self
.maps
.entry(Rc::clone(&path))
.or_insert(ShmHandle::default());
let entry = match self.maps.entry(Rc::clone(&path)) {
Entry::Occupied(mut e) => {
if flags & syscall::O_EXCL != 0 && flags & syscall::O_CREAT != 0 {
return Err(Error::new(EEXIST));
}
e.into_mut()
}
Entry::Vacant(e) => {
if flags & syscall::O_CREAT == 0 {
return Err(Error::new(ENOENT));
}
e.insert(ShmHandle::default())
}
};
entry.refs += 1;
self.handles.insert(self.next_id, path);
@@ -42,12 +55,12 @@ impl SchemeSync for ShmScheme {
self.next_id += 1;
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::empty(),
flags: NewFdFlags::POSITIONED,
})
}
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
// Write scheme name
const PREFIX: &[u8] = b"shm:";
const PREFIX: &[u8] = b"/scheme/shm/";
let len = cmp::min(PREFIX.len(), buf.len());
buf[..len].copy_from_slice(&PREFIX[..len]);
if len < PREFIX.len() {
@@ -68,10 +81,32 @@ impl SchemeSync for ShmScheme {
Entry::Vacant(_) => panic!("handle pointing to nothing"),
};
entry.get_mut().refs -= 1;
if entry.get().refs == 0 && entry.get().unlinked {
// There is no other reference to this entry, drop
entry.remove_entry();
}
}
fn unlink(&mut self, path: &str, ctx: &CallerCtx) -> Result<()> {
let path = Rc::from(path);
let mut entry = match self.maps.entry(Rc::clone(&path)) {
Entry::Occupied(e) => e,
Entry::Vacant(_) => return Err(Error::new(ENOENT)),
};
entry.get_mut().unlinked = true;
if entry.get().refs == 0 {
// There is no other reference to this entry, drop
entry.remove_entry();
}
Ok(())
}
fn ftruncate(&mut self, id: usize, len: u64, _ctx: &CallerCtx) -> Result<()> {
let path = self.handles.get(&id).ok_or(Error::new(EBADF))?;
self.maps
.get_mut(path)
.expect("handle pointing to nothing")
.buffer = Some(MmapGuard::alloc((len as usize).div_ceil(PAGE_SIZE))?);
Ok(())
}
fn mmap_prep(
&mut self,
@@ -95,12 +130,51 @@ impl SchemeSync for ShmScheme {
}
Ok(buf.as_ptr() + offset as usize)
}
//TODO: this should be only handled by ftruncate
ref mut buf @ None => {
*buf = Some(MmapGuard::alloc(size.div_ceil(PAGE_SIZE))?);
Ok(buf.as_mut().unwrap().as_ptr() + offset as usize)
}
}
}
fn read(
&mut self,
id: usize,
buf: &mut [u8],
offset: u64,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
let path = self.handles.get(&id).ok_or(Error::new(EBADF))?;
match self
.maps
.get_mut(path)
.expect("handle pointing to nothing")
.buffer
{
Some(ref mut map) => map.read(offset as usize, buf),
None => Err(Error::new(ERANGE)),
}
}
fn write(
&mut self,
id: usize,
buf: &[u8],
offset: u64,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
let path = self.handles.get(&id).ok_or(Error::new(EBADF))?;
match self
.maps
.get_mut(path)
.expect("handle pointing to nothing")
.buffer
{
Some(ref mut map) => map.write(offset as usize, buf),
None => Err(Error::new(ERANGE)),
}
}
}
pub struct MmapGuard {
@@ -116,7 +190,7 @@ impl MmapGuard {
&Map {
offset: 0,
size,
flags: MAP_PRIVATE,
flags: MAP_PRIVATE | PROT_READ | PROT_WRITE,
address: 0,
},
)
@@ -130,6 +204,44 @@ impl MmapGuard {
pub fn as_ptr(&self) -> usize {
self.base
}
pub fn as_slice(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.base as *const u8, self.size) }
}
pub fn as_slice_mut(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.base as *mut u8, self.size) }
}
pub fn read(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let read_len = buf.len();
let end = offset
.checked_add(read_len)
.ok_or_else(|| Error::new(ERANGE))?;
if end > self.size {
return Err(Error::new(ERANGE));
}
let mmap_slice = Self::as_slice(self);
let source_slice = &mmap_slice[offset..end];
buf.copy_from_slice(source_slice);
Ok(read_len)
}
pub fn write(&mut self, offset: usize, buf: &[u8]) -> Result<usize> {
let write_len = buf.len();
let end = offset
.checked_add(write_len)
.ok_or_else(|| Error::new(ERANGE))?;
if end > self.size {
return Err(Error::new(ERANGE));
}
let mmap_slice = Self::as_slice_mut(self);
let dest_slice = &mut mmap_slice[offset..end];
dest_slice.copy_from_slice(buf);
Ok(write_len)
}
}
impl Drop for MmapGuard {
fn drop(&mut self) {