Skip to content

Commit c712790

Browse files
lauraltjiangliu
authored andcommitted
move build_desc_chain to MockSplitQueue
Moved a helper function that creates a descriptor chain from virtio-block/request.rs to the mock framework, so that it can be used by multiple crates. Also made it a bit more generic, and moved the creation of the queue outside of the function. This way it is also more obvious that there's a queue involved in building the descriptor chain, as opposed to how things were before. Signed-off-by: Laura Loghin <[email protected]>
1 parent c5ec512 commit c712790

File tree

2 files changed

+60
-60
lines changed

2 files changed

+60
-60
lines changed

crates/devices/virtio-blk/src/request.rs

Lines changed: 15 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ impl Request {
252252
mod tests {
253253
use super::*;
254254

255-
use vm_memory::{Address, GuestMemoryMmap};
255+
use vm_memory::GuestMemoryMmap;
256256

257-
use virtio_queue::defs::{VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
257+
use virtio_queue::defs::VIRTQ_DESC_F_WRITE;
258258
use virtio_queue::mock::MockSplitQueue;
259259

260260
impl PartialEq for Error {
@@ -290,64 +290,20 @@ mod tests {
290290
}
291291
}
292292

293-
// Helper method that writes a descriptor chain to a `GuestMemoryMmap` object and returns
294-
// the associated `DescriptorChain` object. `descs` represents a slice of `Descriptor` objects
295-
// which are used to populate the chain. This method ensures the next flags and values are
296-
// set properly for the desired chain, but keeps the other characteristics of the input
297-
// descriptors (`addr`, `len`, other flags).
298-
// The queue/descriptor chain related information is written in memory starting with
299-
// address 0. The `addr` fields of the input descriptors should start at a sufficiently
300-
// greater location (i.e. 1MiB, or `0x10_0000`).
301-
fn build_desc_chain<'a>(
302-
mem: &'a GuestMemoryMmap,
303-
descs: &[Descriptor],
304-
) -> DescriptorChain<&'a GuestMemoryMmap> {
305-
// Support a max of 16 descriptors for now.
306-
let vq = MockSplitQueue::new(mem, 16);
307-
for (idx, desc) in descs.iter().enumerate() {
308-
let i = idx as u16;
309-
let addr = desc.addr().0;
310-
let len = desc.len();
311-
let (flags, next) = if idx == descs.len() - 1 {
312-
// Clear the NEXT flag if it was set. The value of the next field of the
313-
// Descriptor doesn't matter at this point.
314-
(desc.flags() & !VIRTQ_DESC_F_NEXT, 0)
315-
} else {
316-
// Ensure that the next flag is set and that we are referring the following
317-
// descriptor. This ignores any value is actually present in `desc.next`.
318-
(desc.flags() | VIRTQ_DESC_F_NEXT, i + 1)
319-
};
320-
321-
let desc = Descriptor::new(addr, len, flags, next);
322-
vq.desc_table().store(i, desc);
323-
}
324-
325-
// Put the descriptor index 0 in the first available ring position.
326-
mem.write_obj(0u16, vq.avail_addr().unchecked_add(4))
327-
.unwrap();
328-
329-
// Set `avail_idx` to 1.
330-
mem.write_obj(1u16, vq.avail_addr().unchecked_add(2))
331-
.unwrap();
332-
333-
vq.create_queue(mem)
334-
.iter()
335-
.unwrap()
336-
.next()
337-
.expect("failed to build desc chain")
338-
}
339-
340293
#[test]
341294
fn test_parse_request() {
342-
let mem = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x1000_0000)]).unwrap();
295+
let mem: GuestMemoryMmap =
296+
GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x1000_0000)]).unwrap();
343297
// The `build_desc_chain` function will populate the `NEXT` related flags and field.
344298
let v = vec![
345299
// A device-writable request header descriptor.
346300
Descriptor::new(0x10_0000, 0x100, VIRTQ_DESC_F_WRITE, 0),
347301
Descriptor::new(0x20_0000, 0x100, VIRTQ_DESC_F_WRITE, 0),
348302
Descriptor::new(0x30_0000, 0x100, VIRTQ_DESC_F_WRITE, 0),
349303
];
350-
let mut chain = build_desc_chain(&mem, &v[..3]);
304+
// Create a queue of max 16 descriptors and a descriptor chain based on the array above.
305+
let queue = MockSplitQueue::new(&mem, 16);
306+
let mut chain = queue.build_desc_chain(&v[..3]);
351307

