agent: Store whole Uevent in map, rather than just /dev name

Sandbox::pci_device_map contains a mapping from sysfs paths to /dev entries
which is used by get_device_name() to look up the right /dev node.  But,
the map only supplies the answer if the uevent for the device has already
been received, otherwise get_device_name() has to wait for it.

However the matching for already-received and yet-to-come uevents isn't
quite the same which makes the whole system fragile.

In order to make sure the matching for both cases is identical, we need the
already-received side to store the whole uevent to match against, not just
the sysfs path and device name.

So, rename pci_device_map to uevent_map and store the whole uevent there
verbatim.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
David Gibson 2021-03-03 16:41:35 +11:00
parent 0616202580
commit 3642005479
3 changed files with 20 additions and 17 deletions

View File

@ -89,10 +89,10 @@ fn pcipath_to_sysfs(root_bus_sysfs: &str, pcipath: &pci::Path) -> Result<String>
async fn get_device_name(sandbox: &Arc<Mutex<Sandbox>>, dev_addr: &str) -> Result<String> {
let mut sb = sandbox.lock().await;
for (key, value) in sb.pci_device_map.iter() {
for (key, uev) in sb.uevent_map.iter() {
if key.contains(dev_addr) {
info!(sl!(), "Device {} found in pci device map", dev_addr);
return Ok(format!("{}/{}", SYSTEM_DEV_PATH, value));
return Ok(format!("{}/{}", SYSTEM_DEV_PATH, uev.devname));
}
}
@ -780,12 +780,15 @@ mod tests {
let relpath = "/0000:00:0a.0/0000:03:0b.0";
let devpath = format!("{}{}/virtio4/block/{}", root_bus, relpath, devname);
let mut uev = crate::uevent::Uevent::default();
uev.devpath = devpath.clone();
uev.devname = devname.to_string();
let logger = slog::Logger::root(slog::Discard, o!());
let sandbox = Arc::new(Mutex::new(Sandbox::new(&logger).unwrap()));
let mut sb = sandbox.lock().await;
sb.pci_device_map
.insert(devpath.clone(), devname.to_string());
sb.uevent_map.insert(devpath.clone(), uev);
drop(sb); // unlock
let name = get_device_name(&sandbox, relpath).await;
@ -793,7 +796,7 @@ mod tests {
assert_eq!(name.unwrap(), format!("{}/{}", SYSTEM_DEV_PATH, devname));
let mut sb = sandbox.lock().await;
sb.pci_device_map.remove(&devpath);
sb.uevent_map.remove(&devpath);
drop(sb); // unlock
let watcher_sandbox = Arc::clone(&sandbox);

View File

@ -8,6 +8,7 @@ use crate::mount::{get_mount_fs_type, remove_mounts, TYPE_ROOTFS};
use crate::namespace::Namespace;
use crate::netlink::Handle;
use crate::network::Network;
use crate::uevent::Uevent;
use anyhow::{anyhow, Context, Result};
use libc::pid_t;
use oci::{Hook, Hooks};
@ -36,7 +37,7 @@ pub struct Sandbox {
pub network: Network,
pub mounts: Vec<String>,
pub container_mounts: HashMap<String, Vec<String>>,
pub pci_device_map: HashMap<String, String>,
pub uevent_map: HashMap<String, Uevent>,
pub dev_watcher: HashMap<String, tokio::sync::oneshot::Sender<String>>,
pub shared_utsns: Namespace,
pub shared_ipcns: Namespace,
@ -66,7 +67,7 @@ impl Sandbox {
containers: HashMap::new(),
mounts: Vec::new(),
container_mounts: HashMap::new(),
pci_device_map: HashMap::new(),
uevent_map: HashMap::new(),
dev_watcher: HashMap::new(),
shared_utsns: Namespace::new(&logger),
shared_ipcns: Namespace::new(&logger),

View File

@ -17,14 +17,14 @@ use tokio::select;
use tokio::sync::watch::Receiver;
use tokio::sync::Mutex;
#[derive(Debug, Default)]
struct Uevent {
action: String,
devpath: String,
devname: String,
subsystem: String,
#[derive(Debug, Default, Clone)]
pub struct Uevent {
pub action: String,
pub devpath: String,
pub devname: String,
pub subsystem: String,
seqnum: String,
interface: String,
pub interface: String,
}
impl Uevent {
@ -67,9 +67,8 @@ impl Uevent {
let pci_root_bus_path = create_pci_root_bus_path();
let mut sb = sandbox.lock().await;
// Add the device node name to the pci device map.
sb.pci_device_map
.insert(self.devpath.clone(), self.devname.clone());
// Record the event by sysfs path
sb.uevent_map.insert(self.devpath.clone(), self.clone());
// Notify watchers that are interested in the udev event.
// Close the channel after watcher has been notified.