From 5c4e7b36fad8d3f75ca2363873d8aca6eb3253b5 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Fri, 7 Jul 2023 16:51:27 +1000 Subject: [PATCH] make getty work Signed-off-by: Anhad Singh --- Cargo.lock | 4 + inputd/Cargo.toml | 1 + inputd/src/lib.rs | 25 ++++ inputd/src/main.rs | 116 +++++++++++++++++-- vesad/Cargo.toml | 1 + vesad/src/scheme.rs | 16 ++- virtio-core/src/transport.rs | 5 + virtio-gpud/Cargo.toml | 2 + virtio-gpud/src/main.rs | 101 +++++++++++----- virtio-gpud/src/scheme.rs | 215 ++++++++++++++++++++++++----------- 10 files changed, 375 insertions(+), 111 deletions(-) create mode 100644 inputd/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9960ef6c71..517d78f2bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -680,6 +680,7 @@ version = "0.1.0" dependencies = [ "anyhow", "log", + "orbclient", "redox-daemon", "redox-log", "redox_syscall 0.3.5", @@ -1921,6 +1922,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "vesad" version = "0.1.0" dependencies = [ + "inputd", "orbclient", "ransid", "redox-daemon", @@ -1968,12 +1970,14 @@ version = "0.1.0" dependencies = [ "anyhow", "futures", + "inputd", "log", "orbclient", "paste", "pcid", "redox-daemon", "redox_syscall 0.3.5", + "spin", "static_assertions", "virtio-core", ] diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index 75c1a048a5..dfc537236e 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -10,3 +10,4 @@ log = "0.4.19" redox-daemon = "0.1.0" redox-log = "0.1.1" redox_syscall = "0.3.5" +orbclient = "0.3.27" diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs new file mode 100644 index 0000000000..9ad4ae5876 --- /dev/null +++ b/inputd/src/lib.rs @@ -0,0 +1,25 @@ +use std::fs::File; +use std::io::{Error, Read}; + +pub struct Handle(File); + +impl Handle { + pub fn new>(device_name: S) -> Result { + let path = format!("input:handle/{}", device_name.into()); + Ok(Self(File::open(path)?)) + } + + // The return value is the display identifier. It will be used to uniquely + // identify the display on activation events. + pub fn register(&mut self) -> Result { + Ok(dbg!(self.0.read(&mut [])?)) + } +} + +#[repr(packed)] +pub struct Damage { + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32, +} diff --git a/inputd/src/main.rs b/inputd/src/main.rs index c16cf90325..3f78339d2e 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -15,10 +15,11 @@ use std::collections::BTreeMap; use std::fs::File; use std::io::{Read, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; -#[derive(Debug)] enum Handle { Producer, Consumer { @@ -26,6 +27,7 @@ enum Handle { pending: Vec, notified: bool, }, + Device(Arc), } impl Handle { @@ -36,27 +38,46 @@ impl Handle { struct InputScheme { handles: BTreeMap, + next_id: AtomicUsize, + next_vt_id: AtomicUsize, + + vts: BTreeMap>, + super_key: bool, + active_vt: Option<(Arc, File)>, } impl InputScheme { pub fn new() -> Self { Self { next_id: AtomicUsize::new(0), + next_vt_id: AtomicUsize::new(1), + handles: BTreeMap::new(), + vts: BTreeMap::new(), + super_key: false, + active_vt: None, } } } impl SchemeMut for InputScheme { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { - let handle_ty = match path { + let mut path_parts = path.split('/'); + + let command = path_parts.next().ok_or(SysError::new(EINVAL))?; + + let handle_ty = match command { "producer" => Handle::Producer, "consumer" => Handle::Consumer { events: EventFlags::empty(), pending: Vec::new(), notified: false, }, + "handle" => { + let value = path_parts.next().ok_or(SysError::new(EINVAL))?; + Handle::Device(Arc::new(value.to_string())) + } _ => unreachable!("inputd: invalid path {path}"), }; @@ -72,17 +93,24 @@ impl SchemeMut for InputScheme { fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - if let Handle::Consumer { pending, .. } = handle { - let copy = core::cmp::min(pending.len(), buf.len()); + match handle { + Handle::Consumer { pending, .. } => { + let copy = core::cmp::min(pending.len(), buf.len()); - for (i, byte) in pending.drain(..copy).enumerate() { - buf[i] = byte; + for (i, byte) in pending.drain(..copy).enumerate() { + buf[i] = byte; + } + + Ok(copy) } - Ok(copy) - } else { - // A producer cannot read from the channel. - unreachable!() + Handle::Device(device) => { + let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); + self.vts.insert(vt, device.clone()); + Ok(vt) + } + + _ => unreachable!(), } } @@ -91,6 +119,74 @@ impl SchemeMut for InputScheme { return Ok(1); } + let events = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Event, + buf.len() / core::mem::size_of::(), + ) + }; + + for event in events.iter() { + let mut new_active_opt = None; + match event.to_option() { + EventOption::Key(key_event) => match key_event.scancode { + f @ 0x3B..=0x44 if self.super_key => { + // F1 through F10 + new_active_opt = Some((f - 0x3A) as usize); + } + + 0x57 if self.super_key => { + // F11 + new_active_opt = Some(11); + } + + 0x58 if self.super_key => { + // F12 + new_active_opt = Some(12); + } + + 0x5B => { + // Super + self.super_key = key_event.pressed; + } + + _ => (), + }, + + _ => continue, + } + + if let Some(new_active) = new_active_opt { + if let Some(vt) = self.vts.get(&new_active) { + // Result: display/virtio-gpu:3/acvtivate + let activate = format!("display/{vt}:{new_active}/activate"); + log::info!("inputd: switching to VT #{new_active} ({activate})"); + + let file = File::open(&activate).unwrap(); + // Drop the old active VT first. + // + // TODO(andypython): This can be drastically improved by introducting something + // like ioctl() to the display scheme. + for (vt, device) in self.vts.iter() { + if vt == &new_active { + continue; + } + + let deactivate = format!("display/{device}:{}/deactivate", vt); + let _ = File::open(&deactivate); + + if device.contains("virtio") { + break; + } + } + + self.active_vt = Some((vt.clone(), file)); + } else { + log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); + } + } + } + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; assert!(handle.is_producer()); diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index a77d65c2e6..9b247aabe2 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -9,6 +9,7 @@ ransid = "0.4" rusttype = { version = "0.2", optional = true } redox_syscall = "0.3" redox-daemon = "0.1" +inputd = { path = "../inputd" } [features] default = [] diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index d50c12902b..493eb7888e 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -38,10 +38,13 @@ pub struct DisplayScheme { next_id: usize, pub handles: BTreeMap, super_key: bool, + inputd_handle: inputd::Handle, } impl DisplayScheme { pub fn new(mut framebuffers: Vec, spec: &[bool]) -> DisplayScheme { + let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); + let mut onscreens = Vec::new(); for fb in framebuffers.iter_mut() { onscreens.push(unsafe { @@ -51,7 +54,6 @@ impl DisplayScheme { let mut vts = BTreeMap::>>::new(); - let mut vt_i = 1; for &vt_type in spec.iter() { let mut screens = BTreeMap::>::new(); for fb_i in 0..framebuffers.len() { @@ -62,8 +64,7 @@ impl DisplayScheme { Box::new(TextScreen::new(Display::new(fb.width, fb.height))) }); } - vts.insert(VtIndex(vt_i), screens); - vt_i += 1; + vts.insert(VtIndex(inputd_handle.register().unwrap()), screens); } DisplayScheme { @@ -74,6 +75,7 @@ impl DisplayScheme { next_id: 0, handles: BTreeMap::new(), super_key: false, + inputd_handle } } @@ -168,11 +170,15 @@ impl SchemeMut for DisplayScheme { let screen_i = ScreenIndex( vt_screen.next().unwrap_or("").parse::().unwrap_or(0) ); - if let Some(screens) = self.vts.get(&vt_i) { - if screens.contains_key(&screen_i) { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { for cmd in parts { if cmd == "activate" { self.active = vt_i; + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); } } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index bc56de2149..a1a913d3fd 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -380,6 +380,11 @@ impl<'a> StandardTransport<'a> { }) } + pub fn reset(&self) { + let mut common = self.common.lock().unwrap(); + common.device_status.set(DeviceStatusFlags::empty()); + } + pub fn check_device_feature(&self, feature: u32) -> bool { let mut common = self.common.lock().unwrap(); diff --git a/virtio-gpud/Cargo.toml b/virtio-gpud/Cargo.toml index 02249c294c..c06c18d87e 100644 --- a/virtio-gpud/Cargo.toml +++ b/virtio-gpud/Cargo.toml @@ -13,7 +13,9 @@ paste = "1.0.13" virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } +inputd = { path = "../inputd" } redox-daemon = "0.1" redox_syscall = "0.3" orbclient = "0.3.27" +spin = "0.9.8" diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index f9671f2485..bbe5675688 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -22,6 +22,7 @@ #![feature(int_roundings)] +use std::cell::UnsafeCell; use std::fs::File; use std::io::{Read, Write}; @@ -144,6 +145,15 @@ pub struct ControlHeader { padding: [u8; 3], } +impl ControlHeader { + pub fn with_ty(ty: CommandTy) -> Self { + Self { + ty: VolatileCell::new(ty), + ..Default::default() + } + } +} + impl Default for ControlHeader { fn default() -> Self { Self { @@ -157,44 +167,41 @@ impl Default for ControlHeader { } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct GpuRect { - pub x: VolatileCell, - pub y: VolatileCell, - pub width: VolatileCell, - pub height: VolatileCell, + pub x: u32, + pub y: u32, + pub width: u32, + pub height: u32, } impl GpuRect { pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { Self { - x: VolatileCell::new(x), - y: VolatileCell::new(y), - width: VolatileCell::new(width), - height: VolatileCell::new(height), + x, + y, + width, + height, } } - - #[inline] - pub fn width(&self) -> u32 { - self.width.get() - } - - #[inline] - pub fn height(&self) -> u32 { - self.height.get() - } } #[derive(Debug)] #[repr(C)] pub struct DisplayInfo { - pub rect: GpuRect, + rect: UnsafeCell, pub enabled: VolatileCell, pub flags: VolatileCell, } +impl DisplayInfo { + pub fn rect(&self) -> &GpuRect { + // SAFETY: We never give out mutable references to `self.rect`. + unsafe { &*self.rect.get() } + } +} + #[derive(Debug)] #[repr(C)] pub struct GetDisplayInfo { @@ -274,16 +281,31 @@ pub struct AttachBacking { impl AttachBacking { pub fn new(resource_id: u32, num_entries: u32) -> Self { Self { - header: ControlHeader { - ty: VolatileCell::new(CommandTy::ResourceAttachBacking), - ..Default::default() - }, + header: ControlHeader::with_ty(CommandTy::ResourceAttachBacking), resource_id, num_entries, } } } +#[derive(Debug)] +#[repr(C)] +pub struct DetachBacking { + pub header: ControlHeader, + pub resource_id: u32, + pub padding: u32, +} + +impl DetachBacking { + pub fn new(resource_id: u32) -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::ResourceDetachBacking), + resource_id, + padding: 0, + } + } +} + #[derive(Debug)] #[repr(C)] pub struct ResourceFlush { @@ -296,11 +318,7 @@ pub struct ResourceFlush { impl ResourceFlush { pub fn new(resource_id: u32, rect: GpuRect) -> Self { Self { - header: ControlHeader { - ty: VolatileCell::new(CommandTy::ResourceFlush), - ..Default::default() - }, - + header: ControlHeader::with_ty(CommandTy::ResourceFlush), rect, resource_id, padding: 0, @@ -308,6 +326,24 @@ impl ResourceFlush { } } +#[derive(Debug)] +#[repr(C)] +pub struct ResourceUnref { + pub header: ControlHeader, + pub resource_id: u32, + pub padding: u32, +} + +impl ResourceUnref { + pub fn new(resource_id: u32) -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::ResourceUnref), + resource_id, + padding: 0, + } + } +} + #[repr(C)] #[derive(Debug)] pub struct SetScanout { @@ -389,7 +425,12 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { deamon.ready().unwrap(); let mut socket_file = File::create(":display/virtio-gpu")?; - let mut scheme = scheme::Scheme::new(config, control_queue.clone(), cursor_queue.clone())?; + let mut scheme = futures::executor::block_on(scheme::Scheme::new( + config, + control_queue.clone(), + cursor_queue.clone(), + device.transport.clone(), + ))?; loop { let mut packet = Packet::default(); diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 89c524a517..b0490c8cce 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -1,23 +1,38 @@ use std::collections::BTreeMap; -use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; +use inputd::Damage; use syscall::{Dma, Error as SysError, SchemeMut, EINVAL}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; -use virtio_core::transport::{Error, Queue}; +use virtio_core::transport::{Error, Queue, StandardTransport}; use virtio_core::utils::VolatileCell; use crate::*; static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. +impl Into for &Damage { + fn into(self) -> GpuRect { + GpuRect { + x: self.x as u32, + y: self.y as u32, + width: self.width as u32, + height: self.height as u32, + } + } +} + pub struct Display<'a> { control_queue: Arc>, cursor_queue: Arc>, + transport: Arc>, - mapped: Option, + // TODO(andypython): Remove the need for the spin crate after the `once_cell` + // API is stabilized. + mapped: spin::Once, width: u32, height: u32, @@ -30,24 +45,25 @@ impl<'a> Display<'a> { pub fn new( control_queue: Arc>, cursor_queue: Arc>, - _display_info: &mut DisplayInfo, + transport: Arc>, id: usize, ) -> Self { Self { control_queue, cursor_queue, - mapped: None, + mapped: spin::Once::new(), width: 1920, height: 1080, + transport, id, resource_id: RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst), } } - async fn get_fpath(&mut self, buffer: &mut [u8]) -> Result { + async fn get_fpath(&self, buffer: &mut [u8]) -> Result { let path = format!("display/virtio-gpu:3.0/{}/{}", self.width, self.height); // Copy the path into the target buffer. @@ -55,7 +71,7 @@ impl<'a> Display<'a> { Ok(path.len()) } - async fn send_request(&mut self, request: Dma) -> Result, Error> { + async fn send_request(&self, request: Dma) -> Result, Error> { let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&request)) @@ -66,15 +82,15 @@ impl<'a> Display<'a> { Ok(header) } - async fn flush_resource(&mut self, flush: ResourceFlush) -> Result<(), Error> { + async fn flush_resource(&self, flush: ResourceFlush) -> Result<(), Error> { let header = self.send_request(Dma::new(flush)?).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); Ok(()) } - async fn map_screen(&mut self, offset: usize) -> Result { - if let Some(mapped) = self.mapped { + async fn map_screen(&self, offset: usize) -> Result { + if let Some(mapped) = self.mapped.get() { return Ok(mapped + offset); } @@ -124,74 +140,128 @@ impl<'a> Display<'a> { self.control_queue.send(command).await; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - self.flush().await?; - self.mapped = Some(mapped); - Ok(mapped + offset) - } - async fn flush(&mut self) -> Result<(), Error> { - let rect = GpuRect::new(0, 0, self.width, self.height); - let scanout_request = Dma::new(SetScanout::new(self.id as u32, self.resource_id, rect))?; + let scanout_request = Dma::new(SetScanout::new( + self.id as u32, + self.resource_id, + GpuRect::new(0, 0, self.width, self.height), + ))?; let header = self.send_request(scanout_request).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0, 0, self.width, self.height); - let req = Dma::new(XferToHost2d::new(self.resource_id, rect))?; + self.flush(None).await?; + self.mapped.call_once(|| mapped); + + Ok(mapped + offset) + } + + /// If `damage` is `None`, the entire screen is flushed. + async fn flush(&self, damage: Option<&Damage>) -> Result<(), Error> { + let damage = if let Some(damage) = damage { + damage.into() + } else { + GpuRect { + x: 0, + y: 0, + width: self.width, + height: self.height, + } + }; + + let req = Dma::new(XferToHost2d::new( + self.resource_id, + GpuRect { + x: 0, + y: 0, + width: self.width, + height: self.height, + }, + ))?; let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0, 0, self.width, self.height); - self.flush_resource(ResourceFlush::new(self.resource_id, rect)) + self.flush_resource(ResourceFlush::new(self.resource_id, damage.clone())) .await?; Ok(()) } + + /// This detaches any backing pages from the display and unrefs the resource. Also resets the + /// device, which is required to go back to legacy mode. + async fn detach(&self) -> Result<(), Error> { + let request = Dma::new(DetachBacking::new(self.resource_id))?; + let header = self.send_request(request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + let request = Dma::new(ResourceUnref::new(self.resource_id))?; + let header = self.send_request(request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + // Go back to legacy mode. + self.transport.reset(); + Ok(()) + } } pub struct Scheme<'a> { - control_queue: Arc>, - cursor_queue: Arc>, - config: &'a mut GpuConfig, - /// File descriptor allocator. - next_id: AtomicUsize, - handles: BTreeMap>, + handles: BTreeMap>>, + inputd_handle: inputd::Handle, + displays: Vec>>, } impl<'a> Scheme<'a> { - pub fn new( + pub async fn new( config: &'a mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>, - ) -> Result { - Ok(Self { - control_queue, - cursor_queue, + transport: Arc>, + ) -> Result, Error> { + let displays = Self::probe( + control_queue.clone(), + cursor_queue.clone(), + transport.clone(), config, - next_id: AtomicUsize::new(0), + ) + .await?; + + Ok(Self { handles: BTreeMap::new(), + inputd_handle: inputd::Handle::new("virtio-gpu").unwrap(), + displays, }) } - async fn open_display(&self, id: usize) -> Result, Error> { - let mut display_info = self.get_display_info().await?; - let displays = &mut display_info.display_info[..self.config.num_scanouts() as usize]; + async fn probe( + control_queue: Arc>, + cursor_queue: Arc>, + transport: Arc>, + config: &GpuConfig, + ) -> Result>>, Error> { + let mut display_info = Self::get_display_info(control_queue.clone()).await?; + let displays = &mut display_info.display_info[..config.num_scanouts() as usize]; - let display = displays.get_mut(id).ok_or(SysError::new(syscall::ENOENT))?; + let mut result = vec![]; - log::info!( - "virtio-gpu: opening display ({}x{}px)", - display.rect.width(), - display.rect.height() - ); + for (id, info) in displays.iter().enumerate() { + log::info!( + "virtio-gpu: opening display ({}x{}px)", + info.rect().width, + info.rect().height + ); - Ok(Display::new( - self.control_queue.clone(), - self.cursor_queue.clone(), - display, - id, - )) + let display = Display::new( + control_queue.clone(), + cursor_queue.clone(), + transport.clone(), + id, + ); + + result.push(Arc::new(display)); + } + + Ok(result) } - async fn get_display_info(&self) -> Result, Error> { + async fn get_display_info(control_queue: Arc>) -> Result, Error> { let header = Dma::new(ControlHeader { ty: VolatileCell::new(CommandTy::GetDisplayInfo), ..Default::default() @@ -203,7 +273,7 @@ impl<'a> Scheme<'a> { .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) .build(); - self.control_queue.send(command).await; + control_queue.send(command).await; assert!(response.header.ty.get() == CommandTy::RespOkDisplayInfo); Ok(response) @@ -217,16 +287,30 @@ impl<'a> SchemeMut for Scheme<'a> { let mut parts = path.split('/'); let mut screen = parts.next().unwrap_or("").split('.'); - let vt_index = screen.next().unwrap_or("").parse::().unwrap_or(1); + static YES: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true); + if YES.load(Ordering::SeqCst) { + YES.store(false, Ordering::SeqCst); + } + + let fd = screen.next().unwrap_or("").parse::().unwrap(); + + if path.contains("deactivate") { + log::info!("virtio-gpu: deactivating display at file #{}", fd); + + let handle = self.handles.get(&fd).unwrap(); + futures::executor::block_on(handle.detach()).unwrap(); + + return Ok(0); + } + let id = screen.next().unwrap_or("").parse::().unwrap_or(0); - dbg!(&vt_index, &id); + dbg!(&id); - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - let display = futures::executor::block_on(self.open_display(id)) - .map_err(|_| SysError::new(syscall::ENOENT))?; + let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?; - self.handles.insert(fd, display); + let fd = self.inputd_handle.register().unwrap(); + self.handles.insert(fd, display.clone()); Ok(fd) } @@ -269,7 +353,7 @@ impl<'a> SchemeMut for Scheme<'a> { fn fsync(&mut self, id: usize) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - futures::executor::block_on(handle.flush()).unwrap(); + futures::executor::block_on(handle.flush(None)).unwrap(); Ok(0) } @@ -281,17 +365,16 @@ impl<'a> SchemeMut for Scheme<'a> { fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let damages = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Damage, + buf.len() / core::mem::size_of::(), + ) + }; - // SAFETY: lmao - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - handle.mapped.unwrap() as *mut u8, - buf.len(), - ); + for damage in damages { + futures::executor::block_on(handle.flush(Some(damage))).unwrap(); } - - futures::executor::block_on(handle.flush()).unwrap(); Ok(buf.len()) }