virtio-devices: mem: Allow for an initial size

This commit gives the possibility to create a virtio-mem device with
some memory already plugged into it. This is preliminary work to be
able to reboot a VM with the virtio-mem region being already resized.

Signed-off-by: Hui Zhu <teawater@antfin.com>
Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Hui Zhu 2020-08-10 18:22:55 +08:00 committed by Sebastien Boeuf
parent 8b5202aa5a
commit 33a1e37c35
2 changed files with 51 additions and 31 deletions

View File

@ -185,6 +185,36 @@ struct VirtioMemConfig {
// Safe because it only has data and has no implicit padding. // Safe because it only has data and has no implicit padding.
unsafe impl ByteValued for VirtioMemConfig {} unsafe impl ByteValued for VirtioMemConfig {}
fn virtio_mem_config_resize(config: &mut VirtioMemConfig, size: u64) -> result::Result<(), Error> {
if config.requested_size == size {
return Err(Error::ResizeInval(format!(
"Virtio-mem resize {} is same with current config.requested_size",
size
)));
} else if size > config.region_size {
let region_size = config.region_size;
return Err(Error::ResizeInval(format!(
"Virtio-mem resize {} is bigger than config.region_size {}",
size, region_size
)));
} else if size % (config.block_size as u64) != 0 {
let block_size = config.block_size;
return Err(Error::ResizeInval(format!(
"Virtio-mem resize {} is not aligned with config.block_size {}",
size, block_size
)));
}
config.requested_size = size;
let tmp_size = cmp::min(
config.region_size,
config.requested_size + VIRTIO_MEM_USABLE_EXTENT,
);
config.usable_region_size = cmp::max(config.usable_region_size, tmp_size);
Ok(())
}
struct Request { struct Request {
req: VirtioMemReq, req: VirtioMemReq,
status_addr: GuestAddress, status_addr: GuestAddress,
@ -622,37 +652,16 @@ impl EpollHelperHandler for MemEpollHandler {
let size = self.resize.get_size(); let size = self.resize.get_size();
let mut config = self.config.lock().unwrap(); let mut config = self.config.lock().unwrap();
let mut signal_error = false; let mut signal_error = false;
let r = if config.requested_size == size { let mut r = virtio_mem_config_resize(&mut config, size);
Err(Error::ResizeInval(format!( r = match r {
"Virtio-mem resize {} is same with current config.requested_size", Err(e) => Err(e),
size _ => match self.signal(&VirtioInterruptType::Config) {
))) Err(e) => {
} else if size > config.region_size { signal_error = true;
let region_size = config.region_size; Err(Error::ResizeTriggerFail(e))
Err(Error::ResizeInval(format!( }
"Virtio-mem resize {} is bigger than config.region_size {}", _ => Ok(()),
size, region_size },
)))
} else if size % (config.block_size as u64) != 0 {
let block_size = config.block_size;
Err(Error::ResizeInval(format!(
"Virtio-mem resize {} is not aligned with config.block_size {}",
size, block_size
)))
} else {
config.requested_size = size;
let tmp_size = cmp::min(
config.region_size,
config.requested_size + VIRTIO_MEM_USABLE_EXTENT,
);
config.usable_region_size = cmp::max(config.usable_region_size, tmp_size);
if let Err(e) = self.signal(&VirtioInterruptType::Config) {
signal_error = true;
error!("Error signalling config: {:?}", e);
Err(Error::ResizeTriggerFail(e))
} else {
Ok(())
}
}; };
if let Err(e) = self.resize.send(r) { if let Err(e) = self.resize.send(r) {
error!("Sending \"resize\" reponse: {:?}", e); error!("Sending \"resize\" reponse: {:?}", e);
@ -702,6 +711,7 @@ impl Mem {
resize: Resize, resize: Resize,
seccomp_action: SeccompAction, seccomp_action: SeccompAction,
numa_node_id: Option<u16>, numa_node_id: Option<u16>,
initial_size: u64,
) -> io::Result<Mem> { ) -> io::Result<Mem> {
let region_len = region.len(); let region_len = region.len();
@ -726,6 +736,15 @@ impl Mem {
config.requested_size + VIRTIO_MEM_USABLE_EXTENT, config.requested_size + VIRTIO_MEM_USABLE_EXTENT,
); );
if initial_size != 0 {
virtio_mem_config_resize(&mut config, initial_size).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Virtio-mem resize {} got {:?}", initial_size, e),
)
})?;
}
if let Some(node_id) = numa_node_id { if let Some(node_id) = numa_node_id {
avail_features |= 1u64 << VIRTIO_MEM_F_ACPI_PXM; avail_features |= 1u64 << VIRTIO_MEM_F_ACPI_PXM;
config.node_id = node_id; config.node_id = node_id;

View File

@ -2451,6 +2451,7 @@ impl DeviceManager {
.map_err(DeviceManagerError::TryCloneVirtioMemResize)?, .map_err(DeviceManagerError::TryCloneVirtioMemResize)?,
self.seccomp_action.clone(), self.seccomp_action.clone(),
node_id, node_id,
0,
) )
.map_err(DeviceManagerError::CreateVirtioMem)?, .map_err(DeviceManagerError::CreateVirtioMem)?,
)); ));