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 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 off_t occlum_lseek(int fd, off_t offset, int whence);
extern int occlum_pipe(int fds[2]); 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, extern int occlum_spawn(int* child_pid, const char* path,
const char** argv, const char** argv,

@ -4,71 +4,100 @@ use {std};
pub type FileDesc = u32; pub type FileDesc = u32;
// Invariant 1: fd < max_fd, where fd is any fd in the table #[derive(Debug, Default)]
// Invariant 2: max_fd = table.size()
// Invariant 3: num_fds <= table.size()
#[derive(Clone, Debug, Default)]
#[repr(C)] #[repr(C)]
pub struct FileTable { pub struct FileTable {
table: Vec<Option<FileRef>>, table: Vec<Option<FileTableEntry>>,
max_fd: FileDesc, num_fds: usize,
num_fds: u32,
} }
#[derive(Debug, Clone)]
struct FileTableEntry {
file: FileRef,
close_on_spawn: bool,
}
impl FileTable { impl FileTable {
pub fn new() -> FileTable { pub fn new() -> FileTable {
FileTable { FileTable {
table: Vec::with_capacity(0), table: Vec::with_capacity(4),
max_fd: 0,
num_fds: 0, 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 mut table = &mut self.table;
let free_fd = if self.num_fds < self.max_fd { let min_free_fd = if self.num_fds < table.len() {
table.iter().enumerate() table.iter().enumerate().find(|&(idx, opt)| opt.is_none())
.find(|&(idx, opt)| opt.is_none()).unwrap().0 as FileDesc .unwrap().0
} else { } else {
table.push(None); table.push(None);
self.max_fd += 1; table.len() - 1
self.num_fds
}; };
table[free_fd as usize] = Some(file); table[min_free_fd as usize] = Some(FileTableEntry::new(file,
close_on_spawn));
self.num_fds += 1; self.num_fds += 1;
free_fd min_free_fd as FileDesc
} }
pub fn get(&self, fd: FileDesc) -> Option<FileRef> { pub fn get(&self, fd: FileDesc) -> Option<FileRef> {
if fd >= self.max_fd { if fd as usize >= self.table.len() {
return None; return None;
} }
let table = &self.table; 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> { pub fn del(&mut self, fd: FileDesc) -> Option<FileRef> {
if fd >= self.max_fd { if fd as usize >= self.table.len() {
return None; return None;
} }
let mut del_file = None; let mut del_entry = None;
let table = &mut self.table; let table = &mut self.table;
std::mem::swap(&mut del_file, &mut table[fd as usize]); std::mem::swap(&mut del_entry, &mut table[fd as usize]);
if del_file.is_none() {
return None;
}
self.num_fds -= 1; self.num_fds -= 1;
if fd + 1 == self.max_fd { del_entry.map(|entry| entry.file)
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;
} impl Clone for FileTable {
del_file 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_CREAT : u32 = 0x00000040;
pub const O_TRUNC : u32 = 0x00000200; pub const O_TRUNC : u32 = 0x00000200;
pub const O_APPEND : u32 = 0x00000400; pub const O_APPEND : u32 = 0x00000400;
pub const O_CLOEXEC: u32 = 0x00080000;
// TODO: use the type defined in Rust libc. // 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( let file_ref : Arc<Box<File>> = Arc::new(Box::new(
SgxFile::new(sgx_file, is_readable, is_writable, is_append)?)); SgxFile::new(sgx_file, is_readable, is_writable, is_append)?));
let fd = {
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap(); let mut current = current_ref.lock().unwrap();
let fd = current_process.get_files_mut().put(file_ref); let close_on_spawn = flags & O_CLOEXEC != 0;
current.get_files_mut().put(file_ref, close_on_spawn)
};
Ok(fd) 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 current_ref = process::get_current();
let mut current = current_ref.lock().unwrap(); let mut current = current_ref.lock().unwrap();
let pipe = Pipe::new()?; let pipe = Pipe::new()?;
let mut file_table = current.get_files_mut(); let mut file_table = current.get_files_mut();
let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader))); let close_on_spawn = flags & O_CLOEXEC != 0;
let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer))); 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]) 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())); let stdout : Arc<Box<File>> = Arc::new(Box::new(StdoutFile::new()));
// TODO: implement and use a real stderr // TODO: implement and use a real stderr
let stderr = stdout.clone(); let stderr = stdout.clone();
file_table.put(stdin); file_table.put(stdin, false);
file_table.put(stdout); file_table.put(stdout, false);
file_table.put(stderr); file_table.put(stderr, false);
Ok(file_table) 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) 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; 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> { #[no_mangle]
check_mut_array_from_user(fds_u, 2)?; pub extern "C" fn occlum_pipe(fds: *mut c_int) -> c_int {
let fds = fs::do_pipe()?; occlum_pipe2(fds, 0)
unsafe {
*fds_u.offset(0) = fds[0] as c_int;
*fds_u.offset(1) = fds[1] as c_int;
}
Ok(())
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn occlum_pipe(fds: *mut c_int) -> c_int { pub extern "C" fn occlum_pipe2(fds: *mut c_int, flags: c_int) -> c_int {
match do_pipe(fds) { match do_pipe2(fds, flags) {
Ok(()) => { Ok(()) => {
0 0
}, },

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