1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00

Improved error handling

The error::Error enum has changed to provide additional information,
especially about missing files and failed IOCTL commands.
This commit is contained in:
l_schmid 2017-05-11 21:05:52 +02:00
parent d687208b01
commit bb0e1f2a36
8 changed files with 104 additions and 41 deletions

View file

@ -14,24 +14,36 @@ pub struct Multi {
impl Multi {
pub fn new(num: u8, path: &str) -> Result<Multi> {
let cpu_path = format!("/sys/hermit/isle{}/path", num);
let bin_path= format!("/sys/hermit/isle{}/cpus", num);
// request a new isle, enforce close
{
let mut path_file = File::create(format!("/sys/hermit/isle{}/path", num)).map_err(|_| Error::InvalidFile)?;
let mut cpus_file = File::create(format!("/sys/hermit/isle{}/cpus", num)).map_err(|_| Error::InvalidFile)?;
let mut path_file = File::create(&bin_path)
.map_err(|_| Error::InvalidFile(bin_path.clone()))?;
let mut cpus_file = File::create(&cpu_path)
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
let cpus = hermit_env::num_cpus();
path_file.write_all(path.as_bytes()).map_err(|_| Error::InvalidFile)?;
cpus_file.write_all(cpus.as_bytes()).map_err(|_| Error::InvalidFile)?;
path_file.write_all(path.as_bytes())
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
cpus_file.write_all(cpus.as_bytes())
.map_err(|_| Error::InvalidFile(bin_path))?;
}
// check the result
let mut path_file = File::create(format!("/sys/hermit/isle{}/cpus", num)).map_err(|_| Error::InvalidFile)?;
let mut path_file = File::create(&cpu_path)
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
let mut result = String::new();
path_file.read_to_string(&mut result).map_err(|_| Error::InvalidFile)?;
path_file.read_to_string(&mut result)
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
if result.parse::<i32>().map_err(|_| Error::InvalidFile)? == -1 {
if result.parse::<i32>().map_err(|_| Error::InvalidFile(cpu_path))? == -1 {
return Err(Error::MultiIsleFailed);
}

View file

@ -1,18 +1,60 @@
use std::result;
use std::{result, fmt};
use nix;
use errno::errno;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
InternalError,
NotEnoughMemory,
InvalidFile,
FailedIOCTL(nix::Error),
InvalidFile(String),
IOCTL(NameIOCTL),
KernelNotLoaded,
MissingFrequency,
MultiIsleFailed,
CannotCreateTmpFile(usize),
QEmu((String, String))
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InternalError => write!(f, "An internal error has occurred, please report."),
Error::NotEnoughMemory => write!(f, "The host system has not enough memory, please check your memory usage."),
Error::InvalidFile(ref file) => write!(f, "The file {} was not found or is invalid.", file),
Error::IOCTL(ref name) => {
let e = errno();
write!(f, "The IOCTL command {:?} has failed: {}", name, e)
},
Error::KernelNotLoaded => write!(f, "Please load the kernel before your start the virtual machine."),
Error::MissingFrequency => write!(f, "Couldn't get the CPU frequency from you system. (is /proc/cpuinfo missing?)"),
Error::MultiIsleFailed => write!(f, "The Multi isle was selected on a system without supported, please load the kernel driver."),
Error::CannotCreateTmpFile(_) => write!(f, "Couldn't create a tmp file in /tmp."),
Error::QEmu((_, ref stderr)) => write!(f, "The qemu binary has encountered an error: {}", stderr)
}
}
}
#[derive(Debug)]
pub enum NameIOCTL {
GetVersion,
CreateVM,
GetMsrIndexList,
CheckExtension,
GetVCPUMMAPSize,
GetSupportedCpuID,
SetCpuID2,
CreateVcpu,
SetMemoryAlias,
SetNRMMUPages,
GetNRMMUPages,
SetMemoryRegion,
SetUserMemoryRegion,
CreateIRQChip,
Run,
GetRegs,
SetRegs,
GetSRegs,
SetSRegs
}

View file

@ -54,7 +54,7 @@ impl IsleKind {
_ => File::open(format!("/sys/hermit/isle{}/log", self.get_num()))
};
let mut file = file.map_err(|_| Error::InvalidFile)?;
let mut file = file.map_err(|x| Error::InvalidFile(format!("{:?}",x)))?;
let mut reader = BufReader::new(file);
//let mut result = String::new();
@ -95,11 +95,13 @@ impl IsleKind {
}
pub fn stop(&self) -> Result<()> {
let mut cpus_file = File::create(format!("/sys/hermit/isle{}/cpus", self.get_num()))
.map_err(|_| Error::InvalidFile)?;
let cpu_path = format!("/sys/hermit/isle{}/cpus", self.get_num());
let mut cpus_file = File::create(&cpu_path)
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
cpus_file.write("-1".as_bytes())
.map_err(|_| Error::InvalidFile);
.map_err(|_| Error::InvalidFile(cpu_path));
Ok(())
}

View file

@ -1441,7 +1441,7 @@ impl kvm_cpuid_entry2 {
ebx: 0,
ecx: 0,
edx: 0,
padding: [0; 3]
padding: [0u32; 3]
}
}
}
@ -1497,19 +1497,19 @@ impl Clone for kvm_cpuid_entry2 {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Copy)]
#[derive(Debug, Copy)]
pub struct kvm_cpuid2 {
pub nent: __u32,
pub padding: __u32,
pub entries: [kvm_cpuid_entry2; 100]
pub entries: [kvm_cpuid_entry2; 4]
}
impl kvm_cpuid2 {
pub fn empty() -> kvm_cpuid2 {
kvm_cpuid2 {
nent: 100,
nent: 4,
padding: 0,
entries: [kvm_cpuid_entry2::empty(); 100]
entries: [kvm_cpuid_entry2::empty(); 4]
}
}
}

