From 4e0c18914f3e1eb76076646eb33d9569553741b4 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sat, 23 Mar 2019 00:18:42 +0800 Subject: [PATCH] Implement sys_sendfile --- kernel/src/drivers/block/virtio_blk.rs | 4 +- kernel/src/drivers/net/e1000.rs | 4 +- kernel/src/syscall/fs.rs | 65 ++++++++++++++++++++++++++ kernel/src/syscall/misc.rs | 4 +- kernel/src/syscall/mod.rs | 1 + 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/kernel/src/drivers/block/virtio_blk.rs b/kernel/src/drivers/block/virtio_blk.rs index ea5253e8..5fff2d7d 100644 --- a/kernel/src/drivers/block/virtio_blk.rs +++ b/kernel/src/drivers/block/virtio_blk.rs @@ -105,7 +105,7 @@ bitflags! { impl Driver for VirtIOBlkDriver { fn try_handle_interrupt(&self, _irq: Option) -> bool { - let mut driver = self.0.lock(); + let driver = self.0.lock(); // ensure header page is mapped active_table().map_if_not_exists(driver.header as usize, driver.header as usize); @@ -214,7 +214,7 @@ pub fn virtio_blk_init(node: &Node) { // configure two virtqueues: ingress and egress header.guest_page_size.write(PAGE_SIZE as u32); // one page - let mut driver = VirtIOBlkDriver(Mutex::new(VirtIOBlk { + let driver = VirtIOBlkDriver(Mutex::new(VirtIOBlk { interrupt: node.prop_u32("interrupts").unwrap(), interrupt_parent: node.prop_u32("interrupt-parent").unwrap(), header: from as usize, diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 3e76f568..3d52bd7d 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -206,7 +206,7 @@ impl<'a> phy::Device<'a> for E1000Driver { let send_desc = &mut send_queue[index]; let recv_queue_size = PAGE_SIZE / size_of::(); - let mut recv_queue = unsafe { + let recv_queue = unsafe { slice::from_raw_parts_mut(driver.recv_page as *mut E1000RecvDesc, recv_queue_size) }; let mut rdt = e1000[E1000_RDT].read(); @@ -296,7 +296,7 @@ impl phy::TxToken for E1000TxToken { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) }; let send_queue_size = PAGE_SIZE / size_of::(); - let mut send_queue = unsafe { + let send_queue = unsafe { slice::from_raw_parts_mut(driver.send_page as *mut E1000SendDesc, send_queue_size) }; let mut tdt = e1000[E1000_TDT].read(); diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 7fa708c8..c68ec8d7 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -2,6 +2,7 @@ use core::mem::size_of; use core::cmp::min; +use core::cell::UnsafeCell; use rcore_fs::vfs::Timespec; use crate::fs::*; @@ -587,6 +588,70 @@ pub fn sys_sync() -> SysResult { Ok(0) } +pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usize) -> SysResult { + info!("sendfile: out: {}, in: {}, offset: {:?}, count: {}", out_fd, in_fd, offset, count); + let proc = process(); + // We know it's save, pacify the borrow checker + let proc_cell = UnsafeCell::new(proc); + let proc_in = unsafe {&mut *proc_cell.get()}; + let proc_out = unsafe {&mut *proc_cell.get()}; + //let in_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(in_fd)?).get() }; + //let out_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(out_fd)?).get() }; + let in_file = proc_in.get_file(in_fd)?; + let out_file = proc_out.get_file(out_fd)?; + let mut buffer = [0u8; 1024]; + if offset.is_null() { + // read from current file offset + let mut bytes_read = 0; + while bytes_read < count { + let len = min(buffer.len(), count - bytes_read); + let read_len = in_file.read(&mut buffer)?; + if read_len == 0 { + break; + } + bytes_read += 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(SysError::EBADF); + } + bytes_written += write_len; + } + } + return Ok(bytes_read); + } else { + let mut proc_mem = unsafe {&mut *proc_cell.get()}; + proc_mem.vm.check_mut_ptr(offset)?; + let mut read_offset = unsafe { + *offset + }; + // read from specified offset and write 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)?; + 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(SysError::EBADF); + } + bytes_written += write_len; + } + } + unsafe { + *offset = read_offset; + } + return Ok(bytes_read); + } +} + impl Process { pub fn get_file(&mut self, fd: usize) -> Result<&mut FileHandle, SysError> { self.files.get_mut(&fd).ok_or(SysError::EBADF).and_then(|f| { diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index d422e0f9..07c2211a 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -117,9 +117,7 @@ const LINUX_REBOOT_CMD_HALT: u32 = 0xcdef0123; pub fn sys_reboot(magic: u32, magic2: u32, cmd: u32, arg: *const u8) -> SysResult { // we will skip verifying magic if cmd == LINUX_REBOOT_CMD_HALT { - unsafe { - cpu::exit_in_qemu(1); - } + cpu::exit_in_qemu(1); } Ok(0) } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 6768a1cd..b721bc4f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -66,6 +66,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize { SYS_SCHED_YIELD => sys_yield(), SYS_NANOSLEEP => sys_nanosleep(args[0] as *const TimeSpec), SYS_GETPID => sys_getpid(), + SYS_SENDFILE => sys_sendfile(args[0], args[1], args[3] as *mut usize, args[4]), SYS_SOCKET => sys_socket(args[0], args[1], args[2]), SYS_CONNECT => sys_connect(args[0], args[1] as *const SockAddr, args[2]), SYS_ACCEPT => sys_accept(args[0], args[1] as *mut SockAddr, args[2] as *mut u32),