Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions init/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/reboot.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
Expand All @@ -32,6 +33,7 @@

#define KRUN_EXIT_CODE_IOCTL 0x7602
#define KRUN_REMOVE_ROOT_DIR_IOCTL 0x7603
#define KRUN_EXIT_VM_IOCTL 0x7604

#define KRUN_MAGIC "KRUN"
#define KRUN_FOOTER_LEN 12
Expand Down Expand Up @@ -1003,6 +1005,41 @@ void set_exit_code(int code)
close(fd);
}

static void request_vm_exit(void)
{
int fd;
int ret;
int virtiofs_check;

virtiofs_check = is_virtiofs("/");
if (virtiofs_check < 0) {
printf("Warning: Could not determine filesystem type for root\n");
}

if (virtiofs_check == 0) {
return;
}

fd = open("/", O_RDONLY);
if (fd < 0) {
perror("Couldn't open root filesystem to request VM exit");
return;
}

ret = ioctl(fd, KRUN_EXIT_VM_IOCTL, 0);
if (ret < 0) {
perror("Error using the ioctl to request VM exit");
}

close(fd);
}

static void shutdown_vm(void)
{
sync();
request_vm_exit();
}

int try_mount(const char *source, const char *target, const char *fstype,
unsigned long mountflags, const void *data)
{
Expand Down Expand Up @@ -1241,13 +1278,12 @@ int main(int argc, char **argv)
// Not the first child, ignore it.
};

// The workload's entrypoint has exited, record its exit code and exit
// ourselves.
if (WIFEXITED(status)) {
set_exit_code(WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
set_exit_code(WTERMSIG(status) + 128);
}
shutdown_vm();
}

return 0;
Expand Down
10 changes: 9 additions & 1 deletion src/devices/src/virtio/fs/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crossbeam_channel::Sender;
use std::cmp;
use std::io::Write;
use std::sync::atomic::{AtomicI32, AtomicU64, Ordering};
use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU64, Ordering};
use std::sync::Arc;
use std::thread::JoinHandle;

Expand Down Expand Up @@ -49,6 +49,8 @@ pub struct Fs {
worker_thread: Option<JoinHandle<()>>,
worker_stopfd: EventFd,
exit_code: Arc<AtomicI32>,
exit_request: Arc<AtomicBool>,
exit_evt: EventFd,
#[cfg(target_os = "macos")]
map_sender: Option<Sender<WorkerMessage>>,
}
Expand All @@ -58,7 +60,9 @@ impl Fs {
fs_id: String,
shared_dir: String,
exit_code: Arc<AtomicI32>,
exit_request: Arc<AtomicBool>,
allow_root_dir_delete: bool,
exit_evt: EventFd,
) -> super::Result<Fs> {
let avail_features = (1u64 << VIRTIO_F_VERSION_1) | (1u64 << VIRTIO_RING_F_EVENT_IDX);

Expand All @@ -83,6 +87,8 @@ impl Fs {
worker_thread: None,
worker_stopfd: EventFd::new(EFD_NONBLOCK).map_err(FsError::EventFd)?,
exit_code,
exit_request,
exit_evt,
#[cfg(target_os = "macos")]
map_sender: None,
})
Expand Down Expand Up @@ -185,6 +191,8 @@ impl VirtioDevice for Fs {
self.passthrough_cfg.clone(),
self.worker_stopfd.try_clone().unwrap(),
self.exit_code.clone(),
self.exit_request.clone(),
self.exit_evt.try_clone().unwrap(),
#[cfg(target_os = "macos")]
self.map_sender.clone(),
);
Expand Down
3 changes: 2 additions & 1 deletion src/devices/src/virtio/fs/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::ffi::{CStr, CString};
use std::fs::File;
use std::io;
use std::mem;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::{AtomicBool, AtomicI32};
use std::sync::{Arc, Mutex};
use std::time::Duration;

