diff --git a/ipcd/src/shm.rs b/ipcd/src/shm.rs index b1e16ed996..340663e492 100644 --- a/ipcd/src/shm.rs +++ b/ipcd/src/shm.rs @@ -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, refs: usize, + unlinked: bool, } pub struct ShmScheme { maps: HashMap, ShmHandle>, @@ -29,12 +31,23 @@ impl ShmScheme { } impl SchemeSync for ShmScheme { - fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result { + //FIXME: Handle O_RDONLY/O_WRONLY/O_RDWR + fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result { 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 { // 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 { + 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 { + 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 { + 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 { + 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) {