From 224b564595ca8c219565f2a3a7dd51e4ed282981 Mon Sep 17 00:00:00 2001 From: elliptic Date: Fri, 16 Feb 2024 04:32:20 -0500 Subject: [PATCH] bug fixes --- xc-bin/src/run.rs | 4 +++ xc/src/container/runner/mod.rs | 39 ++++++++++++++++++------- xcd/src/context.rs | 12 +++++++- xcd/src/image/mod.rs | 22 ++++++++++++-- xcd/src/resources/volume/drivers/zfs.rs | 2 +- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/xc-bin/src/run.rs b/xc-bin/src/run.rs index 12b4c10..b6de159 100644 --- a/xc-bin/src/run.rs +++ b/xc-bin/src/run.rs @@ -159,6 +159,9 @@ pub(crate) struct CreateArgs { #[arg(long = "tun")] pub(crate) tun_ifaces: Vec, + + #[arg(long = "max.children", default_value="0")] + pub(crate) max_children: u32 } impl CreateArgs { @@ -288,6 +291,7 @@ impl CreateArgs { main_ip_selector: self.main_address_selector, tun_interfaces: Some(self.tun_ifaces), tap_interfaces: Some(self.tap_ifaces), + children_max: self.max_children, ..InstantiateRequest::default() }) } diff --git a/xc/src/container/runner/mod.rs b/xc/src/container/runner/mod.rs index 8ed69b7..fa56d9d 100644 --- a/xc/src/container/runner/mod.rs +++ b/xc/src/container/runner/mod.rs @@ -406,6 +406,8 @@ impl ProcessRunner { use ipc::proto::write_response; use ipc::transport::PacketTransport; + debug!(method, "runloop control stream event"); + let packet = if method == "exec" { let jexec = IpcJexec::from_packet_failable(request, |value| { serde_json::from_value(value.clone()) @@ -499,7 +501,7 @@ impl ProcessRunner { trace!( pid, ancestor, - "NOTE_EXIT: {pid} exited; ancestor: {ancestor}" + "NOTE_EXIT" ); if let Some(pos) = descentdant.iter().position(|x| *x == pid) { @@ -507,7 +509,7 @@ impl ProcessRunner { } let descentdant_gone = descentdant.is_empty(); if descentdant_gone { - debug!("all descentdant of pid {ancestor} are gone"); + debug!(ancestor, "all descentdants are gone"); } if ancestor == pid || descentdant_gone { @@ -515,7 +517,7 @@ impl ProcessRunner { if stat.pid() == ancestor { if ancestor == pid { stat.set_exited(event.data() as i32); - info!("exited: {}", event.data()); + info!(pid, exit_code=event.data(), "pid exited"); unsafe { freebsd::nix::libc::waitpid(pid as i32, std::ptr::null_mut(), 0) }; @@ -544,6 +546,7 @@ impl ProcessRunner { if descentdant_gone { stat.set_tree_exited(); if stat.id() == "main" { + info!(id=self.container.id, jid=self.container.jid, "main process exited"); self.main_exited = true; self.container.finished_at = Some(epoch_now_nano()); if (self.container.deinit_norun || self.deinits.is_empty()) @@ -694,14 +697,12 @@ impl ProcessRunner { } } } - if self.should_kill { - break 'kq; - } } } EventFilter::EVFILT_USER => { debug!("{event:#?}"); if self.container.deinit_norun || self.deinits.is_empty() { + // this is a hard kill break 'kq; } else { debug!("activating deinit queue"); @@ -772,12 +773,18 @@ pub fn run( auto_start: bool, ) -> (i32, Receiver, Receiver) { let (tx, rx) = channel(container.serialized()); - let (ltx, lrx) = channel(true); + let (ltx, lrx) = channel(false); let (parent, sender) = std::os::unix::net::UnixStream::pair().unwrap(); if let Ok(fork_result) = unsafe { freebsd::nix::unistd::fork() } { + ltx.send_if_modified(|x| { + *x = true; + true + }); match fork_result { freebsd::nix::unistd::ForkResult::Child => { + let title = std::ffi::CString::new(format!("worker jid={}", container.jid)).unwrap(); + unsafe { freebsd::libc::setproctitle(title.as_ptr()) }; let kq = unsafe { freebsd::nix::libc::kqueue() }; let mut pr = ProcessRunner::new(kq, container, auto_start); pr.add_control_stream(ControlStream::new(control_stream)); @@ -793,8 +800,11 @@ pub fn run( kevent_classic(kq, &recv_events, &mut []).unwrap(); let mut control_stream = ControlStream::new(parent); + let mut control_stream_closed = false; + let mut worker_process_exited = false; + std::thread::spawn(move || { - 'kq: loop { + while !(control_stream_closed && worker_process_exited) { let nenv = kevent_classic(kq, &[], &mut recv_events).unwrap(); let events = &recv_events[..nenv]; @@ -802,7 +812,7 @@ pub fn run( if event.filter().unwrap() == EventFilter::EVFILT_READ { let bytes = event.data() as usize; if bytes == 0 { - break 'kq; + control_stream_closed = true; } else { match control_stream.try_get_request(event.data() as usize) { Err(err) => { @@ -823,12 +833,19 @@ pub fn run( } } } else if event.filter().unwrap() == EventFilter::EVFILT_PROC { - break 'kq; + info!("worker process exited with status {}", event.data()); + worker_process_exited = true; } } } + + info!("reap worker process"); + unsafe { + freebsd::libc::waitpid(child.as_raw(), core::ptr::null_mut(), 0); + } + ltx.send_if_modified(|x| { - *x = true; + *x = false; true }); }); diff --git a/xcd/src/context.rs b/xcd/src/context.rs index 344e329..3d74458 100644 --- a/xcd/src/context.rs +++ b/xcd/src/context.rs @@ -552,6 +552,7 @@ impl ServerContext { site.stage(&applied.image)?; let netgroups = applied.request.netgroups.clone(); + let jailing_datasets = applied.request.jail_datasets.clone(); let blueprint = InstantiateBlueprint::new(id, applied, &mut this.devfs_store, &cred, &mut res)?; @@ -569,7 +570,16 @@ impl ServerContext { warn!("pf is disabled"); } - site.run_container(blueprint)?; + match site.run_container(blueprint) { + Ok(_) => (), + Err(error) => { + for dataset in jailing_datasets.iter() { + res.dataset_tracker.unjail(dataset); + } + return Err(error) + } + }; + let notify = site.container_notify.clone().unwrap(); let jail = site.container_dump().unwrap(); let arc_site = Arc::new(RwLock::new(site)); diff --git a/xcd/src/image/mod.rs b/xcd/src/image/mod.rs index aa86687..d1a9514 100644 --- a/xcd/src/image/mod.rs +++ b/xcd/src/image/mod.rs @@ -587,13 +587,31 @@ impl RootFsRecipe { file.push(digest.digest.as_str()); let file_path = file.to_string_lossy().to_string(); debug!(file_path, "extracting"); - _ = tokio::process::Command::new("ocitar") + match tokio::process::Command::new("ocitar") .arg("-xf") .arg(&file) .arg("-C") .arg(&root) .status() - .await; + .await + { + Ok(status) => { + if !status.success() { + debug!( + file_path, + root=root.to_str(), + exit_code=status.code(), + "failed to extract file to root: ocitar exit with non-zero exit code") + } + }, + Err(error) => { + debug!( + file_path, + root=root.to_str(), + error=error.to_string(), + "failed to extract file to root"); + } + } debug!(file_path, "finished"); } handle.snapshot2(target_dataset, "xc")?; diff --git a/xcd/src/resources/volume/drivers/zfs.rs b/xcd/src/resources/volume/drivers/zfs.rs index 3217a6b..85f28e3 100644 --- a/xcd/src/resources/volume/drivers/zfs.rs +++ b/xcd/src/resources/volume/drivers/zfs.rs @@ -144,7 +144,7 @@ impl VolumeDriver for ZfsDriver { Ok(Mount { options: Vec::from_iter(mount_options), - ..Mount::nullfs(&mount_point, &real_dest) + ..Mount::nullfs(&mount_point, real_dest) }) } }