Support O_CLOEXEC on open() or pipe2()

This commit is contained in:
Tate, Hongliang Tian 2019-01-06 22:11:51 +08:00
parent 98b4508a0d
commit d40af94aaf
6 changed files with 100 additions and 52 deletions

@ -18,6 +18,7 @@ extern ssize_t occlum_readv(int fd, struct iovec* iov, int count);
extern ssize_t occlum_writev(int fd, const struct iovec* iov, int count);
extern off_t occlum_lseek(int fd, off_t offset, int whence);
extern int occlum_pipe(int fds[2]);
extern int occlum_pipe2(int fds[2], int flags);
extern int occlum_spawn(int* child_pid, const char* path,
const char** argv,

@ -4,71 +4,100 @@ use {std};
pub type FileDesc = u32;
// Invariant 1: fd < max_fd, where fd is any fd in the table
// Invariant 2: max_fd = table.size()
// Invariant 3: num_fds <= table.size()
#[derive(Clone, Debug, Default)]
#[derive(Debug, Default)]
#[repr(C)]
pub struct FileTable {
table: Vec<Option<FileRef>>,
max_fd: FileDesc,
num_fds: u32,
table: Vec<Option<FileTableEntry>>,
num_fds: usize,
}
#[derive(Debug, Clone)]
struct FileTableEntry {
file: FileRef,
close_on_spawn: bool,
}
impl FileTable {
pub fn new() -> FileTable {
FileTable {
table: Vec::with_capacity(0),
max_fd: 0,
table: Vec::with_capacity(4),
num_fds: 0,
}
}
pub fn put(&mut self, file: FileRef) -> FileDesc {
pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc {
let mut table = &mut self.table;
let free_fd = if self.num_fds < self.max_fd {
table.iter().enumerate()
.find(|&(idx, opt)| opt.is_none()).unwrap().0 as FileDesc
let min_free_fd = if self.num_fds < table.len() {
table.iter().enumerate().find(|&(idx, opt)| opt.is_none())
.unwrap().0
} else {
table.push(None);
self.max_fd += 1;
self.num_fds
table.len() - 1
};
table[free_fd as usize] = Some(file);
table[min_free_fd as usize] = Some(FileTableEntry::new(file,
close_on_spawn));
self.num_fds += 1;
free_fd
min_free_fd as FileDesc
}
pub fn get(&self, fd: FileDesc) -> Option<FileRef> {
if fd >= self.max_fd {
if fd as usize >= self.table.len() {
return None;
}
let table = &self.table;
table[fd as usize].as_ref().map(|file_ref| file_ref.clone())
table[fd as usize].as_ref().map(|entry| entry.file.clone())
}
pub fn del(&mut self, fd: FileDesc) -> Option<FileRef> {
if fd >= self.max_fd {
if fd as usize >= self.table.len() {
return None;
}
let mut del_file = None;
let mut del_entry = None;
let table = &mut self.table;
std::mem::swap(&mut del_file, &mut table[fd as usize]);
if del_file.is_none() {
return None;
}
std::mem::swap(&mut del_entry, &mut table[fd as usize]);
self.num_fds -= 1;
if fd + 1 == self.max_fd {
self.max_fd = table.iter().enumerate().rev()
.find(|&(idx, opt)| opt.is_some())
.map_or(0, |(max_used_fd,opt)| max_used_fd + 1) as FileDesc;
}
del_file
del_entry.map(|entry| entry.file)
}
}
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,
}
}
}
impl FileTableEntry {
fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry {
FileTableEntry {
file,
close_on_spawn,
}
}
}

@ -17,6 +17,7 @@ pub const O_RDWR : u32 = 0x00000002;
pub const O_CREAT : u32 = 0x00000040;
pub const O_TRUNC : u32 = 0x00000200;
pub const O_APPEND : u32 = 0x00000400;
pub const O_CLOEXEC: u32 = 0x00080000;
// TODO: use the type defined in Rust libc.
//
@ -54,10 +55,12 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
let file_ref : Arc<Box<File>> = Arc::new(Box::new(
SgxFile::new(sgx_file, is_readable, is_writable, is_append)?));
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
let fd = current_process.get_files_mut().put(file_ref);
let fd = {
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let close_on_spawn = flags & O_CLOEXEC != 0;
current.get_files_mut().put(file_ref, close_on_spawn)
};
Ok(fd)
}
@ -111,13 +114,16 @@ pub fn do_close(fd: FileDesc) -> Result<(), Error> {
}
}
pub fn do_pipe() -> Result<[FileDesc; 2], Error> {
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let pipe = Pipe::new()?;
let mut file_table = current.get_files_mut();
let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)));
let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)));
let close_on_spawn = flags & O_CLOEXEC != 0;
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);
Ok([reader_fd, writer_fd])
}

@ -80,9 +80,9 @@ fn init_files(parent_ref: &ProcessRef) -> Result<FileTable, Error> {
let stdout : Arc<Box<File>> = Arc::new(Box::new(StdoutFile::new()));
// TODO: implement and use a real stderr
let stderr = stdout.clone();
file_table.put(stdin);
file_table.put(stdout);
file_table.put(stderr);
file_table.put(stdin, false);
file_table.put(stdout, false);
file_table.put(stderr, false);
Ok(file_table)
}

@ -195,6 +195,17 @@ fn do_brk(new_brk_addr: *const c_void) -> Result<*const c_void, Error> {
vm::do_brk(new_brk_addr).map(|ret_brk_addr| ret_brk_addr as *const c_void)
}
fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> {
check_mut_array_from_user(fds_u, 2)?;
// TODO: how to deal with open flags???
let fds = fs::do_pipe2(flags as u32)?;
unsafe {
*fds_u.offset(0) = fds[0] as c_int;
*fds_u.offset(1) = fds[1] as c_int;
}
Ok(())
}
const MAP_FAILED : *const c_void = ((-1) as i64) as *const c_void;
@ -237,19 +248,14 @@ pub extern "C" fn occlum_brk(addr: *const c_void) -> *const c_void {
}
}
fn do_pipe(fds_u: *mut c_int) -> Result<(), Error> {
check_mut_array_from_user(fds_u, 2)?;
let fds = fs::do_pipe()?;
unsafe {
*fds_u.offset(0) = fds[0] as c_int;
*fds_u.offset(1) = fds[1] as c_int;
}
Ok(())
#[no_mangle]
pub extern "C" fn occlum_pipe(fds: *mut c_int) -> c_int {
occlum_pipe2(fds, 0)
}
#[no_mangle]
pub extern "C" fn occlum_pipe(fds: *mut c_int) -> c_int {
match do_pipe(fds) {
pub extern "C" fn occlum_pipe2(fds: *mut c_int, flags: c_int) -> c_int {
match do_pipe2(fds, flags) {
Ok(()) => {
0
},

@ -119,6 +119,12 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
ret = (long) occlum_pipe(fds);
break;
}
case SYS_pipe2: {
DECL_SYSCALL_ARG(int*, fds, arg0);
DECL_SYSCALL_ARG(int, flags, arg1);
ret = (long) occlum_pipe2(fds, flags);
break;
}
default:
ret = occlum_unknown(num);
break;