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
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ progenitor-client = "0.14.0"
proptest = "1.5.0"
quote = "1.0"
rand = "0.9.1"
rand_pcg = "0.9.0"
reqwest = { version = "0.13", default-features = false }
ring = "0.17"
ron = "0.8"
Expand Down
2 changes: 2 additions & 0 deletions lib/propolis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ tempfile.workspace = true
slog-term.workspace = true
slog-async.workspace = true
rand.workspace = true
rand_pcg.workspace = true
ron.workspace = true

[features]
default = []
Expand Down
87 changes: 3 additions & 84 deletions lib/propolis/src/block/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use super::{
};
use crate::accessors::MemAccessor;
use crate::block;
use crate::util::bitmap::Bitmap;

use futures::stream::FuturesUnordered;
use futures::Stream;
Expand Down Expand Up @@ -1020,7 +1021,7 @@ impl WorkerCollection {
limit: NonZeroUsize,
qid_hint: Option<QueueId>,
) -> Bitmap {
probes::block_worker_collection_wake!(|| (wake_wids.0, limit.get()));
probes::block_worker_collection_wake!(|| (wake_wids.bits(), limit.get()));

let mut num_woken = 0;
let mut idle_wids = wake_wids.iter();
Expand All @@ -1041,7 +1042,7 @@ impl WorkerCollection {

let remainder = idle_wids.remainder();

probes::block_worker_collection_woken!(|| (remainder.0, num_woken));
probes::block_worker_collection_woken!(|| (remainder.bits(), num_woken));

remainder
}
Expand Down Expand Up @@ -1361,85 +1362,3 @@ impl<T: Copy + Clone + Default> Default for Versioned<T> {
Self::new(T::default())
}
}

/// Simple bitmap which facilitates iterator over bits which are asserted
#[derive(Copy, Clone, Default)]
pub(crate) struct Bitmap(u64);
impl Bitmap {
const TOP_BIT: usize = u64::BITS as usize;

pub const ALL: Self = Self(u64::MAX);

pub fn set(&mut self, idx: usize) {
assert!(idx < Self::TOP_BIT);
self.0 |= 1u64 << idx;
}
pub fn unset(&mut self, idx: usize) {
assert!(idx < Self::TOP_BIT);
self.0 &= !(1u64 << idx);
}
pub fn set_all(&mut self, other: Bitmap) {
self.0 |= other.0;
}
pub fn lowest_set(&self) -> Option<usize> {
if self.0.count_ones() == 0 {
None
} else {
Some(self.0.trailing_zeros() as usize)
}
}
pub fn count(&self) -> usize {
self.0.count_ones() as usize
}
pub fn is_empty(&self) -> bool {
self.count() == 0
}
pub fn take(&mut self) -> Self {
Self(std::mem::replace(&mut self.0, 0))
}
/// Get iterator which emits indices of bits which are set in this map.
pub fn iter(&self) -> BitIter {
BitIter(*self)
}
/// Get iterator which emits indices of bits which are set in this map.
/// It will infinitely loop back to the first bit whenever the last bit is
/// reached.
pub fn looping_iter(&self) -> LoopIter {
LoopIter { orig: *self, cur: *self }
}
}

pub struct BitIter(Bitmap);
impl Iterator for BitIter {
type Item = usize;

fn next(&mut self) -> Option<Self::Item> {
let idx = self.0.lowest_set()?;
self.0.unset(idx);
Some(idx)
}
}
impl BitIter {
fn remainder(self) -> Bitmap {
self.0
}
}
pub struct LoopIter {
cur: Bitmap,
orig: Bitmap,
}
impl Iterator for LoopIter {
type Item = usize;

fn next(&mut self) -> Option<Self::Item> {
if self.orig.count() == 0 {
return None;
}
if self.cur.count() == 0 {
self.cur = self.orig;
}
let idx = self.cur.lowest_set().unwrap();
self.cur.unset(idx);
Some(idx)
}
}
3 changes: 2 additions & 1 deletion lib/propolis/src/block/minder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ use pin_project_lite::pin_project;
use tokio::sync::futures::Notified;
use tokio::sync::Notify;

