Add readv and writev

This commit is contained in:
Tate, Hongliang Tian 2018-11-29 21:56:09 +08:00
parent 4c3f556c7d
commit f2ebc5c330
6 changed files with 303 additions and 21 deletions

@ -8,8 +8,9 @@ use std::io::{Read, Write, Seek, SeekFrom};
pub trait File : Debug + Sync + Send {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error>;
fn write(&self, buf: &[u8]) -> Result<usize, Error>;
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error>;
fn writev<'a, 'b>(&self, bufs: &'a [&'b [u8]]) -> Result<usize, Error>;
//pub seek(&mut self, ) -> Result<usize, Error>;
}
pub type FileRef = Arc<Box<File>>;
@ -48,6 +49,18 @@ impl File for SgxFile {
let inner = inner_guard.borrow_mut();
inner.write(buf)
}
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.readv(bufs)
}
fn writev<'a, 'b>(&self, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.writev(bufs)
}
}
#[derive(Clone)]
@ -67,6 +80,7 @@ impl SgxFileInner {
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
// TODO: recover from error
file.seek(seek_pos).map_err(
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
@ -95,6 +109,70 @@ impl SgxFileInner {
self.pos += read_len;
Ok(read_len)
}
pub fn writev<'a, 'b>(&mut self, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos).map_err(
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let mut total_bytes = 0;
for buf in bufs {
match file.write(buf) {
Ok(this_bytes) => {
if this_bytes == 0 { break; }
total_bytes += this_bytes;
if this_bytes < buf.len() { break; }
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return Err(Error::new(Errno::EINVAL, "Failed to write")),
// a partially failure
_ => break,
}
}
}
}
self.pos += total_bytes;
Ok(total_bytes)
}
fn readv<'a, 'b>(&mut self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos).map_err(
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let mut total_bytes = 0;
for buf in bufs {
match file.read(buf) {
Ok(this_bytes) => {
if this_bytes == 0 { break; }
total_bytes += this_bytes;
if this_bytes < buf.len() { break; }
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return Err(Error::new(Errno::EINVAL, "Failed to write")),
// a partially failure
_ => break,
}
}
}
}
self.pos += total_bytes;
Ok(total_bytes)
}
}
unsafe impl Send for SgxFileInner {}
@ -130,6 +208,33 @@ impl File for StdoutFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdout does not support reading"))
}
fn writev<'a, 'b>(&self, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
let mut guard = self.inner.lock();
let mut total_bytes = 0;
for buf in bufs {
match guard.write(buf) {
Ok(this_len) => {
if this_len == 0 { break; }
total_bytes += this_len;
if this_len < buf.len() { break; }
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return Err(Error::new(Errno::EINVAL, "Failed to write")),
// a partially failure
_ => break,
}
}
}
}
Ok(total_bytes)
}
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdout does not support reading"))
}
}
impl Debug for StdoutFile {
@ -165,6 +270,33 @@ impl File for StdinFile {
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdin does not support reading"))
}
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
let mut guard = self.inner.lock();
let mut total_bytes = 0;
for buf in bufs {
match guard.read(buf) {
Ok(this_len) => {
if this_len == 0 { break; }
total_bytes += this_len;
if this_len < buf.len() { break; }
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return Err(Error::new(Errno::EINVAL, "Failed to write")),
// a partially failure
_ => break,
}
}
}
}
Ok(total_bytes)
}
fn writev<'a, 'b>(&self, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdin does not support reading"))
}
}
impl Debug for StdinFile {

@ -63,6 +63,22 @@ pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
file_ref.read(buf)
}
pub fn do_writev<'a, 'b>(fd: FileDesc, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.file_table.get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_write]"))?;
file_ref.writev(bufs)
}
pub fn do_readv<'a, 'b>(fd: FileDesc, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.file_table.get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_read]"))?;
file_ref.readv(bufs)
}
pub fn do_close(fd: FileDesc) -> Result<(), Error> {
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();

@ -77,6 +77,7 @@ pub fn do_spawn<P: AsRef<Path>>(elf_path: &P, argv: &[CString], envp: &[CString]
//let stdin = Arc::new(SgxMutex::new(Box::new(StdinFile::new())));
let stdin : Arc<Box<File>> = Arc::new(Box::new(StdinFile::new()));
let stdout : Arc<Box<File>> = Arc::new(Box::new(StdoutFile::new()));
// TODO: implement and use a real stderr
let stderr = stdout.clone();
file_table.put(stdin);
file_table.put(stdout);

@ -4,6 +4,8 @@
#include <sys/types.h>
#include "syscall_nr.h"
struct iovec;
#ifdef __cplusplus
extern "C" {
#endif
@ -12,6 +14,8 @@ extern int occlum_open(const char* path, int flags, int mode);
extern int occlum_close(int fd);
extern ssize_t occlum_read(int fd, void* buf, size_t size);
extern ssize_t occlum_write(int fd, const void* buf, size_t size);
extern ssize_t occlum_readv(int fd, struct iovec* iov, int count);
extern ssize_t occlum_writev(int fd, const struct iovec* iov, int count);
extern int occlum_spawn(int* child_pid, const char* path,
const char** argv,
const char** envp);

@ -5,18 +5,33 @@ use std::ffi::{CStr, CString};
//use std::libc_fs as fs;
//use std::libc_io as io;
fn check_ptr_from_user<T>(user_ptr: *const T) -> Result<*const T, Error> {
Ok(user_ptr)
#[allow(non_camel_case_types)]
pub struct iovec_t {
base: *const c_void,
len: size_t,
}
fn check_mut_ptr_from_user<T>(user_ptr: *mut T) -> Result<*mut T, Error> {
Ok(user_ptr)
fn check_ptr_from_user<T>(user_ptr: *const T) -> Result<(), Error> {
Ok(())
}
fn check_mut_ptr_from_user<T>(user_ptr: *mut T) -> Result<(), Error> {
Ok(())
}
fn check_array_from_user<T>(user_buf: *const T, count: usize) -> Result<(), Error> {
Ok(())
}
fn check_mut_array_from_user<T>(user_buf: *mut T, count: usize) -> Result<(), Error> {
Ok(())
}
fn clone_string_from_user_safely(user_ptr: *const c_char)
-> Result<String, Error>
{
let user_ptr = check_ptr_from_user(user_ptr)?;
check_ptr_from_user(user_ptr)?;
let string = unsafe {
CStr::from_ptr(user_ptr).to_string_lossy().into_owned()
};
@ -31,6 +46,93 @@ fn clone_cstrings_from_user_safely(user_ptr: *const *const c_char)
}
fn do_read(fd: c_int, buf: *mut c_void, size: size_t)
-> Result<size_t, Error>
{
let fd = fd as file_table::FileDesc;
let safe_buf = {
let buf = buf as *mut u8;
let size = size as usize;
check_mut_array_from_user(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
fs::do_read(fd, safe_buf)
}
fn do_write(fd: c_int, buf: *const c_void, size: size_t)
-> Result<size_t, Error>
{
let fd = fd as file_table::FileDesc;
let safe_buf = {
let buf = buf as *mut u8;
let size = size as usize;
check_array_from_user(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) }
};
fs::do_write(fd, safe_buf)
}
fn do_writev(fd: c_int, iov: *const iovec_t, count: c_int)
-> Result<size_t, Error>
{
let fd = fd as file_table::FileDesc;
let count = {
if count < 0 {
return Err(Error::new(Errno::EINVAL, "Invalid count of iovec"));
}
count as usize
};
check_array_from_user(iov, count);
let bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
let iov = unsafe { &*iov_ptr };
let buf = unsafe {
std::slice::from_raw_parts(iov.base as * const u8, iov.len)
};
bufs_vec[iov_i] = buf;
}
bufs_vec
};
let bufs = &bufs_vec[..];
fs::do_writev(fd, bufs)
}
fn do_readv(fd: c_int, iov: *mut iovec_t, count: c_int)
-> Result<size_t, Error>
{
let fd = fd as file_table::FileDesc;
let count = {
if count < 0 {
return Err(Error::new(Errno::EINVAL, "Invalid count of iovec"));
}
count as usize
};
check_array_from_user(iov, count);
let mut bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
let iov = unsafe { &*iov_ptr };
let buf = unsafe {
std::slice::from_raw_parts_mut(iov.base as * mut u8, iov.len)
};
bufs_vec[iov_i] = buf;
}
bufs_vec
};
let bufs = &mut bufs_vec[..];
fs::do_readv(fd, bufs)
}
#[no_mangle]
pub extern "C" fn occlum_open(path_buf: * const c_char, flags: c_int, mode: c_int) -> c_int {
let path = unsafe {
@ -60,10 +162,7 @@ pub extern "C" fn occlum_close(fd: c_int) -> c_int {
#[no_mangle]
pub extern "C" fn occlum_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssize_t {
let buf = unsafe {
std::slice::from_raw_parts_mut(buf as *mut u8, size as usize)
};
match fs::do_read(fd as file_table::FileDesc, buf) {
match do_read(fd, buf, size) {
Ok(read_len) => {
read_len as ssize_t
},
@ -75,16 +174,7 @@ pub extern "C" fn occlum_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssi
#[no_mangle]
pub extern "C" fn occlum_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t {
/* let str_from_c = unsafe {
CStr::from_ptr(buf as * const i8).to_string_lossy().into_owned()
};
println!("occlum_write: {}", str_from_c);
size as ssize_t
*/
let buf = unsafe {
std::slice::from_raw_parts(buf as *const u8, size as usize)
};
match fs::do_write(fd as file_table::FileDesc, buf) {
match do_write(fd, buf, size) {
Ok(write_len) => {
write_len as ssize_t
},
@ -94,6 +184,31 @@ pub extern "C" fn occlum_write(fd: c_int, buf: * const c_void, size: size_t) ->
}
}
#[no_mangle]
pub extern "C" fn occlum_readv(fd: c_int, iov: * mut iovec_t, count: c_int) -> ssize_t {
match do_readv(fd, iov, count) {
Ok(read_len) => {
read_len as ssize_t
},
Err(e) => {
e.errno.as_retval() as ssize_t
}
}
}
#[no_mangle]
pub extern "C" fn occlum_writev(fd: c_int, iov: * const iovec_t, count: c_int) -> ssize_t {
match do_writev(fd, iov, count) {
Ok(write_len) => {
write_len as ssize_t
},
Err(e) => {
e.errno.as_retval() as ssize_t
}
}
}
#[no_mangle]
pub extern "C" fn occlum_getpid() -> c_uint
{
@ -118,7 +233,7 @@ fn do_spawn(child_pid_ptr: *mut c_uint,
envp: *const *const c_char)
-> Result<(), Error>
{
let child_pid_ptr = check_mut_ptr_from_user(child_pid_ptr)?;
check_mut_ptr_from_user(child_pid_ptr)?;
let path = clone_string_from_user_safely(path)?;
let argv = clone_cstrings_from_user_safely(argv)?;
let envp = clone_cstrings_from_user_safely(envp)?;

@ -40,6 +40,20 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
ret = occlum_read(fd, buf, buf_size);
break;
}
case SYS_writev: {
DECL_SYSCALL_ARG(int, fd, arg0);
DECL_SYSCALL_ARG(const struct iovec*, iov, arg1);
DECL_SYSCALL_ARG(int, count, arg2);
ret = occlum_writev(fd, iov, count);
break;
}
case SYS_readv: {
DECL_SYSCALL_ARG(int, fd, arg0);
DECL_SYSCALL_ARG(struct iovec*, iov, arg1);
DECL_SYSCALL_ARG(int, count, arg2);
ret = occlum_readv(fd, iov, count);
break;
}
case SYS_spawn: {
DECL_SYSCALL_ARG(int*, child_pid, arg0);
DECL_SYSCALL_ARG(const char*, path, arg1);