From f711d20475dbea4dbd14650cf97738a674224e52 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 28 Mar 2019 12:25:42 +0800 Subject: [PATCH 01/37] add socket syscalls, directly forward to libc --- src/Enclave.edl | 1 + src/libos/src/syscall/mod.rs | 139 ++++++++++++++++++++++++++++++++++- src/sgxenv.mk | 2 +- 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/Enclave.edl b/src/Enclave.edl index 71bbdd60..034febdf 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -4,6 +4,7 @@ enclave { from "sgx_tstdc.edl" import *; from "sgx_tstd.edl" import *; from "sgx_tprotected_fs.edl" import *; + from "sgx_net.edl" import *; trusted { /* define ECALLs here. */ diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index a0b392d8..fe6ef772 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -1,6 +1,14 @@ -use {fs, process, std, vm}; -use fs::{FileDesc, off_t}; +//! System call handler +//! +//! # Syscall processing flow +//! +//! 1. User call `__occlum_syscall` (at `syscall_entry_x86_64.S`) +//! 2. Do some bound checks then call `dispatch_syscall` (at this file) +//! 3. Dispatch the syscall to `do_*` (at this file) +//! 4. Do some memory checks then call `mod::do_*` (at each module) + use fs::File; +use fs::{off_t, FileDesc}; use prelude::*; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; @@ -8,6 +16,7 @@ use std::ptr; use time::timeval_t; use util::mem_util::from_user::*; use vm::{VMAreaFlags, VMResizeOptions}; +use {fs, process, std, vm}; use super::*; @@ -35,6 +44,7 @@ pub extern "C" fn dispatch_syscall( num, arg0, arg1, arg2, arg3, arg4, arg5 ); let ret = match num { + // file SYS_OPEN => do_open(arg0 as *const i8, arg1 as u32, arg2 as u32), SYS_CLOSE => do_close(arg0 as FileDesc), SYS_READ => do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize), @@ -71,6 +81,7 @@ pub extern "C" fn dispatch_syscall( SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), SYS_UNLINK => do_unlink(arg0 as *const i8), + // process SYS_EXIT => do_exit(arg0 as i32), SYS_SPAWN => do_spawn( arg0 as *mut u32, @@ -100,6 +111,7 @@ pub extern "C" fn dispatch_syscall( SYS_ARCH_PRCTL => do_arch_prctl(arg0 as u32, arg1 as *mut usize), SYS_SET_TID_ADDRESS => do_set_tid_address(arg0 as *mut pid_t), + // memory SYS_MMAP => do_mmap( arg0 as usize, arg1 as usize, @@ -131,6 +143,41 @@ pub extern "C" fn dispatch_syscall( SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t), + // socket + SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int), + SYS_CONNECT => do_connect( + arg0 as c_int, + arg1 as *const libc::sockaddr, + arg2 as libc::socklen_t, + ), + SYS_ACCEPT => do_accept( + arg0 as c_int, + arg1 as *mut libc::sockaddr, + arg2 as *mut libc::socklen_t, + arg3 as c_int, + ), + SYS_SHUTDOWN => do_shutdown(arg0 as c_int, arg1 as c_int), + SYS_BIND => do_bind( + arg0 as c_int, + arg1 as *const libc::sockaddr, + arg2 as libc::socklen_t, + ), + SYS_LISTEN => do_listen(arg0 as c_int, arg1 as c_int), + SYS_SETSOCKOPT => do_setsockopt( + arg0 as c_int, + arg1 as c_int, + arg2 as c_int, + arg3 as *const c_void, + arg4 as libc::socklen_t, + ), + SYS_GETSOCKOPT => do_getsockopt( + arg0 as c_int, + arg1 as c_int, + arg2 as c_int, + arg3 as *mut c_void, + arg4 as *mut libc::socklen_t, + ), + _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5), }; debug!("syscall return: {:?}", ret); @@ -696,3 +743,91 @@ fn do_set_tid_address(tidptr: *mut pid_t) -> Result { check_mut_ptr(tidptr)?; process::do_set_tid_address(tidptr).map(|tid| tid as isize) } + +fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result { + info!( + "socket: domain: {}, socket_type: {}, protocol: {}", + domain, socket_type, protocol + ); + let ret = unsafe { libc::ocall::socket(domain, socket_type, protocol) }; + Ok(ret as isize) +} + +fn do_connect( + fd: c_int, + addr: *const libc::sockaddr, + addr_len: libc::socklen_t, +) -> Result { + info!( + "connect: fd: {}, addr: {:?}, addr_len: {}", + fd, addr, addr_len + ); + let ret = unsafe { libc::ocall::connect(fd, addr, addr_len) }; + Ok(ret as isize) +} + +fn do_accept( + fd: c_int, + addr: *mut libc::sockaddr, + addr_len: *mut libc::socklen_t, + flags: c_int, +) -> Result { + info!( + "accept: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", + fd, addr, addr_len, flags + ); + let ret = unsafe { libc::ocall::accept4(fd, addr, addr_len, flags) }; + Ok(ret as isize) +} + +fn do_shutdown(fd: c_int, how: c_int) -> Result { + info!("shutdown: fd: {}, how: {}", fd, how); + let ret = unsafe { libc::ocall::shutdown(fd, how) }; + Ok(ret as isize) +} + +fn do_bind( + fd: c_int, + addr: *const libc::sockaddr, + addr_len: libc::socklen_t, +) -> Result { + info!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len); + let ret = unsafe { libc::ocall::bind(fd, addr, addr_len) }; + Ok(ret as isize) +} + +fn do_listen(fd: c_int, backlog: c_int) -> Result { + info!("listen: fd: {}, backlog: {}", fd, backlog); + let ret = unsafe { libc::ocall::listen(fd, backlog) }; + Ok(ret as isize) +} + +fn do_setsockopt( + fd: c_int, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: libc::socklen_t, +) -> Result { + info!( + "setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", + fd, level, optname, optval, optlen + ); + let ret = unsafe { libc::ocall::setsockopt(fd, level, optname, optval, optlen) }; + Ok(ret as isize) +} + +fn do_getsockopt( + fd: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut libc::socklen_t, +) -> Result { + info!( + "getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", + fd, level, optname, optval, optlen + ); + let ret = unsafe { libc::ocall::getsockopt(fd, level, optname, optval, optlen) }; + Ok(ret as isize) +} diff --git a/src/sgxenv.mk b/src/sgxenv.mk index f03cf685..6a81cded 100644 --- a/src/sgxenv.mk +++ b/src/sgxenv.mk @@ -38,7 +38,7 @@ else endif RUST_SGX_SDK_DIR := $(PROJECT_DIR)/deps/rust-sgx-sdk -SGX_COMMON_CFLAGS += -I$(RUST_SGX_SDK_DIR)/common/ -I$(RUST_SGX_SDK_DIR)/edl/ +SGX_COMMON_CFLAGS += -I$(RUST_SGX_SDK_DIR)/common/inc/ -I$(RUST_SGX_SDK_DIR)/edl/ ifneq ($(SGX_MODE), HW) Urts_Library_Name := sgx_urts_sim From e5bc58d3f03b5e7346a628633a5bba1bf890f112 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 2 Apr 2019 17:53:20 +0800 Subject: [PATCH 02/37] simplify log color --- src/libos/src/util/log.rs | 63 ++++++++++++--------------------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/src/libos/src/util/log.rs b/src/libos/src/util/log.rs index e938ba33..ee21aff1 100644 --- a/src/libos/src/util/log.rs +++ b/src/libos/src/util/log.rs @@ -22,11 +22,9 @@ impl Log for SimpleLogger { fn log(&self, record: &Record) { if self.enabled(record.metadata()) { let color = Color::from(record.level()); - let (show, code) = color.to_console_code(); println!( - "\u{1B}[{};{}m[{:>5}] {}\u{1B}[0m", - show, - code + 30, + "\u{1B}[{}m[{:>5}] {}\u{1B}[0m", + color as u8, record.level(), record.args() ); @@ -42,7 +40,7 @@ impl From for Color { Level::Warn => Color::Yellow, Level::Info => Color::Blue, Level::Debug => Color::Green, - Level::Trace => Color::DarkGray, + Level::Trace => Color::BrightBlack, } } } @@ -51,43 +49,20 @@ impl From for Color { #[derive(Debug, Clone, Copy, Eq, PartialEq)] #[repr(u8)] pub enum Color { - Black = 0, - Blue = 1, - Green = 2, - Cyan = 3, - Red = 4, - Magenta = 5, - Brown = 6, - LightGray = 7, - DarkGray = 8, - LightBlue = 9, - LightGreen = 10, - LightCyan = 11, - LightRed = 12, - Pink = 13, - Yellow = 14, - White = 15, -} - -impl Color { - fn to_console_code(&self) -> (u8, u8) { - match self { - Color::Black => (0, 0), - Color::Blue => (0, 4), - Color::Green => (0, 2), - Color::Cyan => (0, 6), - Color::Red => (0, 1), - Color::Magenta => (0, 5), - Color::Brown => (0, 3), - Color::LightGray => (1, 7), - Color::DarkGray => (0, 7), - Color::LightBlue => (1, 4), - Color::LightGreen => (1, 2), - Color::LightCyan => (1, 6), - Color::LightRed => (1, 1), - Color::Pink => (1, 5), - Color::Yellow => (1, 3), - Color::White => (1, 0), - } - } + Black = 30, + Red = 31, + Green = 32, + Yellow = 33, + Blue = 34, + Magenta = 35, + Cyan = 36, + White = 37, + BrightBlack = 90, + BrightRed = 91, + BrightGreen = 92, + BrightYellow = 93, + BrightBlue = 94, + BrightMagenta = 95, + BrightCyan = 96, + BrightWhite = 97, } From 0dda84d7f20df15f76d40c3eea703c54aa01360b Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 3 Apr 2019 01:04:10 +0800 Subject: [PATCH 03/37] add test for simple socket syscalls --- test/Makefile | 2 +- test/client/Makefile | 5 ++++ test/client/main.c | 52 ++++++++++++++++++++++++++++++++++++++ test/server/Makefile | 5 ++++ test/server/main.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 test/client/Makefile create mode 100644 test/client/main.c create mode 100644 test/server/Makefile create mode 100644 test/server/main.c diff --git a/test/Makefile b/test/Makefile index 8d698b00..280ee50e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread +TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread clone server # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput diff --git a/test/client/Makefile b/test/client/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/client/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/client/main.c b/test/client/main.c new file mode 100644 index 00000000..844a79df --- /dev/null +++ b/test/client/main.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, const char *argv[]) { + const int BUF_SIZE = 0x1000; + const char* message = "Hello world!"; + int ret; + + if (argc != 2) { + printf("usage: ./client \n"); + return -1; + } + + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + printf("create socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(6666); + + ret = inet_pton(AF_INET, argv[1], &servaddr.sin_addr); + if (ret <= 0) { + printf("inet_pton error for %s\n", argv[1]); + return -1; + } + + ret = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (ret < 0) { + printf("connect error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + printf("send msg to server: %s\n", message); + ret = send(sockfd, message, strlen(message), 0); + if (ret < 0) { + printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + close(sockfd); + return 0; +} \ No newline at end of file diff --git a/test/server/Makefile b/test/server/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/server/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/server/main.c b/test/server/main.c new file mode 100644 index 00000000..27094499 --- /dev/null +++ b/test/server/main.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, const char *argv[]) { + const int BUF_SIZE = 0x1000; + int ret; + + int listenfd = socket(AF_INET, SOCK_STREAM, 0); + if (listenfd < 0) { + printf("create socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(6666); + + ret = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (ret < 0) { + printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + ret = listen(listenfd, 10); + if (ret < 0) { + printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + int client_pid; + char* client_argv[] = {"client", "127.0.0.1"}; + ret = posix_spawn(&client_pid, "client", NULL, NULL, client_argv, NULL); + if (ret < 0) { + printf("spawn client process error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + printf("====== waiting for client's request ======\n"); + int connect_fd = accept(listenfd, (struct sockaddr *) NULL, NULL); + if (connect_fd < 0) { + printf("accept socket error: %s(errno: %d)", strerror(errno), errno); + return -1; + } + char buff[BUF_SIZE]; + int n = recv(connect_fd, buff, BUF_SIZE, 0); + buff[n] = '\0'; + printf("recv msg from client: %s\n", buff); + close(connect_fd); + + close(listenfd); +} \ No newline at end of file From 5b90d9064361c21cc702f5abb97328481a165c31 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 3 Apr 2019 01:06:46 +0800 Subject: [PATCH 04/37] implement SocketFile. pass socket test --- src/libos/src/entry.rs | 2 +- src/libos/src/errno.rs | 9 ++ src/libos/src/fs/file.rs | 4 +- src/libos/src/fs/mod.rs | 3 + src/libos/src/fs/socket_file.rs | 110 +++++++++++++++++++++++++ src/libos/src/syscall/mod.rs | 140 +++++++++++++++++++++++++++++--- src/libos/src/util/log.rs | 3 +- test/Makefile | 2 +- test/client/main.c | 2 +- 9 files changed, 258 insertions(+), 17 deletions(-) create mode 100644 src/libos/src/fs/socket_file.rs diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index f0de3087..719c07e0 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -64,7 +64,7 @@ fn parse_arguments( // TODO: make sure do_boot can only be called once fn do_boot(path_str: &str, argv: &Vec) -> Result<(), Error> { - info!("boot: path: {:?}, argv: {:?}", path_str, argv); +// info!("boot: path: {:?}, argv: {:?}", path_str, argv); util::mpx_util::mpx_enable()?; let envp = std::vec::Vec::new(); diff --git a/src/libos/src/errno.rs b/src/libos/src/errno.rs index 9957fd1a..3abfec08 100644 --- a/src/libos/src/errno.rs +++ b/src/libos/src/errno.rs @@ -39,6 +39,7 @@ impl fmt::Display for Error { } #[derive(Clone, Copy, Debug, PartialEq)] +#[repr(u8)] pub enum Errno { EUNDEF = 0, EPERM = 1, @@ -86,6 +87,14 @@ impl Errno { pub fn as_retval(&self) -> i32 { -(*self as i32) } + pub fn from_retval(ret: i32) -> Self { + let ret = if ret <= 0 && ret >= -39 { + (-ret) as u8 + } else { + 0 + }; + unsafe { core::mem::transmute(ret) } + } } impl fmt::Display for Errno { diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index 79d0e415..3dbb71ad 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -3,8 +3,9 @@ use std; use std::borrow::BorrowMut; use std::fmt; use std::io::SeekFrom; +use std::any::Any; -pub trait File: Debug + Sync + Send { +pub trait File: Debug + Sync + Send + Any { fn read(&self, buf: &mut [u8]) -> Result; fn write(&self, buf: &[u8]) -> Result; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result; @@ -17,6 +18,7 @@ pub trait File: Debug + Sync + Send { fn sync_all(&self) -> Result<(), Error>; fn sync_data(&self) -> Result<(), Error>; fn read_entry(&self) -> Result; + fn as_any(&self) -> &Any { unimplemented!() } } pub type FileRef = Arc>; diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 162f7062..cdaff66d 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -9,12 +9,14 @@ use super::*; pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile}; pub use self::file_table::{FileDesc, FileTable}; pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; +pub use self::socket_file::SocketFile; use self::inode_file::OpenOptions; pub use self::pipe::Pipe; mod file; mod file_table; mod inode_file; +mod socket_file; mod pipe; mod sgx_impl; @@ -206,6 +208,7 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result { } pub fn do_close(fd: FileDesc) -> Result<(), Error> { + info!("close: fd: {}", fd); let current_ref = process::get_current(); let current_process = current_ref.lock().unwrap(); let file_table_ref = current_process.get_files(); diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs new file mode 100644 index 00000000..97471e94 --- /dev/null +++ b/src/libos/src/fs/socket_file.rs @@ -0,0 +1,110 @@ +use super::*; +use std::any::Any; + +/// Native Linux socket +#[derive(Debug)] +pub struct SocketFile { + fd: c_int, +} + +impl SocketFile { + pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result { + let ret = unsafe { libc::ocall::socket(domain, socket_type, protocol) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(SocketFile { fd: ret }) + } + } + + pub fn accept( + &self, + addr: *mut libc::sockaddr, + addr_len: *mut libc::socklen_t, + flags: c_int, + ) -> Result { + let ret = unsafe { libc::ocall::accept4(self.fd, addr, addr_len, flags) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(SocketFile { fd: ret }) + } + } + + pub fn fd(&self) -> c_int { + self.fd + } +} + +impl Drop for SocketFile { + fn drop(&mut self) { + let ret = unsafe { libc::ocall::close(self.fd) }; + if ret < 0 { + warn!("socket (host fd: {}) close failed", self.fd); + } + } +} + +impl File for SocketFile { + fn read(&self, buf: &mut [u8]) -> Result { + let ret = unsafe { libc::ocall::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len()) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(ret as usize) + } + } + + fn write(&self, buf: &[u8]) -> Result { + let ret = unsafe { libc::ocall::write(self.fd, buf.as_ptr() as *const c_void, buf.len()) }; + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(ret as usize) + } + } + + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + unimplemented!() + } + + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + unimplemented!() + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + unimplemented!() + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + unimplemented!() + } + + fn seek(&self, pos: SeekFrom) -> Result { + Err(Error::new(Errno::ESPIPE, "Socket does not support seek")) + } + + fn metadata(&self) -> Result { + unimplemented!() + } + + fn set_len(&self, len: u64) -> Result<(), Error> { + unimplemented!() + } + + fn sync_all(&self) -> Result<(), Error> { + unimplemented!() + } + + fn sync_data(&self) -> Result<(), Error> { + unimplemented!() + } + + fn read_entry(&self) -> Result { + unimplemented!() + } + + fn as_any(&self) -> &Any { + self + } +} diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index fe6ef772..1293aba5 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,8 +7,7 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::File; -use fs::{off_t, FileDesc}; +use fs::{File, SocketFile, off_t, FileDesc, FileRef}; use prelude::*; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; @@ -21,6 +20,7 @@ use {fs, process, std, vm}; use super::*; use self::consts::*; +use std::any::Any; // Use the internal syscall wrappers from sgx_tstd //use std::libc_fs as fs; @@ -177,6 +177,22 @@ pub extern "C" fn dispatch_syscall( arg3 as *mut c_void, arg4 as *mut libc::socklen_t, ), + SYS_SENDTO => do_sendto( + arg0 as c_int, + arg1 as *const c_void, + arg2 as size_t, + arg3 as c_int, + arg4 as *const libc::sockaddr, + arg5 as libc::socklen_t, + ), + SYS_RECVFROM => do_recvfrom( + arg0 as c_int, + arg1 as *mut c_void, + arg2 as size_t, + arg3 as c_int, + arg4 as *mut libc::sockaddr, + arg5 as *mut libc::socklen_t, + ), _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5), }; @@ -654,6 +670,7 @@ fn do_gettimeofday(tv_u: *mut timeval_t) -> Result { const MAP_FAILED: *const c_void = ((-1) as i64) as *const c_void; fn do_exit(status: i32) -> ! { + info!("exit: {}", status); extern "C" { fn do_exit_task() -> !; } @@ -749,8 +766,15 @@ fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result> = Arc::new(Box::new(socket)); + + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + + let fd = proc.get_files().lock().unwrap().put(file_ref, false); + Ok(fd as isize) } fn do_connect( @@ -762,7 +786,12 @@ fn do_connect( "connect: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len ); - let ret = unsafe { libc::ocall::connect(fd, addr, addr_len) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::connect(socket.fd(), addr, addr_len) }; Ok(ret as isize) } @@ -776,13 +805,26 @@ fn do_accept( "accept: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", fd, addr, addr_len, flags ); - let ret = unsafe { libc::ocall::accept4(fd, addr, addr_len, flags) }; - Ok(ret as isize) + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let new_socket = socket.accept(addr, addr_len, flags)?; + let new_file_ref: Arc> = Arc::new(Box::new(new_socket)); + let new_fd = proc.get_files().lock().unwrap().put(new_file_ref, false); + + Ok(new_fd as isize) } fn do_shutdown(fd: c_int, how: c_int) -> Result { info!("shutdown: fd: {}, how: {}", fd, how); - let ret = unsafe { libc::ocall::shutdown(fd, how) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::shutdown(socket.fd(), how) }; Ok(ret as isize) } @@ -792,13 +834,23 @@ fn do_bind( addr_len: libc::socklen_t, ) -> Result { info!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len); - let ret = unsafe { libc::ocall::bind(fd, addr, addr_len) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::bind(socket.fd(), addr, addr_len) }; Ok(ret as isize) } fn do_listen(fd: c_int, backlog: c_int) -> Result { info!("listen: fd: {}, backlog: {}", fd, backlog); - let ret = unsafe { libc::ocall::listen(fd, backlog) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::listen(socket.fd(), backlog) }; Ok(ret as isize) } @@ -813,7 +865,12 @@ fn do_setsockopt( "setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", fd, level, optname, optval, optlen ); - let ret = unsafe { libc::ocall::setsockopt(fd, level, optname, optval, optlen) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::setsockopt(socket.fd(), level, optname, optval, optlen) }; Ok(ret as isize) } @@ -828,6 +885,65 @@ fn do_getsockopt( "getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", fd, level, optname, optval, optlen ); - let ret = unsafe { libc::ocall::getsockopt(fd, level, optname, optval, optlen) }; + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::getsockopt(socket.fd(), level, optname, optval, optlen) }; Ok(ret as isize) } + +fn do_sendto( + fd: c_int, + base: *const c_void, + len: size_t, + flags: c_int, + addr: *const libc::sockaddr, + addr_len: libc::socklen_t, +) -> Result { + info!( + "sendto: fd: {}, base: {:?}, len: {}, addr: {:?}, addr_len: {}", + fd, base, len, addr, addr_len + ); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::sendto(socket.fd(), base, len, flags, addr, addr_len) }; + Ok(ret as isize) +} + +fn do_recvfrom( + fd: c_int, + base: *mut c_void, + len: size_t, + flags: c_int, + addr: *mut libc::sockaddr, + addr_len: *mut libc::socklen_t, +) -> Result { + info!( + "recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}", + fd, base, len, flags, addr, addr_len + ); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = unsafe { libc::ocall::recvfrom(socket.fd(), base, len, flags, addr, addr_len) }; + Ok(ret as isize) +} + +trait AsSocket { + fn as_socket(&self) -> Result<&SocketFile, Error>; +} + +impl AsSocket for FileRef { + fn as_socket(&self) -> Result<&SocketFile, Error> { + self.as_any() + .downcast_ref::() + .ok_or(Error::new(Errno::EBADF, "not a socket")) + } +} diff --git a/src/libos/src/util/log.rs b/src/libos/src/util/log.rs index ee21aff1..302dd3db 100644 --- a/src/libos/src/util/log.rs +++ b/src/libos/src/util/log.rs @@ -23,9 +23,10 @@ impl Log for SimpleLogger { if self.enabled(record.metadata()) { let color = Color::from(record.level()); println!( - "\u{1B}[{}m[{:>5}] {}\u{1B}[0m", + "\u{1B}[{}m[{:>5}][{}] {}\u{1B}[0m", color as u8, record.level(), + crate::process::do_getpid(), record.args() ); } diff --git a/test/Makefile b/test/Makefile index 280ee50e..d53d3a5d 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread clone server +TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread client server # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput diff --git a/test/client/main.c b/test/client/main.c index 844a79df..558aa580 100644 --- a/test/client/main.c +++ b/test/client/main.c @@ -14,7 +14,7 @@ int main(int argc, const char *argv[]) { if (argc != 2) { printf("usage: ./client \n"); - return -1; + return 0; } int sockfd = socket(AF_INET, SOCK_STREAM, 0); From f62809096e413397ce585931c432df70944b3af6 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 8 Apr 2019 16:22:52 +0800 Subject: [PATCH 05/37] use libc::off_t --- src/libos/src/fs/mod.rs | 6 ------ src/libos/src/prelude.rs | 3 +-- src/libos/src/syscall/mod.rs | 2 +- src/libos/src/vm/mod.rs | 2 +- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index cdaff66d..384a5f1a 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -20,12 +20,6 @@ mod socket_file; mod pipe; mod sgx_impl; -// TODO: use the type defined in Rust libc. -// -// However, off_t is defined as u64 in the current Rust SGX SDK, which is -// wrong (see issue https://github.com/baidu/rust-sgx-sdk/issues/46) -#[allow(non_camel_case_types)] -pub type off_t = i64; pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { let flags = OpenFlags::from_bits_truncate(flags); diff --git a/src/libos/src/prelude.rs b/src/libos/src/prelude.rs index 2c9708b3..2a1d1ccc 100644 --- a/src/libos/src/prelude.rs +++ b/src/libos/src/prelude.rs @@ -1,4 +1,5 @@ pub use sgx_trts::libc; +pub use sgx_trts::libc::off_t; pub use sgx_types::*; use std; @@ -26,8 +27,6 @@ pub use errno::Errno; pub use errno::Errno::*; pub use errno::Error; -pub use fs::off_t; - macro_rules! debug_trace { () => { println!("> Line = {}, File = {}", line!(), file!()) diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 1293aba5..eb0fe921 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,7 +7,7 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::{File, SocketFile, off_t, FileDesc, FileRef}; +use fs::{File, SocketFile, FileDesc, FileRef}; use prelude::*; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; diff --git a/src/libos/src/vm/mod.rs b/src/libos/src/vm/mod.rs index db1500ab..33585928 100644 --- a/src/libos/src/vm/mod.rs +++ b/src/libos/src/vm/mod.rs @@ -1,4 +1,4 @@ -use fs::{off_t, FileDesc}; +use fs::FileDesc; use prelude::*; use process::{get_current, Process, ProcessRef}; use std::fmt; From 7bd2ce50f2897868562d77b89f564c37e54ed5be Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 9 Apr 2019 00:04:44 +0800 Subject: [PATCH 06/37] implement select and poll without test --- src/libos/src/fs/io_multiplexing.rs | 128 ++++++++++++++++++++++++++++ src/libos/src/fs/mod.rs | 2 + src/libos/src/syscall/mod.rs | 109 ++++++++++++++++++++++- 3 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 src/libos/src/fs/io_multiplexing.rs diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs new file mode 100644 index 00000000..2316bff9 --- /dev/null +++ b/src/libos/src/fs/io_multiplexing.rs @@ -0,0 +1,128 @@ +use super::*; +use crate::syscall::AsSocket; +use std::vec::Vec; + +/// Forward to host `poll` +/// (sgx_libc doesn't have `select`) +pub fn do_select( + nfds: usize, + readfds: &mut libc::fd_set, + writefds: &mut libc::fd_set, + exceptfds: &mut libc::fd_set, + timeout: Option, +) -> Result { + // convert libos fd to Linux fd + let mut host_to_libos_fd = [0; libc::FD_SETSIZE]; + let mut polls = Vec::::new(); + + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_table_ref = proc.get_files().lock().unwrap(); + + for fd in 0..nfds { + let (r, w, e) = (readfds.is_set(fd), writefds.is_set(fd), exceptfds.is_set(fd)); + if !(r || w || e) { + continue; + } + let host_fd = file_table_ref.get(fd as FileDesc)?.as_socket()?.fd(); + + host_to_libos_fd[host_fd as usize] = fd; + let mut events = 0; + if r { events |= libc::POLLIN; } + if w { events |= libc::POLLOUT; } + if e { events |= libc::POLLERR; } + + polls.push(libc::pollfd { + fd: host_fd as c_int, + events, + revents: 0, + }); + } + + let timeout = match timeout { + None => -1, + Some(tv) => (tv.tv_sec * 1000 + tv.tv_usec / 1000) as i32, + }; + + let ret = unsafe { + libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout) + }; + + if ret < 0 { + return Err(Error::new(Errno::from_retval(ret as i32), "")); + } + + // convert fd back and write fdset + readfds.clear(); + writefds.clear(); + exceptfds.clear(); + + for poll in polls.iter() { + let fd = host_to_libos_fd[poll.fd as usize]; + if poll.revents & libc::POLLIN != 0 { + readfds.set(fd); + } + if poll.revents & libc::POLLOUT != 0 { + writefds.set(fd); + } + if poll.revents & libc::POLLERR != 0 { + exceptfds.set(fd); + } + } + + Ok(ret as usize) +} + +pub fn do_poll( + polls: &mut [libc::pollfd], + timeout: c_int, +) -> Result { + info!("poll: [..], timeout: {}", timeout); + + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + + // convert libos fd to Linux fd + for poll in polls.iter_mut() { + let file_ref = proc.get_files().lock().unwrap().get(poll.fd as FileDesc)?; + let socket = file_ref.as_socket()?; + poll.fd = socket.fd(); + } + let ret = unsafe { + libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout) + }; + // recover fd ? + + if ret < 0 { + Err(Error::new(Errno::from_retval(ret as i32), "")) + } else { + Ok(ret as usize) + } +} + +/// Safe methods for `libc::fd_set` +trait FdSetExt { + fn set(&mut self, fd: usize); + fn clear(&mut self); + fn is_set(&mut self, fd: usize) -> bool; +} + +impl FdSetExt for libc::fd_set { + fn set(&mut self, fd: usize) { + assert!(fd < libc::FD_SETSIZE); + unsafe { + libc::FD_SET(fd as c_int, self); + } + } + + fn clear(&mut self) { + unsafe { + libc::FD_ZERO(self); + } + } + + fn is_set(&mut self, fd: usize) -> bool { + assert!(fd < libc::FD_SETSIZE); + unsafe { libc::FD_ISSET(fd as c_int, self) } + } +} diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 384a5f1a..e648e25a 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -12,6 +12,7 @@ pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; pub use self::socket_file::SocketFile; use self::inode_file::OpenOptions; pub use self::pipe::Pipe; +pub use self::io_multiplexing::*; mod file; mod file_table; @@ -19,6 +20,7 @@ mod inode_file; mod socket_file; mod pipe; mod sgx_impl; +mod io_multiplexing; pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index eb0fe921..2d75663f 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -81,6 +81,33 @@ pub extern "C" fn dispatch_syscall( SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), SYS_UNLINK => do_unlink(arg0 as *const i8), + // IO multiplexing + SYS_SELECT => do_select( + arg0 as c_int, + arg1 as *mut libc::fd_set, + arg2 as *mut libc::fd_set, + arg3 as *mut libc::fd_set, + arg4 as *const libc::timeval, + ), + SYS_POLL => do_poll( + arg0 as *mut libc::pollfd, + arg1 as libc::nfds_t, + arg2 as c_int, + ), + SYS_EPOLL_CREATE => do_epoll_create1(arg0 as c_int), + SYS_EPOLL_CTL => do_epoll_ctl( + arg0 as c_int, + arg1 as c_int, + arg2 as c_int, + arg3 as *const libc::epoll_event, + ), + SYS_EPOLL_WAIT => do_epoll_wait( + arg0 as c_int, + arg1 as *mut libc::epoll_event, + arg2 as c_int, + arg3 as c_int, + ), + // process SYS_EXIT => do_exit(arg0 as i32), SYS_SPAWN => do_spawn( @@ -936,7 +963,87 @@ fn do_recvfrom( Ok(ret as isize) } -trait AsSocket { +fn do_select( + nfds: c_int, + readfds: *mut libc::fd_set, + writefds: *mut libc::fd_set, + exceptfds: *mut libc::fd_set, + timeout: *const libc::timeval +) -> Result { + // check arguments + if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int { + return Err(Error::new(EINVAL, "nfds is negative or exceeds the resource limit")); + } + let nfds = nfds as usize; + + let mut zero_fds0: libc::fd_set = unsafe { core::mem::zeroed() }; + let mut zero_fds1: libc::fd_set = unsafe { core::mem::zeroed() }; + let mut zero_fds2: libc::fd_set = unsafe { core::mem::zeroed() }; + + let readfds = if !readfds.is_null() { + check_mut_ptr(readfds)?; + unsafe { &mut *readfds } + } else { + &mut zero_fds0 + }; + let writefds = if !writefds.is_null() { + check_mut_ptr(writefds)?; + unsafe { &mut *writefds } + } else { + &mut zero_fds1 + }; + let exceptfds = if !exceptfds.is_null() { + check_mut_ptr(exceptfds)?; + unsafe { &mut *exceptfds } + } else { + &mut zero_fds2 + }; + let timeout = if !timeout.is_null() { + check_ptr(timeout)?; + Some(unsafe { timeout.read() }) + } else { + None + }; + + let n = fs::do_select(nfds, readfds, writefds, exceptfds, timeout)?; + Ok(n as isize) +} + +fn do_poll( + fds: *mut libc::pollfd, + nfds: libc::nfds_t, + timeout: c_int, +) -> Result { + check_mut_array(fds, nfds as usize)?; + let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) }; + + let n = fs::do_poll(polls, timeout)?; + Ok(n as isize) +} + +fn do_epoll_create1(flags: c_int) -> Result { + unimplemented!() +} + +fn do_epoll_ctl( + epfd: c_int, + op: c_int, + fd: c_int, + event: *const libc::epoll_event, +) -> Result { + unimplemented!() +} + +fn do_epoll_wait( + epfd: c_int, + events: *mut libc::epoll_event, + maxevents: c_int, + timeout: c_int, +) -> Result { + unimplemented!() +} + +pub trait AsSocket { fn as_socket(&self) -> Result<&SocketFile, Error>; } From f9121a025e93e66b704dfad75fabff6ebf6e1d54 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 9 Apr 2019 01:40:30 +0800 Subject: [PATCH 07/37] implement epoll --- src/libos/src/fs/io_multiplexing.rs | 284 ++++++++++++++++++++++++++++ src/libos/src/syscall/mod.rs | 43 ++++- 2 files changed, 322 insertions(+), 5 deletions(-) diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 2316bff9..456ae88d 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -1,6 +1,9 @@ use super::*; use crate::syscall::AsSocket; use std::vec::Vec; +use std::collections::btree_map::BTreeMap; +use std::fmt; +use std::any::Any; /// Forward to host `poll` /// (sgx_libc doesn't have `select`) @@ -100,6 +103,56 @@ pub fn do_poll( } } +pub fn do_epoll_create1(flags: c_int) -> Result { + info!("epoll_create1: flags: {}", flags); + + let epoll = EpollFile::new()?; + let file_ref: Arc> = Arc::new(Box::new(epoll)); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let fd = { + let close_on_spawn = flags & libc::EPOLL_CLOEXEC != 0; + proc.get_files().lock().unwrap().put(file_ref, close_on_spawn) + }; + Ok(fd) +} + +pub fn do_epoll_ctl( + epfd: FileDesc, + op: EpollOp, + fd: FileDesc, +) -> Result<(), Error> { + info!("epoll_ctl: epfd: {}, op: {:?}, fd: {}", epfd, op, fd); + + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let mut file_ref = proc.get_files().lock().unwrap().get(epfd)?; + let mut epoll = file_ref.as_epoll()?.inner.lock().unwrap(); + + match op { + EpollOp::Add(event) => epoll.add(fd, event)?, + EpollOp::Modify(event) => epoll.modify(fd, event)?, + EpollOp::Delete => epoll.remove(fd)?, + } + Ok(()) +} + +pub fn do_epoll_wait( + epfd: FileDesc, + events: &mut [libc::epoll_event], + timeout: c_int, +) -> Result { + info!("epoll_wait: epfd: {}, len: {:?}, timeout: {}", epfd, events.len(), timeout); + + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let mut file_ref = proc.get_files().lock().unwrap().get(epfd)?; + let mut epoll = file_ref.as_epoll()?.inner.lock().unwrap(); + + let count = epoll.wait(events, timeout)?; + Ok(count) +} + /// Safe methods for `libc::fd_set` trait FdSetExt { fn set(&mut self, fd: usize); @@ -126,3 +179,234 @@ impl FdSetExt for libc::fd_set { unsafe { libc::FD_ISSET(fd as c_int, self) } } } + +pub enum EpollOp { + Add(libc::epoll_event), + Modify(libc::epoll_event), + Delete +} + +impl Debug for EpollOp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self { + EpollOp::Add(_) => "Add", + EpollOp::Modify(_) => "Modify", + EpollOp::Delete => "Delete", + }; + write!(f, "{}", s) + } +} + +pub struct EpollFile { + inner: SgxMutex, +} + +impl EpollFile { + pub fn new() -> Result { + Ok(Self { + inner: SgxMutex::new(EpollFileInner::new()?) + }) + } +} + +struct EpollFileInner { + epoll_fd: c_int, + fd_to_host: BTreeMap, + fd_to_libos: BTreeMap, +} + +// FIXME: What if a Linux fd is closed but still in an epoll? +impl EpollFileInner { + /// Create a new Linux epoll file descriptor + pub fn new() -> Result { + let ret = unsafe { libc::ocall::epoll_create1(0) }; + if ret < 0 { + return Err(Error::new(Errno::from_retval(ret as i32), "")); + } + Ok(EpollFileInner { + epoll_fd: ret, + fd_to_host: BTreeMap::new(), + fd_to_libos: BTreeMap::new(), + }) + } + + /// Add `fd` to the interest list and associate the settings + /// specified in `event` with the internal file linked to `fd`. + pub fn add(&mut self, fd: FileDesc, mut event: libc::epoll_event) -> Result<(), Error> { + if self.fd_to_host.contains_key(&fd) { + return Err(Error::new(EEXIST, "fd is exist in epoll")); + } + // query host fd + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd)?; + let host_fd = file_ref.as_socket()?.fd() as FileDesc; + + let ret = unsafe { + libc::ocall::epoll_ctl( + self.epoll_fd, + libc::EPOLL_CTL_ADD, + host_fd as c_int, + &mut event, + ) + }; + if ret < 0 { + return Err(Error::new(Errno::from_retval(ret as i32), "")); + } + self.fd_to_host.insert(fd, host_fd); + self.fd_to_libos.insert(host_fd, fd); + Ok(()) + } + + /// Change the settings associated with `fd` in the interest list to + /// the new settings specified in `event`. + pub fn modify(&mut self, fd: FileDesc, mut event: libc::epoll_event) -> Result<(), Error> { + let host_fd = *self.fd_to_host.get(&fd) + .ok_or(Error::new(EINVAL, "fd is not exist in epoll"))?; + let ret = unsafe { + libc::ocall::epoll_ctl( + self.epoll_fd, + libc::EPOLL_CTL_MOD, + host_fd as c_int, + &mut event, + ) + }; + if ret < 0 { + return Err(Error::new(Errno::from_retval(ret as i32), "")); + } + Ok(()) + } + + /// Remove the target file descriptor `fd` from the interest list. + pub fn remove(&mut self, fd: FileDesc) -> Result<(), Error> { + let host_fd = *self.fd_to_host.get(&fd) + .ok_or(Error::new(EINVAL, "fd is not exist in epoll"))?; + let ret = unsafe { + libc::ocall::epoll_ctl( + self.epoll_fd, + libc::EPOLL_CTL_DEL, + host_fd as c_int, + core::ptr::null_mut(), + ) + }; + if ret < 0 { + return Err(Error::new(Errno::from_retval(ret as i32), "")); + } + self.fd_to_host.remove(&fd); + self.fd_to_libos.remove(&host_fd); + Ok(()) + } + + /// Wait for an I/O event on the epoll. + /// Returns the number of file descriptors ready for the requested I/O. + pub fn wait( + &mut self, + events: &mut [libc::epoll_event], + timeout: c_int, + ) -> Result { + let ret = unsafe { + libc::ocall::epoll_wait( + self.epoll_fd, + events.as_mut_ptr(), + events.len() as c_int, + timeout, + ) + }; + if ret < 0 { + return Err(Error::new(Errno::from_retval(ret as i32), "")); + } + // convert host fd to libos + let count = ret as usize; + for event in events[0..count].iter_mut() { + let host_fd = event.u64 as FileDesc; + let fd = self.fd_to_libos[&host_fd]; + event.u64 = fd as u64; + } + Ok(count) + } +} + +impl Drop for EpollFileInner { + fn drop(&mut self) { + unsafe { + libc::ocall::close(self.epoll_fd); + } + } +} + +impl File for EpollFile { + fn read(&self, buf: &mut [u8]) -> Result { + unimplemented!() + } + + fn write(&self, buf: &[u8]) -> Result { + unimplemented!() + } + + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { + unimplemented!() + } + + fn write_at(&self, offset: usize, buf: &[u8]) -> Result { + unimplemented!() + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + unimplemented!() + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + unimplemented!() + } + + fn seek(&self, pos: SeekFrom) -> Result { + Err(Error::new(Errno::ESPIPE, "Epoll does not support seek")) + } + + fn metadata(&self) -> Result { + unimplemented!() + } + + fn set_len(&self, len: u64) -> Result<(), Error> { + unimplemented!() + } + + fn sync_all(&self) -> Result<(), Error> { + unimplemented!() + } + + fn sync_data(&self) -> Result<(), Error> { + unimplemented!() + } + + fn read_entry(&self) -> Result { + unimplemented!() + } + + fn as_any(&self) -> &Any { + self + } +} + +impl Debug for EpollFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let inner = self.inner.lock().unwrap(); + f.debug_struct("EpollFile") + .field("epoll_fd", &inner.epoll_fd) + .field("fds", &inner.fd_to_host.keys()) + .field("host_fds", &inner.fd_to_host.values()) + .finish() + } +} + +pub trait AsEpoll { + fn as_epoll(&self) -> Result<&EpollFile, Error>; +} + +impl AsEpoll for FileRef { + fn as_epoll(&self) -> Result<&EpollFile, Error> { + self.as_any() + .downcast_ref::() + .ok_or(Error::new(Errno::EBADF, "not a epoll")) + } +} diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 2d75663f..6b0c793c 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,7 +7,7 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::{File, SocketFile, FileDesc, FileRef}; +use fs::{File, SocketFile, FileDesc, FileRef, EpollOp}; use prelude::*; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; @@ -94,7 +94,8 @@ pub extern "C" fn dispatch_syscall( arg1 as libc::nfds_t, arg2 as c_int, ), - SYS_EPOLL_CREATE => do_epoll_create1(arg0 as c_int), + SYS_EPOLL_CREATE => do_epoll_create(arg0 as c_int), + SYS_EPOLL_CREATE1 => do_epoll_create1(arg0 as c_int), SYS_EPOLL_CTL => do_epoll_ctl( arg0 as c_int, arg1 as c_int, @@ -1021,8 +1022,16 @@ fn do_poll( Ok(n as isize) } +fn do_epoll_create(size: c_int) -> Result { + if size <= 0 { + return Err(Error::new(EINVAL, "size is not positive")); + } + do_epoll_create1(0) +} + fn do_epoll_create1(flags: c_int) -> Result { - unimplemented!() + let fd = fs::do_epoll_create1(flags)?; + Ok(fd as isize) } fn do_epoll_ctl( @@ -1031,7 +1040,20 @@ fn do_epoll_ctl( fd: c_int, event: *const libc::epoll_event, ) -> Result { - unimplemented!() + let event = if event.is_null() { + None + } else { + check_ptr(event)?; + Some(unsafe { event.read() }) + }; + let op = match (op, event) { + (libc::EPOLL_CTL_ADD, Some(event)) => EpollOp::Add(event), + (libc::EPOLL_CTL_MOD, Some(event)) => EpollOp::Modify(event), + (libc::EPOLL_CTL_DEL, _) => EpollOp::Delete, + _ => return Err(Error::new(EINVAL, "invalid epoll op or event ptr")), + }; + fs::do_epoll_ctl(epfd as FileDesc, op, fd as FileDesc)?; + Ok(0) } fn do_epoll_wait( @@ -1040,7 +1062,18 @@ fn do_epoll_wait( maxevents: c_int, timeout: c_int, ) -> Result { - unimplemented!() + let maxevents = { + if maxevents <= 0 { + return Err(Error::new(EINVAL, "maxevents <= 0")); + } + maxevents as usize + }; + let events = { + check_mut_array(events, maxevents)?; + unsafe { std::slice::from_raw_parts_mut(events, maxevents) } + }; + let count = fs::do_epoll_wait(epfd as FileDesc, events, timeout)?; + Ok(count as isize) } pub trait AsSocket { From bd9a3dd578ad420d90017da3da5f96e3202063e8 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 11 Apr 2019 19:10:12 +0800 Subject: [PATCH 08/37] fix epoll_ctl deadlock --- src/libos/src/fs/io_multiplexing.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 456ae88d..a998ecd6 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -126,11 +126,15 @@ pub fn do_epoll_ctl( let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); - let mut file_ref = proc.get_files().lock().unwrap().get(epfd)?; + let mut file_table_ref = proc.get_files().lock().unwrap(); + let mut file_ref = file_table_ref.get(epfd)?; let mut epoll = file_ref.as_epoll()?.inner.lock().unwrap(); match op { - EpollOp::Add(event) => epoll.add(fd, event)?, + EpollOp::Add(event) => { + let host_fd = file_table_ref.get(fd)?.as_socket()?.fd() as FileDesc; + epoll.add(fd, host_fd, event)?; + }, EpollOp::Modify(event) => epoll.modify(fd, event)?, EpollOp::Delete => epoll.remove(fd)?, } @@ -232,16 +236,10 @@ impl EpollFileInner { /// Add `fd` to the interest list and associate the settings /// specified in `event` with the internal file linked to `fd`. - pub fn add(&mut self, fd: FileDesc, mut event: libc::epoll_event) -> Result<(), Error> { + pub fn add(&mut self, fd: FileDesc, host_fd: FileDesc, mut event: libc::epoll_event) -> Result<(), Error> { if self.fd_to_host.contains_key(&fd) { return Err(Error::new(EEXIST, "fd is exist in epoll")); } - // query host fd - let current_ref = process::get_current(); - let mut proc = current_ref.lock().unwrap(); - let file_ref = proc.get_files().lock().unwrap().get(fd)?; - let host_fd = file_ref.as_socket()?.fd() as FileDesc; - let ret = unsafe { libc::ocall::epoll_ctl( self.epoll_fd, From 3defc8b9aa3837a45e5b4111be1ace468137ad77 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 11 Apr 2019 19:14:53 +0800 Subject: [PATCH 09/37] update sefs --- deps/sefs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/sefs b/deps/sefs index 166616e5..2865c419 160000 --- a/deps/sefs +++ b/deps/sefs @@ -1 +1 @@ -Subproject commit 166616e5ade1a5c929f705fd1564ef0ea337ba72 +Subproject commit 2865c419b3d36a8b0e7ef843b115cb1ecb3176f8 From 6d432b0a0303f7768e2cb824edd43ac1dff6668a Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 13:42:19 +0800 Subject: [PATCH 10/37] fix deadlock when log getting pid --- src/libos/src/process/mod.rs | 2 +- src/libos/src/process/task.rs | 10 ++++++++++ src/libos/src/util/log.rs | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libos/src/process/mod.rs b/src/libos/src/process/mod.rs index 86c6017e..a8d32e2f 100644 --- a/src/libos/src/process/mod.rs +++ b/src/libos/src/process/mod.rs @@ -1,5 +1,5 @@ pub use self::process::{Status, IDLE_PROCESS}; -pub use self::task::{get_current, run_task}; +pub use self::task::{get_current, run_task, current_pid}; pub use self::process_table::{get}; pub use self::exit::{do_exit, do_wait4, ChildProcessFilter}; pub use self::spawn::{do_spawn, FileAction}; diff --git a/src/libos/src/process/task.rs b/src/libos/src/process/task.rs index 244c473e..89fcde6a 100644 --- a/src/libos/src/process/task.rs +++ b/src/libos/src/process/task.rs @@ -68,6 +68,12 @@ thread_local! { static _CURRENT_PROCESS_PTR: Cell<*const SgxMutex> = { Cell::new(0 as *const SgxMutex) }; + // for log getting pid without locking process + static _PID: Cell = Cell::new(0); +} + +pub fn current_pid() -> pid_t { + _PID.with(|p| p.get()) } pub fn get_current() -> ProcessRef { @@ -81,6 +87,9 @@ pub fn get_current() -> ProcessRef { } fn set_current(process: &ProcessRef) { + let pid = process.lock().unwrap().get_pid(); + _PID.with(|p| p.set(pid)); + let process_ref_clone = process.clone(); let process_ptr = Arc::into_raw(process_ref_clone); @@ -90,6 +99,7 @@ fn set_current(process: &ProcessRef) { } fn reset_current() { + _PID.with(|p| p.set(0)); let mut process_ptr = _CURRENT_PROCESS_PTR.with(|cp| cp.replace(0 as *const SgxMutex)); // Prevent memory leakage diff --git a/src/libos/src/util/log.rs b/src/libos/src/util/log.rs index 302dd3db..621db02c 100644 --- a/src/libos/src/util/log.rs +++ b/src/libos/src/util/log.rs @@ -26,7 +26,7 @@ impl Log for SimpleLogger { "\u{1B}[{}m[{:>5}][{}] {}\u{1B}[0m", color as u8, record.level(), - crate::process::do_getpid(), + crate::process::current_pid(), record.args() ); } From 80a73eaa0d8fd53876a90ed2816dfa7fc5bae8a7 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 14:27:48 +0800 Subject: [PATCH 11/37] fix close_on_spawn and file_actions --- src/libos/src/fs/file_table.rs | 37 +++++++++++------------------- src/libos/src/process/spawn/mod.rs | 3 +++ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/libos/src/fs/file_table.rs b/src/libos/src/fs/file_table.rs index 0e60c108..2ff33e33 100644 --- a/src/libos/src/fs/file_table.rs +++ b/src/libos/src/fs/file_table.rs @@ -4,7 +4,7 @@ use std; pub type FileDesc = u32; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] #[repr(C)] pub struct FileTable { table: Vec>, @@ -123,30 +123,19 @@ impl FileTable { None => errno!(EBADF, "Invalid file descriptor"), } } -} -impl Clone for FileTable { - fn clone(&self) -> FileTable { - // Only clone file descriptors that are not close-on-spawn - let mut num_cloned_fds = 0; - let cloned_table = self - .table - .iter() - .map(|entry| match entry { - Some(file_table_entry) => match file_table_entry.close_on_spawn { - false => { - num_cloned_fds += 1; - Some(file_table_entry.clone()) - } - true => None, - }, - None => None, - }) - .collect(); - - FileTable { - table: cloned_table, - num_fds: num_cloned_fds, + /// Remove file descriptors that are close-on-spawn + pub fn close_on_spawn(&mut self) { + for entry in self.table.iter_mut() { + let need_close = if let Some(entry) = entry { + entry.close_on_spawn + } else { + false + }; + if need_close { + *entry = None; + self.num_fds -= 1; + } } } } diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index 3dd58ec1..ca218537 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -87,6 +87,7 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result 0; if should_inherit_file_table { + // Fork: clone file table let mut cloned_file_table = parent.get_files().lock().unwrap().clone(); // Perform file actions to modify the cloned file table for file_action in file_actions { @@ -102,6 +103,8 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result Date: Fri, 12 Apr 2019 15:14:11 +0800 Subject: [PATCH 12/37] add simple epoll test. fix epoll_wait, accept4 --- src/libos/src/fs/io_multiplexing.rs | 9 +- src/libos/src/syscall/mod.rs | 12 +- test/Makefile | 2 +- test/server_epoll/Makefile | 5 + test/server_epoll/main.c | 186 ++++++++++++++++++++++++++++ 5 files changed, 202 insertions(+), 12 deletions(-) create mode 100644 test/server_epoll/Makefile create mode 100644 test/server_epoll/main.c diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index a998ecd6..214f369f 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -313,14 +313,7 @@ impl EpollFileInner { if ret < 0 { return Err(Error::new(Errno::from_retval(ret as i32), "")); } - // convert host fd to libos - let count = ret as usize; - for event in events[0..count].iter_mut() { - let host_fd = event.u64 as FileDesc; - let fd = self.fd_to_libos[&host_fd]; - event.u64 = fd as u64; - } - Ok(count) + Ok(ret as usize) } } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 7a9cf0f2..3c843f06 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -198,7 +198,13 @@ pub extern "C" fn dispatch_syscall( arg1 as *const libc::sockaddr, arg2 as libc::socklen_t, ), - SYS_ACCEPT => do_accept( + SYS_ACCEPT => do_accept4( + arg0 as c_int, + arg1 as *mut libc::sockaddr, + arg2 as *mut libc::socklen_t, + 0, + ), + SYS_ACCEPT4 => do_accept4( arg0 as c_int, arg1 as *mut libc::sockaddr, arg2 as *mut libc::socklen_t, @@ -882,14 +888,14 @@ fn do_connect( Ok(ret as isize) } -fn do_accept( +fn do_accept4( fd: c_int, addr: *mut libc::sockaddr, addr_len: *mut libc::socklen_t, flags: c_int, ) -> Result { info!( - "accept: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", + "accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", fd, addr, addr_len, flags ); let current_ref = process::get_current(); diff --git a/test/Makefile b/test/Makefile index e9181d9e..4d4ca4cb 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server +TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput diff --git a/test/server_epoll/Makefile b/test/server_epoll/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/server_epoll/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/server_epoll/main.c b/test/server_epoll/main.c new file mode 100644 index 00000000..22f8867c --- /dev/null +++ b/test/server_epoll/main.c @@ -0,0 +1,186 @@ +// Modified from https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXEVENTS 64 + +static int +create_and_bind() { + int listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (listenfd < 0) { + printf("create socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(6666); + + int ret = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (ret < 0) { + printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + return listenfd; +} + +int +main(int argc, char *argv[]) { + int sfd = create_and_bind(); + + int s = listen(sfd, SOMAXCONN); + if (s == -1) { + perror("listen"); + return -1; + } + + int efd = epoll_create1(0); + if (efd == -1) { + perror("epoll_create"); + return -1; + } + + struct epoll_event event; + event.data.fd = sfd; + event.events = EPOLLIN | EPOLLET; + s = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event); + if (s == -1) { + perror("epoll_ctl"); + return -1; + } + + /* Buffer where events are returned */ + struct epoll_event *events = calloc(MAXEVENTS, sizeof event); + + // spawn clients + int client_pid; + char* client_argv[] = {"client", "127.0.0.1"}; + for(int i=0; i<3; ++i) { + int ret = posix_spawn(&client_pid, "client", NULL, NULL, client_argv, NULL); + if (ret < 0) { + printf("spawn client process error: %s(errno: %d)\n", strerror(errno), errno); + return -1; + } + } + + /* The event loop */ + int done_count = 0; + while (done_count < 3) { + int n = epoll_wait(efd, events, MAXEVENTS, -1); + for (int i = 0; i < n; i++) { + if ((events[i].events & EPOLLERR) || + (events[i].events & EPOLLHUP) || + (!(events[i].events & EPOLLIN))) { + /* An error has occured on this fd, or the socket is not + ready for reading (why were we notified then?) */ + fprintf(stderr, "epoll error\n"); + close(events[i].data.fd); + continue; + } else if (sfd == events[i].data.fd) { + /* We have a notification on the listening socket, which + means one or more incoming connections. */ + while (1) { + struct sockaddr in_addr; + socklen_t in_len; + int infd; + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + + in_len = sizeof in_addr; + infd = accept4(sfd, &in_addr, &in_len, SOCK_NONBLOCK); + if (infd == -1) { + if ((errno == EAGAIN) || + (errno == EWOULDBLOCK)) { + /* We have processed all incoming + connections. */ + break; + } else { + perror("accept"); + break; + } + } + + s = getnameinfo(&in_addr, in_len, + hbuf, sizeof hbuf, + sbuf, sizeof sbuf, + NI_NUMERICHOST | NI_NUMERICSERV); + if (s == 0) { + printf("Accepted connection on descriptor %d " + "(host=%s, port=%s)\n", infd, hbuf, sbuf); + } + + // add it to the list of fds to monitor + event.data.fd = infd; + event.events = EPOLLIN | EPOLLET; + s = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event); + if (s == -1) { + perror("epoll_ctl"); + return -1; + } + } + continue; + } else { + /* We have data on the fd waiting to be read. Read and + display it. We must read whatever data is available + completely, as we are running in edge-triggered mode + and won't get a notification again for the same + data. */ + int done = 0; + + while (1) { + ssize_t count; + char buf[512]; + + count = read(events[i].data.fd, buf, sizeof buf); + if (count == -1) { + /* If errno == EAGAIN, that means we have read all + data. So go back to the main loop. */ + if (errno != EAGAIN) { + perror("read"); + done = 1; + } + break; + } else if (count == 0) { + /* End of file. The remote has closed the + connection. */ + done = 1; + break; + } + + /* Write the buffer to standard output */ + s = write(1, buf, count); + if (s == -1) { + perror("write"); + return -1; + } + } + + if (done) { + printf("Closed connection on descriptor %d\n", + events[i].data.fd); + + /* Closing the descriptor will make epoll remove it + from the set of descriptors which are monitored. */ + close(events[i].data.fd); + + done_count ++; + } + } + } + } + + free(events); + + close(sfd); + + return EXIT_SUCCESS; +} From b2d75f386c5af306fa57793edebe159ef7f6e2b0 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 15:16:23 +0800 Subject: [PATCH 13/37] support readlink "/proc/self/exe". impl dummy fcntl.getfl --- src/libos/src/fs/access.rs | 2 ++ src/libos/src/fs/mod.rs | 30 +++++++++++++++++++++++++----- src/sgxenv.mk | 2 +- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/libos/src/fs/access.rs b/src/libos/src/fs/access.rs index e2910a73..d4cb347d 100644 --- a/src/libos/src/fs/access.rs +++ b/src/libos/src/fs/access.rs @@ -35,6 +35,7 @@ impl AccessFlags { pub const AT_FDCWD : i32 = -100; pub fn do_faccessat(dirfd: Option, path: &str, mode: AccessModes, flags: AccessFlags) -> Result<(), Error> { + info!("faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}", dirfd, path, mode, flags); match dirfd { // TODO: handle dirfd Some(dirfd) => errno!(ENOSYS, "cannot accept dirfd"), @@ -43,6 +44,7 @@ pub fn do_faccessat(dirfd: Option, path: &str, mode: AccessModes, flag } pub fn do_access(path: &str, mode: AccessModes) -> Result<(), Error> { + info!("access: path: {:?}, mode: {:?}", path, mode); let current_ref = process::get_current(); let mut current = current_ref.lock().unwrap(); let inode = current.lookup_inode(path)?; diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 5b74b496..d0c57b66 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -216,6 +216,7 @@ pub fn do_close(fd: FileDesc) -> Result<(), Error> { } pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> { + info!("pipe2: flags: {:#x}", flags); let flags = OpenFlags::from_bits_truncate(flags); let current_ref = process::get_current(); let current = current_ref.lock().unwrap(); @@ -226,6 +227,7 @@ pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> { let close_on_spawn = flags.contains(OpenFlags::CLOEXEC); let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), close_on_spawn); let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), close_on_spawn); + info!("pipe2: reader_fd: {}, writer_fd: {}", reader_fd, writer_fd); Ok([reader_fd, writer_fd]) } @@ -658,7 +660,7 @@ impl FcntlCmd { } pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result { - info!("do_fcntl: {:?}, {:?}", &fd, cmd); + info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd); let current_ref = process::get_current(); let mut current = current_ref.lock().unwrap(); let files_ref = current.get_files(); @@ -687,15 +689,33 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result { 0 }, FcntlCmd::GetFl() => { - unimplemented!(); + let _ = files.get_entry_mut(fd)?; + warn!("fcntl.getfl is unimplemented"); + 0 }, FcntlCmd::SetFl(flags) => { - unimplemented!(); + let _ = files.get_entry_mut(fd)?; + warn!("fcntl.setfl is unimplemented"); + 0 }, }) } pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result { - // TODO: support symbolic links - errno!(EINVAL, "not a symbolic link") + info!("readlink: path: {:?}", path); + match path { + "/proc/self/exe" => { + // get cwd + let current_ref = process::get_current(); + let current = current_ref.lock().unwrap(); + let cwd = current.get_cwd(); + let len = cwd.len().min(buf.len()); + buf[0..len].copy_from_slice(&cwd.as_bytes()[0..len]); + Ok(0) + } + _ => { + // TODO: support symbolic links + errno!(EINVAL, "not a symbolic link") + } + } } diff --git a/src/sgxenv.mk b/src/sgxenv.mk index 6a81cded..f03cf685 100644 --- a/src/sgxenv.mk +++ b/src/sgxenv.mk @@ -38,7 +38,7 @@ else endif RUST_SGX_SDK_DIR := $(PROJECT_DIR)/deps/rust-sgx-sdk -SGX_COMMON_CFLAGS += -I$(RUST_SGX_SDK_DIR)/common/inc/ -I$(RUST_SGX_SDK_DIR)/edl/ +SGX_COMMON_CFLAGS += -I$(RUST_SGX_SDK_DIR)/common/ -I$(RUST_SGX_SDK_DIR)/edl/ ifneq ($(SGX_MODE), HW) Urts_Library_Name := sgx_urts_sim From 82f41696187459bb349fe19dd95d477cad38b88a Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 16:54:49 +0800 Subject: [PATCH 14/37] enlarge preallocated space. sync file system on exit. --- src/libos/src/entry.rs | 6 ++++++ src/libos/src/vm/vm_space_prealloced.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 719c07e0..f299d51e 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -78,5 +78,11 @@ fn do_boot(path_str: &str, argv: &Vec) -> Result<(), Error> { // TODO: make sure do_run() cannot be called after do_boot() fn do_run() -> Result { let exit_status = process::run_task()?; + + // sync file system + // TODO: only sync when all processes exit + use rcore_fs::vfs::FileSystem; + crate::fs::ROOT_INODE.fs().sync()?; + Ok(exit_status) } diff --git a/src/libos/src/vm/vm_space_prealloced.c b/src/libos/src/vm/vm_space_prealloced.c index cfcd0abd..62fba785 100644 --- a/src/libos/src/vm/vm_space_prealloced.c +++ b/src/libos/src/vm/vm_space_prealloced.c @@ -1,6 +1,6 @@ #include -#define DATA_SPACE_SIZE (32*1024*1024) +#define DATA_SPACE_SIZE (96*1024*1024) static char __prealloced_data_space[DATA_SPACE_SIZE] __attribute__ (( From 58a7f7c126e3a0ae4be1605bc8d7703cb0bc2d93 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 12 Apr 2019 18:02:40 +0800 Subject: [PATCH 15/37] simplify epoll_ctl --- src/libos/src/fs/io_multiplexing.rs | 88 +++-------------------------- src/libos/src/syscall/mod.rs | 17 ++---- 2 files changed, 12 insertions(+), 93 deletions(-) diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 214f369f..6432aede 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -119,8 +119,9 @@ pub fn do_epoll_create1(flags: c_int) -> Result { pub fn do_epoll_ctl( epfd: FileDesc, - op: EpollOp, + op: c_int, fd: FileDesc, + event: *const libc::epoll_event, ) -> Result<(), Error> { info!("epoll_ctl: epfd: {}, op: {:?}, fd: {}", epfd, op, fd); @@ -130,14 +131,9 @@ pub fn do_epoll_ctl( let mut file_ref = file_table_ref.get(epfd)?; let mut epoll = file_ref.as_epoll()?.inner.lock().unwrap(); - match op { - EpollOp::Add(event) => { - let host_fd = file_table_ref.get(fd)?.as_socket()?.fd() as FileDesc; - epoll.add(fd, host_fd, event)?; - }, - EpollOp::Modify(event) => epoll.modify(fd, event)?, - EpollOp::Delete => epoll.remove(fd)?, - } + let host_fd = file_table_ref.get(fd)?.as_socket()?.fd() as FileDesc; + epoll.ctl(op, host_fd, event)?; + Ok(()) } @@ -184,23 +180,6 @@ impl FdSetExt for libc::fd_set { } } -pub enum EpollOp { - Add(libc::epoll_event), - Modify(libc::epoll_event), - Delete -} - -impl Debug for EpollOp { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let s = match self { - EpollOp::Add(_) => "Add", - EpollOp::Modify(_) => "Modify", - EpollOp::Delete => "Delete", - }; - write!(f, "{}", s) - } -} - pub struct EpollFile { inner: SgxMutex, } @@ -215,8 +194,6 @@ impl EpollFile { struct EpollFileInner { epoll_fd: c_int, - fd_to_host: BTreeMap, - fd_to_libos: BTreeMap, } // FIXME: What if a Linux fd is closed but still in an epoll? @@ -229,44 +206,17 @@ impl EpollFileInner { } Ok(EpollFileInner { epoll_fd: ret, - fd_to_host: BTreeMap::new(), - fd_to_libos: BTreeMap::new(), }) } - /// Add `fd` to the interest list and associate the settings - /// specified in `event` with the internal file linked to `fd`. - pub fn add(&mut self, fd: FileDesc, host_fd: FileDesc, mut event: libc::epoll_event) -> Result<(), Error> { - if self.fd_to_host.contains_key(&fd) { - return Err(Error::new(EEXIST, "fd is exist in epoll")); - } - let ret = unsafe { - libc::ocall::epoll_ctl( - self.epoll_fd, - libc::EPOLL_CTL_ADD, - host_fd as c_int, - &mut event, - ) - }; - if ret < 0 { - return Err(Error::new(Errno::from_retval(ret as i32), "")); - } - self.fd_to_host.insert(fd, host_fd); - self.fd_to_libos.insert(host_fd, fd); - Ok(()) - } - /// Change the settings associated with `fd` in the interest list to - /// the new settings specified in `event`. - pub fn modify(&mut self, fd: FileDesc, mut event: libc::epoll_event) -> Result<(), Error> { - let host_fd = *self.fd_to_host.get(&fd) - .ok_or(Error::new(EINVAL, "fd is not exist in epoll"))?; + pub fn ctl(&mut self, op: c_int, host_fd: FileDesc, event: *const libc::epoll_event) -> Result<(), Error> { let ret = unsafe { libc::ocall::epoll_ctl( self.epoll_fd, - libc::EPOLL_CTL_MOD, + op, host_fd as c_int, - &mut event, + event as *mut _, ) }; if ret < 0 { @@ -275,26 +225,6 @@ impl EpollFileInner { Ok(()) } - /// Remove the target file descriptor `fd` from the interest list. - pub fn remove(&mut self, fd: FileDesc) -> Result<(), Error> { - let host_fd = *self.fd_to_host.get(&fd) - .ok_or(Error::new(EINVAL, "fd is not exist in epoll"))?; - let ret = unsafe { - libc::ocall::epoll_ctl( - self.epoll_fd, - libc::EPOLL_CTL_DEL, - host_fd as c_int, - core::ptr::null_mut(), - ) - }; - if ret < 0 { - return Err(Error::new(Errno::from_retval(ret as i32), "")); - } - self.fd_to_host.remove(&fd); - self.fd_to_libos.remove(&host_fd); - Ok(()) - } - /// Wait for an I/O event on the epoll. /// Returns the number of file descriptors ready for the requested I/O. pub fn wait( @@ -384,8 +314,6 @@ impl Debug for EpollFile { let inner = self.inner.lock().unwrap(); f.debug_struct("EpollFile") .field("epoll_fd", &inner.epoll_fd) - .field("fds", &inner.fd_to_host.keys()) - .field("host_fds", &inner.fd_to_host.values()) .finish() } } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 3c843f06..0bea6239 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,7 +7,7 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::{File, SocketFile, FileDesc, FileRef, EpollOp, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd}; +use fs::{File, SocketFile, FileDesc, FileRef, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd}; use prelude::*; use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; @@ -1105,19 +1105,10 @@ fn do_epoll_ctl( fd: c_int, event: *const libc::epoll_event, ) -> Result { - let event = if event.is_null() { - None - } else { + if !event.is_null() { check_ptr(event)?; - Some(unsafe { event.read() }) - }; - let op = match (op, event) { - (libc::EPOLL_CTL_ADD, Some(event)) => EpollOp::Add(event), - (libc::EPOLL_CTL_MOD, Some(event)) => EpollOp::Modify(event), - (libc::EPOLL_CTL_DEL, _) => EpollOp::Delete, - _ => return Err(Error::new(EINVAL, "invalid epoll op or event ptr")), - }; - fs::do_epoll_ctl(epfd as FileDesc, op, fd as FileDesc)?; + } + fs::do_epoll_ctl(epfd as FileDesc, op, fd as FileDesc, event)?; Ok(0) } From d19676032d2912b4298bafa6075f659303e00d9b Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 13 Apr 2019 12:05:50 +0800 Subject: [PATCH 16/37] implement add_open in posix_spawn --- src/libos/src/fs/mod.rs | 42 +++++++++++++++++------------- src/libos/src/process/spawn/mod.rs | 30 +++++++++++++++------ src/libos/src/syscall/mod.rs | 11 +++++--- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index d0c57b66..d845563e 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -35,24 +35,8 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); - let inode = if flags.contains(OpenFlags::CREATE) { - let (dir_path, file_name) = split_path(&path); - let dir_inode = proc.lookup_inode(dir_path)?; - match dir_inode.find(file_name) { - Ok(file_inode) => { - if flags.contains(OpenFlags::EXCLUSIVE) { - return Err(Error::new(EEXIST, "file exists")); - } - file_inode - } - Err(FsError::EntryNotFound) => dir_inode.create(file_name, FileType::File, mode)?, - Err(e) => return Err(Error::from(e)), - } - } else { - proc.lookup_inode(&path)? - }; - - let file_ref: Arc> = Arc::new(Box::new(INodeFile::open(inode, flags.to_options())?)); + let file = proc.open_file(path, flags, mode)?; + let file_ref: Arc> = Arc::new(Box::new(file)); let fd = { let close_on_spawn = flags.contains(OpenFlags::CLOEXEC); @@ -363,6 +347,28 @@ extern "C" { } impl Process { + /// Open a file on the process. But DO NOT add it to file table. + pub fn open_file(&self, path: &str, flags: OpenFlags, mode: u32) -> Result { + let inode = if flags.contains(OpenFlags::CREATE) { + let (dir_path, file_name) = split_path(&path); + let dir_inode = self.lookup_inode(dir_path)?; + match dir_inode.find(file_name) { + Ok(file_inode) => { + if flags.contains(OpenFlags::EXCLUSIVE) { + return Err(Error::new(EEXIST, "file exists")); + } + file_inode + } + Err(FsError::EntryNotFound) => dir_inode.create(file_name, FileType::File, mode)?, + Err(e) => return Err(Error::from(e)), + } + } else { + self.lookup_inode(&path)? + }; + INodeFile::open(inode, flags.to_options()) + } + + /// Lookup INode from the cwd of the process pub fn lookup_inode(&self, path: &str) -> Result, Error> { debug!("lookup_inode: cwd: {:?}, path: {:?}", self.get_cwd(), path); if path.len() > 0 && path.as_bytes()[0] == b'/' { diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index ca218537..b8654c2f 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -1,7 +1,7 @@ use xmas_elf::{ElfFile, header, program, sections}; use xmas_elf::symbol_table::Entry; -use fs::{File, FileDesc, FileTable, INodeExt, ROOT_INODE, StdinFile, StdoutFile}; +use fs::{File, FileDesc, FileTable, INodeExt, ROOT_INODE, StdinFile, StdoutFile, OpenFlags}; use std::ffi::{CStr, CString}; use std::path::Path; use std::sgxfs::SgxFile; @@ -20,8 +20,14 @@ mod segment; #[derive(Debug)] pub enum FileAction { - // TODO: Add open action - // Open(...) + /// open(path, oflag, mode) had been called, and the returned file + /// descriptor, if not `fd`, had been changed to `fd`. + Open { + path: String, + mode: u32, + oflag: u32, + fd: FileDesc, + }, Dup2(FileDesc, FileDesc), Close(FileDesc), } @@ -92,14 +98,22 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result { - let file = cloned_file_table.get(*old_fd)?; + &FileAction::Open { ref path, mode, oflag, fd} => { + let flags = OpenFlags::from_bits_truncate(oflag); + let file = parent.open_file(path.as_str(), flags, mode)?; + let file_ref: Arc> = Arc::new(Box::new(file)); + + let close_on_spawn = flags.contains(OpenFlags::CLOEXEC); + cloned_file_table.put_at(fd, file_ref, close_on_spawn); + } + &FileAction::Dup2(old_fd, new_fd) => { + let file = cloned_file_table.get(old_fd)?; if old_fd != new_fd { - cloned_file_table.put_at(*new_fd, file, false); + cloned_file_table.put_at(new_fd, file, false); } } - FileAction::Close(fd) => { - cloned_file_table.del(*fd)?; + &FileAction::Close(fd) => { + cloned_file_table.del(fd)?; } } } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 0bea6239..6bc09dd8 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -283,7 +283,7 @@ pub struct FdOp { srcfd: u32, oflag: u32, mode: u32, - path: *const u8, + path: *const i8, } fn clone_file_actions_safely(fdop_ptr: *const FdOp) -> Result, Error> { @@ -297,9 +297,12 @@ fn clone_file_actions_safely(fdop_ptr: *const FdOp) -> Result, E let file_action = match fdop.cmd { FDOP_CLOSE => FileAction::Close(fdop.fd), FDOP_DUP2 => FileAction::Dup2(fdop.srcfd, fdop.fd), - FDOP_OPEN => { - return errno!(EINVAL, "Not implemented"); - } + FDOP_OPEN => FileAction::Open { + path: clone_cstring_safely(fdop.path)?.to_string_lossy().into_owned(), + mode: fdop.mode, + oflag: fdop.oflag, + fd: fdop.fd, + }, _ => { return errno!(EINVAL, "Unknown file action command"); } From 4811044c149a06ed92ec08bc50e2521e0af8db13 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 13 Apr 2019 21:03:10 +0800 Subject: [PATCH 17/37] fix SgxFile read/write empty buffer --- src/libos/src/fs/sgx_impl.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libos/src/fs/sgx_impl.rs b/src/libos/src/fs/sgx_impl.rs index 748584d1..b60c651b 100644 --- a/src/libos/src/fs/sgx_impl.rs +++ b/src/libos/src/fs/sgx_impl.rs @@ -64,6 +64,9 @@ unsafe impl Sync for LockedFile {} impl File for LockedFile { fn read_at(&self, buf: &mut [u8], offset: usize) -> DevResult { + if buf.len() == 0 { + return Ok(0); + } let mut file = self.0.lock().unwrap(); let offset = offset as u64; file.seek(SeekFrom::Start(offset)) @@ -73,6 +76,9 @@ impl File for LockedFile { } fn write_at(&self, buf: &[u8], offset: usize) -> DevResult { + if buf.len() == 0 { + return Ok(0); + } let mut file = self.0.lock().unwrap(); let offset = offset as u64; file.seek(SeekFrom::Start(offset)) From 58ff7b88b5ec35d2add422dbc8a5897b4b508c55 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 14 Apr 2019 20:31:19 +0800 Subject: [PATCH 18/37] fix SgxFile seek after the end --- src/libos/src/fs/sgx_impl.rs | 16 +++++++++++++++- src/sgxenv.mk | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libos/src/fs/sgx_impl.rs b/src/libos/src/fs/sgx_impl.rs index b60c651b..87684676 100644 --- a/src/libos/src/fs/sgx_impl.rs +++ b/src/libos/src/fs/sgx_impl.rs @@ -4,7 +4,7 @@ use rcore_fs_sefs::dev::*; use std::boxed::Box; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; -use std::sgxfs::{OpenOptions, remove, SgxFile}; +use std::sgxfs::{remove, OpenOptions, SgxFile}; use std::sync::SgxMutex as Mutex; use std::time::{SystemTime, UNIX_EPOCH}; @@ -80,6 +80,20 @@ impl File for LockedFile { return Ok(0); } let mut file = self.0.lock().unwrap(); + + // SgxFile do not support seek a position after the end. + // So check the size and padding zeros if necessary. + let file_size = file.seek(SeekFrom::End(0)).expect("failed to tell SgxFile") as usize; + if file_size < offset { + static ZEROS: [u8; 0x1000] = [0; 0x1000]; + let mut rest_len = offset - file_size; + while rest_len != 0 { + let l = rest_len.min(0x1000); + let len = file.write(&ZEROS[..l]).expect("failed to write SgxFile"); + rest_len -= len; + } + } + let offset = offset as u64; file.seek(SeekFrom::Start(offset)) .expect("failed to seek SgxFile"); diff --git a/src/sgxenv.mk b/src/sgxenv.mk index f03cf685..d57fb414 100644 --- a/src/sgxenv.mk +++ b/src/sgxenv.mk @@ -38,7 +38,7 @@ else endif RUST_SGX_SDK_DIR := $(PROJECT_DIR)/deps/rust-sgx-sdk -SGX_COMMON_CFLAGS += -I$(RUST_SGX_SDK_DIR)/common/ -I$(RUST_SGX_SDK_DIR)/edl/ +SGX_COMMON_CFLAGS += -I$(RUST_SGX_SDK_DIR)/common/ -I$(RUST_SGX_SDK_DIR)/common/inc/ -I$(RUST_SGX_SDK_DIR)/edl/ ifneq ($(SGX_MODE), HW) Urts_Library_Name := sgx_urts_sim From 5d9b8e4fa33c6f6f5cb69471d533521d8b695c75 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 21 Apr 2019 17:26:17 +0800 Subject: [PATCH 19/37] implement missing IO function for SocketFile --- src/libos/src/fs/socket_file.rs | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs index 97471e94..7c24f927 100644 --- a/src/libos/src/fs/socket_file.rs +++ b/src/libos/src/fs/socket_file.rs @@ -64,20 +64,40 @@ impl File for SocketFile { } } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { - unimplemented!() + fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { + self.read(buf) } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { - unimplemented!() + fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { + self.write(buf) } fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { - unimplemented!() + let mut total_len = 0; + for buf in bufs { + match self.read(buf) { + Ok(len) => { + total_len += len; + } + Err(_) if total_len != 0 => break, + Err(e) => return Err(e.into()), + } + } + Ok(total_len) } fn writev(&self, bufs: &[&[u8]]) -> Result { - unimplemented!() + let mut total_len = 0; + for buf in bufs { + match self.write(buf) { + Ok(len) => { + total_len += len; + } + Err(_) if total_len != 0 => break, + Err(e) => return Err(e.into()), + } + } + Ok(total_len) } fn seek(&self, pos: SeekFrom) -> Result { From ad98a1698e1a995224a41c6e6ca4ecc90294029d Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 21 Apr 2019 17:28:06 +0800 Subject: [PATCH 20/37] add timing by shenyouren --- src/Enclave.edl | 2 ++ src/libos/src/entry.rs | 4 ++++ src/pal/pal.c | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/src/Enclave.edl b/src/Enclave.edl index 034febdf..82e084fd 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -10,6 +10,8 @@ enclave { /* define ECALLs here. */ public int libos_boot([in, string] const char* executable_path, [user_check] const char** argv); public int libos_run(void); + /* This is only for debug usage */ + public int dummy_ecall(void); }; untrusted { diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index f299d51e..6bad71a2 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -35,6 +35,10 @@ pub extern "C" fn libos_run() -> i32 { .unwrap_or(EXIT_STATUS_INTERNAL_ERROR) } +#[no_mangle] +pub extern "C" fn dummy_ecall() -> i32 { + 0 +} // Use 127 as a special value to indicate internal error from libos, not from // user programs, although it is completely ok for a user program to return 127. const EXIT_STATUS_INTERNAL_ERROR: i32 = 127; diff --git a/src/pal/pal.c b/src/pal/pal.c index 91d3cf31..f0937c6a 100644 --- a/src/pal/pal.c +++ b/src/pal/pal.c @@ -213,6 +213,9 @@ void ocall_sync(void) { /* Application entry */ int SGX_CDECL main(int argc, const char *argv[]) { + struct timeval startup, libosready, appdie; + + gettimeofday(&startup, NULL); sgx_status_t sgx_ret = SGX_SUCCESS; int status = 0; uint32_t sealed_log_size = 1024; @@ -238,9 +241,22 @@ int SGX_CDECL main(int argc, const char *argv[]) print_error_message(sgx_ret); return status; } + // First ecall do a lot initializations. + // Count it as startup time. + dummy_ecall(global_eid, &status); + + gettimeofday(&libosready, NULL); status = wait_all_tasks(); + gettimeofday(&appdie, NULL); + + uint64_t libos_startup_time, app_runtime; + libos_startup_time = (libosready.tv_sec - startup.tv_sec) * 1000000 + (libosready.tv_usec - startup.tv_usec); + app_runtime = (appdie.tv_sec - libosready.tv_sec) * 1000000 + (appdie.tv_usec - libosready.tv_usec); + printf("LibOS startup time: %d microseconds\n", libos_startup_time); + printf("Apps running time: %d microseconds\n", app_runtime); + /* Destroy the enclave */ sgx_destroy_enclave(global_eid); From f4dacdc01da2c7cdc050846cf85b7907510eb7d6 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 21 Apr 2019 18:04:48 +0800 Subject: [PATCH 21/37] add cache for SgxFile --- src/libos/src/fs/sgx_impl.rs | 73 +++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/src/libos/src/fs/sgx_impl.rs b/src/libos/src/fs/sgx_impl.rs index 87684676..f25a4ff2 100644 --- a/src/libos/src/fs/sgx_impl.rs +++ b/src/libos/src/fs/sgx_impl.rs @@ -5,11 +5,13 @@ use std::boxed::Box; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::sgxfs::{remove, OpenOptions, SgxFile}; -use std::sync::SgxMutex as Mutex; +use std::sync::{SgxMutex as Mutex, Arc}; use std::time::{SystemTime, UNIX_EPOCH}; +use std::collections::BTreeMap; pub struct SgxStorage { path: PathBuf, + file_cache: Mutex>, } impl SgxStorage { @@ -17,46 +19,73 @@ impl SgxStorage { // assert!(path.as_ref().is_dir()); SgxStorage { path: path.as_ref().to_path_buf(), + file_cache: Mutex::new(BTreeMap::new()) } } + /// Get file by `file_id`. + /// It lookups cache first, if miss, then call `open_fn` to open one, + /// and add it to cache before return. + fn get(&self, file_id: usize, open_fn: impl FnOnce(&Self) -> LockedFile) -> LockedFile { + // query cache + let mut caches = self.file_cache.lock().unwrap(); + if let Some(locked_file) = caches.get(&file_id) { + // hit, return + return locked_file.clone(); + } + // miss, open one + let locked_file = open_fn(self); + // add to cache + caches.insert(file_id, locked_file.clone()); + locked_file + } } impl Storage for SgxStorage { fn open(&self, file_id: usize) -> DevResult> { - let mut path = self.path.to_path_buf(); - path.push(format!("{}", file_id)); - // TODO: key - let key = [0u8; 16]; - let file = OpenOptions::new() - .read(true) - .update(true) - .open_ex(path, &key) - .expect("failed to open SgxFile"); - Ok(Box::new(LockedFile(Mutex::new(file)))) + let locked_file = self.get(file_id, |this| { + let mut path = this.path.to_path_buf(); + path.push(format!("{}", file_id)); + // TODO: key + let key = [0u8; 16]; + let file = OpenOptions::new() + .read(true) + .update(true) + .open_ex(path, &key) + .expect("failed to open SgxFile"); + LockedFile(Arc::new(Mutex::new(file))) + }); + Ok(Box::new(locked_file)) } fn create(&self, file_id: usize) -> DevResult> { - let mut path = self.path.to_path_buf(); - path.push(format!("{}", file_id)); - // TODO: key - let key = [0u8; 16]; - let file = OpenOptions::new() - .write(true) - .update(true) - .open_ex(path, &key) - .expect("failed to create SgxFile"); - Ok(Box::new(LockedFile(Mutex::new(file)))) + let locked_file = self.get(file_id, |this| { + let mut path = this.path.to_path_buf(); + path.push(format!("{}", file_id)); + // TODO: key + let key = [0u8; 16]; + let file = OpenOptions::new() + .write(true) + .update(true) + .open_ex(path, &key) + .expect("failed to create SgxFile"); + LockedFile(Arc::new(Mutex::new(file))) + }); + Ok(Box::new(locked_file)) } fn remove(&self, file_id: usize) -> DevResult<()> { let mut path = self.path.to_path_buf(); path.push(format!("{}", file_id)); remove(path).expect("failed to remove SgxFile"); + // remove from cache + let mut caches = self.file_cache.lock().unwrap(); + caches.remove(&file_id); Ok(()) } } -pub struct LockedFile(Mutex); +#[derive(Clone)] +pub struct LockedFile(Arc>); // `sgx_tstd::sgxfs::SgxFile` not impl Send ... unsafe impl Send for LockedFile {} From b99344d7f5604a3b25f5aea66babf9f999bceb9b Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 22 Apr 2019 15:37:19 +0800 Subject: [PATCH 22/37] implement sys_sendfile --- src/libos/src/fs/mod.rs | 51 +++++++++++++++ src/libos/src/syscall/mod.rs | 121 +++++++++++++++++++++-------------- 2 files changed, 124 insertions(+), 48 deletions(-) diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index d845563e..966cb46a 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -14,6 +14,7 @@ use self::inode_file::OpenOptions; pub use self::pipe::Pipe; pub use self::io_multiplexing::*; pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat}; +use std::mem::uninitialized; mod file; mod file_table; @@ -342,6 +343,56 @@ pub fn do_unlink(path: &str) -> Result<(), Error> { Ok(()) } +pub fn do_sendfile( + out_fd: FileDesc, + in_fd: FileDesc, + offset: Option, + count: usize, +) -> Result<(usize, usize), Error> { // (len, offset) + info!( + "sendfile: out: {}, in: {}, offset: {:?}, count: {}", + out_fd, in_fd, offset, count + ); + let current_ref = process::get_current(); + let current_process = current_ref.lock().unwrap(); + let file_table_ref = current_process.get_files(); + let mut file_table = file_table_ref.lock().unwrap(); + + let in_file = file_table.get(in_fd)?; + let out_file = file_table.get(out_fd)?; + let mut buffer: [u8; 1024] = unsafe { uninitialized() }; + + let mut read_offset = match offset { + Some(offset) => offset, + None => in_file.seek(SeekFrom::Current(0))?, + } as usize; + + // read from specified offset and write new offset back + let mut bytes_read = 0; + while bytes_read < count { + let len = min(buffer.len(), count - bytes_read); + let read_len = in_file.read_at(read_offset, &mut buffer[..len])?; + if read_len == 0 { + break; + } + bytes_read += read_len; + read_offset += read_len; + let mut bytes_written = 0; + while bytes_written < read_len { + let write_len = out_file.write(&buffer[bytes_written..])?; + if write_len == 0 { + return Err(Error::new(EBADF, "sendfile write return 0")); + } + bytes_written += write_len; + } + } + + if offset.is_none() { + in_file.seek(SeekFrom::Current(bytes_read as i64))?; + } + Ok((bytes_read, read_offset)) +} + extern "C" { fn ocall_sync() -> sgx_status_t; } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 6bc09dd8..a7d87327 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,16 +7,16 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::{File, SocketFile, FileDesc, FileRef, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd}; +use fs::{AccessFlags, AccessModes, FcntlCmd, File, FileDesc, FileRef, SocketFile, AT_FDCWD}; +use misc::{resource_t, rlimit_t, utsname_t}; use prelude::*; -use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; +use process::{pid_t, ChildProcessFilter, CloneFlags, FileAction, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; use std::ptr; use time::timeval_t; use util::mem_util::from_user::*; use vm::{VMAreaFlags, VMResizeOptions}; use {fs, process, std, vm}; -use misc::{utsname_t, resource_t, rlimit_t}; use super::*; @@ -84,6 +84,12 @@ pub extern "C" fn dispatch_syscall( SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), SYS_UNLINK => do_unlink(arg0 as *const i8), SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize), + SYS_SENDFILE => do_sendfile( + arg0 as FileDesc, + arg1 as FileDesc, + arg2 as *mut off_t, + arg3 as usize, + ), SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), // IO multiplexing @@ -171,11 +177,7 @@ pub extern "C" fn dispatch_syscall( arg3 as i32, arg4 as usize, ), - SYS_MPROTECT => do_mprotect( - arg0 as usize, - arg1 as usize, - arg2 as u32, - ), + SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32), SYS_BRK => do_brk(arg0 as usize), SYS_PIPE => do_pipe2(arg0 as *mut i32, 0), @@ -188,8 +190,12 @@ pub extern "C" fn dispatch_syscall( SYS_UNAME => do_uname(arg0 as *mut utsname_t), - SYS_PRLIMIT64 => do_prlimit(arg0 as pid_t, arg1 as u32, arg2 as *const rlimit_t, arg3 as *mut rlimit_t), - + SYS_PRLIMIT64 => do_prlimit( + arg0 as pid_t, + arg1 as u32, + arg2 as *const rlimit_t, + arg3 as *mut rlimit_t, + ), // socket SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int), @@ -250,7 +256,7 @@ pub extern "C" fn dispatch_syscall( _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5), }; - debug!("syscall return: {:?}", ret); + info!("=> {:?}", ret); match ret { Ok(code) => code as isize, @@ -298,7 +304,9 @@ fn clone_file_actions_safely(fdop_ptr: *const FdOp) -> Result, E FDOP_CLOSE => FileAction::Close(fdop.fd), FDOP_DUP2 => FileAction::Dup2(fdop.srcfd, fdop.fd), FDOP_OPEN => FileAction::Open { - path: clone_cstring_safely(fdop.path)?.to_string_lossy().into_owned(), + path: clone_cstring_safely(fdop.path)? + .to_string_lossy() + .into_owned(), mode: fdop.mode, oflag: fdop.oflag, fd: fdop.fd, @@ -352,8 +360,7 @@ pub fn do_clone( if flags.contains(CloneFlags::CLONE_PARENT_SETTID) { check_mut_ptr(ptid)?; Some(ptid) - } - else { + } else { None } }; @@ -361,8 +368,7 @@ pub fn do_clone( if flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) { check_mut_ptr(ctid)?; Some(ctid) - } - else { + } else { None } }; @@ -370,8 +376,7 @@ pub fn do_clone( if flags.contains(CloneFlags::CLONE_SETTLS) { check_mut_ptr(new_tls as *mut usize)?; Some(new_tls) - } - else { + } else { None } }; @@ -381,17 +386,11 @@ pub fn do_clone( Ok(child_pid as isize) } -pub fn do_futex( - futex_addr: *const i32, - futex_op: u32, - futex_val: i32, -) -> Result { +pub fn do_futex(futex_addr: *const i32, futex_op: u32, futex_val: i32) -> Result { check_ptr(futex_addr)?; let (futex_op, futex_flags) = process::futex_op_and_flags_from_u32(futex_op)?; match futex_op { - FutexOp::FUTEX_WAIT => { - process::futex_wait(futex_addr, futex_val).map(|_| 0) - } + FutexOp::FUTEX_WAIT => process::futex_wait(futex_addr, futex_val).map(|_| 0), FutexOp::FUTEX_WAKE => { let max_count = { if futex_val < 0 { @@ -399,9 +398,8 @@ pub fn do_futex( } futex_val as usize }; - process::futex_wake(futex_addr, max_count) - .map(|count| count as isize) - }, + process::futex_wake(futex_addr, max_count).map(|count| count as isize) + } _ => errno!(ENOSYS, "the futex operation is not supported"), } } @@ -627,11 +625,7 @@ fn do_mremap( Ok(ret_addr as isize) } -fn do_mprotect( - addr: usize, - len: usize, - prot: u32, -) -> Result { +fn do_mprotect(addr: usize, len: usize, prot: u32) -> Result { // TODO: implement it Ok(0) } @@ -710,7 +704,6 @@ fn do_getegid() -> Result { Ok(0) } - fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result { check_mut_array(fds_u, 2)?; // TODO: how to deal with open flags??? @@ -761,7 +754,15 @@ fn do_exit(status: i32) -> ! { } } -fn do_unknown(num: u32, arg0: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize) -> Result { +fn do_unknown( + num: u32, + arg0: isize, + arg1: isize, + arg2: isize, + arg3: isize, + arg4: isize, + arg5: isize, +) -> Result { warn!( "unknown or unsupported syscall (# = {}): {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}", num, arg0, arg1, arg2, arg3, arg4, arg5 @@ -841,6 +842,28 @@ fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result Result { + let offset = if offset_ptr.is_null() { + None + } else { + check_mut_ptr(offset_ptr)?; + Some(unsafe { offset_ptr.read() }) + }; + + let (len, offset) = fs::do_sendfile(out_fd, in_fd, offset, count)?; + if !offset_ptr.is_null() { + unsafe { + offset_ptr.write(offset as off_t); + } + } + Ok(len as isize) +} + fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result { let cmd = FcntlCmd::from_raw(cmd, arg)?; fs::do_fcntl(fd, &cmd) @@ -1037,11 +1060,14 @@ fn do_select( readfds: *mut libc::fd_set, writefds: *mut libc::fd_set, exceptfds: *mut libc::fd_set, - timeout: *const libc::timeval + timeout: *const libc::timeval, ) -> Result { // check arguments if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int { - return Err(Error::new(EINVAL, "nfds is negative or exceeds the resource limit")); + return Err(Error::new( + EINVAL, + "nfds is negative or exceeds the resource limit", + )); } let nfds = nfds as usize; @@ -1078,11 +1104,7 @@ fn do_select( Ok(n as isize) } -fn do_poll( - fds: *mut libc::pollfd, - nfds: libc::nfds_t, - timeout: c_int, -) -> Result { +fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result { check_mut_array(fds, nfds as usize)?; let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) }; @@ -1153,14 +1175,18 @@ fn do_uname(name: *mut utsname_t) -> Result { misc::do_uname(name).map(|_| 0) } -fn do_prlimit(pid: pid_t, resource: u32, new_limit: *const rlimit_t, old_limit: *mut rlimit_t) -> Result { +fn do_prlimit( + pid: pid_t, + resource: u32, + new_limit: *const rlimit_t, + old_limit: *mut rlimit_t, +) -> Result { let resource = resource_t::from_u32(resource)?; let new_limit = { if new_limit != ptr::null() { check_ptr(new_limit)?; Some(unsafe { &*new_limit }) - } - else { + } else { None } }; @@ -1168,8 +1194,7 @@ fn do_prlimit(pid: pid_t, resource: u32, new_limit: *const rlimit_t, old_limit: if old_limit != ptr::null_mut() { check_mut_ptr(old_limit)?; Some(unsafe { &mut *old_limit }) - } - else { + } else { None } }; From 54243c543a9d25d04161684bfc26dd2eaa11333a Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 22 Apr 2019 15:54:39 +0800 Subject: [PATCH 23/37] use errno! macro for all error --- src/libos/src/fs/file.rs | 32 +++++++++++------------ src/libos/src/fs/inode_file.rs | 16 ++++++------ src/libos/src/fs/io_multiplexing.rs | 12 ++++----- src/libos/src/fs/mod.rs | 14 +++++----- src/libos/src/fs/pipe.rs | 18 +++++-------- src/libos/src/fs/socket_file.rs | 10 +++---- src/libos/src/prelude.rs | 2 +- src/libos/src/process/spawn/init_stack.rs | 4 +-- src/libos/src/process/spawn/mod.rs | 2 +- src/libos/src/syscall/mod.rs | 21 +++++++-------- src/libos/src/vm/mod.rs | 6 ++--- src/libos/src/vm/process_vm.rs | 4 +-- 12 files changed, 66 insertions(+), 75 deletions(-) diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index 3dbb71ad..1a880dd6 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -37,7 +37,7 @@ impl SgxFile { is_append: bool, ) -> Result { if !is_readable && !is_writable { - return Err(Error::new(Errno::EINVAL, "Invalid permissions")); + return errno!(EINVAL, "Invalid permissions"); } Ok(SgxFile { @@ -132,7 +132,7 @@ struct SgxFileInner { impl SgxFileInner { pub fn write(&mut self, buf: &[u8]) -> Result { if !self.is_writable { - return Err(Error::new(Errno::EINVAL, "File not writable")); + return errno!(EINVAL, "File not writable"); } let mut file_guard = self.file.lock().unwrap(); @@ -160,7 +160,7 @@ impl SgxFileInner { pub fn read(&mut self, buf: &mut [u8]) -> Result { if !self.is_readable { - return Err(Error::new(Errno::EINVAL, "File not readable")); + return errno!(EINVAL, "File not readable"); } let mut file_guard = self.file.lock().unwrap(); @@ -193,7 +193,7 @@ impl SgxFileInner { let backward_offset = (-relative_offset) as usize; if self.pos < backward_offset { // underflow - return Err(Error::new(Errno::EINVAL, "Invalid seek position")); + return errno!(EINVAL, "Invalid seek position"); } SeekFrom::Start((self.pos - backward_offset) as u64) } @@ -209,7 +209,7 @@ impl SgxFileInner { pub fn writev(&mut self, bufs: &[&[u8]]) -> Result { if !self.is_writable { - return Err(Error::new(Errno::EINVAL, "File not writable")); + return errno!(EINVAL, "File not writable"); } let mut file_guard = self.file.lock().unwrap(); @@ -235,7 +235,7 @@ impl SgxFileInner { Err(e) => { match total_bytes { // a complete failure - 0 => return Err(Error::new(Errno::EINVAL, "Failed to write")), + 0 => return errno!(EINVAL, "Failed to write"), // a partially failure _ => break, } @@ -249,7 +249,7 @@ impl SgxFileInner { fn readv(&mut self, bufs: &mut [&mut [u8]]) -> Result { if !self.is_readable { - return Err(Error::new(Errno::EINVAL, "File not readable")); + return errno!(EINVAL, "File not readable"); } let mut file_guard = self.file.lock().unwrap(); @@ -271,7 +271,7 @@ impl SgxFileInner { Err(e) => { match total_bytes { // a complete failure - 0 => return Err(Error::new(Errno::EINVAL, "Failed to write")), + 0 => return errno!(EINVAL, "Failed to write"), // a partially failure _ => break, } @@ -307,7 +307,7 @@ impl StdoutFile { impl File for StdoutFile { fn read(&self, buf: &mut [u8]) -> Result { - Err(Error::new(Errno::EBADF, "Stdout does not support read")) + errno!(EBADF, "Stdout does not support read") } fn write(&self, buf: &[u8]) -> Result { @@ -329,7 +329,7 @@ impl File for StdoutFile { } fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { - Err(Error::new(Errno::EBADF, "Stdout does not support read")) + errno!(EBADF, "Stdout does not support read") } fn writev(&self, bufs: &[&[u8]]) -> Result { @@ -346,7 +346,7 @@ impl File for StdoutFile { Err(e) => { match total_bytes { // a complete failure - 0 => return Err(Error::new(Errno::EINVAL, "Failed to write")), + 0 => return errno!(EINVAL, "Failed to write"), // a partially failure _ => break, } @@ -357,7 +357,7 @@ impl File for StdoutFile { } fn seek(&self, seek_pos: SeekFrom) -> Result { - Err(Error::new(Errno::ESPIPE, "Stdout does not support seek")) + errno!(ESPIPE, "Stdout does not support seek") } fn metadata(&self) -> Result { @@ -414,7 +414,7 @@ impl File for StdinFile { } fn write(&self, buf: &[u8]) -> Result { - Err(Error::new(Errno::EBADF, "Stdin does not support write")) + errno!(EBADF, "Stdin does not support write") } fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { @@ -439,7 +439,7 @@ impl File for StdinFile { Err(e) => { match total_bytes { // a complete failure - 0 => return Err(Error::new(Errno::EINVAL, "Failed to write")), + 0 => return errno!(EINVAL, "Failed to write"), // a partially failure _ => break, } @@ -450,11 +450,11 @@ impl File for StdinFile { } fn writev(&self, bufs: &[&[u8]]) -> Result { - Err(Error::new(Errno::EBADF, "Stdin does not support write")) + errno!(EBADF, "Stdin does not support write") } fn seek(&self, pos: SeekFrom) -> Result { - Err(Error::new(Errno::ESPIPE, "Stdin does not support seek")) + errno!(ESPIPE, "Stdin does not support seek") } fn metadata(&self) -> Result { diff --git a/src/libos/src/fs/inode_file.rs b/src/libos/src/fs/inode_file.rs index 014615ea..ff737788 100644 --- a/src/libos/src/fs/inode_file.rs +++ b/src/libos/src/fs/inode_file.rs @@ -32,7 +32,7 @@ pub struct OpenOptions { impl File for INodeFile { fn read(&self, buf: &mut [u8]) -> Result { if !self.options.read { - return Err(Error::new(Errno::EBADF, "File not readable")); + return errno!(EBADF, "File not readable"); } let mut offset = self.offset.lock().unwrap(); let len = self.inode.read_at(*offset, buf)?; @@ -42,7 +42,7 @@ impl File for INodeFile { fn write(&self, buf: &[u8]) -> Result { if !self.options.write { - return Err(Error::new(Errno::EBADF, "File not writable")); + return errno!(EBADF, "File not writable"); } let mut offset = self.offset.lock().unwrap(); if self.options.append { @@ -56,7 +56,7 @@ impl File for INodeFile { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { if !self.options.read { - return Err(Error::new(Errno::EBADF, "File not readable")); + return errno!(EBADF, "File not readable"); } let len = self.inode.read_at(offset, buf)?; Ok(len) @@ -64,7 +64,7 @@ impl File for INodeFile { fn write_at(&self, offset: usize, buf: &[u8]) -> Result { if !self.options.write { - return Err(Error::new(Errno::EBADF, "File not writable")); + return errno!(EBADF, "File not writable"); } let len = self.inode.write_at(offset, buf)?; Ok(len) @@ -72,7 +72,7 @@ impl File for INodeFile { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { if !self.options.read { - return Err(Error::new(Errno::EBADF, "File not readable")); + return errno!(EBADF, "File not readable"); } let mut offset = self.offset.lock().unwrap(); let mut total_len = 0; @@ -91,7 +91,7 @@ impl File for INodeFile { fn writev(&self, bufs: &[&[u8]]) -> Result { if !self.options.write { - return Err(Error::new(Errno::EBADF, "File not writable")); + return errno!(EBADF, "File not writable"); } let mut offset = self.offset.lock().unwrap(); if self.options.append { @@ -129,7 +129,7 @@ impl File for INodeFile { fn set_len(&self, len: u64) -> Result<(), Error> { if !self.options.write { - return Err(Error::new(EBADF, "File not writable. Can't set len.")); + return errno!(EBADF, "File not writable. Can't set len."); } self.inode.resize(len as usize)?; Ok(()) @@ -147,7 +147,7 @@ impl File for INodeFile { fn read_entry(&self) -> Result { if !self.options.read { - return Err(Error::new(EBADF, "File not readable. Can't read entry.")); + return errno!(EBADF, "File not readable. Can't read entry."); } let mut offset = self.offset.lock().unwrap(); let name = self.inode.get_entry(*offset)?; diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 6432aede..79f18062 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -52,7 +52,7 @@ pub fn do_select( }; if ret < 0 { - return Err(Error::new(Errno::from_retval(ret as i32), "")); + return errno!(Errno::from_retval(ret as i32), ""); } // convert fd back and write fdset @@ -97,7 +97,7 @@ pub fn do_poll( // recover fd ? if ret < 0 { - Err(Error::new(Errno::from_retval(ret as i32), "")) + errno!(Errno::from_retval(ret as i32), "") } else { Ok(ret as usize) } @@ -202,7 +202,7 @@ impl EpollFileInner { pub fn new() -> Result { let ret = unsafe { libc::ocall::epoll_create1(0) }; if ret < 0 { - return Err(Error::new(Errno::from_retval(ret as i32), "")); + return errno!(Errno::from_retval(ret as i32), ""); } Ok(EpollFileInner { epoll_fd: ret, @@ -220,7 +220,7 @@ impl EpollFileInner { ) }; if ret < 0 { - return Err(Error::new(Errno::from_retval(ret as i32), "")); + return errno!(Errno::from_retval(ret as i32), ""); } Ok(()) } @@ -241,7 +241,7 @@ impl EpollFileInner { ) }; if ret < 0 { - return Err(Error::new(Errno::from_retval(ret as i32), "")); + return errno!(Errno::from_retval(ret as i32), ""); } Ok(ret as usize) } @@ -281,7 +281,7 @@ impl File for EpollFile { } fn seek(&self, pos: SeekFrom) -> Result { - Err(Error::new(Errno::ESPIPE, "Epoll does not support seek")) + errno!(ESPIPE, "Epoll does not support seek") } fn metadata(&self) -> Result { diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 966cb46a..6151891f 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -173,7 +173,7 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result { let file_ref = current_process.get_files().lock().unwrap().get(fd)?; let info = file_ref.metadata()?; if info.type_ != FileType::Dir { - return Err(Error::new(ENOTDIR, "")); + return errno!(ENOTDIR, ""); } let mut writer = unsafe { DirentBufWriter::new(buf) }; loop { @@ -267,7 +267,7 @@ pub fn do_chdir(path: &str) -> Result<(), Error> { let inode = current_process.lookup_inode(path)?; let info = inode.metadata()?; if info.type_ != FileType::Dir { - return Err(Error::new(ENOTDIR, "")); + return errno!(ENOTDIR, ""); } current_process.change_cwd(path); Ok(()) @@ -295,7 +295,7 @@ pub fn do_mkdir(path: &str, mode: usize) -> Result<(), Error> { let (dir_path, file_name) = split_path(&path); let inode = current_process.lookup_inode(dir_path)?; if inode.find(file_name).is_ok() { - return Err(Error::new(EEXIST, "")); + return errno!(EEXIST, ""); } inode.create(file_name, FileType::Dir, mode as u32)?; Ok(()) @@ -310,7 +310,7 @@ pub fn do_rmdir(path: &str) -> Result<(), Error> { let dir_inode = current_process.lookup_inode(dir_path)?; let file_inode = dir_inode.find(file_name)?; if file_inode.metadata()?.type_ != FileType::Dir { - return Err(Error::new(ENOTDIR, "rmdir on not directory")); + return errno!(ENOTDIR, "rmdir on not directory"); } dir_inode.unlink(file_name)?; Ok(()) @@ -337,7 +337,7 @@ pub fn do_unlink(path: &str) -> Result<(), Error> { let dir_inode = current_process.lookup_inode(dir_path)?; let file_inode = dir_inode.find(file_name)?; if file_inode.metadata()?.type_ == FileType::Dir { - return Err(Error::new(EISDIR, "unlink on directory")); + return errno!(EISDIR, "unlink on directory"); } dir_inode.unlink(file_name)?; Ok(()) @@ -381,7 +381,7 @@ pub fn do_sendfile( while bytes_written < read_len { let write_len = out_file.write(&buffer[bytes_written..])?; if write_len == 0 { - return Err(Error::new(EBADF, "sendfile write return 0")); + return errno!(EBADF, "sendfile write return 0"); } bytes_written += write_len; } @@ -406,7 +406,7 @@ impl Process { match dir_inode.find(file_name) { Ok(file_inode) => { if flags.contains(OpenFlags::EXCLUSIVE) { - return Err(Error::new(EEXIST, "file exists")); + return errno!(EEXIST, "file exists"); } file_inode } diff --git a/src/libos/src/fs/pipe.rs b/src/libos/src/fs/pipe.rs index 75cb77d9..643af65d 100644 --- a/src/libos/src/fs/pipe.rs +++ b/src/libos/src/fs/pipe.rs @@ -37,10 +37,7 @@ impl File for PipeReader { } fn write(&self, buf: &[u8]) -> Result { - Err(Error::new( - Errno::EBADF, - "PipeReader does not support write", - )) + errno!(EBADF, "PipeReader does not support write") } fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { @@ -76,14 +73,11 @@ impl File for PipeReader { } fn writev(&self, bufs: &[&[u8]]) -> Result { - Err(Error::new( - Errno::EBADF, - "PipeReader does not support write", - )) + errno!(EBADF, "PipeReader does not support write") } fn seek(&self, pos: SeekFrom) -> Result { - Err(Error::new(Errno::ESPIPE, "Pipe does not support seek")) + errno!(ESPIPE, "Pipe does not support seek") } fn metadata(&self) -> Result { @@ -117,7 +111,7 @@ pub struct PipeWriter { impl File for PipeWriter { fn read(&self, buf: &mut [u8]) -> Result { - Err(Error::new(Errno::EBADF, "PipeWriter does not support read")) + errno!(EBADF, "PipeWriter does not support read") } fn write(&self, buf: &[u8]) -> Result { @@ -133,7 +127,7 @@ impl File for PipeWriter { } fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { - Err(Error::new(Errno::EBADF, "PipeWriter does not support read")) + errno!(EBADF, "PipeWriter does not support read") } fn writev(&self, bufs: &[&[u8]]) -> Result { @@ -161,7 +155,7 @@ impl File for PipeWriter { } fn seek(&self, seek_pos: SeekFrom) -> Result { - Err(Error::new(Errno::ESPIPE, "Pipe does not support seek")) + errno!(ESPIPE, "Pipe does not support seek") } fn metadata(&self) -> Result { diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs index 7c24f927..3bb5e8fb 100644 --- a/src/libos/src/fs/socket_file.rs +++ b/src/libos/src/fs/socket_file.rs @@ -11,7 +11,7 @@ impl SocketFile { pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result { let ret = unsafe { libc::ocall::socket(domain, socket_type, protocol) }; if ret < 0 { - Err(Error::new(Errno::from_retval(ret as i32), "")) + errno!(Errno::from_retval(ret as i32), "") } else { Ok(SocketFile { fd: ret }) } @@ -25,7 +25,7 @@ impl SocketFile { ) -> Result { let ret = unsafe { libc::ocall::accept4(self.fd, addr, addr_len, flags) }; if ret < 0 { - Err(Error::new(Errno::from_retval(ret as i32), "")) + errno!(Errno::from_retval(ret as i32), "") } else { Ok(SocketFile { fd: ret }) } @@ -49,7 +49,7 @@ impl File for SocketFile { fn read(&self, buf: &mut [u8]) -> Result { let ret = unsafe { libc::ocall::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len()) }; if ret < 0 { - Err(Error::new(Errno::from_retval(ret as i32), "")) + errno!(Errno::from_retval(ret as i32), "") } else { Ok(ret as usize) } @@ -58,7 +58,7 @@ impl File for SocketFile { fn write(&self, buf: &[u8]) -> Result { let ret = unsafe { libc::ocall::write(self.fd, buf.as_ptr() as *const c_void, buf.len()) }; if ret < 0 { - Err(Error::new(Errno::from_retval(ret as i32), "")) + errno!(Errno::from_retval(ret as i32), "") } else { Ok(ret as usize) } @@ -101,7 +101,7 @@ impl File for SocketFile { } fn seek(&self, pos: SeekFrom) -> Result { - Err(Error::new(Errno::ESPIPE, "Socket does not support seek")) + errno!(ESPIPE, "Socket does not support seek") } fn metadata(&self) -> Result { diff --git a/src/libos/src/prelude.rs b/src/libos/src/prelude.rs index 59a9e3a1..113b3b5c 100644 --- a/src/libos/src/prelude.rs +++ b/src/libos/src/prelude.rs @@ -35,7 +35,7 @@ macro_rules! debug_trace { } macro_rules! errno { - ($errno: ident, $msg: expr) => {{ + ($errno: expr, $msg: expr) => {{ println!( "ERROR: {} ({}, line {} in file {})", $errno, diff --git a/src/libos/src/process/spawn/init_stack.rs b/src/libos/src/process/spawn/init_stack.rs index b12af26a..e2338460 100644 --- a/src/libos/src/process/spawn/init_stack.rs +++ b/src/libos/src/process/spawn/init_stack.rs @@ -139,7 +139,7 @@ impl StackBuf { let old_pos = self.stack_pos.get(); let new_pos = align_down(old_pos - size, align); if new_pos < self.stack_bottom { - return Err(Error::new(Errno::ENOMEM, "No enough space in buffer")); + return errno!(ENOMEM, "No enough space in buffer"); } new_pos }; @@ -274,7 +274,7 @@ impl AuxTable { pub fn set_val(&mut self, key: AuxKey, val: u64) -> Result<(), Error> { if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE { - return Err(Error::new(Errno::EINVAL, "Illegal key")); + return errno!(EINVAL, "Illegal key"); } self.values[key as usize] = Some(val); Ok(()) diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index b8654c2f..edf95126 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -65,7 +65,7 @@ pub fn do_spawn>( let program_entry = { let program_entry = base_addr + elf_helper::get_start_address(&elf_file)?; if !vm.get_code_vma().contains_obj(program_entry, 16) { - return Err(Error::new(Errno::EINVAL, "Invalid program entry")); + return errno!(EINVAL, "Invalid program entry"); } program_entry }; diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index a7d87327..81a0b076 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -436,7 +436,7 @@ fn do_write(fd: FileDesc, buf: *const u8, size: usize) -> Result { fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result { let count = { if count < 0 { - return Err(Error::new(Errno::EINVAL, "Invalid count of iovec")); + return errno!(EINVAL, "Invalid count of iovec"); } count as usize }; @@ -461,7 +461,7 @@ fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result Result { let count = { if count < 0 { - return Err(Error::new(Errno::EINVAL, "Invalid count of iovec")); + return errno!(EINVAL, "Invalid count of iovec"); } count as usize }; @@ -538,7 +538,7 @@ fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result { 0 => { // SEEK_SET if offset < 0 { - return Err(Error::new(Errno::EINVAL, "Invalid offset")); + return errno!(EINVAL, "Invalid offset"); } SeekFrom::Start(offset as u64) } @@ -551,7 +551,7 @@ fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result { SeekFrom::End(offset) } _ => { - return Err(Error::new(Errno::EINVAL, "Invalid whence")); + return errno!(EINVAL, "Invalid whence"); } }; @@ -767,7 +767,7 @@ fn do_unknown( "unknown or unsupported syscall (# = {}): {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}", num, arg0, arg1, arg2, arg3, arg4, arg5 ); - Err(Error::new(ENOSYS, "Unknown syscall")) + errno!(ENOSYS, "Unknown syscall") } fn do_getcwd(buf: *mut u8, size: usize) -> Result { @@ -779,7 +779,7 @@ fn do_getcwd(buf: *mut u8, size: usize) -> Result { let mut proc = proc_ref.lock().unwrap(); let cwd = proc.get_cwd(); if cwd.len() + 1 > safe_buf.len() { - return Err(Error::new(ERANGE, "buf is not long enough")); + return errno!(ERANGE, "buf is not long enough"); } safe_buf[..cwd.len()].copy_from_slice(cwd.as_bytes()); safe_buf[cwd.len()] = 0; @@ -1064,10 +1064,7 @@ fn do_select( ) -> Result { // check arguments if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int { - return Err(Error::new( - EINVAL, - "nfds is negative or exceeds the resource limit", - )); + return errno!(EINVAL, "nfds is negative or exceeds the resource limit"); } let nfds = nfds as usize; @@ -1114,7 +1111,7 @@ fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result fn do_epoll_create(size: c_int) -> Result { if size <= 0 { - return Err(Error::new(EINVAL, "size is not positive")); + return errno!(EINVAL, "size is not positive"); } do_epoll_create1(0) } @@ -1145,7 +1142,7 @@ fn do_epoll_wait( ) -> Result { let maxevents = { if maxevents <= 0 { - return Err(Error::new(EINVAL, "maxevents <= 0")); + return errno!(EINVAL, "maxevents <= 0"); } maxevents as usize }; diff --git a/src/libos/src/vm/mod.rs b/src/libos/src/vm/mod.rs index a56a707c..16aa41d5 100644 --- a/src/libos/src/vm/mod.rs +++ b/src/libos/src/vm/mod.rs @@ -74,7 +74,7 @@ pub struct VMAllocOptions { impl VMAllocOptions { pub fn new(size: usize) -> Result { if size % PAGE_SIZE != 0 { - return Err(Error::new(Errno::EINVAL, "Size is not page-aligned")); + return errno!(EINVAL, "Size is not page-aligned"); } Ok(VMAllocOptions { size, @@ -84,7 +84,7 @@ impl VMAllocOptions { pub fn addr(&mut self, addr: VMAddrOption) -> Result<&mut Self, Error> { if addr.is_addr_given() && addr.get_addr() % PAGE_SIZE != 0 { - return Err(Error::new(Errno::EINVAL, "Invalid address")); + return errno!(EINVAL, "Invalid address"); } self.addr = addr; Ok(self) @@ -175,7 +175,7 @@ pub struct VMResizeOptions { impl VMResizeOptions { pub fn new(new_size: usize) -> Result { if new_size % PAGE_SIZE != 0 { - return Err(Error::new(Errno::EINVAL, "Size is not page-aligned")); + return errno!(EINVAL, "Size is not page-aligned"); } Ok(VMResizeOptions { new_size, diff --git a/src/libos/src/vm/process_vm.rs b/src/libos/src/vm/process_vm.rs index f4a416d3..2aed5155 100644 --- a/src/libos/src/vm/process_vm.rs +++ b/src/libos/src/vm/process_vm.rs @@ -169,7 +169,7 @@ impl ProcessVM { VMAddrOption::Beyond(mmap_start_addr) } else { if addr < mmap_start_addr { - return Err(Error::new(Errno::EINVAL, "Beyond valid memory range")); + return errno!(EINVAL, "Beyond valid memory range"); } // TODO: Fixed or Hint? Should hanle mmap flags VMAddrOption::Hint(addr) @@ -212,7 +212,7 @@ impl ProcessVM { options: &VMResizeOptions, ) -> Result { // TODO: Implement this! - Err(Error::new(Errno::EINVAL, "Not implemented")) + errno!(EINVAL, "Not implemented") } pub fn brk(&mut self, new_brk: usize) -> Result { From 9c9d1eed3a2dfa57f526322ccff6534420454617 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 22 Apr 2019 16:32:40 +0800 Subject: [PATCH 24/37] implement /dev/null --- src/libos/src/fs/mod.rs | 11 ++++-- src/libos/src/fs/null.rs | 54 ++++++++++++++++++++++++++++++ src/libos/src/process/spawn/mod.rs | 2 +- 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/libos/src/fs/null.rs diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 6151891f..00208c18 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -14,6 +14,7 @@ use self::inode_file::OpenOptions; pub use self::pipe::Pipe; pub use self::io_multiplexing::*; pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat}; +use self::null::NullFile; use std::mem::uninitialized; mod file; @@ -24,6 +25,7 @@ mod pipe; mod sgx_impl; mod io_multiplexing; mod access; +mod null; pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { @@ -37,7 +39,7 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { let mut proc = current_ref.lock().unwrap(); let file = proc.open_file(path, flags, mode)?; - let file_ref: Arc> = Arc::new(Box::new(file)); + let file_ref: Arc> = Arc::new(file); let fd = { let close_on_spawn = flags.contains(OpenFlags::CLOEXEC); @@ -399,7 +401,10 @@ extern "C" { impl Process { /// Open a file on the process. But DO NOT add it to file table. - pub fn open_file(&self, path: &str, flags: OpenFlags, mode: u32) -> Result { + pub fn open_file(&self, path: &str, flags: OpenFlags, mode: u32) -> Result, Error> { + if path == "/dev/null" { + return Ok(Box::new(NullFile)); + } let inode = if flags.contains(OpenFlags::CREATE) { let (dir_path, file_name) = split_path(&path); let dir_inode = self.lookup_inode(dir_path)?; @@ -416,7 +421,7 @@ impl Process { } else { self.lookup_inode(&path)? }; - INodeFile::open(inode, flags.to_options()) + Ok(Box::new(INodeFile::open(inode, flags.to_options())?)) } /// Lookup INode from the cwd of the process diff --git a/src/libos/src/fs/null.rs b/src/libos/src/fs/null.rs new file mode 100644 index 00000000..454d7f12 --- /dev/null +++ b/src/libos/src/fs/null.rs @@ -0,0 +1,54 @@ +use super::*; + +#[derive(Debug)] +pub struct NullFile; + +impl File for NullFile { + fn read(&self, _buf: &mut [u8]) -> Result { + unimplemented!() + } + + fn write(&self, _buf: &[u8]) -> Result { + Ok(0) + } + + fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { + unimplemented!() + } + + fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { + unimplemented!() + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + unimplemented!() + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + unimplemented!() + } + + fn seek(&self, pos: SeekFrom) -> Result { + unimplemented!() + } + + fn metadata(&self) -> Result { + unimplemented!() + } + + fn set_len(&self, len: u64) -> Result<(), Error> { + unimplemented!() + } + + fn sync_all(&self) -> Result<(), Error> { + unimplemented!() + } + + fn sync_data(&self) -> Result<(), Error> { + unimplemented!() + } + + fn read_entry(&self) -> Result { + unimplemented!() + } +} diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index edf95126..fee26df7 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -101,7 +101,7 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result { let flags = OpenFlags::from_bits_truncate(oflag); let file = parent.open_file(path.as_str(), flags, mode)?; - let file_ref: Arc> = Arc::new(Box::new(file)); + let file_ref: Arc> = Arc::new(file); let close_on_spawn = flags.contains(OpenFlags::CLOEXEC); cloned_file_table.put_at(fd, file_ref, close_on_spawn); From 76f9ff380bc7a1f3ba9f339cf41f4b05e96268fc Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 22 Apr 2019 17:40:56 +0800 Subject: [PATCH 25/37] add timing for syscall --- src/libos/Cargo.toml | 1 + src/libos/src/syscall/mod.rs | 31 +++++++++++++++++++++++++++++++ src/libos/src/time/mod.rs | 6 ++++++ 3 files changed, 38 insertions(+) diff --git a/src/libos/Cargo.toml b/src/libos/Cargo.toml index 71e1fec9..1627c480 100644 --- a/src/libos/Cargo.toml +++ b/src/libos/Cargo.toml @@ -15,6 +15,7 @@ rcore-fs-sefs = { path = "../../deps/sefs/rcore-fs-sefs" } [features] default = [] +syscall_timing = [] [target.'cfg(not(target_env = "sgx"))'.dependencies] xmas-elf = { path = "../../deps/xmas-elf" } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 81a0b076..fabb966a 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -29,6 +29,8 @@ use std::any::Any; mod consts; +static mut SYSCALL_TIMING: [usize; 361] = [0; 361]; + #[no_mangle] #[deny(unreachable_patterns)] pub extern "C" fn dispatch_syscall( @@ -44,6 +46,14 @@ pub extern "C" fn dispatch_syscall( "syscall {}: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}", num, arg0, arg1, arg2, arg3, arg4, arg5 ); + #[cfg(feature = "syscall_timing")] + let time_start = { + if crate::process::current_pid() == 1 && num == SYS_EXIT { + print_syscall_timing(); + } + crate::time::do_gettimeofday().as_usec() + }; + let ret = match num { // file SYS_OPEN => do_open(arg0 as *const i8, arg1 as u32, arg2 as u32), @@ -256,6 +266,16 @@ pub extern "C" fn dispatch_syscall( _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5), }; + + #[cfg(feature = "syscall_timing")] + { + let time_end = crate::time::do_gettimeofday().as_usec(); + let time = time_end - time_start; + unsafe { + SYSCALL_TIMING[num as usize] += time as usize; + } + } + info!("=> {:?}", ret); match ret { @@ -264,6 +284,17 @@ pub extern "C" fn dispatch_syscall( } } +#[cfg(feature = "syscall_timing")] +fn print_syscall_timing() { + println!("syscall timing:"); + for (i, &time) in unsafe { SYSCALL_TIMING }.iter().enumerate() { + if time == 0 { + continue; + } + println!("{:>3}: {:>6} us", i, time); + } +} + #[allow(non_camel_case_types)] pub struct iovec_t { base: *const c_void, diff --git a/src/libos/src/time/mod.rs b/src/libos/src/time/mod.rs index 8fd99706..d458a319 100644 --- a/src/libos/src/time/mod.rs +++ b/src/libos/src/time/mod.rs @@ -16,6 +16,12 @@ pub struct timeval_t { usec: suseconds_t, } +impl timeval_t { + pub fn as_usec(&self) -> usize { + (self.sec * 1000000 + self.usec) as usize + } +} + pub fn do_gettimeofday() -> timeval_t { let mut tv: timeval_t = Default::default(); unsafe { From 141094e95e0c49e2917ddbdd3bba6d422d786889 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Mon, 22 Apr 2019 21:55:57 +0800 Subject: [PATCH 26/37] fix return value from libc::ocall --- src/libos/src/fs/io_multiplexing.rs | 81 ++++++++++++++++------------- src/libos/src/fs/socket_file.rs | 8 +-- src/libos/src/syscall/mod.rs | 24 +++++++++ 3 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 79f18062..f3f52951 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -1,9 +1,9 @@ use super::*; use crate::syscall::AsSocket; -use std::vec::Vec; +use std::any::Any; use std::collections::btree_map::BTreeMap; use std::fmt; -use std::any::Any; +use std::vec::Vec; /// Forward to host `poll` /// (sgx_libc doesn't have `select`) @@ -23,7 +23,11 @@ pub fn do_select( let file_table_ref = proc.get_files().lock().unwrap(); for fd in 0..nfds { - let (r, w, e) = (readfds.is_set(fd), writefds.is_set(fd), exceptfds.is_set(fd)); + let (r, w, e) = ( + readfds.is_set(fd), + writefds.is_set(fd), + exceptfds.is_set(fd), + ); if !(r || w || e) { continue; } @@ -31,9 +35,15 @@ pub fn do_select( host_to_libos_fd[host_fd as usize] = fd; let mut events = 0; - if r { events |= libc::POLLIN; } - if w { events |= libc::POLLOUT; } - if e { events |= libc::POLLERR; } + if r { + events |= libc::POLLIN; + } + if w { + events |= libc::POLLOUT; + } + if e { + events |= libc::POLLERR; + } polls.push(libc::pollfd { fd: host_fd as c_int, @@ -47,12 +57,10 @@ pub fn do_select( Some(tv) => (tv.tv_sec * 1000 + tv.tv_usec / 1000) as i32, }; - let ret = unsafe { - libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout) - }; + let ret = unsafe { libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout) }; if ret < 0 { - return errno!(Errno::from_retval(ret as i32), ""); + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); } // convert fd back and write fdset @@ -76,10 +84,7 @@ pub fn do_select( Ok(ret as usize) } -pub fn do_poll( - polls: &mut [libc::pollfd], - timeout: c_int, -) -> Result { +pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result { info!("poll: [..], timeout: {}", timeout); let current_ref = process::get_current(); @@ -91,13 +96,11 @@ pub fn do_poll( let socket = file_ref.as_socket()?; poll.fd = socket.fd(); } - let ret = unsafe { - libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout) - }; + let ret = unsafe { libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout) }; // recover fd ? if ret < 0 { - errno!(Errno::from_retval(ret as i32), "") + errno!(Errno::from_retval(unsafe { libc::errno() }), "") } else { Ok(ret as usize) } @@ -112,7 +115,10 @@ pub fn do_epoll_create1(flags: c_int) -> Result { let mut proc = current_ref.lock().unwrap(); let fd = { let close_on_spawn = flags & libc::EPOLL_CLOEXEC != 0; - proc.get_files().lock().unwrap().put(file_ref, close_on_spawn) + proc.get_files() + .lock() + .unwrap() + .put(file_ref, close_on_spawn) }; Ok(fd) } @@ -142,7 +148,12 @@ pub fn do_epoll_wait( events: &mut [libc::epoll_event], timeout: c_int, ) -> Result { - info!("epoll_wait: epfd: {}, len: {:?}, timeout: {}", epfd, events.len(), timeout); + info!( + "epoll_wait: epfd: {}, len: {:?}, timeout: {}", + epfd, + events.len(), + timeout + ); let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); @@ -187,7 +198,7 @@ pub struct EpollFile { impl EpollFile { pub fn new() -> Result { Ok(Self { - inner: SgxMutex::new(EpollFileInner::new()?) + inner: SgxMutex::new(EpollFileInner::new()?), }) } } @@ -202,25 +213,21 @@ impl EpollFileInner { pub fn new() -> Result { let ret = unsafe { libc::ocall::epoll_create1(0) }; if ret < 0 { - return errno!(Errno::from_retval(ret as i32), ""); + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); } - Ok(EpollFileInner { - epoll_fd: ret, - }) + Ok(EpollFileInner { epoll_fd: ret }) } - - pub fn ctl(&mut self, op: c_int, host_fd: FileDesc, event: *const libc::epoll_event) -> Result<(), Error> { - let ret = unsafe { - libc::ocall::epoll_ctl( - self.epoll_fd, - op, - host_fd as c_int, - event as *mut _, - ) - }; + pub fn ctl( + &mut self, + op: c_int, + host_fd: FileDesc, + event: *const libc::epoll_event, + ) -> Result<(), Error> { + let ret = + unsafe { libc::ocall::epoll_ctl(self.epoll_fd, op, host_fd as c_int, event as *mut _) }; if ret < 0 { - return errno!(Errno::from_retval(ret as i32), ""); + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); } Ok(()) } @@ -241,7 +248,7 @@ impl EpollFileInner { ) }; if ret < 0 { - return errno!(Errno::from_retval(ret as i32), ""); + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); } Ok(ret as usize) } diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs index 3bb5e8fb..a84f545a 100644 --- a/src/libos/src/fs/socket_file.rs +++ b/src/libos/src/fs/socket_file.rs @@ -11,7 +11,7 @@ impl SocketFile { pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result { let ret = unsafe { libc::ocall::socket(domain, socket_type, protocol) }; if ret < 0 { - errno!(Errno::from_retval(ret as i32), "") + errno!(Errno::from_retval(unsafe { libc::errno() }), "") } else { Ok(SocketFile { fd: ret }) } @@ -25,7 +25,7 @@ impl SocketFile { ) -> Result { let ret = unsafe { libc::ocall::accept4(self.fd, addr, addr_len, flags) }; if ret < 0 { - errno!(Errno::from_retval(ret as i32), "") + errno!(Errno::from_retval(unsafe { libc::errno() }), "") } else { Ok(SocketFile { fd: ret }) } @@ -49,7 +49,7 @@ impl File for SocketFile { fn read(&self, buf: &mut [u8]) -> Result { let ret = unsafe { libc::ocall::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len()) }; if ret < 0 { - errno!(Errno::from_retval(ret as i32), "") + errno!(Errno::from_retval(unsafe { libc::errno() }), "") } else { Ok(ret as usize) } @@ -58,7 +58,7 @@ impl File for SocketFile { fn write(&self, buf: &[u8]) -> Result { let ret = unsafe { libc::ocall::write(self.fd, buf.as_ptr() as *const c_void, buf.len()) }; if ret < 0 { - errno!(Errno::from_retval(ret as i32), "") + errno!(Errno::from_retval(unsafe { libc::errno() }), "") } else { Ok(ret as usize) } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index fabb966a..927c5678 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -942,6 +942,9 @@ fn do_connect( let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::connect(socket.fd(), addr, addr_len) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } @@ -975,6 +978,9 @@ fn do_shutdown(fd: c_int, how: c_int) -> Result { let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::shutdown(socket.fd(), how) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } @@ -990,6 +996,9 @@ fn do_bind( let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::bind(socket.fd(), addr, addr_len) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } @@ -1001,6 +1010,9 @@ fn do_listen(fd: c_int, backlog: c_int) -> Result { let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::listen(socket.fd(), backlog) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } @@ -1021,6 +1033,9 @@ fn do_setsockopt( let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::setsockopt(socket.fd(), level, optname, optval, optlen) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } @@ -1041,6 +1056,9 @@ fn do_getsockopt( let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::getsockopt(socket.fd(), level, optname, optval, optlen) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } @@ -1062,6 +1080,9 @@ fn do_sendto( let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::sendto(socket.fd(), base, len, flags, addr, addr_len) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } @@ -1083,6 +1104,9 @@ fn do_recvfrom( let socket = file_ref.as_socket()?; let ret = unsafe { libc::ocall::recvfrom(socket.fd(), base, len, flags, addr, addr_len) }; + if ret < 0 { + return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); + } Ok(ret as isize) } From 1326924dbbd1dec5af7df6ae1f4199161c1c9f35 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 23 Apr 2019 00:36:48 +0800 Subject: [PATCH 27/37] fix errno = 0 and introduce macro 'try_libc' --- src/libos/src/errno.rs | 106 ++++++++++++++++++++++++++-- src/libos/src/fs/io_multiplexing.rs | 32 ++------- src/libos/src/fs/socket_file.rs | 35 +++------ src/libos/src/prelude.rs | 21 +++++- src/libos/src/syscall/mod.rs | 66 ++++++++--------- 5 files changed, 170 insertions(+), 90 deletions(-) diff --git a/src/libos/src/errno.rs b/src/libos/src/errno.rs index 3abfec08..78efa487 100644 --- a/src/libos/src/errno.rs +++ b/src/libos/src/errno.rs @@ -81,19 +81,111 @@ pub enum Errno { ENOLCK = 37, ENOSYS = 38, ENOTEMPTY = 39, + ELOOP = 40, + EWOULDBLOCK = 41, + ENOMSG = 42, + EIDRM = 43, + ECHRNG = 44, + EL2NSYNC = 45, + EL3HLT = 46, + EL3RST = 47, + ELNRNG = 48, + EUNATCH = 49, + ENOCSI = 50, + EL2HLT = 51, + EBADE = 52, + EBADR = 53, + EXFULL = 54, + ENOANO = 55, + EBADRQC = 56, + EBADSLT = 57, + EDEADLOCK = 58, + EBFONT = 59, + ENOSTR = 60, + ENODATA = 61, + ETIME = 62, + ENOSR = 63, + ENONET = 64, + ENOPKG = 65, + EREMOTE = 66, + ENOLINK = 67, + EADV = 68, + ESRMNT = 69, + ECOMM = 70, + EPROTO = 71, + EMULTIHOP = 72, + EDOTDOT = 73, + EBADMSG = 74, + EOVERFLOW = 75, + ENOTUNIQ = 76, + EBADFD = 77, + EREMCHG = 78, + ELIBACC = 79, + ELIBBAD = 80, + ELIBSCN = 81, + ELIBMAX = 82, + ELIBEXEC = 83, + EILSEQ = 84, + ERESTART = 85, + ESTRPIPE = 86, + EUSERS = 87, + ENOTSOCK = 88, + EDESTADDRREQ = 89, + EMSGSIZE = 90, + EPROTOTYPE = 91, + ENOPROTOOPT = 92, + EPROTONOSUPPORT = 93, + ESOCKTNOSUPPORT = 94, + EOPNOTSUPP = 95, + EPFNOSUPPORT = 96, + EAFNOSUPPORT = 97, + EADDRINUSE = 98, + EADDRNOTAVAIL = 99, + ENETDOWN = 100, + ENETUNREACH = 101, + ENETRESET = 102, + ECONNABORTED = 103, + ECONNRESET = 104, + ENOBUFS = 105, + EISCONN = 106, + ENOTCONN = 107, + ESHUTDOWN = 108, + ETOOMANYREFS = 109, + ETIMEDOUT = 110, + ECONNREFUSED = 111, + EHOSTDOWN = 112, + EHOSTUNREACH = 113, + EALREADY = 114, + EINPROGRESS = 115, + ESTALE = 116, + EUCLEAN = 117, + ENOTNAM = 118, + ENAVAIL = 119, + EISNAM = 120, + EREMOTEIO = 121, + EDQUOT = 122, + ENOMEDIUM = 123, + EMEDIUMTYPE = 124, + ECANCELED = 125, + ENOKEY = 126, + EKEYEXPIRED = 127, + EKEYREVOKED = 128, + EKEYREJECTED = 129, + EOWNERDEAD = 130, + ENOTRECOVERABLE = 131, + ERFKILL = 132, + EHWPOISON = 133, } impl Errno { pub fn as_retval(&self) -> i32 { -(*self as i32) } - pub fn from_retval(ret: i32) -> Self { - let ret = if ret <= 0 && ret >= -39 { - (-ret) as u8 - } else { - 0 - }; - unsafe { core::mem::transmute(ret) } + pub fn from_errno(mut errno: i32) -> Self { + if errno < 0 || errno > 133 { + errno = 0; + } + unsafe { core::mem::transmute(errno as u8) } } } diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index f3f52951..59e1c962 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -57,11 +57,7 @@ pub fn do_select( Some(tv) => (tv.tv_sec * 1000 + tv.tv_usec / 1000) as i32, }; - let ret = unsafe { libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout) }; - - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout)); // convert fd back and write fdset readfds.clear(); @@ -96,14 +92,9 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result Result { @@ -211,10 +202,7 @@ struct EpollFileInner { impl EpollFileInner { /// Create a new Linux epoll file descriptor pub fn new() -> Result { - let ret = unsafe { libc::ocall::epoll_create1(0) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::epoll_create1(0)); Ok(EpollFileInner { epoll_fd: ret }) } @@ -225,10 +213,7 @@ impl EpollFileInner { event: *const libc::epoll_event, ) -> Result<(), Error> { let ret = - unsafe { libc::ocall::epoll_ctl(self.epoll_fd, op, host_fd as c_int, event as *mut _) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + try_libc!(libc::ocall::epoll_ctl(self.epoll_fd, op, host_fd as c_int, event as *mut _)); Ok(()) } @@ -239,17 +224,14 @@ impl EpollFileInner { events: &mut [libc::epoll_event], timeout: c_int, ) -> Result { - let ret = unsafe { + let ret = try_libc!( libc::ocall::epoll_wait( self.epoll_fd, events.as_mut_ptr(), events.len() as c_int, timeout, ) - }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + ); Ok(ret as usize) } } diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs index a84f545a..baaa87f8 100644 --- a/src/libos/src/fs/socket_file.rs +++ b/src/libos/src/fs/socket_file.rs @@ -9,12 +9,8 @@ pub struct SocketFile { impl SocketFile { pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result { - let ret = unsafe { libc::ocall::socket(domain, socket_type, protocol) }; - if ret < 0 { - errno!(Errno::from_retval(unsafe { libc::errno() }), "") - } else { - Ok(SocketFile { fd: ret }) - } + let ret = try_libc!(libc::ocall::socket(domain, socket_type, protocol)); + Ok(SocketFile { fd: ret }) } pub fn accept( @@ -23,12 +19,8 @@ impl SocketFile { addr_len: *mut libc::socklen_t, flags: c_int, ) -> Result { - let ret = unsafe { libc::ocall::accept4(self.fd, addr, addr_len, flags) }; - if ret < 0 { - errno!(Errno::from_retval(unsafe { libc::errno() }), "") - } else { - Ok(SocketFile { fd: ret }) - } + let ret = try_libc!(libc::ocall::accept4(self.fd, addr, addr_len, flags)); + Ok(SocketFile { fd: ret }) } pub fn fd(&self) -> c_int { @@ -40,28 +32,21 @@ impl Drop for SocketFile { fn drop(&mut self) { let ret = unsafe { libc::ocall::close(self.fd) }; if ret < 0 { - warn!("socket (host fd: {}) close failed", self.fd); + let errno = unsafe { libc::errno() }; + warn!("socket (host fd: {}) close failed: errno = {}", self.fd, errno); } } } impl File for SocketFile { fn read(&self, buf: &mut [u8]) -> Result { - let ret = unsafe { libc::ocall::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len()) }; - if ret < 0 { - errno!(Errno::from_retval(unsafe { libc::errno() }), "") - } else { - Ok(ret as usize) - } + let ret = try_libc!(libc::ocall::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len())); + Ok(ret as usize) } fn write(&self, buf: &[u8]) -> Result { - let ret = unsafe { libc::ocall::write(self.fd, buf.as_ptr() as *const c_void, buf.len()) }; - if ret < 0 { - errno!(Errno::from_retval(unsafe { libc::errno() }), "") - } else { - Ok(ret as usize) - } + let ret = try_libc!(libc::ocall::write(self.fd, buf.as_ptr() as *const c_void, buf.len())); + Ok(ret as usize) } fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { diff --git a/src/libos/src/prelude.rs b/src/libos/src/prelude.rs index 113b3b5c..74235313 100644 --- a/src/libos/src/prelude.rs +++ b/src/libos/src/prelude.rs @@ -35,7 +35,7 @@ macro_rules! debug_trace { } macro_rules! errno { - ($errno: expr, $msg: expr) => {{ + ($errno: ident, $msg: expr) => {{ println!( "ERROR: {} ({}, line {} in file {})", $errno, @@ -47,6 +47,25 @@ macro_rules! errno { }}; } +// return Err(errno) if libc return -1 +macro_rules! try_libc { + ($ret: expr) => {{ + let ret = unsafe { $ret }; + if ret == -1 { + let errno = unsafe { libc::errno() }; + // println will cause libc ocall and overwrite errno + println!( + "ERROR from libc: {} (line {} in file {})", + errno, + line!(), + file!() + ); + return Err(Error::new(Errno::from_errno(errno), "libc error")); + } + ret + }}; +} + pub fn align_up(addr: usize, align: usize) -> usize { (addr + (align - 1)) / align * align } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 927c5678..9d37531e 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -941,10 +941,7 @@ fn do_connect( let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::connect(socket.fd(), addr, addr_len) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::connect(socket.fd(), addr, addr_len)); Ok(ret as isize) } @@ -977,10 +974,7 @@ fn do_shutdown(fd: c_int, how: c_int) -> Result { let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::shutdown(socket.fd(), how) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how)); Ok(ret as isize) } @@ -995,10 +989,7 @@ fn do_bind( let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::bind(socket.fd(), addr, addr_len) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::bind(socket.fd(), addr, addr_len)); Ok(ret as isize) } @@ -1009,10 +1000,7 @@ fn do_listen(fd: c_int, backlog: c_int) -> Result { let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::listen(socket.fd(), backlog) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::listen(socket.fd(), backlog)); Ok(ret as isize) } @@ -1032,10 +1020,13 @@ fn do_setsockopt( let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::setsockopt(socket.fd(), level, optname, optval, optlen) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::setsockopt( + socket.fd(), + level, + optname, + optval, + optlen + )); Ok(ret as isize) } @@ -1055,10 +1046,13 @@ fn do_getsockopt( let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::getsockopt(socket.fd(), level, optname, optval, optlen) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::getsockopt( + socket.fd(), + level, + optname, + optval, + optlen + )); Ok(ret as isize) } @@ -1079,10 +1073,14 @@ fn do_sendto( let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::sendto(socket.fd(), base, len, flags, addr, addr_len) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::sendto( + socket.fd(), + base, + len, + flags, + addr, + addr_len + )); Ok(ret as isize) } @@ -1103,10 +1101,14 @@ fn do_recvfrom( let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; let socket = file_ref.as_socket()?; - let ret = unsafe { libc::ocall::recvfrom(socket.fd(), base, len, flags, addr, addr_len) }; - if ret < 0 { - return errno!(Errno::from_retval(unsafe { libc::errno() }), ""); - } + let ret = try_libc!(libc::ocall::recvfrom( + socket.fd(), + base, + len, + flags, + addr, + addr_len + )); Ok(ret as isize) } From 26189dddaa62f12f58b96c8ab2937b40bc7c7f1b Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 23 Apr 2019 01:43:41 +0800 Subject: [PATCH 28/37] implement fcntl & ioctl for socket. fix lighttpd performance --- src/libos/src/fs/file.rs | 15 ++++++- src/libos/src/fs/inode_file.rs | 4 ++ src/libos/src/fs/mod.rs | 62 +++++++++++++++----------- src/libos/src/fs/null.rs | 4 ++ src/libos/src/fs/pipe.rs | 8 ++++ src/libos/src/process/spawn/init_vm.rs | 2 +- src/libos/src/syscall/mod.rs | 19 ++++++++ src/libos/src/vm/mod.rs | 7 +++ 8 files changed, 91 insertions(+), 30 deletions(-) diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index 1a880dd6..e95ce894 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -3,7 +3,6 @@ use std; use std::borrow::BorrowMut; use std::fmt; use std::io::SeekFrom; -use std::any::Any; pub trait File: Debug + Sync + Send + Any { fn read(&self, buf: &mut [u8]) -> Result; @@ -18,7 +17,7 @@ pub trait File: Debug + Sync + Send + Any { fn sync_all(&self) -> Result<(), Error>; fn sync_data(&self) -> Result<(), Error>; fn read_entry(&self) -> Result; - fn as_any(&self) -> &Any { unimplemented!() } + fn as_any(&self) -> &Any; } pub type FileRef = Arc>; @@ -116,6 +115,10 @@ impl File for SgxFile { fn read_entry(&self) -> Result { unimplemented!() } + + fn as_any(&self) -> &Any { + self + } } #[derive(Clone)] @@ -379,6 +382,10 @@ impl File for StdoutFile { fn read_entry(&self) -> Result { unimplemented!() } + + fn as_any(&self) -> &Any { + self + } } impl Debug for StdoutFile { @@ -476,6 +483,10 @@ impl File for StdinFile { fn read_entry(&self) -> Result { unimplemented!() } + + fn as_any(&self) -> &Any { + self + } } impl Debug for StdinFile { diff --git a/src/libos/src/fs/inode_file.rs b/src/libos/src/fs/inode_file.rs index ff737788..9cca09f5 100644 --- a/src/libos/src/fs/inode_file.rs +++ b/src/libos/src/fs/inode_file.rs @@ -154,6 +154,10 @@ impl File for INodeFile { *offset += 1; Ok(name) } + + fn as_any(&self) -> &Any { + self + } } impl INodeFile { diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 00208c18..e7e6a74e 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -16,6 +16,7 @@ pub use self::io_multiplexing::*; pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat}; use self::null::NullFile; use std::mem::uninitialized; +use std::any::Any; mod file; mod file_table; @@ -468,6 +469,8 @@ bitflags! { const TRUNCATE = 1 << 9; /// append on each write const APPEND = 1 << 10; + /// non block + const NONBLOCK = 1 << 11; /// close on exec const CLOEXEC = 1 << 19; } @@ -694,28 +697,19 @@ pub enum FcntlCmd { /// Get the file status flags GetFl(), /// Set the file status flags - SetFl(OpenFlags), + SetFl(u32), } -pub const F_DUPFD : u32 = 0; -pub const F_GETFD : u32 = 1; -pub const F_SETFD : u32 = 2; -pub const F_GETFL : u32 = 3; -pub const F_SETFL : u32 = 4; -pub const F_DUPFD_CLOEXEC : u32 = 1030; - -pub const FD_CLOEXEC : u32 = 1; - impl FcntlCmd { #[deny(unreachable_patterns)] pub fn from_raw(cmd: u32, arg: u64) -> Result { - Ok(match cmd { - F_DUPFD => FcntlCmd::DupFd(arg as FileDesc), - F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc), - F_GETFD => FcntlCmd::GetFd(), - F_SETFD => FcntlCmd::SetFd(arg as u32), - F_GETFL => FcntlCmd::GetFl(), - F_SETFL => FcntlCmd::SetFl(OpenFlags::from_bits_truncate(arg as u32)), + Ok(match cmd as c_int { + libc::F_DUPFD => FcntlCmd::DupFd(arg as FileDesc), + libc::F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc), + libc::F_GETFD => FcntlCmd::GetFd(), + libc::F_SETFD => FcntlCmd::SetFd(arg as u32), + libc::F_GETFL => FcntlCmd::GetFl(), + libc::F_SETFL => FcntlCmd::SetFl(arg as u32), _ => return errno!(EINVAL, "invalid command"), }) } @@ -739,7 +733,7 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result { FcntlCmd::GetFd() => { let entry = files.get_entry(fd)?; let fd_flags = if entry.is_close_on_spawn() { - FD_CLOEXEC + libc::FD_CLOEXEC } else { 0 }; @@ -747,19 +741,33 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result { }, FcntlCmd::SetFd(fd_flags) => { let entry = files.get_entry_mut(fd)?; - entry.set_close_on_spawn((fd_flags & FD_CLOEXEC) != 0); + entry.set_close_on_spawn((fd_flags & libc::FD_CLOEXEC as u32) != 0); 0 }, FcntlCmd::GetFl() => { - let _ = files.get_entry_mut(fd)?; - warn!("fcntl.getfl is unimplemented"); - 0 - }, + let file = files.get(fd)?; + if let Ok(socket) = file.as_socket() { + let ret = try_libc!(libc::ocall::fcntl_arg0(socket.fd(), libc::F_GETFL)); + ret as isize + } else { + warn!("fcntl.getfl is unimplemented"); + 0 + } + } FcntlCmd::SetFl(flags) => { - let _ = files.get_entry_mut(fd)?; - warn!("fcntl.setfl is unimplemented"); - 0 - }, + let file = files.get(fd)?; + if let Ok(socket) = file.as_socket() { + let ret = try_libc!(libc::ocall::fcntl_arg1( + socket.fd(), + libc::F_SETFL, + *flags as c_int + )); + ret as isize + } else { + warn!("fcntl.setfl is unimplemented"); + 0 + } + } }) } diff --git a/src/libos/src/fs/null.rs b/src/libos/src/fs/null.rs index 454d7f12..18382360 100644 --- a/src/libos/src/fs/null.rs +++ b/src/libos/src/fs/null.rs @@ -51,4 +51,8 @@ impl File for NullFile { fn read_entry(&self) -> Result { unimplemented!() } + + fn as_any(&self) -> &Any { + self + } } diff --git a/src/libos/src/fs/pipe.rs b/src/libos/src/fs/pipe.rs index 643af65d..d0aab595 100644 --- a/src/libos/src/fs/pipe.rs +++ b/src/libos/src/fs/pipe.rs @@ -99,6 +99,10 @@ impl File for PipeReader { fn read_entry(&self) -> Result { unimplemented!() } + + fn as_any(&self) -> &Any { + self + } } unsafe impl Send for PipeReader {} @@ -177,6 +181,10 @@ impl File for PipeWriter { fn read_entry(&self) -> Result { unimplemented!() } + + fn as_any(&self) -> &Any { + self + } } unsafe impl Send for PipeWriter {} diff --git a/src/libos/src/process/spawn/init_vm.rs b/src/libos/src/process/spawn/init_vm.rs index e01f7f3a..0a4d0442 100644 --- a/src/libos/src/process/spawn/init_vm.rs +++ b/src/libos/src/process/spawn/init_vm.rs @@ -5,7 +5,7 @@ use xmas_elf::{header, program, sections, ElfFile}; pub const DEFAULT_STACK_SIZE: usize = 1 * 1024 * 1024; pub const DEFAULT_HEAP_SIZE: usize = 2 * 1024 * 1024; -pub const DEFAULT_MMAP_SIZE: usize = 2 * 1024 * 1024; +pub const DEFAULT_MMAP_SIZE: usize = 8 * 1024 * 1024; pub fn do_init(elf_file: &ElfFile, elf_buf: &[u8]) -> Result { let mut code_seg = get_code_segment(elf_file)?; diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 9d37531e..8587a145 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -101,6 +101,7 @@ pub extern "C" fn dispatch_syscall( arg3 as usize, ), SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), + SYS_IOCTL => do_ioctl(arg0 as FileDesc, arg1 as c_int, arg2 as *mut c_int), // IO multiplexing SYS_SELECT => do_select( @@ -280,6 +281,7 @@ pub extern "C" fn dispatch_syscall( match ret { Ok(code) => code as isize, + Err(e) if e.errno.as_retval() == 0 => panic!("undefined errno"), Err(e) => e.errno.as_retval() as isize, } } @@ -900,6 +902,23 @@ fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result { fs::do_fcntl(fd, &cmd) } +fn do_ioctl(fd: FileDesc, cmd: c_int, argp: *mut c_int) -> Result { + info!( + "ioctl: fd: {}, cmd: {}, argp: {:?}", + fd, cmd, argp + ); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + if let Ok(socket) = file_ref.as_socket() { + let ret = try_libc!(libc::ocall::ioctl_arg1(socket.fd(), cmd, argp)); + Ok(ret as isize) + } else { + warn!("ioctl is unimplemented"); + errno!(ENOSYS, "ioctl is unimplemented") + } +} + fn do_arch_prctl(code: u32, addr: *mut usize) -> Result { let code = process::ArchPrctlCode::from_u32(code)?; check_mut_ptr(addr)?; diff --git a/src/libos/src/vm/mod.rs b/src/libos/src/vm/mod.rs index 16aa41d5..6dbc7170 100644 --- a/src/libos/src/vm/mod.rs +++ b/src/libos/src/vm/mod.rs @@ -16,6 +16,7 @@ pub use self::process_vm::ProcessVM; // TODO: separate proc and flags // TODO: accept fd and offset pub fn do_mmap(addr: usize, size: usize, flags: VMAreaFlags) -> Result { + info!("mmap: addr: {:#x}, size: {:#x}, flags: {:?}", addr, size, flags); let current_ref = get_current(); let current_process = current_ref.lock().unwrap(); let current_vm_ref = current_process.get_vm(); @@ -24,6 +25,7 @@ pub fn do_mmap(addr: usize, size: usize, flags: VMAreaFlags) -> Result Result<(), Error> { + info!("munmap: addr: {:#x}, size: {:#x}", addr, size); let current_ref = get_current(); let current_process = current_ref.lock().unwrap(); let current_vm_ref = current_process.get_vm(); @@ -37,6 +39,10 @@ pub fn do_mremap( old_size: usize, options: &VMResizeOptions, ) -> Result { + info!( + "mremap: oldaddr: {:#x}, oldsize: {:#x}, options: {:?}", + old_addr, old_size, options + ); let current_ref = get_current(); let current_process = current_ref.lock().unwrap(); let current_vm_ref = current_process.get_vm(); @@ -45,6 +51,7 @@ pub fn do_mremap( } pub fn do_brk(addr: usize) -> Result { + info!("brk: addr: {:#x}", addr); let current_ref = get_current(); let current_process = current_ref.lock().unwrap(); let current_vm_ref = current_process.get_vm(); From 0437e81f362209c2a4560eb1187acb618d50357d Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 23 Apr 2019 12:58:28 +0800 Subject: [PATCH 29/37] fix impl File for Stdin/Stdout --- src/libos/src/errno.rs | 6 ++++ src/libos/src/fs/file.rs | 61 +++++++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/libos/src/errno.rs b/src/libos/src/errno.rs index 78efa487..11a70f45 100644 --- a/src/libos/src/errno.rs +++ b/src/libos/src/errno.rs @@ -22,6 +22,12 @@ impl convert::From<(Errno, &'static str)> for Error { } } +impl convert::From for Error { + fn from(info: std::io::Error) -> Error { + Error::new(Errno::from_errno(info.raw_os_error().unwrap()), "std::io::Error") + } +} + impl error::Error for Error { fn description(&self) -> &str { self.desc diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index e95ce894..a56fb8a8 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -323,12 +323,12 @@ impl File for StdoutFile { Ok(write_len) } - fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { - unimplemented!() + fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { + self.read(buf) } - fn write_at(&self, offset: usize, buf: &[u8]) -> Result { - unimplemented!() + fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { + self.write(buf) } fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { @@ -364,23 +364,38 @@ impl File for StdoutFile { } fn metadata(&self) -> Result { - unimplemented!() + Ok(Metadata { + dev: 0, + 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_: FileType::File, + mode: 0, + nlinks: 0, + uid: 0, + gid: 0 + }) } - fn set_len(&self, len: u64) -> Result<(), Error> { - unimplemented!() + fn set_len(&self, _len: u64) -> Result<(), Error> { + errno!(EINVAL, "Stdout does not support set_len") } fn sync_all(&self) -> Result<(), Error> { - unimplemented!() + self.sync_data() } fn sync_data(&self) -> Result<(), Error> { - unimplemented!() + self.inner.lock().flush()?; + Ok(()) } fn read_entry(&self) -> Result { - unimplemented!() + errno!(ENOTDIR, "Stdout does not support read_entry") } fn as_any(&self) -> &Any { @@ -465,23 +480,37 @@ impl File for StdinFile { } fn metadata(&self) -> Result { - unimplemented!() + Ok(Metadata { + dev: 0, + 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_: FileType::File, + mode: 0, + nlinks: 0, + uid: 0, + gid: 0 + }) } - fn set_len(&self, len: u64) -> Result<(), Error> { - unimplemented!() + fn set_len(&self, _len: u64) -> Result<(), Error> { + errno!(EINVAL, "Stdin does not support set_len") } fn sync_all(&self) -> Result<(), Error> { - unimplemented!() + self.sync_data() } fn sync_data(&self) -> Result<(), Error> { - unimplemented!() + Ok(()) } fn read_entry(&self) -> Result { - unimplemented!() + errno!(ENOTDIR, "Stdin does not support read_entry") } fn as_any(&self) -> &Any { From f846ba11f2b8f7c2d4131f1cc23152fd50910f01 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 23 Apr 2019 14:00:44 +0800 Subject: [PATCH 30/37] fix wait4 not removing child --- src/libos/src/process/exit.rs | 12 +++++------- src/libos/src/process/process.rs | 6 ++++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libos/src/process/exit.rs b/src/libos/src/process/exit.rs index a7da5b33..621473cc 100644 --- a/src/libos/src/process/exit.rs +++ b/src/libos/src/process/exit.rs @@ -20,8 +20,7 @@ pub fn do_exit(exit_status: i32) { current.status = Status::ZOMBIE; // Update children - for child_weak in ¤t.children { - let child_ref = child_weak.upgrade().unwrap(); + for child_ref in current.get_children_iter() { let mut child = child_ref.lock().unwrap(); child.parent = Some(IDLE_PROCESS.clone()); } @@ -69,8 +68,7 @@ pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Res let mut current = current_ref.lock().unwrap(); let mut any_child_to_wait_for = false; - for child_weak in current.get_children() { - let child_ref = child_weak.upgrade().unwrap(); + for child_ref in current.get_children_iter() { let child = child_ref.lock().unwrap(); let may_wait_for = match child_filter { @@ -82,8 +80,9 @@ pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Res continue; } - // Return immediately as a child that we wait for has alreay exited + // Return immediately as a child that we wait for has already exited if child.status == Status::ZOMBIE { + process_table::remove(child.pid); return Ok(child.pid); } @@ -107,8 +106,7 @@ pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Res let mut current = current_ref.lock().unwrap(); let child_i = { let mut child_i_opt = None; - for (child_i, child_weak) in current.children.iter().enumerate() { - let child_ref = child_weak.upgrade().unwrap(); + for (child_i, child_ref) in current.get_children_iter().enumerate() { let child = child_ref.lock().unwrap(); if child.get_pid() != child_pid { continue; diff --git a/src/libos/src/process/process.rs b/src/libos/src/process/process.rs index fbfeffd3..2baedb06 100644 --- a/src/libos/src/process/process.rs +++ b/src/libos/src/process/process.rs @@ -88,8 +88,10 @@ impl Process { pub fn get_parent(&self) -> &ProcessRef { self.parent.as_ref().unwrap() } - pub fn get_children(&self) -> &[ProcessWeakRef] { - &self.children + pub fn get_children_iter(&self) -> impl Iterator + '_ { + self.children + .iter() + .filter_map(|child_weak| child_weak.upgrade()) } pub fn change_cwd(&mut self, path: &str) { if path.len() > 0 && path.as_bytes()[0] == b'/' { From 9106bd46f24f9463ed83ff41d764abe48cb0ccb7 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 23 Apr 2019 22:00:38 +0800 Subject: [PATCH 31/37] fix for php. include incomplete code for UnixSocket --- src/libos/Enclave_config.xml | 2 +- src/libos/src/fs/file.rs | 4 +- src/libos/src/fs/io_multiplexing.rs | 1 - src/libos/src/fs/mod.rs | 6 +- src/libos/src/fs/socket_file.rs | 28 ++- src/libos/src/fs/unix_socket.rs | 310 +++++++++++++++++++++++++ src/libos/src/prelude.rs | 4 +- src/libos/src/process/exit.rs | 2 +- src/libos/src/process/spawn/init_vm.rs | 4 +- src/libos/src/process/spawn/mod.rs | 3 +- src/libos/src/process/wait.rs | 8 +- src/libos/src/syscall/mod.rs | 168 ++++++++++---- src/libos/src/vm/vm_space_prealloced.c | 2 +- 13 files changed, 475 insertions(+), 67 deletions(-) create mode 100644 src/libos/src/fs/unix_socket.rs diff --git a/src/libos/Enclave_config.xml b/src/libos/Enclave_config.xml index 5f853be5..7d9f7639 100644 --- a/src/libos/Enclave_config.xml +++ b/src/libos/Enclave_config.xml @@ -3,7 +3,7 @@ 0 0 0x100000 - 0x1000000 + 0x2000000 8 1 0 diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index a56fb8a8..82ae1e5e 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -373,7 +373,7 @@ impl File for StdoutFile { atime: Timespec { sec: 0, nsec: 0 }, mtime: Timespec { sec: 0, nsec: 0 }, ctime: Timespec { sec: 0, nsec: 0 }, - type_: FileType::File, + type_: FileType::CharDevice, mode: 0, nlinks: 0, uid: 0, @@ -489,7 +489,7 @@ impl File for StdinFile { atime: Timespec { sec: 0, nsec: 0 }, mtime: Timespec { sec: 0, nsec: 0 }, ctime: Timespec { sec: 0, nsec: 0 }, - type_: FileType::File, + type_: FileType::CharDevice, mode: 0, nlinks: 0, uid: 0, diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 59e1c962..419a1ab8 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -1,5 +1,4 @@ use super::*; -use crate::syscall::AsSocket; use std::any::Any; use std::collections::btree_map::BTreeMap; use std::fmt; diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index e7e6a74e..ad6c7041 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -9,7 +9,8 @@ use super::*; pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile}; pub use self::file_table::{FileDesc, FileTable}; pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; -pub use self::socket_file::SocketFile; +pub use self::socket_file::{SocketFile, AsSocket}; +pub use self::unix_socket::{UnixSocketFile, AsUnixSocket}; use self::inode_file::OpenOptions; pub use self::pipe::Pipe; pub use self::io_multiplexing::*; @@ -27,6 +28,7 @@ mod sgx_impl; mod io_multiplexing; mod access; mod null; +mod unix_socket; pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { @@ -363,7 +365,7 @@ pub fn do_sendfile( let in_file = file_table.get(in_fd)?; let out_file = file_table.get(out_fd)?; - let mut buffer: [u8; 1024] = unsafe { uninitialized() }; + let mut buffer: [u8; 1024 * 11] = unsafe { uninitialized() }; let mut read_offset = match offset { Some(offset) => offset, diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs index baaa87f8..7391c05b 100644 --- a/src/libos/src/fs/socket_file.rs +++ b/src/libos/src/fs/socket_file.rs @@ -90,7 +90,21 @@ impl File for SocketFile { } fn metadata(&self) -> Result { - unimplemented!() + Ok(Metadata { + dev: 0, + 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_: FileType::Socket, + mode: 0, + nlinks: 0, + uid: 0, + gid: 0 + }) } fn set_len(&self, len: u64) -> Result<(), Error> { @@ -113,3 +127,15 @@ impl File for SocketFile { self } } + +pub trait AsSocket { + fn as_socket(&self) -> Result<&SocketFile, Error>; +} + +impl AsSocket for FileRef { + fn as_socket(&self) -> Result<&SocketFile, Error> { + self.as_any() + .downcast_ref::() + .ok_or(Error::new(Errno::EBADF, "not a socket")) + } +} diff --git a/src/libos/src/fs/unix_socket.rs b/src/libos/src/fs/unix_socket.rs new file mode 100644 index 00000000..6aeae486 --- /dev/null +++ b/src/libos/src/fs/unix_socket.rs @@ -0,0 +1,310 @@ +use super::*; +use std::collections::btree_map::BTreeMap; +use util::ring_buf::{RingBufReader, RingBufWriter, RingBuf}; +use std::sync::SgxMutex as Mutex; +use alloc::prelude::ToString; +use std::fmt; + +pub struct UnixSocketFile { + inner: Mutex +} + +impl File for UnixSocketFile { + fn read(&self, buf: &mut [u8]) -> Result { + let mut inner = self.inner.lock().unwrap(); + inner.read(buf) + } + + fn write(&self, buf: &[u8]) -> Result { + let mut inner = self.inner.lock().unwrap(); + inner.write(buf) + } + + fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { + self.read(buf) + } + + fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { + self.write(buf) + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + let mut inner = self.inner.lock().unwrap(); + let mut total_len = 0; + for buf in bufs { + match inner.read(buf) { + Ok(len) => { + total_len += len; + } + Err(_) if total_len != 0 => break, + Err(e) => return Err(e.into()), + } + } + Ok(total_len) + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + let mut inner = self.inner.lock().unwrap(); + let mut total_len = 0; + for buf in bufs { + match inner.write(buf) { + Ok(len) => { + total_len += len; + } + Err(_) if total_len != 0 => break, + Err(e) => return Err(e.into()), + } + } + Ok(total_len) + } + + fn seek(&self, pos: SeekFrom) -> Result { + errno!(ESPIPE, "UnixSocket does not support seek") + } + + fn metadata(&self) -> Result { + Ok(Metadata { + dev: 0, + 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_: FileType::Socket, + mode: 0, + nlinks: 0, + uid: 0, + gid: 0 + }) + } + + fn set_len(&self, len: u64) -> Result<(), Error> { + unimplemented!() + } + + fn sync_all(&self) -> Result<(), Error> { + unimplemented!() + } + + fn sync_data(&self) -> Result<(), Error> { + unimplemented!() + } + + fn read_entry(&self) -> Result { + unimplemented!() + } + + fn as_any(&self) -> &Any { + self + } +} + +impl UnixSocketFile { + pub fn new(socket_type: c_int, protocol: c_int) -> Result { + let inner = UnixSocket::new(socket_type, protocol)?; + Ok(UnixSocketFile { inner: Mutex::new(inner) }) + } + + pub fn bind(&self, path: impl AsRef) -> Result<(), Error> { + let mut inner = self.inner.lock().unwrap(); + inner.bind(path) + } + + pub fn listen(&self) -> Result<(), Error> { + let mut inner = self.inner.lock().unwrap(); + inner.listen() + } + + pub fn accept(&self) -> Result { + let mut inner = self.inner.lock().unwrap(); + let new_socket = inner.accept()?; + Ok(UnixSocketFile { inner: Mutex::new(new_socket) }) + } + + pub fn connect(&self, path: impl AsRef) -> Result<(), Error> { + let mut inner = self.inner.lock().unwrap(); + inner.connect(path) + } +} + +impl Debug for UnixSocketFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UnixSocketFile {{ ... }}") + } +} + + +pub trait AsUnixSocket { + fn as_unix_socket(&self) -> Result<&UnixSocketFile, Error>; +} + +impl AsUnixSocket for FileRef { + fn as_unix_socket(&self) -> Result<&UnixSocketFile, Error> { + self.as_any() + .downcast_ref::() + .ok_or(Error::new(Errno::EBADF, "not a unix socket")) + } +} + + +pub struct UnixSocket { + obj: Option>, + status: Status, +} + +enum Status { + None, + Listening, + Connected(Channel), +} + +impl UnixSocket { + /// C/S 1: Create a new unix socket + pub fn new(socket_type: c_int, protocol: c_int) -> Result { + if socket_type == libc::SOCK_STREAM && protocol == 0 { + Ok(UnixSocket { + obj: None, + status: Status::None + }) + } else { + errno!(ENOSYS, "unimplemented unix socket type") + } + } + + /// Server 2: Bind the socket to a file system path + pub fn bind(&mut self, path: impl AsRef) -> Result<(), Error> { + // TODO: check permission + if self.obj.is_some() { + return errno!(EINVAL, "The socket is already bound to an address."); + } + self.obj = Some(UnixSocketObject::create(path)?); + Ok(()) + } + + /// Server 3: Listen to a socket + pub fn listen(&mut self) -> Result<(), Error> { + self.status = Status::Listening; + Ok(()) + } + + /// Server 4: Accept a connection on listening. Non-blocking. + pub fn accept(&mut self) -> Result { + match self.status { + Status::Listening => {} + _ => return errno!(EINVAL, "unix socket is not listening"), + }; + let socket = self.obj.as_mut().unwrap().pop() + .ok_or(Error::new(EAGAIN, "no connections are present to be accepted"))?; + Ok(socket) + } + + /// Client 2: Connect to a path + pub fn connect(&mut self, path: impl AsRef) -> Result<(), Error> { + if let Status::Listening = self.status { + return errno!(EINVAL, "unix socket is listening?"); + } + let obj = UnixSocketObject::get(path) + .ok_or(Error::new(EINVAL, "unix socket path not found"))?; + let (channel1, channel2) = Channel::new_pair(); + self.status = Status::Connected(channel1); + obj.push(UnixSocket { + obj: Some(obj.clone()), + status: Status::Connected(channel2), + }); + Ok(()) + } + + pub fn read(&self, buf: &mut [u8]) -> Result { + if let Status::Connected(channel) = &self.status { + channel.reader.read(buf) + } else { + errno!(EBADF, "UnixSocket is not connected") + } + } + + pub fn write(&self, buf: &[u8]) -> Result { + if let Status::Connected(channel) = &self.status { + channel.writer.write(buf) + } else { + errno!(EBADF, "UnixSocket is not connected") + } + } +} + +impl Drop for UnixSocket { + fn drop(&mut self) { + if let Status::Listening = self.status { + let path = &self.obj.as_ref().unwrap().path; + UnixSocketObject::remove(path); + } + } +} + +pub struct UnixSocketObject { + path: String, + accepted_sockets: Mutex>, +} + +impl UnixSocketObject { + fn push(&self, unix_socket: UnixSocket) { + let mut queue = self.accepted_sockets.lock().unwrap(); + queue.push_back(unix_socket); + } + fn pop(&self) -> Option { + let mut queue = self.accepted_sockets.lock().unwrap(); + queue.pop_front() + } + fn get(path: impl AsRef) -> Option> { + let mut paths = UNIX_SOCKET_OBJS.lock().unwrap(); + paths.get(path.as_ref()).map(|obj| obj.clone()) + } + fn create(path: impl AsRef) -> Result, Error> { + let mut paths = UNIX_SOCKET_OBJS.lock().unwrap(); + if paths.contains_key(path.as_ref()) { + return errno!(EADDRINUSE, "unix socket path already exists"); + } + let obj = Arc::new(UnixSocketObject { + path: path.as_ref().to_string(), + accepted_sockets: Mutex::new(VecDeque::new()) + }); + paths.insert(path.as_ref().to_string(), obj.clone()); + Ok(obj) + } + fn remove(path: impl AsRef) { + let mut paths = UNIX_SOCKET_OBJS.lock().unwrap(); + paths.remove(path.as_ref()); + } +} + +struct Channel { + reader: RingBufReader, + writer: RingBufWriter +} + +unsafe impl Send for Channel {} +unsafe impl Sync for Channel {} + +impl Channel { + fn new_pair() -> (Channel, Channel) { + let buf1 = RingBuf::new(DEFAULT_BUF_SIZE); + let buf2 = RingBuf::new(DEFAULT_BUF_SIZE); + let channel1 = Channel { + reader: buf1.reader, + writer: buf2.writer, + }; + let channel2 = Channel { + reader: buf2.reader, + writer: buf1.writer, + }; + (channel1, channel2) + } +} + +pub const DEFAULT_BUF_SIZE: usize = 1 * 1024 * 1024; + +lazy_static! { + static ref UNIX_SOCKET_OBJS: Mutex>> + = Mutex::new(BTreeMap::new()); +} diff --git a/src/libos/src/prelude.rs b/src/libos/src/prelude.rs index 74235313..7cddd8ce 100644 --- a/src/libos/src/prelude.rs +++ b/src/libos/src/prelude.rs @@ -36,7 +36,7 @@ macro_rules! debug_trace { macro_rules! errno { ($errno: ident, $msg: expr) => {{ - println!( + error!( "ERROR: {} ({}, line {} in file {})", $errno, $msg, @@ -54,7 +54,7 @@ macro_rules! try_libc { if ret == -1 { let errno = unsafe { libc::errno() }; // println will cause libc ocall and overwrite errno - println!( + error!( "ERROR from libc: {} (line {} in file {})", errno, line!(), diff --git a/src/libos/src/process/exit.rs b/src/libos/src/process/exit.rs index 621473cc..ab99ba03 100644 --- a/src/libos/src/process/exit.rs +++ b/src/libos/src/process/exit.rs @@ -101,7 +101,7 @@ pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Res waiter }; - let child_pid = Waiter::sleep_until_woken_with_result(waiter); + let child_pid = waiter.sleep_until_woken_with_result(); let mut current = current_ref.lock().unwrap(); let child_i = { diff --git a/src/libos/src/process/spawn/init_vm.rs b/src/libos/src/process/spawn/init_vm.rs index 0a4d0442..246a870a 100644 --- a/src/libos/src/process/spawn/init_vm.rs +++ b/src/libos/src/process/spawn/init_vm.rs @@ -4,8 +4,8 @@ use std::ptr; use xmas_elf::{header, program, sections, ElfFile}; pub const DEFAULT_STACK_SIZE: usize = 1 * 1024 * 1024; -pub const DEFAULT_HEAP_SIZE: usize = 2 * 1024 * 1024; -pub const DEFAULT_MMAP_SIZE: usize = 8 * 1024 * 1024; +pub const DEFAULT_HEAP_SIZE: usize = 10 * 1024 * 1024; +pub const DEFAULT_MMAP_SIZE: usize = 40 * 1024 * 1024; pub fn do_init(elf_file: &ElfFile, elf_buf: &[u8]) -> Result { let mut code_seg = get_code_segment(elf_file)?; diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index fee26df7..d2bb6551 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -113,7 +113,8 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result { - cloned_file_table.del(fd)?; + // ignore error + cloned_file_table.del(fd); } } } diff --git a/src/libos/src/process/wait.rs b/src/libos/src/process/wait.rs index a753ee9d..23282195 100644 --- a/src/libos/src/process/wait.rs +++ b/src/libos/src/process/wait.rs @@ -48,14 +48,14 @@ where self.inner.lock().unwrap().data } - pub fn sleep_until_woken_with_result(waiter: Waiter) -> R { - while !waiter.inner.lock().unwrap().is_woken { + pub fn sleep_until_woken_with_result(self) -> R { + while !self.inner.lock().unwrap().is_woken { unsafe { - wait_event(waiter.thread); + wait_event(self.thread); } } - waiter.inner.lock().unwrap().result.unwrap() + self.inner.lock().unwrap().result.unwrap() } } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 8587a145..42df50de 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,7 +7,7 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::{AccessFlags, AccessModes, FcntlCmd, File, FileDesc, FileRef, SocketFile, AT_FDCWD}; +use fs::*; use misc::{resource_t, rlimit_t, utsname_t}; use prelude::*; use process::{pid_t, ChildProcessFilter, CloneFlags, FileAction, FutexFlags, FutexOp}; @@ -48,10 +48,15 @@ pub extern "C" fn dispatch_syscall( ); #[cfg(feature = "syscall_timing")] let time_start = { - if crate::process::current_pid() == 1 && num == SYS_EXIT { - print_syscall_timing(); + static mut LAST_PRINT: usize = 0; + let time = crate::time::do_gettimeofday().as_usec(); + unsafe { + if time / 1000000 / 5 > LAST_PRINT { + LAST_PRINT = time / 1000000 / 5; + print_syscall_timing(); + } } - crate::time::do_gettimeofday().as_usec() + time }; let ret = match num { @@ -248,6 +253,11 @@ pub extern "C" fn dispatch_syscall( arg3 as *mut c_void, arg4 as *mut libc::socklen_t, ), + SYS_GETPEERNAME => do_getpeername( + arg0 as c_int, + arg1 as *mut libc::sockaddr, + arg2 as *mut libc::socklen_t, + ), SYS_SENDTO => do_sendto( arg0 as c_int, arg1 as *const c_void, @@ -295,6 +305,9 @@ fn print_syscall_timing() { } println!("{:>3}: {:>6} us", i, time); } + for x in unsafe { SYSCALL_TIMING.iter_mut() } { + *x = 0; + } } #[allow(non_camel_case_types)] @@ -936,8 +949,16 @@ fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result> = Arc::new(Box::new(socket)); + let file_ref: Arc> = match domain { +// libc::AF_LOCAL => { +// let unix_socket = UnixSocketFile::new(socket_type, protocol)?; +// Arc::new(Box::new(unix_socket)) +// } + _ => { + let socket = SocketFile::new(domain, socket_type, protocol)?; + Arc::new(Box::new(socket)) + } + }; let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); @@ -958,10 +979,18 @@ fn do_connect( let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; - let socket = file_ref.as_socket()?; - - let ret = try_libc!(libc::ocall::connect(socket.fd(), addr, addr_len)); - Ok(ret as isize) + if let Ok(socket) = file_ref.as_socket() { + let ret = try_libc!(libc::ocall::connect(socket.fd(), addr, addr_len)); + Ok(ret as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + let addr = addr as *const libc::sockaddr_un; + check_ptr(addr)?; // TODO: check addr_len + let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?.to_string_lossy().into_owned(); + unix_socket.connect(path)?; + Ok(0) + } else { + errno!(EBADF, "not a socket") + } } fn do_accept4( @@ -977,13 +1006,26 @@ fn do_accept4( let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; - let socket = file_ref.as_socket()?; + if let Ok(socket) = file_ref.as_socket() { + let socket = file_ref.as_socket()?; - let new_socket = socket.accept(addr, addr_len, flags)?; - let new_file_ref: Arc> = Arc::new(Box::new(new_socket)); - let new_fd = proc.get_files().lock().unwrap().put(new_file_ref, false); + let new_socket = socket.accept(addr, addr_len, flags)?; + let new_file_ref: Arc> = Arc::new(Box::new(new_socket)); + let new_fd = proc.get_files().lock().unwrap().put(new_file_ref, false); - Ok(new_fd as isize) + Ok(new_fd as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + let addr = addr as *mut libc::sockaddr_un; + check_mut_ptr(addr)?; // TODO: check addr_len + + let new_socket = unix_socket.accept()?; + let new_file_ref: Arc> = Arc::new(Box::new(new_socket)); + let new_fd = proc.get_files().lock().unwrap().put(new_file_ref, false); + + Ok(0) + } else { + errno!(EBADF, "not a socket") + } } fn do_shutdown(fd: c_int, how: c_int) -> Result { @@ -991,10 +1033,12 @@ fn do_shutdown(fd: c_int, how: c_int) -> Result { let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; - let socket = file_ref.as_socket()?; - - let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how)); - Ok(ret as isize) + if let Ok(socket) = file_ref.as_socket() { + let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how)); + Ok(ret as isize) + } else { + errno!(EBADF, "not a socket") + } } fn do_bind( @@ -1006,10 +1050,19 @@ fn do_bind( let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; - let socket = file_ref.as_socket()?; - - let ret = try_libc!(libc::ocall::bind(socket.fd(), addr, addr_len)); - Ok(ret as isize) + if let Ok(socket) = file_ref.as_socket() { + check_ptr(addr)?; // TODO: check addr_len + let ret = try_libc!(libc::ocall::bind(socket.fd(), addr, addr_len)); + Ok(ret as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + let addr = addr as *const libc::sockaddr_un; + check_ptr(addr)?; // TODO: check addr_len + let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?.to_string_lossy().into_owned(); + unix_socket.bind(path)?; + Ok(0) + } else { + errno!(EBADF, "not a socket") + } } fn do_listen(fd: c_int, backlog: c_int) -> Result { @@ -1017,10 +1070,15 @@ fn do_listen(fd: c_int, backlog: c_int) -> Result { let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; - let socket = file_ref.as_socket()?; - - let ret = try_libc!(libc::ocall::listen(socket.fd(), backlog)); - Ok(ret as isize) + if let Ok(socket) = file_ref.as_socket() { + let ret = try_libc!(libc::ocall::listen(socket.fd(), backlog)); + Ok(ret as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + unix_socket.listen()?; + Ok(0) + } else { + errno!(EBADF, "not a socket") + } } fn do_setsockopt( @@ -1037,16 +1095,21 @@ fn do_setsockopt( let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; - let socket = file_ref.as_socket()?; - - let ret = try_libc!(libc::ocall::setsockopt( - socket.fd(), - level, - optname, - optval, - optlen - )); - Ok(ret as isize) + if let Ok(socket) = file_ref.as_socket() { + let ret = try_libc!(libc::ocall::setsockopt( + socket.fd(), + level, + optname, + optval, + optlen + )); + Ok(ret as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + warn!("setsockopt for unix socket is unimplemented"); + Ok(0) + } else { + errno!(EBADF, "not a socket") + } } fn do_getsockopt( @@ -1075,6 +1138,25 @@ fn do_getsockopt( Ok(ret as isize) } +fn do_getpeername( + fd: c_int, + addr: *mut libc::sockaddr, + addr_len: *mut libc::socklen_t, +) -> Result { + info!("getpeername: fd: {}, addr: {:?}, addr_len: {:?}", fd, addr, addr_len); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + let socket = file_ref.as_socket()?; + + let ret = try_libc!(libc::ocall::getpeername( + socket.fd(), + addr, + addr_len + )); + Ok(ret as isize) +} + fn do_sendto( fd: c_int, base: *const c_void, @@ -1230,18 +1312,6 @@ fn do_epoll_wait( Ok(count as isize) } -pub trait AsSocket { - fn as_socket(&self) -> Result<&SocketFile, Error>; -} - -impl AsSocket for FileRef { - fn as_socket(&self) -> Result<&SocketFile, Error> { - self.as_any() - .downcast_ref::() - .ok_or(Error::new(Errno::EBADF, "not a socket")) - } -} - fn do_uname(name: *mut utsname_t) -> Result { check_mut_ptr(name)?; let name = unsafe { &mut *name }; diff --git a/src/libos/src/vm/vm_space_prealloced.c b/src/libos/src/vm/vm_space_prealloced.c index 62fba785..60f81a87 100644 --- a/src/libos/src/vm/vm_space_prealloced.c +++ b/src/libos/src/vm/vm_space_prealloced.c @@ -1,6 +1,6 @@ #include -#define DATA_SPACE_SIZE (96*1024*1024) +#define DATA_SPACE_SIZE (128*1024*1024) static char __prealloced_data_space[DATA_SPACE_SIZE] __attribute__ (( From 9797a64f06e9c234c182284b6242392329e48d39 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 24 Apr 2019 13:28:35 +0800 Subject: [PATCH 32/37] enable unix socket and add test for it --- src/libos/src/syscall/mod.rs | 31 ++++++---- test/Makefile | 2 +- test/unix_socket/Makefile | 5 ++ test/unix_socket/main.c | 117 +++++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 test/unix_socket/Makefile create mode 100644 test/unix_socket/main.c diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 42df50de..fd460417 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -950,10 +950,10 @@ fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result> = match domain { -// libc::AF_LOCAL => { -// let unix_socket = UnixSocketFile::new(socket_type, protocol)?; -// Arc::new(Box::new(unix_socket)) -// } + libc::AF_LOCAL => { + let unix_socket = UnixSocketFile::new(socket_type, protocol)?; + Arc::new(Box::new(unix_socket)) + } _ => { let socket = SocketFile::new(domain, socket_type, protocol)?; Arc::new(Box::new(socket)) @@ -1022,7 +1022,7 @@ fn do_accept4( let new_file_ref: Arc> = Arc::new(Box::new(new_socket)); let new_fd = proc.get_files().lock().unwrap().put(new_file_ref, false); - Ok(0) + Ok(new_fd as isize) } else { errno!(EBADF, "not a socket") } @@ -1147,14 +1147,19 @@ fn do_getpeername( let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; - let socket = file_ref.as_socket()?; - - let ret = try_libc!(libc::ocall::getpeername( - socket.fd(), - addr, - addr_len - )); - Ok(ret as isize) + if let Ok(socket) = file_ref.as_socket() { + let ret = try_libc!(libc::ocall::getpeername( + socket.fd(), + addr, + addr_len + )); + Ok(ret as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + warn!("getpeername for unix socket is unimplemented"); + Ok(0) + } else { + errno!(EBADF, "not a socket") + } } fn do_sendto( diff --git a/test/Makefile b/test/Makefile index 4d4ca4cb..135435a2 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) # Dependencies: need to be compiled but not to run by any Makefile target TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target -TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll +TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket # Benchmarks: need to be compiled and run by bench-% target BENCHES := spawn_and_exit_latency pipe_throughput diff --git a/test/unix_socket/Makefile b/test/unix_socket/Makefile new file mode 100644 index 00000000..8c5a2fb4 --- /dev/null +++ b/test/unix_socket/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := -Wno-incompatible-pointer-types-discards-qualifiers +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/unix_socket/main.c b/test/unix_socket/main.c new file mode 100644 index 00000000..a00c2eb4 --- /dev/null +++ b/test/unix_socket/main.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char SOCK_PATH[] = "echo_socket"; + +int create_server_socket() { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + printf("ERROR: failed to create a unix socket"); + return -1; + } + + struct sockaddr_un local; + local.sun_family = AF_UNIX; + strcpy(local.sun_path, SOCK_PATH); + socklen_t len = strlen(local.sun_path) + sizeof(local.sun_family); + + if (bind(fd, (struct sockaddr *)&local, len) == -1) { + printf("ERROR: failed to bind\n"); + return -1; + } + + if (listen(fd, 5) == -1) { + printf("ERROR: failed to listen\n"); + return -1; + } + return fd; +} + +int create_client_socket() { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + printf("ERROR: failed to create a unix socket"); + return -1; + } + + struct sockaddr_un remote; + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH); + socklen_t len = strlen(remote.sun_path) + sizeof(remote.sun_family); + + if (connect(fd, (struct sockaddr *)&remote, len) == -1) { + printf("ERROR: failed to connect\n"); + return -1; + } + return fd; +} + +int main(int argc, const char* argv[]) { + // XXX: this is a hack! remove this in the future + void* ptr = malloc(64); + free(ptr); + + int listen_fd = create_server_socket(); + if (listen_fd == -1) { + printf("ERROR: failed to create server socket"); + return -1; + } + + int socket_rd_fd = create_client_socket(); + if (socket_rd_fd == -1) { + printf("ERROR: failed to create client socket"); + return -1; + } + + struct sockaddr_un remote; + socklen_t len = sizeof(remote); + int socket_wr_fd = accept(listen_fd, (struct sockaddr *)&remote, &len); + if (socket_wr_fd == -1) { + printf("ERROR: failed to accept socket"); + return -1; + } + + // The following is same as 'pipe' + + posix_spawn_file_actions_t file_actions; + posix_spawn_file_actions_init(&file_actions); + posix_spawn_file_actions_adddup2(&file_actions, socket_wr_fd, STDOUT_FILENO); + posix_spawn_file_actions_addclose(&file_actions, socket_rd_fd); + + const char* msg = "Echo!\n"; + const char* child_prog = "hello_world"; + const char* child_argv[3] = { child_prog, msg, NULL }; + int child_pid; + if (posix_spawn(&child_pid, child_prog, &file_actions, + NULL, child_argv, NULL) < 0) { + printf("ERROR: failed to spawn a child process\n"); + return -1; + } + close(socket_wr_fd); + + const char* expected_str = msg; + size_t expected_len = strlen(expected_str); + char actual_str[32] = {0}; + ssize_t actual_len; + do { + actual_len = read(socket_rd_fd, actual_str, sizeof(actual_str) - 1); + } while (actual_len == 0); + if (strncmp(expected_str, actual_str, expected_len) != 0) { + printf("ERROR: received string is not as expected\n"); + return -1; + } + + int status = 0; + if (wait4(child_pid, &status, 0, NULL) < 0) { + printf("ERROR: failed to wait4 the child process\n"); + return -1; + } + return 0; +} From cccc1cfb588bf555ae409767747d7b6e6c752c9a Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 24 Apr 2019 13:41:01 +0800 Subject: [PATCH 33/37] add unix socket bench --- test/Makefile | 2 +- test/unix_socket/main.c | 4 - test/unix_socket_throughput/Makefile | 5 + test/unix_socket_throughput/main.c | 153 +++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 test/unix_socket_throughput/Makefile create mode 100644 test/unix_socket_throughput/main.c diff --git a/test/Makefile b/test/Makefile index 135435a2..49420478 100644 --- a/test/Makefile +++ b/test/Makefile @@ -6,7 +6,7 @@ TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket # Benchmarks: need to be compiled and run by bench-% target -BENCHES := spawn_and_exit_latency pipe_throughput +BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput # Top-level Makefile targets BUILD_TARGETS := $(TEST_DEPS) $(TESTS) $(BENCHES) diff --git a/test/unix_socket/main.c b/test/unix_socket/main.c index a00c2eb4..4f9af75a 100644 --- a/test/unix_socket/main.c +++ b/test/unix_socket/main.c @@ -54,10 +54,6 @@ int create_client_socket() { } int main(int argc, const char* argv[]) { - // XXX: this is a hack! remove this in the future - void* ptr = malloc(64); - free(ptr); - int listen_fd = create_server_socket(); if (listen_fd == -1) { printf("ERROR: failed to create server socket"); diff --git a/test/unix_socket_throughput/Makefile b/test/unix_socket_throughput/Makefile new file mode 100644 index 00000000..8c5a2fb4 --- /dev/null +++ b/test/unix_socket_throughput/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := -Wno-incompatible-pointer-types-discards-qualifiers +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/unix_socket_throughput/main.c b/test/unix_socket_throughput/main.c new file mode 100644 index 00000000..f8bed173 --- /dev/null +++ b/test/unix_socket_throughput/main.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KB (1024UL) +#define MB (1024UL * 1024UL) +#define GB (1024UL * 1024UL * 1024UL) + +#define TOTAL_BYTES (2 * GB) +#define BUF_SIZE (128 * KB) + +#define MIN(x, y) ((x) <= (y) ? (x) : (y)) + +const char SOCK_PATH[] = "echo_socket"; + +int create_server_socket() { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + printf("ERROR: failed to create a unix socket"); + return -1; + } + + struct sockaddr_un local; + local.sun_family = AF_UNIX; + strcpy(local.sun_path, SOCK_PATH); + socklen_t len = strlen(local.sun_path) + sizeof(local.sun_family); + + if (bind(fd, (struct sockaddr *)&local, len) == -1) { + printf("ERROR: failed to bind\n"); + return -1; + } + + if (listen(fd, 5) == -1) { + printf("ERROR: failed to listen\n"); + return -1; + } + return fd; +} + +int create_client_socket() { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + printf("ERROR: failed to create a unix socket"); + return -1; + } + + struct sockaddr_un remote; + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH); + socklen_t len = strlen(remote.sun_path) + sizeof(remote.sun_family); + + if (connect(fd, (struct sockaddr *)&remote, len) == -1) { + printf("ERROR: failed to connect\n"); + return -1; + } + return fd; +} + +int main(int argc, const char* argv[]) { + int listen_fd = create_server_socket(); + if (listen_fd == -1) { + printf("ERROR: failed to create server socket"); + return -1; + } + + int socket_rd_fd = create_client_socket(); + if (socket_rd_fd == -1) { + printf("ERROR: failed to create client socket"); + return -1; + } + + struct sockaddr_un remote; + socklen_t len = sizeof(remote); + int socket_wr_fd = accept(listen_fd, (struct sockaddr *)&remote, &len); + if (socket_wr_fd == -1) { + printf("ERROR: failed to accept socket"); + return -1; + } + + // The following is same as 'pipe_throughput' + + // Spawn a child process that reads from the pipe + posix_spawn_file_actions_t file_actions; + posix_spawn_file_actions_init(&file_actions); + posix_spawn_file_actions_adddup2(&file_actions, socket_rd_fd, STDIN_FILENO); + posix_spawn_file_actions_addclose(&file_actions, socket_wr_fd); + + int child_pid; + if (posix_spawn(&child_pid, "dev_null", &file_actions, + NULL, NULL, NULL) < 0) { + printf("ERROR: failed to spawn a child process\n"); + return -1; + } + close(socket_rd_fd); + + // Start the timer + struct timeval tv_start, tv_end; + gettimeofday(&tv_start, NULL); + + // Tell the reader how many data are to be transfered + size_t remain_bytes = TOTAL_BYTES; + if (write(socket_wr_fd, &remain_bytes, sizeof(remain_bytes)) != sizeof(remain_bytes)) { + printf("ERROR: failed to write to pipe\n"); + return -1; + } + + // Tell the reader the buffer size that it should use + size_t buf_size = BUF_SIZE; + if (write(socket_wr_fd, &buf_size, sizeof(buf_size)) != sizeof(buf_size)) { + printf("ERROR: failed to write to pipe\n"); + return -1; + } + + // Write a specified amount of data in a buffer of specified size + char buf[BUF_SIZE] = {0}; + while (remain_bytes > 0) { + size_t len = MIN(buf_size, remain_bytes); + if ((len = write(socket_wr_fd, &buf, len)) < 0) { + printf("ERROR: failed to write to pipe\n"); + return -1; + } + remain_bytes -= len; + } + + // Wait for the child process to read all data and exit + int status = 0; + if (wait4(child_pid, &status, 0, NULL) < 0) { + printf("ERROR: failed to wait4 the child process\n"); + return -1; + } + + // Stop the timer + gettimeofday(&tv_end, NULL); + + // Calculate the throughput + double total_s = (tv_end.tv_sec - tv_start.tv_sec) + + (double)(tv_end.tv_usec - tv_start.tv_usec) / 1000000; + if (total_s < 1.0) { + printf("WARNING: run long enough to get meaningful results\n"); + if (total_s == 0) { return 0; } + } + double total_mb = (double)TOTAL_BYTES / MB; + double throughput = total_mb / total_s; + printf("Throughput of unix socket is %.2f MB/s\n", throughput); + return 0; +} From 3850c3123545e41107297d9a3e3d002a003d0d66 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 24 Apr 2019 15:28:05 +0800 Subject: [PATCH 34/37] fix unix socket bench --- test/unix_socket/main.c | 10 ++++----- test/unix_socket_throughput/main.c | 35 ++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/test/unix_socket/main.c b/test/unix_socket/main.c index 4f9af75a..9d32cdd1 100644 --- a/test/unix_socket/main.c +++ b/test/unix_socket/main.c @@ -13,7 +13,7 @@ const char SOCK_PATH[] = "echo_socket"; int create_server_socket() { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { - printf("ERROR: failed to create a unix socket"); + printf("ERROR: failed to create a unix socket\n"); return -1; } @@ -37,7 +37,7 @@ int create_server_socket() { int create_client_socket() { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { - printf("ERROR: failed to create a unix socket"); + printf("ERROR: failed to create a unix socket\n"); return -1; } @@ -56,13 +56,13 @@ int create_client_socket() { int main(int argc, const char* argv[]) { int listen_fd = create_server_socket(); if (listen_fd == -1) { - printf("ERROR: failed to create server socket"); + printf("ERROR: failed to create server socket\n"); return -1; } int socket_rd_fd = create_client_socket(); if (socket_rd_fd == -1) { - printf("ERROR: failed to create client socket"); + printf("ERROR: failed to create client socket\n"); return -1; } @@ -70,7 +70,7 @@ int main(int argc, const char* argv[]) { socklen_t len = sizeof(remote); int socket_wr_fd = accept(listen_fd, (struct sockaddr *)&remote, &len); if (socket_wr_fd == -1) { - printf("ERROR: failed to accept socket"); + printf("ERROR: failed to accept socket\n"); return -1; } diff --git a/test/unix_socket_throughput/main.c b/test/unix_socket_throughput/main.c index f8bed173..25e8cf5d 100644 --- a/test/unix_socket_throughput/main.c +++ b/test/unix_socket_throughput/main.c @@ -23,13 +23,14 @@ const char SOCK_PATH[] = "echo_socket"; int create_server_socket() { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { - printf("ERROR: failed to create a unix socket"); + printf("ERROR: failed to create a unix socket\n"); return -1; } struct sockaddr_un local; local.sun_family = AF_UNIX; strcpy(local.sun_path, SOCK_PATH); + unlink(local.sun_path); socklen_t len = strlen(local.sun_path) + sizeof(local.sun_family); if (bind(fd, (struct sockaddr *)&local, len) == -1) { @@ -47,7 +48,7 @@ int create_server_socket() { int create_client_socket() { int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { - printf("ERROR: failed to create a unix socket"); + printf("ERROR: failed to create a unix socket\n"); return -1; } @@ -64,15 +65,30 @@ int create_client_socket() { } int main(int argc, const char* argv[]) { + size_t buf_size, total_bytes; + if (argc >= 2) { + buf_size = atol(argv[1]); + } else { + buf_size = BUF_SIZE; + } + if (argc >= 3) { + total_bytes = atol(argv[2]); + } else { + // BUG: throughput fall down when buf_size > 65536 + total_bytes = buf_size > 65536? buf_size << 15: buf_size << 21; + } + printf("buf_size = 0x%zx\n", buf_size); + printf("total_bytes = 0x%zx\n", total_bytes); + int listen_fd = create_server_socket(); if (listen_fd == -1) { - printf("ERROR: failed to create server socket"); + printf("ERROR: failed to create server socket\n"); return -1; } int socket_rd_fd = create_client_socket(); if (socket_rd_fd == -1) { - printf("ERROR: failed to create client socket"); + printf("ERROR: failed to create client socket\n"); return -1; } @@ -80,7 +96,7 @@ int main(int argc, const char* argv[]) { socklen_t len = sizeof(remote); int socket_wr_fd = accept(listen_fd, (struct sockaddr *)&remote, &len); if (socket_wr_fd == -1) { - printf("ERROR: failed to accept socket"); + printf("ERROR: failed to accept socket\n"); return -1; } @@ -93,8 +109,10 @@ int main(int argc, const char* argv[]) { posix_spawn_file_actions_addclose(&file_actions, socket_wr_fd); int child_pid; + extern char ** environ; + const char* new_argv[] = {"./dev_null", NULL}; if (posix_spawn(&child_pid, "dev_null", &file_actions, - NULL, NULL, NULL) < 0) { + NULL, new_argv, environ) < 0) { printf("ERROR: failed to spawn a child process\n"); return -1; } @@ -105,14 +123,13 @@ int main(int argc, const char* argv[]) { gettimeofday(&tv_start, NULL); // Tell the reader how many data are to be transfered - size_t remain_bytes = TOTAL_BYTES; + size_t remain_bytes = total_bytes; if (write(socket_wr_fd, &remain_bytes, sizeof(remain_bytes)) != sizeof(remain_bytes)) { printf("ERROR: failed to write to pipe\n"); return -1; } // Tell the reader the buffer size that it should use - size_t buf_size = BUF_SIZE; if (write(socket_wr_fd, &buf_size, sizeof(buf_size)) != sizeof(buf_size)) { printf("ERROR: failed to write to pipe\n"); return -1; @@ -146,7 +163,7 @@ int main(int argc, const char* argv[]) { printf("WARNING: run long enough to get meaningful results\n"); if (total_s == 0) { return 0; } } - double total_mb = (double)TOTAL_BYTES / MB; + double total_mb = (double)total_bytes / MB; double throughput = total_mb / total_s; printf("Throughput of unix socket is %.2f MB/s\n", throughput); return 0; From dd3de96b8e4f49c3f352853fc8338613edeb2ae9 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 24 Apr 2019 19:25:09 +0800 Subject: [PATCH 35/37] hack unix socket for php --- src/libos/src/fs/io_multiplexing.rs | 53 +++++++++++++++++++++++++++-- src/libos/src/fs/unix_socket.rs | 53 ++++++++++++++++++++++++----- src/libos/src/syscall/mod.rs | 33 ++++++++++++++++++ src/libos/src/util/ring_buf.rs | 25 ++++++++++++++ 4 files changed, 152 insertions(+), 12 deletions(-) diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 419a1ab8..0856a18f 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -3,6 +3,7 @@ use std::any::Any; use std::collections::btree_map::BTreeMap; use std::fmt; use std::vec::Vec; +use std::sync::atomic::spin_loop_hint; /// Forward to host `poll` /// (sgx_libc doesn't have `select`) @@ -13,6 +14,7 @@ pub fn do_select( exceptfds: &mut libc::fd_set, timeout: Option, ) -> Result { + info!("select: nfds: {}", nfds); // convert libos fd to Linux fd let mut host_to_libos_fd = [0; libc::FD_SETSIZE]; let mut polls = Vec::::new(); @@ -30,6 +32,29 @@ pub fn do_select( if !(r || w || e) { continue; } + if let Ok(socket) = file_table_ref.get(fd as FileDesc)?.as_unix_socket() { + warn!("select unix socket is unimplemented, spin for read"); + readfds.clear(); + writefds.clear(); + exceptfds.clear(); + + // FIXME: spin poll until can read (hack for php) + while r && socket.poll()?.0 == false { + spin_loop_hint(); + } + + let (rr, ww, ee) = socket.poll()?; + if r && rr { + readfds.set(fd); + } + if w && ww { + writefds.set(fd); + } + if e && ee { + writefds.set(fd); + } + return Ok(1); + } let host_fd = file_table_ref.get(fd as FileDesc)?.as_socket()?.fd(); host_to_libos_fd[host_fd as usize] = fd; @@ -80,7 +105,7 @@ pub fn do_select( } pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result { - info!("poll: [..], timeout: {}", timeout); + info!("poll: {:?}, timeout: {}", polls.iter().map(|p| p.fd).collect::>(), timeout); let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); @@ -88,8 +113,30 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result @@ -127,6 +128,16 @@ impl UnixSocketFile { let mut inner = self.inner.lock().unwrap(); inner.connect(path) } + + pub fn poll(&self) -> Result<(bool, bool, bool), Error> { + let mut inner = self.inner.lock().unwrap(); + inner.poll() + } + + pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<(), Error> { + let mut inner = self.inner.lock().unwrap(); + inner.ioctl(cmd, argp) + } } impl Debug for UnixSocketFile { @@ -189,14 +200,19 @@ impl UnixSocket { Ok(()) } - /// Server 4: Accept a connection on listening. Non-blocking. + /// Server 4: Accept a connection on listening. pub fn accept(&mut self) -> Result { match self.status { Status::Listening => {} _ => return errno!(EINVAL, "unix socket is not listening"), }; - let socket = self.obj.as_mut().unwrap().pop() - .ok_or(Error::new(EAGAIN, "no connections are present to be accepted"))?; + // FIXME: Block. Now spin loop. + let socket = loop { + if let Some(socket) = self.obj.as_mut().unwrap().pop() { + break socket; + } + spin_loop_hint(); + }; Ok(socket) } @@ -217,16 +233,35 @@ impl UnixSocket { } pub fn read(&self, buf: &mut [u8]) -> Result { - if let Status::Connected(channel) = &self.status { - channel.reader.read(buf) - } else { - errno!(EBADF, "UnixSocket is not connected") - } + self.channel()?.reader.read(buf) } pub fn write(&self, buf: &[u8]) -> Result { + self.channel()?.writer.write(buf) + } + + pub fn poll(&self) -> Result<(bool, bool, bool), Error> { // (read, write, error) + let channel = self.channel()?; + let r = channel.reader.can_read(); + let w = channel.writer.can_write(); + Ok((r, w, false)) + } + + pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<(), Error> { + const FIONREAD: c_int = 0x541B; // Get the number of bytes to read + if cmd == FIONREAD { + let bytes_to_read = self.channel()?.reader.bytes_to_read(); + unsafe { argp.write(bytes_to_read as c_int); } + Ok(()) + } else { + warn!("ioctl for unix socket is unimplemented"); + errno!(ENOSYS, "ioctl for unix socket is unimplemented") + } + } + + fn channel(&self) -> Result<&Channel, Error> { if let Status::Connected(channel) = &self.status { - channel.writer.write(buf) + Ok(channel) } else { errno!(EBADF, "UnixSocket is not connected") } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index fd460417..cb992656 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -258,6 +258,11 @@ pub extern "C" fn dispatch_syscall( arg1 as *mut libc::sockaddr, arg2 as *mut libc::socklen_t, ), + SYS_GETSOCKNAME => do_getsockname( + arg0 as c_int, + arg1 as *mut libc::sockaddr, + arg2 as *mut libc::socklen_t, + ), SYS_SENDTO => do_sendto( arg0 as c_int, arg1 as *const c_void, @@ -926,6 +931,10 @@ fn do_ioctl(fd: FileDesc, cmd: c_int, argp: *mut c_int) -> Result if let Ok(socket) = file_ref.as_socket() { let ret = try_libc!(libc::ocall::ioctl_arg1(socket.fd(), cmd, argp)); Ok(ret as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + // TODO: check argp + unix_socket.ioctl(cmd, argp)?; + Ok(0) } else { warn!("ioctl is unimplemented"); errno!(ENOSYS, "ioctl is unimplemented") @@ -1156,6 +1165,30 @@ fn do_getpeername( Ok(ret as isize) } else if let Ok(unix_socket) = file_ref.as_unix_socket() { warn!("getpeername for unix socket is unimplemented"); + errno!(ENOTCONN, "hack for php: Transport endpoint is not connected") + } else { + errno!(EBADF, "not a socket") + } +} + +fn do_getsockname( + fd: c_int, + addr: *mut libc::sockaddr, + addr_len: *mut libc::socklen_t, +) -> Result { + info!("getsockname: fd: {}, addr: {:?}, addr_len: {:?}", fd, addr, addr_len); + let current_ref = process::get_current(); + let mut proc = current_ref.lock().unwrap(); + let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; + if let Ok(socket) = file_ref.as_socket() { + let ret = try_libc!(libc::ocall::getsockname( + socket.fd(), + addr, + addr_len + )); + Ok(ret as isize) + } else if let Ok(unix_socket) = file_ref.as_unix_socket() { + warn!("getsockname for unix socket is unimplemented"); Ok(0) } else { errno!(EBADF, "not a socket") diff --git a/src/libos/src/util/ring_buf.rs b/src/libos/src/util/ring_buf.rs index 56afe700..045e1e4e 100644 --- a/src/libos/src/util/ring_buf.rs +++ b/src/libos/src/util/ring_buf.rs @@ -155,6 +155,20 @@ impl RingBufReader { } Ok(buf_pos) } + + pub fn can_read(&self) -> bool { + self.bytes_to_read() != 0 + } + + pub fn bytes_to_read(&self) -> usize { + let tail = self.inner.get_tail(); + let head = self.inner.get_head(); + if tail <= head { + head - tail + } else { + self.inner.capacity - tail + head + } + } } impl Drop for RingBufReader { @@ -202,4 +216,15 @@ impl RingBufWriter { } Ok(buf_pos) } + + pub fn can_write(&self) -> bool { + let tail = self.inner.get_tail(); + let head = self.inner.get_head(); + let may_write_nbytes = if tail <= head { + self.inner.capacity - head + } else { + tail - head - 1 + }; + may_write_nbytes != 0 + } } From 6e871f7948582c0dde3e370480b785dca0d4f879 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 26 Apr 2019 21:25:55 +0800 Subject: [PATCH 36/37] reformat code using `cargo fmt` --- src/libos/src/entry.rs | 2 +- src/libos/src/errno.rs | 5 +- src/libos/src/fs/access.rs | 16 +++-- src/libos/src/fs/file.rs | 4 +- src/libos/src/fs/file_table.rs | 16 +++-- src/libos/src/fs/inode_file.rs | 2 +- src/libos/src/fs/io_multiplexing.rs | 42 ++++++++---- src/libos/src/fs/mod.rs | 40 +++++------ src/libos/src/fs/sgx_impl.rs | 6 +- src/libos/src/fs/socket_file.rs | 19 ++++-- src/libos/src/fs/unix_socket.rs | 41 +++++++----- src/libos/src/lib.rs | 2 +- src/libos/src/misc/mod.rs | 6 +- src/libos/src/misc/rlimit.rs | 60 ++++++++--------- src/libos/src/misc/uname.rs | 5 +- src/libos/src/prelude.rs | 2 +- src/libos/src/process/arch_prctl.rs | 22 +++--- src/libos/src/process/exit.rs | 4 +- src/libos/src/process/futex.rs | 51 +++++++------- src/libos/src/process/mod.rs | 20 +++--- src/libos/src/process/process.rs | 2 +- src/libos/src/process/process_table.rs | 5 +- src/libos/src/process/spawn/mod.rs | 21 ++++-- src/libos/src/process/thread.rs | 11 +-- src/libos/src/syscall/mod.rs | 40 +++++------ src/libos/src/util/ring_buf.rs | 2 +- src/libos/src/vm/mod.rs | 18 ++--- src/libos/src/vm/process_vm.rs | 93 ++++++++++++++++++-------- src/libos/src/vm/vm_area.rs | 6 +- src/libos/src/vm/vm_range.rs | 49 +++++++++----- 30 files changed, 362 insertions(+), 250 deletions(-) diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 6bad71a2..66e34afb 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -68,7 +68,7 @@ fn parse_arguments( // TODO: make sure do_boot can only be called once fn do_boot(path_str: &str, argv: &Vec) -> Result<(), Error> { -// info!("boot: path: {:?}, argv: {:?}", path_str, argv); + // info!("boot: path: {:?}, argv: {:?}", path_str, argv); util::mpx_util::mpx_enable()?; let envp = std::vec::Vec::new(); diff --git a/src/libos/src/errno.rs b/src/libos/src/errno.rs index 11a70f45..c00f39e3 100644 --- a/src/libos/src/errno.rs +++ b/src/libos/src/errno.rs @@ -24,7 +24,10 @@ impl convert::From<(Errno, &'static str)> for Error { impl convert::From for Error { fn from(info: std::io::Error) -> Error { - Error::new(Errno::from_errno(info.raw_os_error().unwrap()), "std::io::Error") + Error::new( + Errno::from_errno(info.raw_os_error().unwrap()), + "std::io::Error", + ) } } diff --git a/src/libos/src/fs/access.rs b/src/libos/src/fs/access.rs index d4cb347d..201c6864 100644 --- a/src/libos/src/fs/access.rs +++ b/src/libos/src/fs/access.rs @@ -17,7 +17,6 @@ impl AccessModes { } } - bitflags! { pub struct AccessFlags : u32 { const AT_SYMLINK_NOFOLLOW = 0x100; @@ -31,11 +30,18 @@ impl AccessFlags { } } +pub const AT_FDCWD: i32 = -100; -pub const AT_FDCWD : i32 = -100; - -pub fn do_faccessat(dirfd: Option, path: &str, mode: AccessModes, flags: AccessFlags) -> Result<(), Error> { - info!("faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}", dirfd, path, mode, flags); +pub fn do_faccessat( + dirfd: Option, + path: &str, + mode: AccessModes, + flags: AccessFlags, +) -> Result<(), Error> { + info!( + "faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}", + dirfd, path, mode, flags + ); match dirfd { // TODO: handle dirfd Some(dirfd) => errno!(ENOSYS, "cannot accept dirfd"), diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index 82ae1e5e..a45a0e24 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -377,7 +377,7 @@ impl File for StdoutFile { mode: 0, nlinks: 0, uid: 0, - gid: 0 + gid: 0, }) } @@ -493,7 +493,7 @@ impl File for StdinFile { mode: 0, nlinks: 0, uid: 0, - gid: 0 + gid: 0, }) } diff --git a/src/libos/src/fs/file_table.rs b/src/libos/src/fs/file_table.rs index 2ff33e33..be80ba4b 100644 --- a/src/libos/src/fs/file_table.rs +++ b/src/libos/src/fs/file_table.rs @@ -19,7 +19,12 @@ impl FileTable { } } - pub fn dup(&mut self, fd: FileDesc, min_fd: FileDesc, close_on_spawn: bool) -> Result { + pub fn dup( + &mut self, + fd: FileDesc, + min_fd: FileDesc, + close_on_spawn: bool, + ) -> Result { let file_ref = self.get(fd)?; let min_fd = min_fd as usize; @@ -34,11 +39,13 @@ impl FileTable { } } - table.iter() + table + .iter() .enumerate() .skip(min_fd as usize) .find(|&(idx, opt)| opt.is_none()) - .unwrap().0 + .unwrap() + .0 } as FileDesc; self.put_at(min_free_fd, file_ref, close_on_spawn); @@ -50,7 +57,8 @@ impl FileTable { let mut table = &mut self.table; let min_free_fd = if self.num_fds < table.len() { - table.iter() + table + .iter() .enumerate() .find(|&(idx, opt)| opt.is_none()) .unwrap() diff --git a/src/libos/src/fs/inode_file.rs b/src/libos/src/fs/inode_file.rs index 9cca09f5..eb17984a 100644 --- a/src/libos/src/fs/inode_file.rs +++ b/src/libos/src/fs/inode_file.rs @@ -2,8 +2,8 @@ use rcore_fs::vfs::{FileSystem, FsError, INode}; use rcore_fs_sefs::SEFS; use std::fmt; -use super::*; use super::sgx_impl::SgxStorage; +use super::*; lazy_static! { /// The root of file system diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/fs/io_multiplexing.rs index 0856a18f..811ad9ef 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/fs/io_multiplexing.rs @@ -2,8 +2,8 @@ use super::*; use std::any::Any; use std::collections::btree_map::BTreeMap; use std::fmt; -use std::vec::Vec; use std::sync::atomic::spin_loop_hint; +use std::vec::Vec; /// Forward to host `poll` /// (sgx_libc doesn't have `select`) @@ -81,7 +81,11 @@ pub fn do_select( Some(tv) => (tv.tv_sec * 1000 + tv.tv_usec / 1000) as i32, }; - let ret = try_libc!(libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout)); + let ret = try_libc!(libc::ocall::poll( + polls.as_mut_ptr(), + polls.len() as u64, + timeout + )); // convert fd back and write fdset readfds.clear(); @@ -105,7 +109,11 @@ pub fn do_select( } pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result { - info!("poll: {:?}, timeout: {}", polls.iter().map(|p| p.fd).collect::>(), timeout); + info!( + "poll: {:?}, timeout: {}", + polls.iter().map(|p| p.fd).collect::>(), + timeout + ); let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); @@ -138,7 +146,11 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result Result<(), Error> { - let ret = - try_libc!(libc::ocall::epoll_ctl(self.epoll_fd, op, host_fd as c_int, event as *mut _)); + let ret = try_libc!(libc::ocall::epoll_ctl( + self.epoll_fd, + op, + host_fd as c_int, + event as *mut _ + )); Ok(()) } @@ -270,14 +286,12 @@ impl EpollFileInner { events: &mut [libc::epoll_event], timeout: c_int, ) -> Result { - let ret = try_libc!( - libc::ocall::epoll_wait( - self.epoll_fd, - events.as_mut_ptr(), - events.len() as c_int, - timeout, - ) - ); + let ret = try_libc!(libc::ocall::epoll_wait( + self.epoll_fd, + events.as_mut_ptr(), + events.len() as c_int, + timeout, + )); Ok(ret as usize) } } diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index ad6c7041..1fd92bb3 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -1,36 +1,35 @@ -use {process, std}; use prelude::*; use process::Process; use rcore_fs::vfs::{FileType, FsError, INode, Metadata, Timespec}; use std::sgxfs as fs_impl; +use {process, std}; use super::*; +pub use self::access::{do_access, do_faccessat, AccessFlags, AccessModes, AT_FDCWD}; pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile}; pub use self::file_table::{FileDesc, FileTable}; -pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; -pub use self::socket_file::{SocketFile, AsSocket}; -pub use self::unix_socket::{UnixSocketFile, AsUnixSocket}; use self::inode_file::OpenOptions; -pub use self::pipe::Pipe; +pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE}; pub use self::io_multiplexing::*; -pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat}; use self::null::NullFile; -use std::mem::uninitialized; +pub use self::pipe::Pipe; +pub use self::socket_file::{AsSocket, SocketFile}; +pub use self::unix_socket::{AsUnixSocket, UnixSocketFile}; use std::any::Any; +use std::mem::uninitialized; +mod access; mod file; mod file_table; mod inode_file; -mod socket_file; +mod io_multiplexing; +mod null; mod pipe; mod sgx_impl; -mod io_multiplexing; -mod access; -mod null; +mod socket_file; mod unix_socket; - pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { let flags = OpenFlags::from_bits_truncate(flags); info!( @@ -46,7 +45,10 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { let fd = { let close_on_spawn = flags.contains(OpenFlags::CLOEXEC); - proc.get_files().lock().unwrap().put(file_ref, close_on_spawn) + proc.get_files() + .lock() + .unwrap() + .put(file_ref, close_on_spawn) }; Ok(fd) } @@ -353,7 +355,8 @@ pub fn do_sendfile( in_fd: FileDesc, offset: Option, count: usize, -) -> Result<(usize, usize), Error> { // (len, offset) +) -> Result<(usize, usize), Error> { + // (len, offset) info!( "sendfile: out: {}, in: {}, offset: {:?}, count: {}", out_fd, in_fd, offset, count @@ -683,7 +686,6 @@ pub unsafe fn write_cstr(ptr: *mut u8, s: &str) { ptr.add(s.len()).write(0); } - #[derive(Debug)] pub enum FcntlCmd { /// Duplicate the file descriptor fd using the lowest-numbered available @@ -727,11 +729,11 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result { FcntlCmd::DupFd(min_fd) => { let dup_fd = files.dup(fd, *min_fd, false)?; dup_fd as isize - }, + } FcntlCmd::DupFdCloexec(min_fd) => { let dup_fd = files.dup(fd, *min_fd, true)?; dup_fd as isize - }, + } FcntlCmd::GetFd() => { let entry = files.get_entry(fd)?; let fd_flags = if entry.is_close_on_spawn() { @@ -740,12 +742,12 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result { 0 }; fd_flags as isize - }, + } FcntlCmd::SetFd(fd_flags) => { let entry = files.get_entry_mut(fd)?; entry.set_close_on_spawn((fd_flags & libc::FD_CLOEXEC as u32) != 0); 0 - }, + } FcntlCmd::GetFl() => { let file = files.get(fd)?; if let Ok(socket) = file.as_socket() { diff --git a/src/libos/src/fs/sgx_impl.rs b/src/libos/src/fs/sgx_impl.rs index f25a4ff2..2f03cac2 100644 --- a/src/libos/src/fs/sgx_impl.rs +++ b/src/libos/src/fs/sgx_impl.rs @@ -2,12 +2,12 @@ use rcore_fs::dev::TimeProvider; use rcore_fs::vfs::Timespec; use rcore_fs_sefs::dev::*; use std::boxed::Box; +use std::collections::BTreeMap; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::sgxfs::{remove, OpenOptions, SgxFile}; -use std::sync::{SgxMutex as Mutex, Arc}; +use std::sync::{Arc, SgxMutex as Mutex}; use std::time::{SystemTime, UNIX_EPOCH}; -use std::collections::BTreeMap; pub struct SgxStorage { path: PathBuf, @@ -19,7 +19,7 @@ impl SgxStorage { // assert!(path.as_ref().is_dir()); SgxStorage { path: path.as_ref().to_path_buf(), - file_cache: Mutex::new(BTreeMap::new()) + file_cache: Mutex::new(BTreeMap::new()), } } /// Get file by `file_id`. diff --git a/src/libos/src/fs/socket_file.rs b/src/libos/src/fs/socket_file.rs index 7391c05b..7e9cbaa7 100644 --- a/src/libos/src/fs/socket_file.rs +++ b/src/libos/src/fs/socket_file.rs @@ -33,19 +33,30 @@ impl Drop for SocketFile { let ret = unsafe { libc::ocall::close(self.fd) }; if ret < 0 { let errno = unsafe { libc::errno() }; - warn!("socket (host fd: {}) close failed: errno = {}", self.fd, errno); + warn!( + "socket (host fd: {}) close failed: errno = {}", + self.fd, errno + ); } } } impl File for SocketFile { fn read(&self, buf: &mut [u8]) -> Result { - let ret = try_libc!(libc::ocall::read(self.fd, buf.as_mut_ptr() as *mut c_void, buf.len())); + let ret = try_libc!(libc::ocall::read( + self.fd, + buf.as_mut_ptr() as *mut c_void, + buf.len() + )); Ok(ret as usize) } fn write(&self, buf: &[u8]) -> Result { - let ret = try_libc!(libc::ocall::write(self.fd, buf.as_ptr() as *const c_void, buf.len())); + let ret = try_libc!(libc::ocall::write( + self.fd, + buf.as_ptr() as *const c_void, + buf.len() + )); Ok(ret as usize) } @@ -103,7 +114,7 @@ impl File for SocketFile { mode: 0, nlinks: 0, uid: 0, - gid: 0 + gid: 0, }) } diff --git a/src/libos/src/fs/unix_socket.rs b/src/libos/src/fs/unix_socket.rs index 5421d115..81b50c17 100644 --- a/src/libos/src/fs/unix_socket.rs +++ b/src/libos/src/fs/unix_socket.rs @@ -1,13 +1,13 @@ use super::*; -use std::collections::btree_map::BTreeMap; -use util::ring_buf::{RingBufReader, RingBufWriter, RingBuf}; -use std::sync::SgxMutex as Mutex; use alloc::prelude::ToString; +use std::collections::btree_map::BTreeMap; use std::fmt; use std::sync::atomic::spin_loop_hint; +use std::sync::SgxMutex as Mutex; +use util::ring_buf::{RingBuf, RingBufReader, RingBufWriter}; pub struct UnixSocketFile { - inner: Mutex + inner: Mutex, } impl File for UnixSocketFile { @@ -77,7 +77,7 @@ impl File for UnixSocketFile { mode: 0, nlinks: 0, uid: 0, - gid: 0 + gid: 0, }) } @@ -105,7 +105,9 @@ impl File for UnixSocketFile { impl UnixSocketFile { pub fn new(socket_type: c_int, protocol: c_int) -> Result { let inner = UnixSocket::new(socket_type, protocol)?; - Ok(UnixSocketFile { inner: Mutex::new(inner) }) + Ok(UnixSocketFile { + inner: Mutex::new(inner), + }) } pub fn bind(&self, path: impl AsRef) -> Result<(), Error> { @@ -121,7 +123,9 @@ impl UnixSocketFile { pub fn accept(&self) -> Result { let mut inner = self.inner.lock().unwrap(); let new_socket = inner.accept()?; - Ok(UnixSocketFile { inner: Mutex::new(new_socket) }) + Ok(UnixSocketFile { + inner: Mutex::new(new_socket), + }) } pub fn connect(&self, path: impl AsRef) -> Result<(), Error> { @@ -146,7 +150,6 @@ impl Debug for UnixSocketFile { } } - pub trait AsUnixSocket { fn as_unix_socket(&self) -> Result<&UnixSocketFile, Error>; } @@ -159,7 +162,6 @@ impl AsUnixSocket for FileRef { } } - pub struct UnixSocket { obj: Option>, status: Status, @@ -177,7 +179,7 @@ impl UnixSocket { if socket_type == libc::SOCK_STREAM && protocol == 0 { Ok(UnixSocket { obj: None, - status: Status::None + status: Status::None, }) } else { errno!(ENOSYS, "unimplemented unix socket type") @@ -221,8 +223,8 @@ impl UnixSocket { if let Status::Listening = self.status { return errno!(EINVAL, "unix socket is listening?"); } - let obj = UnixSocketObject::get(path) - .ok_or(Error::new(EINVAL, "unix socket path not found"))?; + let obj = + UnixSocketObject::get(path).ok_or(Error::new(EINVAL, "unix socket path not found"))?; let (channel1, channel2) = Channel::new_pair(); self.status = Status::Connected(channel1); obj.push(UnixSocket { @@ -240,7 +242,8 @@ impl UnixSocket { self.channel()?.writer.write(buf) } - pub fn poll(&self) -> Result<(bool, bool, bool), Error> { // (read, write, error) + pub fn poll(&self) -> Result<(bool, bool, bool), Error> { + // (read, write, error) let channel = self.channel()?; let r = channel.reader.can_read(); let w = channel.writer.can_write(); @@ -251,7 +254,9 @@ impl UnixSocket { const FIONREAD: c_int = 0x541B; // Get the number of bytes to read if cmd == FIONREAD { let bytes_to_read = self.channel()?.reader.bytes_to_read(); - unsafe { argp.write(bytes_to_read as c_int); } + unsafe { + argp.write(bytes_to_read as c_int); + } Ok(()) } else { warn!("ioctl for unix socket is unimplemented"); @@ -302,7 +307,7 @@ impl UnixSocketObject { } let obj = Arc::new(UnixSocketObject { path: path.as_ref().to_string(), - accepted_sockets: Mutex::new(VecDeque::new()) + accepted_sockets: Mutex::new(VecDeque::new()), }); paths.insert(path.as_ref().to_string(), obj.clone()); Ok(obj) @@ -315,7 +320,7 @@ impl UnixSocketObject { struct Channel { reader: RingBufReader, - writer: RingBufWriter + writer: RingBufWriter, } unsafe impl Send for Channel {} @@ -340,6 +345,6 @@ impl Channel { pub const DEFAULT_BUF_SIZE: usize = 1 * 1024 * 1024; lazy_static! { - static ref UNIX_SOCKET_OBJS: Mutex>> - = Mutex::new(BTreeMap::new()); + static ref UNIX_SOCKET_OBJS: Mutex>> = + Mutex::new(BTreeMap::new()); } diff --git a/src/libos/src/lib.rs b/src/libos/src/lib.rs index 95d5fe69..a8b397b1 100644 --- a/src/libos/src/lib.rs +++ b/src/libos/src/lib.rs @@ -36,12 +36,12 @@ mod prelude; mod entry; mod errno; mod fs; +mod misc; mod process; mod syscall; mod time; mod util; mod vm; -mod misc; use prelude::*; diff --git a/src/libos/src/misc/mod.rs b/src/libos/src/misc/mod.rs index b6567883..b882c381 100644 --- a/src/libos/src/misc/mod.rs +++ b/src/libos/src/misc/mod.rs @@ -1,7 +1,7 @@ use super::*; -mod uname; mod rlimit; +mod uname; -pub use self::uname::{utsname_t, do_uname}; -pub use self::rlimit::{rlimit_t, resource_t, ResourceLimits, ResourceLimitsRef, do_prlimit}; +pub use self::rlimit::{do_prlimit, resource_t, rlimit_t, ResourceLimits, ResourceLimitsRef}; +pub use self::uname::{do_uname, utsname_t}; diff --git a/src/libos/src/misc/rlimit.rs b/src/libos/src/misc/rlimit.rs index f55acd6c..96754780 100644 --- a/src/libos/src/misc/rlimit.rs +++ b/src/libos/src/misc/rlimit.rs @@ -1,5 +1,5 @@ use super::*; -use process::{pid_t}; +use process::pid_t; #[derive(Debug, Copy, Clone)] pub struct ResourceLimits { @@ -21,13 +21,12 @@ impl Default for ResourceLimits { fn default() -> ResourceLimits { // TODO: set appropriate limits for resources let mut rlimits = ResourceLimits { - rlimits: [ Default::default(); RLIMIT_COUNT ], + rlimits: [Default::default(); RLIMIT_COUNT], }; rlimits } } - #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub struct rlimit_t { @@ -44,41 +43,40 @@ impl Default for rlimit_t { } } - #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum resource_t { - RLIMIT_CPU = 0, - RLIMIT_FSIZE = 1, - RLIMIT_DATA = 2, - RLIMIT_STACK = 3, - RLIMIT_CORE = 4, - RLIMIT_RSS = 5, - RLIMIT_NPROC = 6, - RLIMIT_NOFILE = 7, - RLIMIT_MEMLOCK = 8, - RLIMIT_AS = 9, - RLIMIT_LOCKS = 10, - RLIMIT_SIGPENDING = 11, - RLIMIT_MSGQUEUE = 12, - RLIMIT_NICE = 13, - RLIMIT_RTPRIO = 14, + RLIMIT_CPU = 0, + RLIMIT_FSIZE = 1, + RLIMIT_DATA = 2, + RLIMIT_STACK = 3, + RLIMIT_CORE = 4, + RLIMIT_RSS = 5, + RLIMIT_NPROC = 6, + RLIMIT_NOFILE = 7, + RLIMIT_MEMLOCK = 8, + RLIMIT_AS = 9, + RLIMIT_LOCKS = 10, + RLIMIT_SIGPENDING = 11, + RLIMIT_MSGQUEUE = 12, + RLIMIT_NICE = 13, + RLIMIT_RTPRIO = 14, } const RLIMIT_COUNT: usize = 15; impl resource_t { pub fn from_u32(bits: u32) -> Result { match bits { - 0 => Ok(resource_t::RLIMIT_CPU), - 1 => Ok(resource_t::RLIMIT_FSIZE), - 2 => Ok(resource_t::RLIMIT_DATA), - 3 => Ok(resource_t::RLIMIT_STACK), - 4 => Ok(resource_t::RLIMIT_CORE), - 5 => Ok(resource_t::RLIMIT_RSS), - 6 => Ok(resource_t::RLIMIT_NPROC), - 7 => Ok(resource_t::RLIMIT_NOFILE), - 8 => Ok(resource_t::RLIMIT_MEMLOCK), - 9 => Ok(resource_t::RLIMIT_AS), + 0 => Ok(resource_t::RLIMIT_CPU), + 1 => Ok(resource_t::RLIMIT_FSIZE), + 2 => Ok(resource_t::RLIMIT_DATA), + 3 => Ok(resource_t::RLIMIT_STACK), + 4 => Ok(resource_t::RLIMIT_CORE), + 5 => Ok(resource_t::RLIMIT_RSS), + 6 => Ok(resource_t::RLIMIT_NPROC), + 7 => Ok(resource_t::RLIMIT_NOFILE), + 8 => Ok(resource_t::RLIMIT_MEMLOCK), + 9 => Ok(resource_t::RLIMIT_AS), 10 => Ok(resource_t::RLIMIT_LOCKS), 11 => Ok(resource_t::RLIMIT_SIGPENDING), 12 => Ok(resource_t::RLIMIT_MSGQUEUE), @@ -89,7 +87,6 @@ impl resource_t { } } - pub fn do_prlimit( pid: pid_t, resource: resource_t, @@ -98,8 +95,7 @@ pub fn do_prlimit( ) -> Result<(), Error> { let process_ref = if pid == 0 { process::get_current() - } - else { + } else { process::get(pid)? }; let mut process = process_ref.lock().unwrap(); diff --git a/src/libos/src/misc/uname.rs b/src/libos/src/misc/uname.rs index 0b246f45..12d33595 100644 --- a/src/libos/src/misc/uname.rs +++ b/src/libos/src/misc/uname.rs @@ -34,7 +34,7 @@ pub fn do_uname(name: &mut utsname_t) -> Result<(), Error> { } lazy_static! { - static ref SYSNAME : CString = CString::new("Occlum").unwrap(); + static ref SYSNAME: CString = CString::new("Occlum").unwrap(); static ref NODENAME: CString = CString::new("occlum-node").unwrap(); static ref RELEASE: CString = CString::new("0.1").unwrap(); static ref VERSION: CString = CString::new("0.1").unwrap(); @@ -43,9 +43,8 @@ lazy_static! { } fn copy_from_cstr_to_u8_array(src: &CStr, dst: &mut [u8]) { - let src : &[u8] = src.to_bytes_with_nul(); + let src: &[u8] = src.to_bytes_with_nul(); let len = min(dst.len() - 1, src.len()); dst[..len].copy_from_slice(&src[..len]); dst[len] = 0; } - diff --git a/src/libos/src/prelude.rs b/src/libos/src/prelude.rs index 7cddd8ce..a4c80b5f 100644 --- a/src/libos/src/prelude.rs +++ b/src/libos/src/prelude.rs @@ -14,6 +14,7 @@ pub use std::sync::{ //pub use std::borrow::BorrowMut; pub use std::borrow::ToOwned; pub use std::boxed::Box; +pub use std::cmp::{max, min}; pub use std::cmp::{Ordering, PartialOrd}; pub use std::collections::{HashMap, VecDeque}; pub use std::fmt::{Debug, Display}; @@ -22,7 +23,6 @@ pub use std::iter::Iterator; pub use std::rc::Rc; pub use std::string::String; pub use std::vec::Vec; -pub use std::cmp::{min, max}; pub use errno::Errno; pub use errno::Errno::*; diff --git a/src/libos/src/process/arch_prctl.rs b/src/libos/src/process/arch_prctl.rs index c148e8ba..54d5648b 100644 --- a/src/libos/src/process/arch_prctl.rs +++ b/src/libos/src/process/arch_prctl.rs @@ -22,22 +22,28 @@ impl ArchPrctlCode { } pub fn do_arch_prctl(code: ArchPrctlCode, addr: *mut usize) -> Result<(), Error> { - info!("do_arch_prctl: code: {:?}, addr: {:#o}", code, addr as usize); + info!( + "do_arch_prctl: code: {:?}, addr: {:#o}", + code, addr as usize + ); match code { - ArchPrctlCode::ARCH_SET_FS => { + ArchPrctlCode::ARCH_SET_FS => { let current_ref = get_current(); let mut current = current_ref.lock().unwrap(); let task = &mut current.task; task.user_fsbase_addr = addr as usize; - }, - ArchPrctlCode::ARCH_GET_FS => { + } + ArchPrctlCode::ARCH_GET_FS => { let current_ref = get_current(); let current = current_ref.lock().unwrap(); let task = ¤t.task; - unsafe { *addr = task.user_fsbase_addr; } - }, - ArchPrctlCode::ARCH_SET_GS | ArchPrctlCode::ARCH_GET_GS - => return errno!(EINVAL, "GS cannot be accessed from the user space"), + unsafe { + *addr = task.user_fsbase_addr; + } + } + ArchPrctlCode::ARCH_SET_GS | ArchPrctlCode::ARCH_GET_GS => { + return errno!(EINVAL, "GS cannot be accessed from the user space"); + } } Ok(()) } diff --git a/src/libos/src/process/exit.rs b/src/libos/src/process/exit.rs index ab99ba03..19cd96fc 100644 --- a/src/libos/src/process/exit.rs +++ b/src/libos/src/process/exit.rs @@ -28,7 +28,9 @@ pub fn do_exit(exit_status: i32) { // Notify another process, if any, that waits on ctid (see set_tid_address) if let Some(ctid) = current.clear_child_tid { - unsafe { atomic_store(ctid, 0); } + unsafe { + atomic_store(ctid, 0); + } futex_wake(ctid as *const i32, 1); } diff --git a/src/libos/src/process/futex.rs b/src/libos/src/process/futex.rs index d712e27d..6c68fa2e 100644 --- a/src/libos/src/process/futex.rs +++ b/src/libos/src/process/futex.rs @@ -7,18 +7,18 @@ use std::sync::atomic::{AtomicBool, Ordering}; #[allow(non_camel_case_types)] pub enum FutexOp { - FUTEX_WAIT = 0, - FUTEX_WAKE = 1, - FUTEX_FD = 2, - FUTEX_REQUEUE = 3, - FUTEX_CMP_REQUEUE = 4, - FUTEX_WAKE_OP = 5, - FUTEX_LOCK_PI = 6, - FUTEX_UNLOCK_PI = 7, - FUTEX_TRYLOCK_PI = 8, - FUTEX_WAIT_BITSET = 9, + FUTEX_WAIT = 0, + FUTEX_WAKE = 1, + FUTEX_FD = 2, + FUTEX_REQUEUE = 3, + FUTEX_CMP_REQUEUE = 4, + FUTEX_WAKE_OP = 5, + FUTEX_LOCK_PI = 6, + FUTEX_UNLOCK_PI = 7, + FUTEX_TRYLOCK_PI = 8, + FUTEX_WAIT_BITSET = 9, } -const FUTEX_OP_MASK : u32 = 0x0000_000F; +const FUTEX_OP_MASK: u32 = 0x0000_000F; impl FutexOp { pub fn from_u32(bits: u32) -> Result { @@ -44,12 +44,11 @@ bitflags! { const FUTEX_CLOCK_REALTIME = 256; } } -const FUTEX_FLAGS_MASK : u32 = 0xFFFF_FFF0; +const FUTEX_FLAGS_MASK: u32 = 0xFFFF_FFF0; impl FutexFlags { pub fn from_u32(bits: u32) -> Result { - FutexFlags::from_bits(bits).ok_or_else(|| - Error::new(Errno::EINVAL, "Unknown futex flags")) + FutexFlags::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "Unknown futex flags")) } } @@ -65,12 +64,10 @@ pub fn futex_op_and_flags_from_u32(bits: u32) -> Result<(FutexOp, FutexFlags), E Ok((op, flags)) } - /// Do futex wait pub fn futex_wait(futex_addr: *const i32, futex_val: i32) -> Result<(), Error> { let futex_key = FutexKey::new(futex_addr); - let futex_item = FUTEX_TABLE.lock().unwrap() - .get_or_new_item(futex_key); + let futex_item = FUTEX_TABLE.lock().unwrap().get_or_new_item(futex_key); futex_item.wait(futex_val); @@ -87,11 +84,8 @@ pub fn futex_wake(futex_addr: *const i32, max_count: usize) -> Result = { - SgxMutex::new(FutexTable::new()) - }; + static ref FUTEX_TABLE: SgxMutex = { SgxMutex::new(FutexTable::new()) }; } #[derive(PartialEq, Eq, Hash, Copy, Clone)] @@ -126,7 +120,9 @@ impl FutexItem { while count < max_count { let waiter = { let waiter_option = queue.pop_front(); - if waiter_option.is_none() { break; } + if waiter_option.is_none() { + break; + } waiter_option.unwrap() }; waiter.wake(); @@ -165,15 +161,17 @@ impl FutexTable { pub fn get_or_new_item(&mut self, key: FutexKey) -> FutexItemRef { let table = &mut self.table; - let item = table.entry(key).or_insert_with(|| { - Arc::new(FutexItem::new(key)) - }); + let item = table + .entry(key) + .or_insert_with(|| Arc::new(FutexItem::new(key))); item.clone() } pub fn get_item(&mut self, key: FutexKey) -> Result { let table = &mut self.table; - table.get_mut(&key).map(|item| item.clone()) + table + .get_mut(&key) + .map(|item| item.clone()) .ok_or_else(|| Error::new(Errno::ENOENT, "futex key cannot be found")) } @@ -193,7 +191,6 @@ impl FutexTable { } } - #[derive(Debug)] struct Waiter { thread: *const c_void, diff --git a/src/libos/src/process/mod.rs b/src/libos/src/process/mod.rs index a8d32e2f..19c89fd6 100644 --- a/src/libos/src/process/mod.rs +++ b/src/libos/src/process/mod.rs @@ -1,12 +1,12 @@ -pub use self::process::{Status, IDLE_PROCESS}; -pub use self::task::{get_current, run_task, current_pid}; -pub use self::process_table::{get}; +pub use self::arch_prctl::{do_arch_prctl, ArchPrctlCode}; pub use self::exit::{do_exit, do_wait4, ChildProcessFilter}; +pub use self::futex::{futex_op_and_flags_from_u32, futex_wait, futex_wake, FutexFlags, FutexOp}; +pub use self::process::{Status, IDLE_PROCESS}; +pub use self::process_table::get; pub use self::spawn::{do_spawn, FileAction}; +pub use self::task::{current_pid, get_current, run_task}; +pub use self::thread::{do_clone, do_set_tid_address, CloneFlags, ThreadGroup}; pub use self::wait::{WaitQueue, Waiter}; -pub use self::thread::{do_clone, CloneFlags, ThreadGroup, do_set_tid_address}; -pub use self::futex::{FutexOp, FutexFlags, futex_op_and_flags_from_u32, futex_wake, futex_wait}; -pub use self::arch_prctl::{ArchPrctlCode, do_arch_prctl}; #[allow(non_camel_case_types)] pub type pid_t = u32; @@ -64,18 +64,18 @@ pub fn do_getppid() -> pid_t { parent.get_pid() } +mod arch_prctl; mod exit; +mod futex; mod process; mod process_table; mod spawn; mod task; -mod wait; mod thread; -mod futex; -mod arch_prctl; +mod wait; use self::task::Task; use super::*; use fs::{File, FileRef, FileTable}; +use misc::ResourceLimitsRef; use vm::{ProcessVM, VMRangeTrait}; -use misc::{ResourceLimitsRef}; diff --git a/src/libos/src/process/process.rs b/src/libos/src/process/process.rs index 2baedb06..65e2755a 100644 --- a/src/libos/src/process/process.rs +++ b/src/libos/src/process/process.rs @@ -88,7 +88,7 @@ impl Process { pub fn get_parent(&self) -> &ProcessRef { self.parent.as_ref().unwrap() } - pub fn get_children_iter(&self) -> impl Iterator + '_ { + pub fn get_children_iter(&self) -> impl Iterator + '_ { self.children .iter() .filter_map(|child_weak| child_weak.upgrade()) diff --git a/src/libos/src/process/process_table.rs b/src/libos/src/process/process_table.rs index ed800df7..0c624dd4 100644 --- a/src/libos/src/process/process_table.rs +++ b/src/libos/src/process/process_table.rs @@ -15,7 +15,10 @@ pub fn remove(pid: pid_t) { } pub fn get(pid: pid_t) -> Result { - PROCESS_TABLE.lock().unwrap().get(&pid) + PROCESS_TABLE + .lock() + .unwrap() + .get(&pid) .map(|pr| pr.clone()) .ok_or_else(|| Error::new(Errno::ENOENT, "process not found")) } diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index d2bb6551..63dc7c87 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -1,15 +1,15 @@ -use xmas_elf::{ElfFile, header, program, sections}; use xmas_elf::symbol_table::Entry; +use xmas_elf::{header, program, sections, ElfFile}; -use fs::{File, FileDesc, FileTable, INodeExt, ROOT_INODE, StdinFile, StdoutFile, OpenFlags}; +use fs::{File, FileDesc, FileTable, INodeExt, OpenFlags, StdinFile, StdoutFile, ROOT_INODE}; +use misc::ResourceLimitsRef; use std::ffi::{CStr, CString}; use std::path::Path; use std::sgxfs::SgxFile; use vm::{ProcessVM, VMRangeTrait}; -use misc::{ResourceLimitsRef}; -use super::*; use super::task::Task; +use super::*; use self::init_stack::{AuxKey, AuxTable}; @@ -98,7 +98,12 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result { + &FileAction::Open { + ref path, + mode, + oflag, + fd, + } => { let flags = OpenFlags::from_bits_truncate(oflag); let file = parent.open_file(path.as_str(), flags, mode)?; let file_ref: Arc> = Arc::new(file); @@ -151,7 +156,11 @@ fn init_task( }) } -fn init_auxtbl(base_addr: usize, program_entry: usize, elf_file: &ElfFile) -> Result { +fn init_auxtbl( + base_addr: usize, + program_entry: usize, + elf_file: &ElfFile, +) -> Result { let mut auxtbl = AuxTable::new(); auxtbl.set_val(AuxKey::AT_PAGESZ, 4096)?; auxtbl.set_val(AuxKey::AT_UID, 0)?; diff --git a/src/libos/src/process/thread.rs b/src/libos/src/process/thread.rs index 31837341..d34fd6c5 100644 --- a/src/libos/src/process/thread.rs +++ b/src/libos/src/process/thread.rs @@ -4,7 +4,6 @@ pub struct ThreadGroup { threads: Vec, } - bitflags! { pub struct CloneFlags : u32 { const CLONE_VM = 0x00000100; @@ -40,8 +39,10 @@ pub fn do_clone( ctid: Option<*mut pid_t>, new_tls: Option, ) -> Result { - info!("clone: flags: {:?}, stack_addr: {:?}, ptid: {:?}, ctid: {:?}, new_tls: {:?}", - flags, stack_addr, ptid, ctid, new_tls); + info!( + "clone: flags: {:?}, stack_addr: {:?}, ptid: {:?}, ctid: {:?}, new_tls: {:?}", + flags, stack_addr, ptid, ctid, new_tls + ); // TODO: return error for unsupported flags let current_ref = get_current(); @@ -75,7 +76,9 @@ pub fn do_clone( process_table::put(new_thread_pid, new_thread_ref.clone()); if let Some(ptid) = ptid { - unsafe { *ptid = new_thread_pid; } + unsafe { + *ptid = new_thread_pid; + } } task::enqueue_task(new_thread_ref); diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index cb992656..809d7337 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -921,10 +921,7 @@ fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result { } fn do_ioctl(fd: FileDesc, cmd: c_int, argp: *mut c_int) -> Result { - info!( - "ioctl: fd: {}, cmd: {}, argp: {:?}", - fd, cmd, argp - ); + info!("ioctl: fd: {}, cmd: {}, argp: {:?}", fd, cmd, argp); let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; @@ -994,7 +991,9 @@ fn do_connect( } else if let Ok(unix_socket) = file_ref.as_unix_socket() { let addr = addr as *const libc::sockaddr_un; check_ptr(addr)?; // TODO: check addr_len - let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?.to_string_lossy().into_owned(); + let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })? + .to_string_lossy() + .into_owned(); unix_socket.connect(path)?; Ok(0) } else { @@ -1066,7 +1065,9 @@ fn do_bind( } else if let Ok(unix_socket) = file_ref.as_unix_socket() { let addr = addr as *const libc::sockaddr_un; check_ptr(addr)?; // TODO: check addr_len - let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?.to_string_lossy().into_owned(); + let path = clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })? + .to_string_lossy() + .into_owned(); unix_socket.bind(path)?; Ok(0) } else { @@ -1152,20 +1153,22 @@ fn do_getpeername( addr: *mut libc::sockaddr, addr_len: *mut libc::socklen_t, ) -> Result { - info!("getpeername: fd: {}, addr: {:?}, addr_len: {:?}", fd, addr, addr_len); + info!( + "getpeername: fd: {}, addr: {:?}, addr_len: {:?}", + fd, addr, addr_len + ); let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; if let Ok(socket) = file_ref.as_socket() { - let ret = try_libc!(libc::ocall::getpeername( - socket.fd(), - addr, - addr_len - )); + let ret = try_libc!(libc::ocall::getpeername(socket.fd(), addr, addr_len)); Ok(ret as isize) } else if let Ok(unix_socket) = file_ref.as_unix_socket() { warn!("getpeername for unix socket is unimplemented"); - errno!(ENOTCONN, "hack for php: Transport endpoint is not connected") + errno!( + ENOTCONN, + "hack for php: Transport endpoint is not connected" + ) } else { errno!(EBADF, "not a socket") } @@ -1176,16 +1179,15 @@ fn do_getsockname( addr: *mut libc::sockaddr, addr_len: *mut libc::socklen_t, ) -> Result { - info!("getsockname: fd: {}, addr: {:?}, addr_len: {:?}", fd, addr, addr_len); + info!( + "getsockname: fd: {}, addr: {:?}, addr_len: {:?}", + fd, addr, addr_len + ); let current_ref = process::get_current(); let mut proc = current_ref.lock().unwrap(); let file_ref = proc.get_files().lock().unwrap().get(fd as FileDesc)?; if let Ok(socket) = file_ref.as_socket() { - let ret = try_libc!(libc::ocall::getsockname( - socket.fd(), - addr, - addr_len - )); + let ret = try_libc!(libc::ocall::getsockname(socket.fd(), addr, addr_len)); Ok(ret as isize) } else if let Ok(unix_socket) = file_ref.as_unix_socket() { warn!("getsockname for unix socket is unimplemented"); diff --git a/src/libos/src/util/ring_buf.rs b/src/libos/src/util/ring_buf.rs index 045e1e4e..591f3218 100644 --- a/src/libos/src/util/ring_buf.rs +++ b/src/libos/src/util/ring_buf.rs @@ -2,8 +2,8 @@ use alloc::alloc::{alloc, dealloc, Layout}; use std::cmp::{max, min}; use std::ptr; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::Arc; use super::*; diff --git a/src/libos/src/vm/mod.rs b/src/libos/src/vm/mod.rs index 6dbc7170..74e20873 100644 --- a/src/libos/src/vm/mod.rs +++ b/src/libos/src/vm/mod.rs @@ -5,18 +5,22 @@ use std::fmt; #[macro_use] mod vm_range; -mod vm_area; mod process_vm; +mod vm_area; -pub use self::vm_range::{VMRange, VMRangeTrait}; -pub use self::vm_area::{VMSpace, VMDomain, VMArea, VMAreaFlags, VM_AREA_FLAG_R, VM_AREA_FLAG_W, VM_AREA_FLAG_X}; pub use self::process_vm::ProcessVM; - +pub use self::vm_area::{ + VMArea, VMAreaFlags, VMDomain, VMSpace, VM_AREA_FLAG_R, VM_AREA_FLAG_W, VM_AREA_FLAG_X, +}; +pub use self::vm_range::{VMRange, VMRangeTrait}; // TODO: separate proc and flags // TODO: accept fd and offset pub fn do_mmap(addr: usize, size: usize, flags: VMAreaFlags) -> Result { - info!("mmap: addr: {:#x}, size: {:#x}, flags: {:?}", addr, size, flags); + info!( + "mmap: addr: {:#x}, size: {:#x}, flags: {:?}", + addr, size, flags + ); let current_ref = get_current(); let current_process = current_ref.lock().unwrap(); let current_vm_ref = current_process.get_vm(); @@ -68,7 +72,6 @@ pub enum VMGuardAreaType { Dynamic { size: usize }, } - #[derive(Clone, PartialEq, Default)] pub struct VMAllocOptions { size: usize, @@ -123,7 +126,6 @@ impl fmt::Debug for VMAllocOptions { } } - #[derive(Clone, Copy, Debug, PartialEq)] pub enum VMAddrOption { Any, // Free to choose any address @@ -156,7 +158,6 @@ impl VMAddrOption { } } - /// How VMRange may grow: #[derive(Clone, Copy, Debug, PartialEq)] pub enum VMGrowthType { @@ -171,7 +172,6 @@ impl Default for VMGrowthType { } } - #[derive(Clone, Debug, Default)] pub struct VMResizeOptions { new_size: usize, diff --git a/src/libos/src/vm/process_vm.rs b/src/libos/src/vm/process_vm.rs index 2aed5155..bb64864e 100644 --- a/src/libos/src/vm/process_vm.rs +++ b/src/libos/src/vm/process_vm.rs @@ -46,24 +46,29 @@ impl ProcessVM { ) -> Result { // Allocate the data domain from the global data space let mut data_domain = { - let data_domain_size = code_size + data_size + heap_size - + stack_size + mmap_size; - let data_domain = DATA_SPACE.lock().unwrap().alloc_domain( - data_domain_size, "data_domain")?; + let data_domain_size = code_size + data_size + heap_size + stack_size + mmap_size; + let data_domain = DATA_SPACE + .lock() + .unwrap() + .alloc_domain(data_domain_size, "data_domain")?; data_domain }; // Allocate vmas from the data domain - let (code_vma, data_vma, heap_vma, stack_vma) = - match ProcessVM::alloc_vmas(&mut data_domain, code_size, - data_size, heap_size, stack_size) { - Err(e) => { - // Note: we need to handle error here so that we can - // deallocate the data domain explictly. - DATA_SPACE.lock().unwrap().dealloc_domain(data_domain); - return Err(e); - }, - Ok(vmas) => vmas, - }; + let (code_vma, data_vma, heap_vma, stack_vma) = match ProcessVM::alloc_vmas( + &mut data_domain, + code_size, + data_size, + heap_size, + stack_size, + ) { + Err(e) => { + // Note: we need to handle error here so that we can + // deallocate the data domain explictly. + DATA_SPACE.lock().unwrap().dealloc_domain(data_domain); + return Err(e); + } + Ok(vmas) => vmas, + }; // Initial value of the program break let brk = heap_vma.get_start(); // No mmapped vmas initially @@ -92,7 +97,8 @@ impl ProcessVM { let mut alloc_vma_continuously = |addr: &mut usize, desc, size, flags, growth, fill_zeros| -> Result<_, Error> { let mut options = VMAllocOptions::new(size)?; - options.addr(VMAddrOption::Fixed(*addr))? + options + .addr(VMAddrOption::Fixed(*addr))? .growth(growth)? .description(desc)? .fill_zeros(fill_zeros)?; @@ -104,17 +110,41 @@ impl ProcessVM { let rx_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_X); let rw_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_W); - let code_vma = alloc_vma_continuously(&mut addr, "code_vma", code_size, - rx_flags, VMGrowthType::Fixed, true)?; - let data_vma = alloc_vma_continuously(&mut addr, "data_vma", data_size, - rw_flags, VMGrowthType::Fixed, true)?; - let heap_vma = alloc_vma_continuously(&mut addr, "heap_vma", 0, - rw_flags, VMGrowthType::Upward, true)?; + let code_vma = alloc_vma_continuously( + &mut addr, + "code_vma", + code_size, + rx_flags, + VMGrowthType::Fixed, + true, + )?; + let data_vma = alloc_vma_continuously( + &mut addr, + "data_vma", + data_size, + rw_flags, + VMGrowthType::Fixed, + true, + )?; + let heap_vma = alloc_vma_continuously( + &mut addr, + "heap_vma", + 0, + rw_flags, + VMGrowthType::Upward, + true, + )?; // Preserve the space for heap addr += heap_size; // After the heap is the stack - let stack_vma = alloc_vma_continuously(&mut addr, "stack_vma", stack_size, - rw_flags, VMGrowthType::Downward, false)?; + let stack_vma = alloc_vma_continuously( + &mut addr, + "stack_vma", + stack_size, + rw_flags, + VMGrowthType::Downward, + false, + )?; Ok((code_vma, data_vma, heap_vma, stack_vma)) } @@ -178,7 +208,8 @@ impl ProcessVM { alloc_options }; // TODO: when failed, try to resize data_domain - let new_mmap_vma = self.get_data_domain_mut() + let new_mmap_vma = self + .get_data_domain_mut() .alloc_area(&alloc_options, flags)?; let addr = new_mmap_vma.get_start(); self.mmap_vmas.push(Box::new(new_mmap_vma)); @@ -201,7 +232,8 @@ impl ProcessVM { }; let removed_mmap_vma = self.mmap_vmas.swap_remove(mmap_vma_i); - self.get_data_domain_mut().dealloc_area(unbox(removed_mmap_vma)); + self.get_data_domain_mut() + .dealloc_area(unbox(removed_mmap_vma)); Ok(()) } @@ -229,7 +261,8 @@ impl ProcessVM { let new_heap_end = align_up(new_brk, PAGE_SIZE); let new_heap_size = new_heap_end - heap_start; let mut options = VMResizeOptions::new(new_heap_size)?; - options.addr(VMAddrOption::Fixed(heap_start)) + options + .addr(VMAddrOption::Fixed(heap_start)) .fill_zeros(true); options }; @@ -261,7 +294,9 @@ impl Drop for ProcessVM { } // Remove the domain from its parent space - DATA_SPACE.lock().unwrap().dealloc_domain( - unbox(self.data_domain.take().unwrap())); + DATA_SPACE + .lock() + .unwrap() + .dealloc_domain(unbox(self.data_domain.take().unwrap())); } } diff --git a/src/libos/src/vm/vm_area.rs b/src/libos/src/vm/vm_area.rs index 356cf540..990559cd 100644 --- a/src/libos/src/vm/vm_area.rs +++ b/src/libos/src/vm/vm_area.rs @@ -27,8 +27,7 @@ impl VMSpace { pub fn alloc_domain(&mut self, size: usize, desc: &str) -> Result { let mut options = VMAllocOptions::new(size)?; - options.growth(VMGrowthType::Upward)? - .description(desc)?; + options.growth(VMGrowthType::Upward)?.description(desc)?; let new_range = self.range.alloc_subrange(&options)?; Ok(VMDomain { range: new_range }) @@ -44,7 +43,6 @@ impl VMSpace { } } - #[derive(Debug)] pub struct VMDomain { range: VMRange, @@ -78,7 +76,6 @@ impl VMDomain { } } - #[derive(Debug)] pub struct VMArea { range: VMRange, @@ -97,7 +94,6 @@ impl VMArea { } } - #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct VMAreaFlags(pub u32); diff --git a/src/libos/src/vm/vm_range.rs b/src/libos/src/vm/vm_range.rs index c3e305e0..4181a828 100644 --- a/src/libos/src/vm/vm_range.rs +++ b/src/libos/src/vm/vm_range.rs @@ -46,7 +46,12 @@ pub struct VMRange { impl_vmrange_trait_for!(VMRange, inner); impl VMRange { - pub unsafe fn new(start: usize, end: usize, growth: VMGrowthType, description: &str) -> Result { + pub unsafe fn new( + start: usize, + end: usize, + growth: VMGrowthType, + description: &str, + ) -> Result { if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 { return errno!(EINVAL, "Invalid start and/or end"); } @@ -75,8 +80,10 @@ impl VMRange { debug_assert!(free_space.contains(new_subrange_start)); debug_assert!(free_space.contains(new_subrange_end)); - (free_space.index_in_subranges, VMRangeInner::new( - new_subrange_start, new_subrange_end, options.growth)) + ( + free_space.index_in_subranges, + VMRangeInner::new(new_subrange_start, new_subrange_end, options.growth), + ) }; self.get_subranges_mut() .insert(new_subrange_idx, new_subrange_inner); @@ -186,7 +193,7 @@ impl VMRange { let pre_range = &range_pair[0]; let next_range = &range_pair[1]; - let (free_range_start, free_range_end)= { + let (free_range_start, free_range_end) = { let free_range_start = pre_range.get_end(); let free_range_end = next_range.get_start(); @@ -209,7 +216,7 @@ impl VMRange { match addr { // Want a minimal free_space - VMAddrOption::Any => { }, + VMAddrOption::Any => {} // Prefer to have free_space.start == addr VMAddrOption::Hint(addr) => { if free_space.contains(addr) { @@ -218,7 +225,7 @@ impl VMRange { return Ok(free_space); } } - }, + } // Must have free_space.start == addr VMAddrOption::Fixed(addr) => { if !free_space.contains(addr) { @@ -241,20 +248,24 @@ impl VMRange { continue; } } - }, + } } - if min_big_enough_free_space == None || - free_space < *min_big_enough_free_space.as_ref().unwrap() { + if min_big_enough_free_space == None + || free_space < *min_big_enough_free_space.as_ref().unwrap() + { min_big_enough_free_space = Some(free_space); } } - min_big_enough_free_space - .ok_or_else(|| Error::new(Errno::ENOMEM, "not enough space")) + min_big_enough_free_space.ok_or_else(|| Error::new(Errno::ENOMEM, "not enough space")) } - fn alloc_from_free_space(&self, free_space: &FreeSpace, options: &VMAllocOptions) -> (usize, usize) { + fn alloc_from_free_space( + &self, + free_space: &FreeSpace, + options: &VMAllocOptions, + ) -> (usize, usize) { // Get valid parameters from options let size = options.size; let addr_option = options.addr; @@ -262,8 +273,7 @@ impl VMRange { if let VMAddrOption::Fixed(addr) = addr_option { return (addr, addr + size); - } - else if let VMAddrOption::Hint(addr) = addr_option { + } else if let VMAddrOption::Hint(addr) = addr_option { if free_space.start == addr { return (addr, addr + size); } @@ -349,7 +359,12 @@ impl VMRange { Ok(()) } - fn grow_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize, fill_zeros: bool) -> Result<(), Error> { + fn grow_subrange_to( + &mut self, + subrange: &mut VMRange, + new_size: usize, + fill_zeros: bool, + ) -> Result<(), Error> { let subrange_i = self.position_subrange(subrange); let subranges = self.get_subranges_mut(); @@ -379,7 +394,8 @@ impl VMRange { memset(mem_ptr, 0 as c_int, mem_size); } } - } else { // self.growth == VMGrowthType::Downward + } else { + // self.growth == VMGrowthType::Downward // Can we grow downard? let max_new_size = { let pre_subrange = &subranges[subrange_i - 1]; @@ -429,7 +445,6 @@ impl Drop for VMRange { unsafe impl Send for VMRange {} unsafe impl Sync for VMRange {} - #[derive(Clone, Copy)] pub struct VMRangeInner { start: usize, From 413586f729a04e21ae4b8b88f315792df3858272 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Fri, 26 Apr 2019 22:44:10 +0800 Subject: [PATCH 37/37] add integrity_only_opt and sgx_file_cache feature --- src/libos/Cargo.toml | 6 ++++-- src/libos/src/fs/mod.rs | 1 - src/libos/src/fs/sgx_impl.rs | 6 ++++++ src/libos/src/process/spawn/segment.rs | 9 +++++++-- src/libos/src/vm/process_vm.rs | 4 ++-- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/libos/Cargo.toml b/src/libos/Cargo.toml index 1627c480..86a75d71 100644 --- a/src/libos/Cargo.toml +++ b/src/libos/Cargo.toml @@ -14,8 +14,10 @@ rcore-fs = { path = "../../deps/sefs/rcore-fs" } rcore-fs-sefs = { path = "../../deps/sefs/rcore-fs-sefs" } [features] -default = [] -syscall_timing = [] +default = ["integrity_only_opt", "sgx_file_cache"] +syscall_timing = [] # Timing for each syscall. But it has cost from more ocall. +integrity_only_opt = [] # Clear bss only. It should be disabled if checking memory reads. +sgx_file_cache = [] # Cache SgxFile objects. Invalidation is unimplemented. [target.'cfg(not(target_env = "sgx"))'.dependencies] xmas-elf = { path = "../../deps/xmas-elf" } diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 1fd92bb3..560554a1 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -499,7 +499,6 @@ impl OpenFlags { } } -#[derive(Debug)] #[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes. pub struct LinuxDirent64 { /// Inode number diff --git a/src/libos/src/fs/sgx_impl.rs b/src/libos/src/fs/sgx_impl.rs index 2f03cac2..bc3620d5 100644 --- a/src/libos/src/fs/sgx_impl.rs +++ b/src/libos/src/fs/sgx_impl.rs @@ -25,6 +25,7 @@ impl SgxStorage { /// Get file by `file_id`. /// It lookups cache first, if miss, then call `open_fn` to open one, /// and add it to cache before return. + #[cfg(feature = "sgx_file_cache")] fn get(&self, file_id: usize, open_fn: impl FnOnce(&Self) -> LockedFile) -> LockedFile { // query cache let mut caches = self.file_cache.lock().unwrap(); @@ -38,6 +39,11 @@ impl SgxStorage { caches.insert(file_id, locked_file.clone()); locked_file } + /// Get file by `file_id` without cache. + #[cfg(not(feature = "sgx_file_cache"))] + fn get(&self, file_id: usize, open_fn: impl FnOnce(&Self) -> LockedFile) -> LockedFile { + open_fn(self) + } } impl Storage for SgxStorage { diff --git a/src/libos/src/process/spawn/segment.rs b/src/libos/src/process/spawn/segment.rs index d8846a14..59947aff 100644 --- a/src/libos/src/process/spawn/segment.rs +++ b/src/libos/src/process/spawn/segment.rs @@ -66,10 +66,15 @@ impl Segment { let mut target_buf = unsafe { slice::from_raw_parts_mut( (self.process_base_addr + self.mem_addr) as *mut u8, - self.file_size, + self.mem_size, ) }; - target_buf.copy_from_slice(&elf_buf[self.file_offset..(self.file_offset + self.file_size)]); + target_buf[0..self.file_size] + .copy_from_slice(&elf_buf[self.file_offset..(self.file_offset + self.file_size)]); + #[cfg(feature = "integrity_only_opt")] + for i in &mut target_buf[self.file_size..self.mem_size] { + *i = 0; + } } pub fn set_runtime_info( diff --git a/src/libos/src/vm/process_vm.rs b/src/libos/src/vm/process_vm.rs index bb64864e..f2c471b0 100644 --- a/src/libos/src/vm/process_vm.rs +++ b/src/libos/src/vm/process_vm.rs @@ -116,7 +116,7 @@ impl ProcessVM { code_size, rx_flags, VMGrowthType::Fixed, - true, + !cfg!(feature = "integrity_only_opt"), )?; let data_vma = alloc_vma_continuously( &mut addr, @@ -124,7 +124,7 @@ impl ProcessVM { data_size, rw_flags, VMGrowthType::Fixed, - true, + !cfg!(feature = "integrity_only_opt"), )?; let heap_vma = alloc_vma_continuously( &mut addr,