fix(xenclient): use a single transaction for device setup (#130)

This commit is contained in:
Alex Zenla
2024-05-05 13:39:53 -07:00
committed by GitHub
parent 3187830ff5
commit 51dff0361d
5 changed files with 74 additions and 40 deletions

1
Cargo.lock generated
View File

@ -1600,6 +1600,7 @@ dependencies = [
"elf", "elf",
"env_logger", "env_logger",
"flate2", "flate2",
"indexmap 2.2.6",
"krata-xencall", "krata-xencall",
"krata-xenstore", "krata-xenstore",
"libc", "libc",

View File

@ -791,7 +791,13 @@ impl XenCall {
index, index,
pirq, pirq,
); );
let mut physdev = PhysdevMapPirq::default(); let mut physdev = PhysdevMapPirq {
domid: domid as u16,
typ: 0x1,
index: index as c_int,
pirq: pirq.map(|x| x as c_int).unwrap_or(index as c_int),
..Default::default()
};
physdev.domid = domid as u16; physdev.domid = domid as u16;
physdev.typ = 0x1; physdev.typ = 0x1;
physdev.index = index as c_int; physdev.index = index as c_int;

View File

@ -12,6 +12,7 @@ resolver = "2"
async-trait = { workspace = true } async-trait = { workspace = true }
elf = { workspace = true } elf = { workspace = true }
flate2 = { workspace = true } flate2 = { workspace = true }
indexmap = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
log = { workspace = true } log = { workspace = true }
krata-xencall = { path = "../xencall", version = "^0.0.10" } krata-xencall = { path = "../xencall", version = "^0.0.10" }

View File

@ -20,12 +20,12 @@ use crate::boot::{ArchBootSetup, BootSetup};
use crate::elfloader::ElfImageLoader; use crate::elfloader::ElfImageLoader;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use boot::BootState; use boot::BootState;
use indexmap::IndexMap;
use log::{debug, trace, warn}; use log::{debug, trace, warn};
use pci::{PciBdf, XenPciBackend}; use pci::{PciBdf, XenPciBackend};
use sys::XEN_PAGE_SHIFT; use sys::XEN_PAGE_SHIFT;
use tokio::time::timeout; use tokio::time::timeout;
use std::collections::HashMap;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
@ -36,7 +36,8 @@ use xencall::sys::{
}; };
use xencall::XenCall; use xencall::XenCall;
use xenstore::{ use xenstore::{
XsPermission, XsdClient, XsdInterface, XS_PERM_NONE, XS_PERM_READ, XS_PERM_READ_WRITE, XsPermission, XsdClient, XsdInterface, XsdTransaction, XS_PERM_NONE, XS_PERM_READ,
XS_PERM_READ_WRITE,
}; };
pub mod pci; pub mod pci;
@ -145,6 +146,7 @@ pub struct CreatedDomain {
pub channels: Vec<CreatedChannel>, pub channels: Vec<CreatedChannel>,
} }
#[allow(clippy::too_many_arguments)]
impl XenClient { impl XenClient {
pub async fn open(current_domid: u32) -> Result<XenClient> { pub async fn open(current_domid: u32) -> Result<XenClient> {
let store = XsdClient::open().await?; let store = XsdClient::open().await?;
@ -374,7 +376,10 @@ impl XenClient {
{ {
return Err(Error::IntroduceDomainFailed); return Err(Error::IntroduceDomainFailed);
} }
let tx = self.store.transaction().await?;
self.console_device_add( self.console_device_add(
&tx,
&DomainChannel { &DomainChannel {
typ: config typ: config
.use_console_backend .use_console_backend
@ -397,6 +402,7 @@ impl XenClient {
for (index, channel) in config.channels.iter().enumerate() { for (index, channel) in config.channels.iter().enumerate() {
let (Some(ring_ref), Some(evtchn)) = self let (Some(ring_ref), Some(evtchn)) = self
.console_device_add( .console_device_add(
&tx,
channel, channel,
&p2m, &p2m,
&state, &state,
@ -415,6 +421,7 @@ impl XenClient {
for (index, disk) in config.disks.iter().enumerate() { for (index, disk) in config.disks.iter().enumerate() {
self.disk_device_add( self.disk_device_add(
&tx,
&dom_path, &dom_path,
&backend_dom_path, &backend_dom_path,
config.backend_domid, config.backend_domid,
@ -427,6 +434,7 @@ impl XenClient {
for (index, filesystem) in config.filesystems.iter().enumerate() { for (index, filesystem) in config.filesystems.iter().enumerate() {
self.fs_9p_device_add( self.fs_9p_device_add(
&tx,
&dom_path, &dom_path,
&backend_dom_path, &backend_dom_path,
config.backend_domid, config.backend_domid,
@ -439,6 +447,7 @@ impl XenClient {
for (index, vif) in config.vifs.iter().enumerate() { for (index, vif) in config.vifs.iter().enumerate() {
self.vif_device_add( self.vif_device_add(
&tx,
&dom_path, &dom_path,
&backend_dom_path, &backend_dom_path,
config.backend_domid, config.backend_domid,
@ -451,6 +460,7 @@ impl XenClient {
for (index, pci) in config.pcis.iter().enumerate() { for (index, pci) in config.pcis.iter().enumerate() {
self.pci_device_add( self.pci_device_add(
&tx,
&dom_path, &dom_path,
&backend_dom_path, &backend_dom_path,
config.backend_domid, config.backend_domid,
@ -468,20 +478,21 @@ impl XenClient {
.evtchn_alloc_unbound(domid, config.backend_domid) .evtchn_alloc_unbound(domid, config.backend_domid)
.await?; .await?;
let channel_path = format!("{}/evtchn/{}", dom_path, channel.name); let channel_path = format!("{}/evtchn/{}", dom_path, channel.name);
self.store tx.write_string(&format!("{}/name", channel_path), &channel.name)
.write_string(&format!("{}/name", channel_path), &channel.name)
.await?; .await?;
self.store tx.write_string(&format!("{}/channel", channel_path), &id.to_string())
.write_string(&format!("{}/channel", channel_path), &id.to_string())
.await?; .await?;
} }
tx.commit().await?;
self.call.unpause_domain(domid).await?; self.call.unpause_domain(domid).await?;
Ok(CreatedDomain { domid, channels }) Ok(CreatedDomain { domid, channels })
} }
async fn disk_device_add( async fn disk_device_add(
&self, &self,
tx: &XsdTransaction,
dom_path: &str, dom_path: &str,
backend_dom_path: &str, backend_dom_path: &str,
backend_domid: u32, backend_domid: u32,
@ -519,6 +530,7 @@ impl XenClient {
]; ];
self.device_add( self.device_add(
tx,
"vbd", "vbd",
id, id,
dom_path, dom_path,
@ -532,9 +544,10 @@ impl XenClient {
Ok(()) Ok(())
} }
#[allow(clippy::too_many_arguments, clippy::unnecessary_unwrap)] #[allow(clippy::unnecessary_unwrap)]
async fn console_device_add( async fn console_device_add(
&self, &self,
tx: &XsdTransaction,
channel: &DomainChannel, channel: &DomainChannel,
p2m: &[u64], p2m: &[u64],
state: &BootState, state: &BootState,
@ -587,6 +600,7 @@ impl XenClient {
} }
self.device_add( self.device_add(
tx,
"console", "console",
index as u64, index as u64,
dom_path, dom_path,
@ -602,6 +616,7 @@ impl XenClient {
async fn fs_9p_device_add( async fn fs_9p_device_add(
&self, &self,
tx: &XsdTransaction,
dom_path: &str, dom_path: &str,
backend_dom_path: &str, backend_dom_path: &str,
backend_domid: u32, backend_domid: u32,
@ -625,6 +640,7 @@ impl XenClient {
]; ];
self.device_add( self.device_add(
tx,
"9pfs", "9pfs",
id, id,
dom_path, dom_path,
@ -640,6 +656,7 @@ impl XenClient {
async fn vif_device_add( async fn vif_device_add(
&self, &self,
tx: &XsdTransaction,
dom_path: &str, dom_path: &str,
backend_dom_path: &str, backend_dom_path: &str,
backend_domid: u32, backend_domid: u32,
@ -683,6 +700,7 @@ impl XenClient {
]; ];
self.device_add( self.device_add(
tx,
"vif", "vif",
id, id,
dom_path, dom_path,
@ -696,9 +714,9 @@ impl XenClient {
Ok(()) Ok(())
} }
#[allow(clippy::too_many_arguments)]
async fn pci_device_add( async fn pci_device_add(
&self, &self,
tx: &XsdTransaction,
dom_path: &str, dom_path: &str,
backend_dom_path: &str, backend_dom_path: &str,
backend_domid: u32, backend_domid: u32,
@ -729,7 +747,12 @@ impl XenClient {
} }
} }
// backend.reset(&device.bdf).await?; if let Some(irq) = backend.read_irq(&device.bdf).await? {
let irq = self.call.map_pirq(domid, irq as isize, None).await?;
self.call.irq_permission(domid, irq, true).await?;
}
backend.reset(&device.bdf).await?;
self.call self.call
.assign_device( .assign_device(
@ -743,6 +766,10 @@ impl XenClient {
) )
.await?; .await?;
if device.permissive {
backend.enable_permissive(&device.bdf).await?;
}
let id = 60; let id = 60;
if index == 0 { if index == 0 {
@ -759,6 +786,7 @@ impl XenClient {
]; ];
self.device_add( self.device_add(
tx,
"pci", "pci",
id, id,
dom_path, dom_path,
@ -773,31 +801,26 @@ impl XenClient {
let backend_path = format!("{}/backend/{}/{}/{}", backend_dom_path, "pci", domid, id); let backend_path = format!("{}/backend/{}/{}/{}", backend_dom_path, "pci", domid, id);
let transaction = self.store.transaction().await?; tx.write_string(
format!("{}/key-{}", backend_path, index),
transaction &device.bdf.to_string(),
.write_string( )
format!("{}/key-{}", backend_path, index), .await?;
&device.bdf.to_string(), tx.write_string(
) format!("{}/dev-{}", backend_path, index),
.await?; &device.bdf.to_string(),
transaction )
.write_string( .await?;
format!("{}/dev-{}", backend_path, index),
&device.bdf.to_string(),
)
.await?;
if let Some(vdefn) = device.bdf.vdefn { if let Some(vdefn) = device.bdf.vdefn {
transaction tx.write_string(
.write_string( format!("{}/vdefn-{}", backend_path, index),
format!("{}/vdefn-{}", backend_path, index), &format!("{:#x}", vdefn),
&format!("{:#x}", vdefn), )
) .await?;
.await?;
} }
let mut options = HashMap::new(); let mut options = IndexMap::new();
options.insert("permissive", if device.permissive { "1" } else { "0" }); options.insert("permissive", if device.permissive { "1" } else { "0" });
options.insert("rdm_policy", device.rdm_reserve_policy.to_option_str()); options.insert("rdm_policy", device.rdm_reserve_policy.to_option_str());
options.insert("msitranslate", if device.msi_translate { "1" } else { "0" }); options.insert("msitranslate", if device.msi_translate { "1" } else { "0" });
@ -811,17 +834,14 @@ impl XenClient {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(","); .join(",");
transaction tx.write_string(format!("{}/opts-{}", backend_path, index), &options)
.write_string(format!("{}/opts-{}", backend_path, index), &options)
.await?; .await?;
transaction.commit().await?;
Ok(()) Ok(())
} }
#[allow(clippy::too_many_arguments)]
async fn device_add( async fn device_add(
&self, &self,
tx: &XsdTransaction,
typ: &str, typ: &str,
id: u64, id: u64,
dom_path: &str, dom_path: &str,
@ -866,7 +886,6 @@ impl XenClient {
}, },
]; ];
let tx = self.store.transaction().await?;
tx.mknod(&frontend_path, frontend_perms).await?; tx.mknod(&frontend_path, frontend_perms).await?;
for (p, value) in &frontend_items { for (p, value) in &frontend_items {
let path = format!("{}/{}", frontend_path, *p); let path = format!("{}/{}", frontend_path, *p);
@ -880,7 +899,6 @@ impl XenClient {
let path = format!("{}/{}", backend_path, *p); let path = format!("{}/{}", backend_path, *p);
tx.write_string(&path, value).await?; tx.write_string(&path, value).await?;
} }
tx.commit().await?;
Ok(()) Ok(())
} }

View File

@ -112,6 +112,13 @@ impl XenPciBackend {
Ok(resources) Ok(resources)
} }
pub async fn enable_permissive(&self, bdf: &PciBdf) -> Result<()> {
let mut path: PathBuf = self.path.clone();
path.push("permissive");
fs::write(path, bdf.to_string()).await?;
Ok(())
}
pub async fn has_slot(&self, bdf: &PciBdf) -> Result<bool> { pub async fn has_slot(&self, bdf: &PciBdf) -> Result<bool> {
let mut slots_path = self.path.clone(); let mut slots_path = self.path.clone();
slots_path.push("slots"); slots_path.push("slots");
@ -128,8 +135,9 @@ impl XenPciBackend {
pub async fn reset(&self, bdf: &PciBdf) -> Result<()> { pub async fn reset(&self, bdf: &PciBdf) -> Result<()> {
let mut path: PathBuf = self.path.clone(); let mut path: PathBuf = self.path.clone();
path.push("do_flr"); path.push(bdf.to_string());
fs::write(&path, bdf.to_string()).await?; path.push("reset");
let _ = fs::write(path, "1\n").await;
Ok(()) Ok(())
} }
} }