Expand Down Expand Up @@ -1170,6 +1170,7 @@ pub trait FileSystem {
in_size: u32,
out_size: u32,
exit_code: &Arc<AtomicI32>,
exit_request: &Arc<AtomicBool>,
) -> io::Result<Vec<u8>> {
Err(io::Error::from_raw_os_error(bindings::LINUX_ENOSYS))
}
Expand Down
11 changes: 11 additions & 0 deletions src/devices/src/virtio/fs/linux/passthrough.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2179,6 +2179,7 @@ impl FileSystem for PassthroughFs {
_in_size: u32,
out_size: u32,
exit_code: &Arc<AtomicI32>,
exit_request: &Arc<AtomicBool>,
) -> io::Result<Vec<u8>> {
const VIRTIO_IOC_MAGIC: u8 = b'v';

Expand All @@ -2198,6 +2199,10 @@ impl FileSystem for PassthroughFs {
const VIRTIO_IOC_REMOVE_ROOT_DIR_REQ: u32 =
request_code_none!(VIRTIO_IOC_MAGIC, VIRTIO_IOC_REMOVE_ROOT_DIR_CODE) as u32;

const VIRTIO_IOC_TYPE_EXIT_REQUEST: u8 = 4;
const VIRTIO_IOC_EXIT_REQUEST_REQ: u32 =
request_code_none!(VIRTIO_IOC_MAGIC, VIRTIO_IOC_TYPE_EXIT_REQUEST) as u32;

match cmd {
VIRTIO_IOC_EXPORT_FD_REQ => {
if out_size as usize != VIRTIO_IOC_EXPORT_FD_SIZE {
Expand Down Expand Up @@ -2229,9 +2234,15 @@ impl FileSystem for PassthroughFs {
Ok(ret)
}
VIRTIO_IOC_EXIT_CODE_REQ => {
debug!("virtiofs exit-code ioctl received: {}", arg as i32);
exit_code.store(arg as i32, Ordering::SeqCst);
Ok(Vec::new())
}
VIRTIO_IOC_EXIT_REQUEST_REQ => {
debug!("virtiofs explicit-exit ioctl received");
exit_request.store(true, Ordering::SeqCst);
Ok(Vec::new())
}
VIRTIO_IOC_REMOVE_ROOT_DIR_REQ if self.cfg.allow_root_dir_delete => {
std::fs::remove_dir_all(&self.cfg.root_dir)?;
Ok(Vec::new())
Expand Down
6 changes: 6 additions & 0 deletions src/devices/src/virtio/fs/macos/passthrough.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2435,17 +2435,23 @@ impl FileSystem for PassthroughFs {
_in_size: u32,
_out_size: u32,
exit_code: &Arc<AtomicI32>,
exit_request: &Arc<AtomicBool>,
) -> io::Result<Vec<u8>> {
// We can't use nix::request_code_none here since it's system-dependent
// and we need the value from Linux.
const VIRTIO_IOC_EXIT_CODE_REQ: u32 = 0x7602;
const VIRTIO_IOC_REMOVE_ROOT_DIR_REQ: u32 = 0x7603;
const VIRTIO_IOC_EXIT_REQUEST_REQ: u32 = 0x7604;

match cmd {
VIRTIO_IOC_EXIT_CODE_REQ => {
exit_code.store(arg as i32, Ordering::SeqCst);
Ok(Vec::new())
}
VIRTIO_IOC_EXIT_REQUEST_REQ => {
exit_request.store(true, Ordering::SeqCst);
Ok(Vec::new())
}
VIRTIO_IOC_REMOVE_ROOT_DIR_REQ if self.cfg.allow_root_dir_delete => {
std::fs::remove_dir_all(&self.cfg.root_dir)?;
Ok(Vec::new())
Expand Down
7 changes: 5 additions & 2 deletions src/devices/src/virtio/fs/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::ffi::{CStr, CString};
use std::fs::File;
use std::io::{self, Read, Write};
use std::mem::size_of;
use std::sync::atomic::{AtomicI32, AtomicU64, Ordering};
use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU64, Ordering};
use std::sync::Arc;

use vm_memory::ByteValued;
Expand Down Expand Up @@ -85,6 +85,7 @@ impl<F: FileSystem + Sync> Server<F> {
w: Writer,
shm_region: &Option<VirtioShmRegion>,
exit_code: &Arc<AtomicI32>,
exit_request: &Arc<AtomicBool>,
#[cfg(target_os = "macos")] map_sender: &Option<Sender<WorkerMessage>>,
) -> Result<usize> {
let in_header: InHeader = r.read_obj().map_err(Error::DecodeMessage)?;
Expand Down Expand Up @@ -134,7 +135,7 @@ impl<F: FileSystem + Sync> Server<F> {
x if x == Opcode::Interrupt as u32 => self.interrupt(in_header),
x if x == Opcode::Bmap as u32 => self.bmap(in_header, r, w),
x if x == Opcode::Destroy as u32 => self.destroy(),
x if x == Opcode::Ioctl as u32 => self.ioctl(in_header, r, w, exit_code),
x if x == Opcode::Ioctl as u32 => self.ioctl(in_header, r, w, exit_code, exit_request),
x if x == Opcode::Poll as u32 => self.poll(in_header, r, w),
x if x == Opcode::NotifyReply as u32 => self.notify_reply(in_header, r, w),
x if x == Opcode::BatchForget as u32 => self.batch_forget(in_header, r, w),
Expand Down Expand Up @@ -1185,6 +1186,7 @@ impl<F: FileSystem + Sync> Server<F> {
mut r: Reader,
w: Writer,
exit_code: &Arc<AtomicI32>,
exit_request: &Arc<AtomicBool>,
) -> Result<usize> {
let IoctlIn {
fh,
Expand All @@ -1205,6 +1207,7 @@ impl<F: FileSystem + Sync> Server<F> {
in_size,
out_size,
exit_code,
exit_request,
) {
Ok(data) => {
let out = IoctlOut {
Expand Down
17 changes: 16 additions & 1 deletion src/devices/src/virtio/fs/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crossbeam_channel::Sender;
use utils::worker_message::WorkerMessage;

use std::os::fd::AsRawFd;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use std::sync::Arc;
use std::thread;

Expand All @@ -28,6 +28,8 @@ pub struct FsWorker {
server: Server<PassthroughFs>,
stop_fd: EventFd,
exit_code: Arc<AtomicI32>,
exit_request: Arc<AtomicBool>,
exit_evt: EventFd,
#[cfg(target_os = "macos")]
map_sender: Option<Sender<WorkerMessage>>,
}
Expand All @@ -43,6 +45,8 @@ impl FsWorker {
passthrough_cfg: passthrough::Config,
stop_fd: EventFd,
exit_code: Arc<AtomicI32>,
exit_request: Arc<AtomicBool>,
exit_evt: EventFd,
#[cfg(target_os = "macos")] map_sender: Option<Sender<WorkerMessage>>,
) -> Self {
Self {
Expand All @@ -54,6 +58,8 @@ impl FsWorker {
server: Server::new(PassthroughFs::new(passthrough_cfg).unwrap()),
stop_fd,
exit_code,
exit_request,
exit_evt,
#[cfg(target_os = "macos")]
map_sender,
}
Expand Down Expand Up @@ -160,6 +166,7 @@ impl FsWorker {
writer,
&self.shm_region,
&self.exit_code,
&self.exit_request,
#[cfg(target_os = "macos")]
&self.map_sender,
) {
Expand All @@ -173,6 +180,14 @@ impl FsWorker {
if queue.needs_notification(&self.mem).unwrap() {
self.interrupt.signal_used_queue();
}

if self.exit_request.swap(false, Ordering::SeqCst) {
debug!("virtiofs explicit exit request received; signaling VMM exit event");
if let Err(e) = self.exit_evt.write(1) {
error!("failed to signal VMM exit event: {e}");
}
return;
}
}
}
}
21 changes: 21 additions & 0 deletions src/vmm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use std::io::{self, IsTerminal, Read};
use std::os::fd::AsRawFd;
use std::os::fd::{BorrowedFd, FromRawFd};
use std::path::PathBuf;
#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicI32;
use std::sync::{Arc, Mutex};

Expand Down Expand Up @@ -949,6 +951,8 @@ pub fn build_microvm(

// We use this atomic to record the exit code set by init/init.c in the VM.
let exit_code = Arc::new(AtomicI32::new(i32::MAX));
#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
let exit_request = Arc::new(AtomicBool::new(false));

let mut vmm = Vmm {
guest_memory,
Expand Down Expand Up @@ -1030,6 +1034,13 @@ pub fn build_microvm(
attach_input_devices(&mut vmm, &vm_resources.input_backends, intc.clone())?;
}

#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
let fs_exit_evt = vmm
.exit_evt
.try_clone()
.map_err(Error::EventFd)
.map_err(StartMicrovmError::Internal)?;

#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
attach_fs_devices(
&mut vmm,
Expand All @@ -1039,6 +1050,8 @@ pub fn build_microvm(
export_table,
intc.clone(),
exit_code,
exit_request,
fs_exit_evt,
#[cfg(target_os = "macos")]
_sender,
)?;
Expand Down Expand Up @@ -1873,13 +1886,16 @@ fn attach_mmio_device(
}

#[cfg(not(any(feature = "tee", feature = "aws-nitro")))]
#[allow(clippy::too_many_arguments)]
fn attach_fs_devices(
vmm: &mut Vmm,
fs_devs: &[FsDeviceConfig],
shm_manager: &mut ShmManager,
#[cfg(not(feature = "tee"))] export_table: Option<ExportTable>,
intc: IrqChip,
exit_code: Arc<AtomicI32>,
exit_request: Arc<AtomicBool>,
exit_evt: EventFd,
#[cfg(target_os = "macos")] map_sender: Sender<WorkerMessage>,
) -> std::result::Result<(), StartMicrovmError> {
use self::StartMicrovmError::*;
Expand All @@ -1890,7 +1906,12 @@ fn attach_fs_devices(
config.fs_id.clone(),
config.shared_dir.clone(),
exit_code.clone(),
exit_request.clone(),
config.allow_root_dir_delete,
exit_evt
.try_clone()
.map_err(Error::EventFd)
.map_err(Internal)?,
)
.unwrap(),
));
Expand Down
Loading