Add DevFS for device files
This commit is contained in:
parent
1514be14fd
commit
d6cd89f03b
@ -162,6 +162,10 @@ Occlum can be configured easily via a configuration file named `Occlum.json`, wh
|
||||
"options": {
|
||||
"temporary": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"target": "/dev",
|
||||
"type": "devfs"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -58,6 +58,10 @@
|
||||
"options": {
|
||||
"temporary": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"target": "/dev",
|
||||
"type": "devfs"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
10
src/libos/Cargo.lock
generated
10
src/libos/Cargo.lock
generated
@ -13,6 +13,7 @@ dependencies = [
|
||||
"log",
|
||||
"memoffset",
|
||||
"rcore-fs",
|
||||
"rcore-fs-devfs",
|
||||
"rcore-fs-mountfs",
|
||||
"rcore-fs-ramfs",
|
||||
"rcore-fs-sefs",
|
||||
@ -395,6 +396,15 @@ dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rcore-fs-devfs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rcore-fs",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rcore-fs-mountfs"
|
||||
version = "0.1.0"
|
||||
|
@ -21,6 +21,7 @@ rcore-fs-sefs = { path = "../../deps/sefs/rcore-fs-sefs" }
|
||||
rcore-fs-ramfs = { path = "../../deps/sefs/rcore-fs-ramfs" }
|
||||
rcore-fs-mountfs = { path = "../../deps/sefs/rcore-fs-mountfs" }
|
||||
rcore-fs-unionfs = { path = "../../deps/sefs/rcore-fs-unionfs" }
|
||||
rcore-fs-devfs = { path = "../../deps/sefs/rcore-fs-devfs" }
|
||||
serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] }
|
||||
serde_json = { path = "../../deps/serde-json-sgx" }
|
||||
memoffset = "0.6.1"
|
||||
|
@ -125,6 +125,7 @@ pub enum ConfigMountFsType {
|
||||
TYPE_HOSTFS,
|
||||
TYPE_RAMFS,
|
||||
TYPE_UNIONFS,
|
||||
TYPE_DEVFS,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -199,13 +200,14 @@ impl ConfigEnv {
|
||||
|
||||
impl ConfigMount {
|
||||
fn from_input(input: &InputConfigMount) -> Result<ConfigMount> {
|
||||
const ALL_FS_TYPES: [&str; 4] = ["sefs", "hostfs", "ramfs", "unionfs"];
|
||||
const ALL_FS_TYPES: [&str; 5] = ["sefs", "hostfs", "ramfs", "unionfs", "devfs"];
|
||||
|
||||
let type_ = match input.type_.as_str() {
|
||||
"sefs" => ConfigMountFsType::TYPE_SEFS,
|
||||
"hostfs" => ConfigMountFsType::TYPE_HOSTFS,
|
||||
"ramfs" => ConfigMountFsType::TYPE_RAMFS,
|
||||
"unionfs" => ConfigMountFsType::TYPE_UNIONFS,
|
||||
"devfs" => ConfigMountFsType::TYPE_DEVFS,
|
||||
_ => {
|
||||
return_errno!(EINVAL, "Unsupported file system type");
|
||||
}
|
||||
|
@ -3,24 +3,43 @@ use super::*;
|
||||
#[derive(Debug)]
|
||||
pub struct DevNull;
|
||||
|
||||
impl File for DevNull {
|
||||
fn write(&self, _buf: &[u8]) -> Result<usize> {
|
||||
Ok(_buf.len())
|
||||
impl INode for DevNull {
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
|
||||
Ok(_buf.len())
|
||||
fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result<usize> {
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
||||
Ok(bufs.iter().map(|buf| buf.len()).sum())
|
||||
fn poll(&self) -> vfs::Result<vfs::PollStatus> {
|
||||
Ok(vfs::PollStatus {
|
||||
read: true,
|
||||
write: true,
|
||||
error: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn poll_new(&self) -> IoEvents {
|
||||
IoEvents::IN
|
||||
fn metadata(&self) -> vfs::Result<Metadata> {
|
||||
Ok(Metadata {
|
||||
dev: 1,
|
||||
inode: 0,
|
||||
size: 0,
|
||||
blk_size: 0,
|
||||
blocks: 0,
|
||||
atime: Timespec { sec: 0, nsec: 0 },
|
||||
mtime: Timespec { sec: 0, nsec: 0 },
|
||||
ctime: Timespec { sec: 0, nsec: 0 },
|
||||
type_: vfs::FileType::CharDevice,
|
||||
mode: 0o666,
|
||||
nlinks: 1,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,42 +1,30 @@
|
||||
use super::*;
|
||||
use crate::net::PollEventFlags;
|
||||
use crate::util::random;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DevRandom;
|
||||
|
||||
impl File for DevRandom {
|
||||
fn read(&self, _buf: &mut [u8]) -> Result<usize> {
|
||||
random::get_random(_buf)?;
|
||||
Ok(_buf.len())
|
||||
impl INode for DevRandom {
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> {
|
||||
random::get_random(buf).map_err(|_| FsError::Again)?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
|
||||
self.read(_buf)
|
||||
fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result<usize> {
|
||||
Err(FsError::PermError)
|
||||
}
|
||||
|
||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
||||
let mut total_nbytes = 0;
|
||||
for buf in bufs {
|
||||
match self.read(buf) {
|
||||
Ok(this_nbytes) => {
|
||||
total_nbytes += this_nbytes;
|
||||
}
|
||||
Err(e) => {
|
||||
if total_nbytes > 0 {
|
||||
break;
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(total_nbytes)
|
||||
fn poll(&self) -> vfs::Result<vfs::PollStatus> {
|
||||
Ok(vfs::PollStatus {
|
||||
read: true,
|
||||
write: false,
|
||||
error: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Metadata> {
|
||||
fn metadata(&self) -> vfs::Result<Metadata> {
|
||||
Ok(Metadata {
|
||||
dev: 0,
|
||||
dev: 1,
|
||||
inode: 0,
|
||||
size: 0,
|
||||
blk_size: 0,
|
||||
@ -44,36 +32,16 @@ impl File for DevRandom {
|
||||
atime: Timespec { sec: 0, nsec: 0 },
|
||||
mtime: Timespec { sec: 0, nsec: 0 },
|
||||
ctime: Timespec { sec: 0, nsec: 0 },
|
||||
type_: FileType::CharDevice,
|
||||
mode: (FileMode::S_IRUSR | FileMode::S_IRGRP | FileMode::S_IROTH).bits(),
|
||||
nlinks: 0,
|
||||
type_: vfs::FileType::CharDevice,
|
||||
mode: 0o444,
|
||||
nlinks: 1,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn poll(&self) -> Result<(PollEventFlags)> {
|
||||
Ok(PollEventFlags::POLLIN)
|
||||
}
|
||||
|
||||
fn poll_new(&self) -> IoEvents {
|
||||
IoEvents::IN
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AsDevRandom {
|
||||
fn as_dev_random(&self) -> Result<&DevRandom>;
|
||||
}
|
||||
|
||||
impl AsDevRandom for FileRef {
|
||||
fn as_dev_random(&self) -> Result<&DevRandom> {
|
||||
self.as_any()
|
||||
.downcast_ref::<DevRandom>()
|
||||
.ok_or_else(|| errno!(EBADF, "not random device"))
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,54 @@ extern "C" {
|
||||
#[derive(Debug)]
|
||||
pub struct DevSgx;
|
||||
|
||||
impl File for DevSgx {
|
||||
impl INode for DevSgx {
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> {
|
||||
Err(FsError::PermError)
|
||||
}
|
||||
|
||||
fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result<usize> {
|
||||
Err(FsError::PermError)
|
||||
}
|
||||
|
||||
fn poll(&self) -> vfs::Result<vfs::PollStatus> {
|
||||
Err(FsError::PermError)
|
||||
}
|
||||
|
||||
fn metadata(&self) -> vfs::Result<Metadata> {
|
||||
Ok(Metadata {
|
||||
dev: 1,
|
||||
inode: 0,
|
||||
size: 0,
|
||||
blk_size: 0,
|
||||
blocks: 0,
|
||||
atime: Timespec { sec: 0, nsec: 0 },
|
||||
mtime: Timespec { sec: 0, nsec: 0 },
|
||||
ctime: Timespec { sec: 0, nsec: 0 },
|
||||
type_: vfs::FileType::CharDevice,
|
||||
mode: 0o666,
|
||||
nlinks: 1,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn io_control(&self, _cmd: u32, _data: usize) -> vfs::Result<()> {
|
||||
let mut ioctl_cmd =
|
||||
unsafe { IoctlCmd::new(_cmd, _data as *mut u8).map_err(|_| FsError::InvalidParam)? };
|
||||
self.ioctl(&mut ioctl_cmd).map_err(|e| {
|
||||
error!("{}", e.backtrace());
|
||||
FsError::IOCTLError
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DevSgx {
|
||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||
let nonbuiltin_cmd = match cmd {
|
||||
IoctlCmd::NonBuiltin(nonbuiltin_cmd) => nonbuiltin_cmd,
|
||||
@ -180,14 +227,6 @@ impl File for DevSgx {
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn poll_new(&self) -> IoEvents {
|
||||
IoEvents::IN
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
|
@ -3,31 +3,46 @@ use super::*;
|
||||
#[derive(Debug)]
|
||||
pub struct DevZero;
|
||||
|
||||
impl File for DevZero {
|
||||
fn read(&self, _buf: &mut [u8]) -> Result<usize> {
|
||||
for b in _buf.iter_mut() {
|
||||
impl INode for DevZero {
|
||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> {
|
||||
for b in buf.iter_mut() {
|
||||
*b = 0;
|
||||
}
|
||||
Ok(_buf.len())
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
|
||||
self.read(_buf)
|
||||
fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result<usize> {
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
||||
let mut total_nbytes = 0;
|
||||
for buf in bufs {
|
||||
total_nbytes += self.read(buf)?;
|
||||
}
|
||||
Ok(total_nbytes)
|
||||
fn poll(&self) -> vfs::Result<vfs::PollStatus> {
|
||||
Ok(vfs::PollStatus {
|
||||
read: true,
|
||||
write: true,
|
||||
error: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn poll_new(&self) -> IoEvents {
|
||||
IoEvents::IN
|
||||
fn metadata(&self) -> vfs::Result<Metadata> {
|
||||
Ok(Metadata {
|
||||
dev: 1,
|
||||
inode: 0,
|
||||
size: 0,
|
||||
blk_size: 0,
|
||||
blocks: 0,
|
||||
atime: Timespec { sec: 0, nsec: 0 },
|
||||
mtime: Timespec { sec: 0, nsec: 0 },
|
||||
ctime: Timespec { sec: 0, nsec: 0 },
|
||||
type_: vfs::FileType::CharDevice,
|
||||
mode: 0o666,
|
||||
nlinks: 1,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: 0,
|
||||
})
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,30 @@
|
||||
use super::*;
|
||||
use rcore_fs::vfs;
|
||||
use rcore_fs_devfs::DevFS;
|
||||
|
||||
pub use self::dev_null::DevNull;
|
||||
pub use self::dev_random::{AsDevRandom, DevRandom};
|
||||
pub use self::dev_sgx::DevSgx;
|
||||
pub use self::dev_zero::DevZero;
|
||||
use self::dev_null::DevNull;
|
||||
use self::dev_random::DevRandom;
|
||||
use self::dev_sgx::DevSgx;
|
||||
use self::dev_zero::DevZero;
|
||||
|
||||
mod dev_null;
|
||||
mod dev_random;
|
||||
mod dev_sgx;
|
||||
mod dev_zero;
|
||||
|
||||
/// API to initialize the DevFS
|
||||
pub fn init_devfs() -> Result<Arc<DevFS>> {
|
||||
let devfs = DevFS::new();
|
||||
let dev_null = Arc::new(DevNull) as _;
|
||||
devfs.add("null", dev_null)?;
|
||||
let dev_zero = Arc::new(DevZero) as _;
|
||||
devfs.add("zero", dev_zero)?;
|
||||
let dev_random = Arc::new(DevRandom) as _;
|
||||
devfs.add("random", Arc::clone(&dev_random))?;
|
||||
devfs.add("urandom", Arc::clone(&dev_random))?;
|
||||
devfs.add("arandom", Arc::clone(&dev_random))?;
|
||||
let dev_sgx = Arc::new(DevSgx) as _;
|
||||
devfs.add("sgx", dev_sgx)?;
|
||||
// TODO: Add stdio(stdin, stdout, stderr) into DevFS
|
||||
Ok(devfs)
|
||||
}
|
||||
|
@ -25,6 +25,20 @@ impl IoEvents {
|
||||
Self::from_bits_truncate(raw)
|
||||
}
|
||||
|
||||
pub fn from_poll_status(poll_status: &crate::rcore_fs::vfs::PollStatus) -> Self {
|
||||
if poll_status.error {
|
||||
return Self::ERR;
|
||||
}
|
||||
let mut events = Self::empty();
|
||||
if poll_status.read {
|
||||
events |= Self::IN
|
||||
}
|
||||
if poll_status.write {
|
||||
events |= Self::OUT
|
||||
}
|
||||
events
|
||||
}
|
||||
|
||||
fn contains_unrecognizable_bits(raw: u32) -> bool {
|
||||
// Help to detect four valid but mostly useless flags that we do not
|
||||
// handle, yet: POLLRDNORM, POLLRDBAND, POLLWRNORM, annd POLLWRBAND.
|
||||
|
@ -1,4 +1,3 @@
|
||||
use super::dev_fs::{DevNull, DevRandom, DevSgx, DevZero};
|
||||
use super::*;
|
||||
use process::Process;
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
use super::dev_fs::{DevNull, DevRandom, DevSgx, DevZero};
|
||||
/// Present a per-process view of FS.
|
||||
use super::*;
|
||||
|
||||
@ -40,18 +39,6 @@ impl FsView {
|
||||
|
||||
/// Open a file on the process. But DO NOT add it to file table.
|
||||
pub fn open_file(&self, path: &str, flags: u32, mode: u32) -> Result<Arc<dyn File>> {
|
||||
if path == "/dev/null" {
|
||||
return Ok(Arc::new(DevNull));
|
||||
}
|
||||
if path == "/dev/zero" {
|
||||
return Ok(Arc::new(DevZero));
|
||||
}
|
||||
if path == "/dev/random" || path == "/dev/urandom" || path == "/dev/arandom" {
|
||||
return Ok(Arc::new(DevRandom));
|
||||
}
|
||||
if path == "/dev/sgx" {
|
||||
return Ok(Arc::new(DevSgx));
|
||||
}
|
||||
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
||||
let inode = if creation_flags.no_follow_symlink() {
|
||||
match self.lookup_inode_no_follow(path) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::net::PollEventFlags;
|
||||
use rcore_fs_sefs::dev::SefsMac;
|
||||
|
||||
pub struct INodeFile {
|
||||
@ -196,6 +197,20 @@ impl File for INodeFile {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||
let cmd_num = cmd.cmd_num();
|
||||
let cmd_argp = cmd.arg_ptr() as usize;
|
||||
self.inode.io_control(cmd_num, cmd_argp)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn poll_new(&self) -> IoEvents {
|
||||
match self.inode.poll() {
|
||||
Ok(poll_status) => IoEvents::from_poll_status(&poll_status),
|
||||
Err(_) => IoEvents::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ use std::mem::MaybeUninit;
|
||||
use std::path::Path;
|
||||
use untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen};
|
||||
|
||||
pub use self::dev_fs::AsDevRandom;
|
||||
pub use self::event_file::{AsEvent, EventCreationFlags, EventFile};
|
||||
pub use self::events::{AtomicIoEvents, IoEvents, IoNotifier};
|
||||
pub use self::file::{File, FileRef};
|
||||
|
@ -1,3 +1,4 @@
|
||||
use super::dev_fs;
|
||||
use super::hostfs::HostFS;
|
||||
use super::sefs::{SgxStorage, SgxUuidProvider};
|
||||
use super::*;
|
||||
@ -144,6 +145,10 @@ fn mount_nonroot_fs_according_to(mount_config: &Vec<ConfigMount>, root: &MNode)
|
||||
let ramfs = RamFS::new();
|
||||
mount_fs_at(ramfs, root, &mc.target)?;
|
||||
}
|
||||
TYPE_DEVFS => {
|
||||
let devfs = dev_fs::init_devfs()?;
|
||||
mount_fs_at(devfs, root, &mc.target)?;
|
||||
}
|
||||
TYPE_UNIONFS => {
|
||||
return_errno!(EINVAL, "Cannot mount UnionFS at non-root path");
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rcore_fs;
|
||||
extern crate rcore_fs_devfs;
|
||||
extern crate rcore_fs_mountfs;
|
||||
extern crate rcore_fs_ramfs;
|
||||
extern crate rcore_fs_sefs;
|
||||
|
@ -15,7 +15,7 @@ pub use self::poll::{do_poll, PollEvent, PollEventFlags};
|
||||
pub use self::poll_new::{do_poll_new, PollFd};
|
||||
pub use self::select::{do_select, FdSetExt};
|
||||
|
||||
use fs::{AsDevRandom, AsEvent, CreationFlags, File, FileDesc, FileRef, HostFd, PipeType};
|
||||
use fs::{AsEvent, AsINodeFile, CreationFlags, File, FileDesc, FileRef, HostFd, PipeType};
|
||||
use std::any::Any;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
|
@ -93,7 +93,6 @@ pub fn do_poll(pollfds: &mut [PollEvent], timeout: *mut timeval_t) -> Result<usi
|
||||
if file_ref.as_unix_socket().is_ok()
|
||||
|| file_ref.as_pipe_reader().is_ok()
|
||||
|| file_ref.as_pipe_writer().is_ok()
|
||||
|| file_ref.as_dev_random().is_ok()
|
||||
{
|
||||
let events = file_ref.poll()?;
|
||||
debug!("polled events are {:?}", events);
|
||||
|
@ -61,6 +61,10 @@
|
||||
"options": {
|
||||
"temporary": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"target": "/dev",
|
||||
"type": "devfs"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -258,6 +258,10 @@ fn gen_mount_config(occlum_conf_root_fs_mac: String) -> serde_json::Value {
|
||||
"options": {
|
||||
"temporary": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"target": "/dev",
|
||||
"type": "devfs"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
@ -148,6 +148,7 @@ cmd_init() {
|
||||
mkdir -p image/root
|
||||
mkdir -p image/host
|
||||
mkdir -p image/tmp
|
||||
mkdir -p image/dev
|
||||
local occlum_glibc_lib=/opt/occlum/glibc/lib
|
||||
local cpu_lib=/sys/devices/system/cpu
|
||||
if [ -d "$occlum_glibc_lib" ]; then
|
||||
|
Loading…
Reference in New Issue
Block a user