storage/lived: Use the unified disk scheme implementation
This commit is contained in:
Generated
+1
-1
@@ -780,9 +780,9 @@ name = "lived"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"driver-block",
|
||||
"libredox",
|
||||
"redox-daemon",
|
||||
"redox-scheme 0.3.0",
|
||||
"redox_event",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
@@ -69,6 +69,8 @@ pub trait Disk {
|
||||
fn block_size(&self) -> u32;
|
||||
fn size(&self) -> u64;
|
||||
|
||||
// These operate on a whole multiple of the block size
|
||||
// FIXME maybe only operate on a single block worth of data?
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result<Option<usize>>;
|
||||
fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result<Option<usize>>;
|
||||
}
|
||||
|
||||
@@ -12,5 +12,5 @@ anyhow = "1"
|
||||
libredox = "0.1.3"
|
||||
redox-daemon = "0.1"
|
||||
redox_syscall = { version = "0.5", features = ["std"] }
|
||||
redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" }
|
||||
redox_event = "0.4"
|
||||
driver-block = { path = "../driver-block" }
|
||||
|
||||
+62
-136
@@ -2,46 +2,26 @@
|
||||
|
||||
#![feature(int_roundings)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::str;
|
||||
|
||||
use driver_block::{Disk, DiskScheme};
|
||||
use libredox::call::MmapArgs;
|
||||
use libredox::flag;
|
||||
use redox_scheme::{CallerCtx, OpenResult, RequestKind, Scheme, SignalBehavior, Socket};
|
||||
|
||||
use syscall::data::Stat;
|
||||
use syscall::error::*;
|
||||
use syscall::flag::{MODE_DIR, MODE_FILE};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
|
||||
const LIST: [u8; 2] = *b"0\n";
|
||||
|
||||
#[repr(usize)]
|
||||
enum HandleType {
|
||||
TopLevel = 0,
|
||||
TheData = 1,
|
||||
}
|
||||
impl HandleType {
|
||||
fn try_from_raw(raw: usize) -> Option<Self> {
|
||||
Some(match raw {
|
||||
0 => Self::TopLevel,
|
||||
1 => Self::TheData,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiskScheme {
|
||||
struct LiveDisk {
|
||||
the_data: &'static mut [u8],
|
||||
}
|
||||
|
||||
impl DiskScheme {
|
||||
pub fn new() -> anyhow::Result<DiskScheme> {
|
||||
impl LiveDisk {
|
||||
fn new() -> anyhow::Result<LiveDisk> {
|
||||
let mut phys = 0;
|
||||
let mut size = 0;
|
||||
|
||||
@@ -93,133 +73,79 @@ impl DiskScheme {
|
||||
std::slice::from_raw_parts_mut(base as *mut u8, size)
|
||||
};
|
||||
|
||||
Ok(DiskScheme { the_data })
|
||||
Ok(LiveDisk { the_data })
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for DiskScheme {
|
||||
fn fsize(&mut self, id: usize) -> Result<u64> {
|
||||
Ok(
|
||||
match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? {
|
||||
HandleType::TopLevel => LIST.len() as u64,
|
||||
HandleType::TheData => self.the_data.len() as u64,
|
||||
},
|
||||
)
|
||||
impl Disk for LiveDisk {
|
||||
fn block_size(&self) -> u32 {
|
||||
512
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
fn size(&self) -> u64 {
|
||||
self.the_data.len() as u64
|
||||
}
|
||||
|
||||
fn fsync(&mut self, _id: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn close(&mut self, _id: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
fn xopen(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result<Option<usize>> {
|
||||
let block = block as usize;
|
||||
let block_size = self.block_size() as usize;
|
||||
if block * block_size + buffer.len() > self.size() as usize {
|
||||
return Err(syscall::Error::new(EOVERFLOW));
|
||||
}
|
||||
|
||||
let path_trimmed = path.trim_matches('/');
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: match path_trimmed {
|
||||
"" => HandleType::TopLevel as usize,
|
||||
"0" => HandleType::TheData as usize,
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
},
|
||||
flags: NewFdFlags::POSITIONED,
|
||||
})
|
||||
}
|
||||
fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result<usize> {
|
||||
let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? {
|
||||
HandleType::TheData => &*self.the_data,
|
||||
HandleType::TopLevel => &LIST,
|
||||
};
|
||||
|
||||
let src = usize::try_from(offset)
|
||||
.ok()
|
||||
.and_then(|o| data.get(o..))
|
||||
.unwrap_or(&[]);
|
||||
let byte_count = std::cmp::min(src.len(), buf.len());
|
||||
buf[..byte_count].copy_from_slice(&src[..byte_count]);
|
||||
Ok(byte_count)
|
||||
}
|
||||
fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result<usize> {
|
||||
let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? {
|
||||
HandleType::TheData => &mut *self.the_data,
|
||||
HandleType::TopLevel => return Err(Error::new(EBADF)),
|
||||
};
|
||||
|
||||
let dst = usize::try_from(offset)
|
||||
.ok()
|
||||
.and_then(|o| data.get_mut(o..))
|
||||
.unwrap_or(&mut []);
|
||||
let byte_count = std::cmp::min(dst.len(), buf.len());
|
||||
dst[..byte_count].copy_from_slice(&buf[..byte_count]);
|
||||
Ok(byte_count)
|
||||
buffer
|
||||
.copy_from_slice(&self.the_data[block * block_size..block * block_size + buffer.len()]);
|
||||
Ok(Some(block_size))
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
let path = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? {
|
||||
HandleType::TopLevel => "",
|
||||
HandleType::TheData => "0",
|
||||
};
|
||||
|
||||
let src = format!("disk.live:{}", path).into_bytes();
|
||||
|
||||
let byte_count = std::cmp::min(buf.len(), src.len());
|
||||
buf[..byte_count].copy_from_slice(&src[..byte_count]);
|
||||
|
||||
Ok(byte_count)
|
||||
}
|
||||
fn fstat(&mut self, id: usize, stat_buf: &mut Stat) -> Result<usize> {
|
||||
let (len, mode) = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? {
|
||||
HandleType::TheData => (self.the_data.len(), MODE_FILE | 0o644),
|
||||
HandleType::TopLevel => (LIST.len(), MODE_DIR | 0o755),
|
||||
};
|
||||
|
||||
*stat_buf = Stat {
|
||||
st_mode: mode,
|
||||
st_uid: 0,
|
||||
st_gid: 0,
|
||||
st_size: len.try_into().map_err(|_| Error::new(EOVERFLOW))?,
|
||||
..Stat::default()
|
||||
};
|
||||
|
||||
Ok(0)
|
||||
fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result<Option<usize>> {
|
||||
let block = block as usize;
|
||||
let block_size = self.block_size() as usize;
|
||||
if block * block_size + buffer.len() > self.size() as usize {
|
||||
return Err(syscall::Error::new(EOVERFLOW));
|
||||
}
|
||||
self.the_data[block * block_size..block * block_size + buffer.len()]
|
||||
.copy_from_slice(buffer);
|
||||
Ok(Some(block_size))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
redox_daemon::Daemon::new(move |daemon| {
|
||||
let socket_fd = Socket::create("disk.live").expect("failed to open scheme");
|
||||
let mut scheme = DiskScheme::new().unwrap_or_else(|err| {
|
||||
eprintln!("failed to initialize livedisk scheme: {}", err);
|
||||
std::process::exit(1)
|
||||
});
|
||||
let event_queue = event::EventQueue::new().unwrap();
|
||||
|
||||
event::user_data! {
|
||||
enum Event {
|
||||
Scheme,
|
||||
}
|
||||
};
|
||||
|
||||
let mut scheme = DiskScheme::new(
|
||||
"disk.live".to_owned(),
|
||||
BTreeMap::from([(
|
||||
0,
|
||||
LiveDisk::new().unwrap_or_else(|err| {
|
||||
eprintln!("failed to initialize livedisk scheme: {}", err);
|
||||
std::process::exit(1)
|
||||
}),
|
||||
)]),
|
||||
);
|
||||
|
||||
libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace");
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
scheme.event_handle().raw(),
|
||||
Event::Scheme,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
daemon.ready().expect("failed to signal readiness");
|
||||
|
||||
loop {
|
||||
let req = match socket_fd
|
||||
.next_request(SignalBehavior::Restart)
|
||||
.expect("failed to get next request")
|
||||
{
|
||||
Some(r) => {
|
||||
if let RequestKind::Call(c) = r.kind() {
|
||||
c
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
None => break,
|
||||
};
|
||||
let resp = req.handle_scheme(&mut scheme);
|
||||
socket_fd
|
||||
.write_response(resp, SignalBehavior::Restart)
|
||||
.expect("failed to write packet");
|
||||
for event in event_queue {
|
||||
match event.unwrap().user_data {
|
||||
Event::Scheme => scheme.tick().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
std::process::exit(0);
|
||||
|
||||
Reference in New Issue
Block a user