use crate::block::attachment::Bitmap;
// use crate::block::attachment::Bitmap;
use crate::block::{self, devq_id, probes, Operation, Request};
use crate::block::{DeviceId, MetricConsumer, QueueId, WorkerId};
use crate::util::bitmap::Bitmap;

/// Each emulated block device will have one or more [DeviceQueue]s which can be
/// polled through [next_req()](DeviceQueue::next_req()) to emit IO requests.
Expand Down
4 changes: 2 additions & 2 deletions lib/propolis/src/hw/nvme/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use zerocopy::{FromBytes, IntoBytes};
/// A Submission Queue Entry as represented in memory.
///
/// See NVMe 1.0e Section 4.2 Submission Queue Entry - Command Format
#[derive(Debug, Default, Copy, Clone, FromBytes)]
#[derive(Debug, Default, Copy, Clone, FromBytes, IntoBytes)]
#[repr(C, packed(1))]
pub struct SubmissionQueueEntry {
/// Command Dword 0 (CDW0)
Expand Down Expand Up @@ -106,7 +106,7 @@ impl SubmissionQueueEntry {
/// A Completion Queue Entry as represented in memory.
///
/// See NVMe 1.0e Section 4.5 Completion Queue Entry
#[derive(Debug, Default, Copy, Clone, IntoBytes)]
#[derive(Debug, Default, Copy, Clone, IntoBytes, FromBytes)]
#[repr(C, packed(1))]
pub struct CompletionQueueEntry {
/// Dword 0 (DW0)
Expand Down
7 changes: 7 additions & 0 deletions lib/propolis/src/hw/nvme/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ mod cmds;
mod queue;
mod requests;

#[cfg(test)]
mod test;

use bits::*;
use queue::{CompQueue, QueueId, SubQueue};

Expand Down Expand Up @@ -992,6 +995,7 @@ impl PciNvme {
// Set CC.EN=1 and CSTS.RDY=1
state.ctrl.cc.set_enabled(true);
state.ctrl.csts.set_ready(true);
eprintln!("controller enabled");
self.is_enabled.store(true, Ordering::Release);
}
} else if !new.enabled() && cur.enabled() {
Expand Down Expand Up @@ -1193,6 +1197,7 @@ impl PciNvme {
// Mix in the device ID for probe purposes
let devq_id = devq_id(self.device_id, qid);

// eprintln!("DEVICE: doorbell rung: {} (cq? {}) val={}", qid, is_cq, val);
probes::nvme_doorbell!(|| (
off as u64,
devq_id,
Expand All @@ -1218,6 +1223,7 @@ impl PciNvme {
self.log,
"Doorbell write while controller is disabled"
);
eprintln!("how did it get disabled");
return Err(if is_cq {
NvmeError::InvalidCompQueue(qid)
} else {
Expand Down Expand Up @@ -1458,6 +1464,7 @@ impl MigrateMulti for PciNvme {

let mut ctrl = self.state.lock().unwrap();
ctrl.import(input, self)?;
self.is_enabled.store(ctrl.ctrl.cc.enabled(), Ordering::Release);
drop(ctrl);

MigrateMulti::import(&self.pci_state, offer, ctx)?;
Expand Down
7 changes: 7 additions & 0 deletions lib/propolis/src/hw/nvme/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,9 @@ impl SubQueue {
let devq_id = self.devq_id();
state.db_buf_write(devq_id, &mem);
state.db_buf_read(devq_id, &mem);
if self.id != 0 {
// eprintln!("DEVICE sqid={} got sqe: idx = {}", self.id, idx);
}
return Some((ent, permit.promote(ent.cid()), idx));
}
// TODO: set error state on queue/ctrl if we cannot read entry
Expand Down Expand Up @@ -901,6 +904,10 @@ impl CompQueue {
// TODO: mark the queue/controller in error state?
return;
};
if self.id != 0 {
// eprintln!("DEVICE cqid={}: writing cqe: idx = {}, cid = {}, addr={:x}", self.id, idx, cid, addr.0);
}

let mem = mem.view();
cqe.set_phase(!phase);
mem.write(addr, &cqe);
Expand Down
Loading
Loading