nvmed: add scheme with read/write implemented using polling
This commit is contained in:
+72
-45
@@ -1,4 +1,3 @@
|
||||
//#![deny(warnings)]
|
||||
#![feature(asm)]
|
||||
|
||||
extern crate bitflags;
|
||||
@@ -6,25 +5,17 @@ extern crate spin;
|
||||
extern crate syscall;
|
||||
|
||||
use std::{env, usize};
|
||||
use std::fs::File;
|
||||
use std::io::{ErrorKind, Read, Write};
|
||||
use std::os::unix::io::{RawFd, FromRawFd};
|
||||
|
||||
|
||||
|
||||
use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, Scheme};
|
||||
use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, SchemeBlockMut};
|
||||
|
||||
use self::nvme::Nvme;
|
||||
use self::scheme::DiskScheme;
|
||||
|
||||
mod nvme;
|
||||
|
||||
/*
|
||||
fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> {
|
||||
if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) {
|
||||
Ok((name, fd))
|
||||
} else {
|
||||
syscall::open(&format!(":{}", fallback), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK)
|
||||
.map(|fd| (fallback, fd))
|
||||
}
|
||||
}
|
||||
*/
|
||||
mod scheme;
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
@@ -45,48 +36,84 @@ fn main() {
|
||||
//TODO: Figure out correct size of mapping, not just 256 * 1024
|
||||
let address = unsafe { syscall::physmap(bar, 256 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("nvmed: failed to map address") };
|
||||
{
|
||||
let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate queues");
|
||||
unsafe { nvme.init(); }
|
||||
/*
|
||||
let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("nvmed: failed to create disk scheme");
|
||||
let mut socket = unsafe { File::from_raw_fd(socket_fd) };
|
||||
syscall::fevent(socket_fd, EVENT_READ).expect("nvmed: failed to fevent disk scheme");
|
||||
let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC)
|
||||
.expect("nvmed: failed to open event queue");
|
||||
let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) };
|
||||
|
||||
let mut irq_file = File::open(&format!("irq:{}", irq)).expect("nvmed: failed to open irq file");
|
||||
let irq_fd = irq_file.as_raw_fd();
|
||||
syscall::fevent(irq_fd, EVENT_READ).expect("nvmed: failed to fevent irq file");
|
||||
let irq_fd = syscall::open(
|
||||
&format!("irq:{}", irq),
|
||||
syscall::O_RDWR | syscall::O_NONBLOCK | syscall::O_CLOEXEC
|
||||
).expect("nvmed: failed to open irq file");
|
||||
syscall::write(event_fd, &syscall::Event {
|
||||
id: irq_fd,
|
||||
flags: syscall::EVENT_READ,
|
||||
data: 0,
|
||||
}).expect("nvmed: failed to watch irq file events");
|
||||
let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) };
|
||||
|
||||
let mut event_file = File::open("event:").expect("nvmed: failed to open event file");
|
||||
|
||||
let scheme = DiskScheme::new(nvme::disks(address, &name));
|
||||
let scheme_name = format!("disk/{}", name);
|
||||
let socket_fd = syscall::open(
|
||||
&format!(":{}", scheme_name),
|
||||
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC
|
||||
).expect("nvmed: failed to create disk scheme");
|
||||
syscall::write(event_fd, &syscall::Event {
|
||||
id: socket_fd,
|
||||
flags: syscall::EVENT_READ,
|
||||
data: 1,
|
||||
}).expect("nvmed: failed to watch disk scheme events");
|
||||
let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) };
|
||||
|
||||
syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace");
|
||||
|
||||
loop {
|
||||
let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate driver data");
|
||||
let namespaces = unsafe { nvme.init() };
|
||||
let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces);
|
||||
let mut todo = Vec::new();
|
||||
'events: loop {
|
||||
let mut event = Event::default();
|
||||
if event_file.read(&mut event).expect("nvmed: failed to read event file") == 0 {
|
||||
if event_file.read(&mut event).expect("nvmed: failed to read event queue") == 0 {
|
||||
break;
|
||||
}
|
||||
if event.id == socket_fd {
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
if socket.read(&mut packet).expect("nvmed: failed to read disk scheme") == 0 {
|
||||
break;
|
||||
|
||||
match event.data {
|
||||
0 => {
|
||||
let mut irq = [0; 8];
|
||||
if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() {
|
||||
if scheme.irq() {
|
||||
irq_file.write(&irq).expect("nvmed: failed to write irq file");
|
||||
}
|
||||
}
|
||||
scheme.handle(&mut packet);
|
||||
socket.write(&mut packet).expect("nvmed: failed to write disk scheme");
|
||||
},
|
||||
1 => loop {
|
||||
let mut packet = Packet::default();
|
||||
match socket_file.read(&mut packet) {
|
||||
Ok(0) => break 'events,
|
||||
Ok(_) => (),
|
||||
Err(err) => match err.kind() {
|
||||
ErrorKind::WouldBlock => break,
|
||||
_ => Err(err).expect("nvmed: failed to read disk scheme"),
|
||||
}
|
||||
}
|
||||
todo.push(packet);
|
||||
},
|
||||
unknown => {
|
||||
panic!("nvmed: unknown event data {}", unknown);
|
||||
},
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
if let Some(a) = scheme.handle(&todo[i]) {
|
||||
let mut packet = todo.remove(i);
|
||||
packet.a = a;
|
||||
socket_file.write(&packet).expect("nvmed: failed to write disk scheme");
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
} else if event.id == irq_fd {
|
||||
let mut irq = [0; 8];
|
||||
if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() {
|
||||
//TODO : Test for IRQ
|
||||
//irq_file.write(&irq).expect("nvmed: failed to write irq file");
|
||||
}
|
||||
} else {
|
||||
println!("Unknown event {}", event.id);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//TODO: destroy NVMe stuff
|
||||
}
|
||||
unsafe { let _ = syscall::physunmap(address); }
|
||||
}
|
||||
|
||||
+145
-12
@@ -1,6 +1,7 @@
|
||||
use std::{mem, thread};
|
||||
use std::thread;
|
||||
use std::collections::BTreeMap;
|
||||
use syscall::io::{Dma, Io, Mmio};
|
||||
use syscall::error::Result;
|
||||
use syscall::error::{Error, Result, EINVAL};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(packed)]
|
||||
@@ -124,7 +125,7 @@ impl NvmeCmd {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn io_read(cid: u16, nsid: u32, lba: u64, count: u16, ptr: usize) -> Self {
|
||||
pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self {
|
||||
Self {
|
||||
opcode: 2,
|
||||
flags: 1 << 6,
|
||||
@@ -132,17 +133,17 @@ impl NvmeCmd {
|
||||
nsid: nsid,
|
||||
_rsvd: 0,
|
||||
mptr: 0,
|
||||
dptr: [ptr as u64, (count as u64) << 9],
|
||||
dptr: [ptr0, ptr1],
|
||||
cdw10: lba as u32,
|
||||
cdw11: (lba >> 32) as u32,
|
||||
cdw12: count.saturating_sub(1) as u32, //TODO: Prevent count of 0
|
||||
cdw12: blocks_1 as u32,
|
||||
cdw13: 0,
|
||||
cdw14: 0,
|
||||
cdw15: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn io_write(cid: u16, nsid: u32, lba: u64, count: u16, ptr: usize) -> Self {
|
||||
pub fn io_write(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self {
|
||||
Self {
|
||||
opcode: 1,
|
||||
flags: 1 << 6,
|
||||
@@ -150,10 +151,10 @@ impl NvmeCmd {
|
||||
nsid: nsid,
|
||||
_rsvd: 0,
|
||||
mptr: 0,
|
||||
dptr: [ptr as u64, (count as u64) << 9],
|
||||
dptr: [ptr0, ptr1],
|
||||
cdw10: lba as u32,
|
||||
cdw11: (lba >> 32) as u32,
|
||||
cdw12: count.saturating_sub(1) as u32, //TODO: Prevent count of 0
|
||||
cdw12: blocks_1 as u32,
|
||||
cdw13: 0,
|
||||
cdw14: 0,
|
||||
cdw15: 0,
|
||||
@@ -261,10 +262,18 @@ impl NvmeCompQueue {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NvmeNamespace {
|
||||
pub id: u32,
|
||||
pub blocks: u64,
|
||||
pub block_size: u64,
|
||||
}
|
||||
|
||||
pub struct Nvme {
|
||||
regs: &'static mut NvmeRegs,
|
||||
submission_queues: [NvmeCmdQueue; 2],
|
||||
completion_queues: [NvmeCompQueue; 2],
|
||||
buffer: Dma<[u8; 512 * 4096]>, // 2MB of buffer
|
||||
buffer_prp: Dma<[u64; 512]>, // 4KB of PRP for the buffer
|
||||
}
|
||||
|
||||
impl Nvme {
|
||||
@@ -273,6 +282,8 @@ impl Nvme {
|
||||
regs: unsafe { &mut *(address as *mut NvmeRegs) },
|
||||
submission_queues: [NvmeCmdQueue::new()?, NvmeCmdQueue::new()?],
|
||||
completion_queues: [NvmeCompQueue::new()?, NvmeCompQueue::new()?],
|
||||
buffer: Dma::zeroed()?,
|
||||
buffer_prp: Dma::zeroed()?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -292,7 +303,11 @@ impl Nvme {
|
||||
self.doorbell(2 * (qid as usize) + 1).write(head as u32)
|
||||
}
|
||||
|
||||
pub unsafe fn init(&mut self) {
|
||||
pub unsafe fn init(&mut self) -> BTreeMap<u32, NvmeNamespace> {
|
||||
for i in 0..self.buffer_prp.len() {
|
||||
self.buffer_prp[i] = (self.buffer.physical() + i * 4096) as u64;
|
||||
}
|
||||
|
||||
println!(" - CAPS: {:X}", self.regs.cap.read());
|
||||
println!(" - VS: {:X}", self.regs.vs.read());
|
||||
println!(" - CC: {:X}", self.regs.cc.read());
|
||||
@@ -317,7 +332,7 @@ impl Nvme {
|
||||
{
|
||||
let asq = &self.submission_queues[0];
|
||||
let acq = &self.completion_queues[0];
|
||||
self.regs.aqa.write(((acq.data.len() as u32) << 16) | (asq.data.len() as u32));
|
||||
self.regs.aqa.write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1));
|
||||
self.regs.asq.write(asq.data.physical() as u64);
|
||||
self.regs.acq.write(acq.data.physical() as u64);
|
||||
|
||||
@@ -337,6 +352,7 @@ impl Nvme {
|
||||
}
|
||||
|
||||
{
|
||||
//TODO: Use buffer
|
||||
let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap();
|
||||
|
||||
println!(" - Attempting to identify controller");
|
||||
@@ -391,6 +407,7 @@ impl Nvme {
|
||||
|
||||
let mut nsids = Vec::new();
|
||||
{
|
||||
//TODO: Use buffer
|
||||
let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap();
|
||||
|
||||
println!(" - Attempting to retrieve namespace ID list");
|
||||
@@ -422,7 +439,9 @@ impl Nvme {
|
||||
}
|
||||
}
|
||||
|
||||
let mut namespaces = BTreeMap::new();
|
||||
for &nsid in nsids.iter() {
|
||||
//TODO: Use buffer
|
||||
let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap();
|
||||
|
||||
println!(" - Attempting to identify namespace {}", nsid);
|
||||
@@ -454,6 +473,12 @@ impl Nvme {
|
||||
println!(" - Capacity: {}", capacity);
|
||||
|
||||
//TODO: Read block size
|
||||
|
||||
namespaces.insert(nsid, NvmeNamespace {
|
||||
id: nsid,
|
||||
blocks: size,
|
||||
block_size: 512, // TODO
|
||||
});
|
||||
}
|
||||
|
||||
for io_qid in 1..self.completion_queues.len() {
|
||||
@@ -468,7 +493,7 @@ impl Nvme {
|
||||
let queue = &mut self.submission_queues[qid];
|
||||
let cid = queue.i as u16;
|
||||
let entry = NvmeCmd::create_io_completion_queue(
|
||||
cid, io_qid as u16, ptr, len as u16
|
||||
cid, io_qid as u16, ptr, (len - 1) as u16
|
||||
);
|
||||
let tail = queue.submit(entry);
|
||||
self.submission_queue_tail(qid as u16, tail as u16);
|
||||
@@ -496,7 +521,7 @@ impl Nvme {
|
||||
let cid = queue.i as u16;
|
||||
//TODO: Get completion queue ID through smarter mechanism
|
||||
let entry = NvmeCmd::create_io_submission_queue(
|
||||
cid, io_qid as u16, ptr, len as u16, io_qid as u16
|
||||
cid, io_qid as u16, ptr, (len - 1) as u16, io_qid as u16
|
||||
);
|
||||
let tail = queue.submit(entry);
|
||||
self.submission_queue_tail(qid as u16, tail as u16);
|
||||
@@ -510,5 +535,113 @@ impl Nvme {
|
||||
self.completion_queue_head(qid as u16, head as u16);
|
||||
}
|
||||
}
|
||||
|
||||
namespaces
|
||||
}
|
||||
|
||||
unsafe fn namespace_rw(&mut self, nsid: u32, lba: u64, blocks_1: u16, write: bool) -> Result<()> {
|
||||
let (ptr0, ptr1) = if blocks_1 == 0 {
|
||||
(self.buffer_prp[0], 0)
|
||||
} else if blocks_1 == 1 {
|
||||
(self.buffer_prp[0], self.buffer_prp[1])
|
||||
} else {
|
||||
(self.buffer_prp[0], (self.buffer_prp.physical() + 8) as u64)
|
||||
};
|
||||
|
||||
{
|
||||
let qid = 1;
|
||||
let queue = &mut self.submission_queues[qid];
|
||||
let cid = queue.i as u16;
|
||||
//TODO: Get completion queue ID through smarter mechanism
|
||||
let entry = if write {
|
||||
NvmeCmd::io_write(
|
||||
cid, nsid, lba, blocks_1, ptr0, ptr1
|
||||
)
|
||||
} else {
|
||||
NvmeCmd::io_read(
|
||||
cid, nsid, lba, blocks_1, ptr0, ptr1
|
||||
)
|
||||
};
|
||||
let tail = queue.submit(entry);
|
||||
self.submission_queue_tail(qid as u16, tail as u16);
|
||||
}
|
||||
|
||||
{
|
||||
let qid = 1;
|
||||
let queue = &mut self.completion_queues[qid];
|
||||
let (head, entry) = queue.complete_spin();
|
||||
//TODO: Handle errors
|
||||
self.completion_queue_head(qid as u16, head as u16);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn namespace_read(&mut self, nsid: u32, lba: u64, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
//TODO: Use interrupts
|
||||
|
||||
//TODO: Get real block size
|
||||
let block_size = 512;
|
||||
|
||||
//TODO: Support this
|
||||
if buf.len() % block_size != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
//TODO: Support this
|
||||
if buf.len() > self.buffer.len() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let blocks = buf.len() / block_size;
|
||||
|
||||
if blocks == 0 {
|
||||
return Ok(Some(0));
|
||||
}
|
||||
|
||||
//TODO: Support this
|
||||
if blocks > 0x1_0000 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
self.namespace_rw(nsid, lba, (blocks - 1) as u16, false)?;
|
||||
|
||||
buf.copy_from_slice(&self.buffer[..buf.len()]);
|
||||
|
||||
Ok(Some(buf.len()))
|
||||
}
|
||||
|
||||
pub unsafe fn namespace_write(&mut self, nsid: u32, lba: u64, buf: &[u8]) -> Result<Option<usize>> {
|
||||
//TODO: Use interrupts
|
||||
|
||||
//TODO: Get real block size
|
||||
let block_size = 512;
|
||||
|
||||
//TODO: Support this
|
||||
if buf.len() % block_size != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
//TODO: Support this
|
||||
if buf.len() > self.buffer.len() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let blocks = buf.len() / block_size;
|
||||
|
||||
if blocks == 0 {
|
||||
return Ok(Some(0));
|
||||
}
|
||||
|
||||
//TODO: Support this
|
||||
if blocks > 0x1_0000 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
self.buffer[..buf.len()].copy_from_slice(buf);
|
||||
|
||||
self.namespace_rw(nsid, lba, (blocks - 1) as u16, true)?;
|
||||
|
||||
Ok(Some(buf.len()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::{cmp, str};
|
||||
use std::fmt::Write;
|
||||
use std::io::Read;
|
||||
use syscall::{
|
||||
Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result,
|
||||
Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
|
||||
use crate::nvme::{Nvme, NvmeNamespace};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Handle {
|
||||
List(Vec<u8>, usize),
|
||||
Disk(u32, usize)
|
||||
}
|
||||
|
||||
pub struct DiskScheme {
|
||||
scheme_name: String,
|
||||
nvme: Nvme,
|
||||
disks: BTreeMap<u32, NvmeNamespace>,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
next_id: usize
|
||||
}
|
||||
|
||||
impl DiskScheme {
|
||||
pub fn new(scheme_name: String, nvme: Nvme, disks: BTreeMap<u32, NvmeNamespace>) -> DiskScheme {
|
||||
DiskScheme {
|
||||
scheme_name,
|
||||
nvme,
|
||||
disks,
|
||||
handles: BTreeMap::new(),
|
||||
next_id: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DiskScheme {
|
||||
pub fn irq(&mut self) -> bool {
|
||||
// TODO: implement
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeBlockMut for DiskScheme {
|
||||
fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<Option<usize>> {
|
||||
if uid == 0 {
|
||||
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/');
|
||||
if path_str.is_empty() {
|
||||
if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT {
|
||||
let mut list = String::new();
|
||||
|
||||
for (nsid, _disk) in self.disks.iter() {
|
||||
write!(list, "{}\n", nsid).unwrap();
|
||||
}
|
||||
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::List(list.into_bytes(), 0));
|
||||
Ok(Some(id))
|
||||
} else {
|
||||
Err(Error::new(EISDIR))
|
||||
}
|
||||
} else {
|
||||
let nsid = path_str.parse::<u32>().or(Err(Error::new(ENOENT)))?;
|
||||
|
||||
if self.disks.contains_key(&nsid) {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::Disk(nsid, 0));
|
||||
Ok(Some(id))
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(EACCES))
|
||||
}
|
||||
}
|
||||
|
||||
fn dup(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
|
||||
if ! buf.is_empty() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let new_handle = {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
|
||||
let new_id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(new_id, new_handle);
|
||||
Ok(Some(new_id))
|
||||
}
|
||||
|
||||
fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<Option<usize>> {
|
||||
match *self.handles.get(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::List(ref data, _) => {
|
||||
stat.st_mode = MODE_DIR;
|
||||
stat.st_size = data.len() as u64;
|
||||
Ok(Some(0))
|
||||
},
|
||||
Handle::Disk(number, _) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
stat.st_mode = MODE_FILE;
|
||||
stat.st_size = disk.blocks * disk.block_size;
|
||||
Ok(Some(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
let scheme_name = self.scheme_name.as_bytes();
|
||||
let mut j = 0;
|
||||
while i < buf.len() && j < scheme_name.len() {
|
||||
buf[i] = scheme_name[j];
|
||||
i += 1;
|
||||
j += 1;
|
||||
}
|
||||
|
||||
if i < buf.len() {
|
||||
buf[i] = b':';
|
||||
i += 1;
|
||||
}
|
||||
|
||||
match *handle {
|
||||
Handle::List(_, _) => (),
|
||||
Handle::Disk(number, _) => {
|
||||
let number_str = format!("{}", number);
|
||||
let number_bytes = number_str.as_bytes();
|
||||
j = 0;
|
||||
while i < buf.len() && j < number_bytes.len() {
|
||||
buf[i] = number_bytes[j];
|
||||
i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(i))
|
||||
}
|
||||
|
||||
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::List(ref mut handle, ref mut size) => {
|
||||
let count = (&handle[*size..]).read(buf).unwrap();
|
||||
*size += count;
|
||||
Ok(Some(count))
|
||||
},
|
||||
Handle::Disk(number, ref mut size) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
let block_size = disk.block_size;
|
||||
if let Some(count) = unsafe {
|
||||
self.nvme.namespace_read(disk.id, (*size as u64)/block_size, buf)?
|
||||
} {
|
||||
*size += count;
|
||||
Ok(Some(count))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
|
||||
match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::List(_, _) => {
|
||||
Err(Error::new(EBADF))
|
||||
},
|
||||
Handle::Disk(number, ref mut size) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
let block_size = disk.block_size;
|
||||
if let Some(count) = unsafe {
|
||||
self.nvme.namespace_write(disk.id, (*size as u64)/block_size, buf)?
|
||||
} {
|
||||
*size += count;
|
||||
Ok(Some(count))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<Option<usize>> {
|
||||
match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::List(ref mut handle, ref mut size) => {
|
||||
let len = handle.len() as usize;
|
||||
*size = match whence {
|
||||
SEEK_SET => cmp::min(len, pos),
|
||||
SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize,
|
||||
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
|
||||
_ => return Err(Error::new(EINVAL))
|
||||
};
|
||||
|
||||
Ok(Some(*size))
|
||||
},
|
||||
Handle::Disk(number, ref mut size) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
let len = (disk.blocks * disk.block_size) as usize;
|
||||
*size = match whence {
|
||||
SEEK_SET => cmp::min(len, pos),
|
||||
SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize,
|
||||
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
|
||||
_ => return Err(Error::new(EINVAL))
|
||||
};
|
||||
|
||||
Ok(Some(*size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0)))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user