View file

@ -7,7 +7,7 @@ use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use libc;
use uhyve::{Error, Result};
use uhyve::{Error, Result, NameIOCTL};
use uhyve::vm::VirtualMachine;
/// The normal way of defining a IOCTL interface is provided by C macros. In Rust we have our own
@ -80,7 +80,7 @@ impl Uhyve {
match ioctl::get_version(self.file.as_raw_fd(), ptr::null_mut()) {
Ok(12) => Ok(Version::Version12),
Ok(_) => Ok(Version::Unsupported),
Err(_) => Err(Error::InternalError)
Err(_) => Err(Error::IOCTL(NameIOCTL::GetVersion))
}
}
}

View file

@ -8,7 +8,7 @@ use errno::errno;
use uhyve;
use uhyve::kvm_header::{kvm_sregs, kvm_regs, kvm_segment, kvm_cpuid2};
use uhyve::{Result, Error};
use uhyve::{Result, Error, NameIOCTL};
use uhyve::gdt;
use uhyve::proto;
@ -38,6 +38,7 @@ pub const X86_PDPT_RW: u64 = (1 << 1);
pub const X86_PDPT_PS: u64 = (1 << 7);
pub struct VirtualCPU {
kvm_fd: libc::c_int,
vm_fd: libc::c_int,
pub vcpu_fd: libc::c_int,
id: u8,
@ -62,7 +63,7 @@ impl VirtualCPU {
}?;
let cpu = VirtualCPU {
vm_fd: vm_fd, vcpu_fd: fd, id: id, file: file, run_mem: run_mem
kvm_fd: kvm_fd, vm_fd: vm_fd, vcpu_fd: fd, id: id, file: file, run_mem: run_mem
};
if id == 0 {
@ -83,6 +84,8 @@ impl VirtualCPU {
cpu.set_regs(regs)?;
debug!("Set the CPUID");
cpu.setup_cpuid()?;
Ok(cpu)
@ -91,7 +94,7 @@ impl VirtualCPU {
pub fn create_vcpu(fd: c_int) -> Result<c_int> {
unsafe {
uhyve::ioctl::create_vcpu(fd, ptr::null_mut())
.map_err(|x| Error::FailedIOCTL(x))
.map_err(|_| Error::IOCTL(NameIOCTL::CreateVcpu))
}
}
@ -99,7 +102,7 @@ impl VirtualCPU {
let mut sregs = kvm_sregs::empty();
unsafe {
uhyve::ioctl::get_sregs(self.vcpu_fd, (&mut sregs) as *mut kvm_sregs)
.map_err(|x| Error::FailedIOCTL(x))?;
.map_err(|x| Error::IOCTL(NameIOCTL::GetSRegs))?;
}
Ok(sregs)
@ -108,7 +111,7 @@ impl VirtualCPU {
pub fn set_sregs(&self, mut sregs: kvm_sregs) -> Result<()> {
unsafe {
uhyve::ioctl::set_sregs(self.vcpu_fd, (&mut sregs) as *mut kvm_sregs)
.map_err(|x| Error::FailedIOCTL(x))?;
.map_err(|x| Error::IOCTL(NameIOCTL::SetSRegs))?;
}
Ok(())
@ -117,7 +120,7 @@ impl VirtualCPU {
pub fn set_regs(&self, mut regs: kvm_regs) -> Result<()> {
unsafe {
uhyve::ioctl::set_regs(self.vcpu_fd, (&mut regs) as *mut kvm_regs)
.map_err(|x| Error::FailedIOCTL(x))?;
.map_err(|x| Error::IOCTL(NameIOCTL::SetSRegs))?;
}
Ok(())
@ -125,9 +128,11 @@ impl VirtualCPU {
pub fn get_supported_cpuid(&self) -> Result<kvm_cpuid2> {
let mut cpuid = kvm_cpuid2::empty();
debug!("Size {}", mem::size_of::<kvm_cpuid2>());
unsafe {
uhyve::ioctl::get_supported_cpuid(self.vm_fd, (&mut cpuid) as *mut kvm_cpuid2)
.map_err(|x| Error::FailedIOCTL(x))?;
uhyve::ioctl::get_supported_cpuid(self.kvm_fd, (&mut cpuid) as *mut kvm_cpuid2)
.map_err(|x| Error::IOCTL(NameIOCTL::GetSupportedCpuID))?;
}
Ok(cpuid)
@ -136,7 +141,7 @@ impl VirtualCPU {
pub fn set_cpuid2(&self, mut cpuid: kvm_cpuid2) -> Result<()> {
unsafe {
uhyve::ioctl::set_cpuid2(self.vm_fd, (&mut cpuid) as *mut kvm_cpuid2)
.map_err(|x| Error::FailedIOCTL(x))?;
.map_err(|x| Error::IOCTL(NameIOCTL::SetCpuID2))?;
}
Ok(())
@ -145,14 +150,14 @@ impl VirtualCPU {
pub fn get_mmap_size(vcpu_fd: libc::c_int) -> Result<usize> {
unsafe {
uhyve::ioctl::get_vcpu_mmap_size(vcpu_fd, ptr::null_mut())
.map_err(|x| Error::FailedIOCTL(x)).map(|x| { debug!("MMAP size {}", x); x as usize })
.map_err(|x| Error::IOCTL(NameIOCTL::GetVCPUMMAPSize)).map(|x| { x as usize})
}
}
pub fn single_run(&self, guest_mem: &mut [u8]) -> Result<i32> {
let ret = unsafe {
uhyve::ioctl::run(self.vcpu_fd, ptr::null_mut())
.map_err(|x| Error::FailedIOCTL(x))
.map_err(|x| Error::IOCTL(NameIOCTL::Run))
}?;
if ret == -1 {
@ -270,6 +275,8 @@ impl VirtualCPU {
pub fn setup_cpuid(&self) -> Result<()> {
let mut kvm_cpuid = self.get_supported_cpuid()?;
debug!("Supported CPUs {:?}", kvm_cpuid);
for entry in kvm_cpuid.entries.iter_mut() {
match entry.function {
1 => {

View file

@ -12,7 +12,7 @@ use elf::types::{ELFCLASS64, OSABI, PT_LOAD};
use utils;
use uhyve;
use uhyve::kvm_header::{kvm_userspace_memory_region };
use uhyve::{Result, Error};
use uhyve::{Result, Error, NameIOCTL};
use uhyve::vcpu::VirtualCPU;
//use byteorder::ByteOrder;
@ -43,17 +43,17 @@ impl VirtualMachine {
debug!("UHYVE - Load kernel from {}", path);
// open the file in read only
let file = Mmap::open_path(path, Protection::Read).map_err(|_| Error::InvalidFile)?;
let file = Mmap::open_path(path, Protection::Read).map_err(|_| Error::InvalidFile(path.into()))?;
// parse the header with ELF module
let file_efi = {
let mut data = unsafe { Cursor::new(file.as_slice()) };
elf::File::open_stream(&mut data).map_err(|_| Error::InvalidFile)
elf::File::open_stream(&mut data).map_err(|_| Error::InvalidFile(path.into()))
}?;
if file_efi.ehdr.class != ELFCLASS64 || file_efi.ehdr.osabi != OSABI(0x42) {
return Err(Error::InvalidFile);
return Err(Error::InvalidFile(path.into()));
}
self.elf_entry = Some(file_efi.ehdr.entry);
@ -116,14 +116,14 @@ impl VirtualMachine {
pub fn set_user_memory_region(&self, mut region: kvm_userspace_memory_region) -> Result<()> {
unsafe {
uhyve::ioctl::set_user_memory_region(self.vm_fd, (&mut region) as *mut kvm_userspace_memory_region)
.map_err(|x| Error::FailedIOCTL(x)).map(|_| ())
.map_err(|x| Error::IOCTL(NameIOCTL::SetUserMemoryRegion)).map(|_| ())
}
}
pub fn create_irqchip(&self) -> Result<()> {
unsafe {
uhyve::ioctl::create_irqchip(self.vm_fd, ptr::null_mut())
.map_err(|x| Error::FailedIOCTL(x)).map(|_| ())
.map_err(|x| Error::IOCTL(NameIOCTL::CreateIRQChip)).map(|_| ())
}
}

View file

@ -57,7 +57,7 @@ pub fn delete_tmp_file(name: &str) -> Result<()> {
let res = libc::unlink(c_str.into_raw());
if res < 0 {
return Err(Error::InvalidFile);
return Err(Error::InvalidFile(name.into()));
} else {
return Ok(());
}