352308
let req_header = RequestHeader {
353309
request_type: VIRTIO_BLK_T_IN,
@@ -368,7 +324,7 @@ mod tests {
368324
// A device-readable request status descriptor.
369325
Descriptor::new(0x30_0000, 0x100, 0, 0),
370326
];
371-
let mut chain = build_desc_chain(&mem, &v[..3]);
327+
let mut chain = queue.build_desc_chain(&v[..3]);
372328

373329
// Status descriptor should be device-writable.
374330
assert_eq!(
@@ -382,7 +338,7 @@ mod tests {
382338
// Status descriptor with len = 0.
383339
Descriptor::new(0x30_0000, 0x0, VIRTQ_DESC_F_WRITE, 0),
384340
];
385-
let mut chain = build_desc_chain(&mem, &v[..3]);
341+
let mut chain = queue.build_desc_chain(&v[..3]);
386342
assert_eq!(
387343
Request::parse(&mut chain).unwrap_err(),
388344
Error::DescriptorLengthTooSmall
@@ -393,7 +349,7 @@ mod tests {
393349
Descriptor::new(0x20_0000, 0x100, 0, 0),
394350
Descriptor::new(0x30_0000, 0x100, VIRTQ_DESC_F_WRITE, 0),
395351
];
396-
let mut chain = build_desc_chain(&mem, &v[..3]);
352+
let mut chain = queue.build_desc_chain(&v[..3]);
397353

398354
// Flush request with sector != 0.
399355
let req_header = RequestHeader {
@@ -410,7 +366,7 @@ mod tests {
410366
Error::InvalidFlushSector
411367
);
412368

413-
let mut chain = build_desc_chain(&mem, &v[..3]);
369+
let mut chain = queue.build_desc_chain(&v[..3]);
414370
mem.write_obj::<u32>(VIRTIO_BLK_T_IN, GuestAddress(0x10_0000))
415371
.unwrap();
416372
// We shouldn't read from a device-readable buffer.
@@ -434,7 +390,7 @@ mod tests {
434390
mem.write_obj::<RequestHeader>(req_header, GuestAddress(0x10_0000))
435391
.unwrap();
436392

437-
let mut chain = build_desc_chain(&mem, &v[..4]);
393+
let mut chain = queue.build_desc_chain(&v[..4]);
438394

439395
// The status descriptor would cause a write beyond capacity.
440396
assert_eq!(
@@ -459,7 +415,7 @@ mod tests {
459415
mem.write_obj::<RequestHeader>(req_header, GuestAddress(0x10_0000))
460416
.unwrap();
461417

462-
let mut chain = build_desc_chain(&mem, &v[..4]);
418+
let mut chain = queue.build_desc_chain(&v[..4]);
463419

464420
let request = Request::parse(&mut chain).unwrap();
465421
let expected_request = Request {
@@ -484,7 +440,7 @@ mod tests {
484440
mem.write_obj::<RequestHeader>(req_header, GuestAddress(0x10_0000))
485441
.unwrap();
486442

487-
let mut chain = build_desc_chain(&mem, &v[..4]);
443+
let mut chain = queue.build_desc_chain(&v[..4]);
488444

489445
let request = Request::parse(&mut chain).unwrap();
490446
assert_eq!(request.request_type(), RequestType::Unsupported(2));
@@ -502,7 +458,7 @@ mod tests {
502458
mem.write_obj::<RequestHeader>(req_header, GuestAddress(0x10_0000))
503459
.unwrap();
504460

505-
let mut chain = build_desc_chain(&mem, &v[..2]);
461+
let mut chain = queue.build_desc_chain(&v[..2]);
506462
assert!(Request::parse(&mut chain).is_ok());
507463
}
508464
}

crates/virtio-queue/src/mock.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use vm_memory::{
1212
};
1313

1414
use crate::defs::{VIRTQ_DESC_F_INDIRECT, VIRTQ_DESC_F_NEXT};
15-
use crate::{Descriptor, Queue, QueueState, VirtqUsedElem};
15+
use crate::{Descriptor, DescriptorChain, Queue, QueueState, VirtqUsedElem};
1616

1717
/// Wrapper struct used for accessing a particular address of a GuestMemory area.
1818
pub struct Ref<'a, M, T> {
@@ -367,4 +367,48 @@ impl<'a, M: GuestMemory> MockSplitQueue<'a, M> {
367367
q.state.used_ring = self.used_addr;
368368
q
369369
}
370+
371+
/// Writes a descriptor chain to the memory object of the queue and returns the associated
372+
/// `DescriptorChain` object.
373+
// `descs` represents a slice of `Descriptor` objects which are used to populate the chain.
374+
// This method ensures the next flags and values are set properly for the desired chain, but
375+
// keeps the other characteristics of the input descriptors (`addr`, `len`, other flags).
376+
// The descriptor chain related information is written in memory starting with address 0.
377+
// The `addr` fields of the input descriptors should start at a sufficiently
378+
// greater location (i.e. 1MiB, or `0x10_0000`).
379+
pub fn build_desc_chain(&self, descs: &[Descriptor]) -> DescriptorChain<&M> {
380+
for (idx, desc) in descs.iter().enumerate() {
381+
let i = idx as u16;
382+
let addr = desc.addr().0;
383+
let len = desc.len();
384+
let (flags, next) = if idx == descs.len() - 1 {
385+
// Clear the NEXT flag if it was set. The value of the next field of the
386+
// Descriptor doesn't matter at this point.
387+
(desc.flags() & !VIRTQ_DESC_F_NEXT, 0)
388+
} else {
389+
// Ensure that the next flag is set and that we are referring the following
390+
// descriptor. This ignores any value is actually present in `desc.next`.
391+
(desc.flags() | VIRTQ_DESC_F_NEXT, i + 1)
392+
};
393+
394+
let desc = Descriptor::new(addr, len, flags, next);
395+
self.desc_table().store(i, desc);
396+
}
397+
398+
// Put the descriptor index 0 in the first available ring position.
399+
self.mem
400+
.write_obj(0u16, self.avail_addr().unchecked_add(4))
401+
.unwrap();
402+
403+
// Set `avail_idx` to 1.
404+
self.mem
405+
.write_obj(1u16, self.avail_addr().unchecked_add(2))
406+
.unwrap();
407+
408+
self.create_queue(self.mem)
409+
.iter()
410+
.unwrap()
411+
.next()
412+
.expect("failed to build desc chain")
413+
}
370414
}

0 commit comments

Comments
 (0)