mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 11:05:46 +00:00
vmm: Add a 'resize-zone' action to the API actions
Implement a new VM action called 'resize-zone' allowing the user to resize one specific memory zone at a time. This relies on all the preliminary work from the previous commits to resize each virtio-mem device independently from each others. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
141df701dd
commit
015c78411e
@ -88,7 +88,8 @@ Reboot the VM | `/vm.reboot` | N/A
|
|||||||
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
|
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
|
||||||
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
|
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
|
||||||
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
||||||
Remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
|
||||||
|
Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted
|
||||||
Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created
|
Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created
|
||||||
Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted
|
Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted
|
||||||
|
@ -251,6 +251,23 @@ fn resize_api_command(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resize_zone_api_command(socket: &mut UnixStream, id: &str, size: &str) -> Result<(), Error> {
|
||||||
|
let resize_zone = vmm::api::VmResizeZoneData {
|
||||||
|
id: id.to_owned(),
|
||||||
|
desired_ram: size
|
||||||
|
.parse::<ByteSized>()
|
||||||
|
.map_err(Error::InvalidMemorySize)?
|
||||||
|
.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
simple_api_command(
|
||||||
|
socket,
|
||||||
|
"PUT",
|
||||||
|
"resize-zone",
|
||||||
|
Some(&serde_json::to_string(&resize_zone).unwrap()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||||
let device_config = vmm::config::DeviceConfig::parse(config).map_err(Error::AddDeviceConfig)?;
|
let device_config = vmm::config::DeviceConfig::parse(config).map_err(Error::AddDeviceConfig)?;
|
||||||
|
|
||||||
@ -374,6 +391,19 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.value_of("balloon"),
|
.value_of("balloon"),
|
||||||
),
|
),
|
||||||
|
Some("resize-zone") => resize_zone_api_command(
|
||||||
|
&mut socket,
|
||||||
|
matches
|
||||||
|
.subcommand_matches("resize-zone")
|
||||||
|
.unwrap()
|
||||||
|
.value_of("id")
|
||||||
|
.unwrap(),
|
||||||
|
matches
|
||||||
|
.subcommand_matches("resize-zone")
|
||||||
|
.unwrap()
|
||||||
|
.value_of("size")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
Some("add-device") => add_device_api_command(
|
Some("add-device") => add_device_api_command(
|
||||||
&mut socket,
|
&mut socket,
|
||||||
matches
|
matches
|
||||||
@ -552,6 +582,24 @@ fn main() {
|
|||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("resize-zone")
|
||||||
|
.about("Resize a memory zone")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("id")
|
||||||
|
.long("id")
|
||||||
|
.help("Memory zone identifier")
|
||||||
|
.takes_value(true)
|
||||||
|
.number_of_values(1),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("size")
|
||||||
|
.long("size")
|
||||||
|
.help("New memory zone size in bytes (supports K/M/G suffix)")
|
||||||
|
.takes_value(true)
|
||||||
|
.number_of_values(1),
|
||||||
|
),
|
||||||
|
)
|
||||||
.subcommand(SubCommand::with_name("resume").about("Resume the VM"))
|
.subcommand(SubCommand::with_name("resume").about("Resume the VM"))
|
||||||
.subcommand(SubCommand::with_name("shutdown").about("Shutdown the VM"))
|
.subcommand(SubCommand::with_name("shutdown").about("Shutdown the VM"))
|
||||||
.subcommand(
|
.subcommand(
|
||||||
|
@ -68,6 +68,9 @@ pub enum HttpError {
|
|||||||
/// Could not resize a VM
|
/// Could not resize a VM
|
||||||
VmResize(ApiError),
|
VmResize(ApiError),
|
||||||
|
|
||||||
|
/// Could not resize a memory zone
|
||||||
|
VmResizeZone(ApiError),
|
||||||
|
|
||||||
/// Could not add a device to a VM
|
/// Could not add a device to a VM
|
||||||
VmAddDevice(ApiError),
|
VmAddDevice(ApiError),
|
||||||
|
|
||||||
@ -204,6 +207,7 @@ lazy_static! {
|
|||||||
r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot)));
|
r.routes.insert(endpoint!("/vm.reboot"), Box::new(VmActionHandler::new(VmAction::Reboot)));
|
||||||
r.routes.insert(endpoint!("/vm.remove-device"), Box::new(VmActionHandler::new(VmAction::RemoveDevice(Arc::default()))));
|
r.routes.insert(endpoint!("/vm.remove-device"), Box::new(VmActionHandler::new(VmAction::RemoveDevice(Arc::default()))));
|
||||||
r.routes.insert(endpoint!("/vm.resize"), Box::new(VmActionHandler::new(VmAction::Resize(Arc::default()))));
|
r.routes.insert(endpoint!("/vm.resize"), Box::new(VmActionHandler::new(VmAction::Resize(Arc::default()))));
|
||||||
|
r.routes.insert(endpoint!("/vm.resize-zone"), Box::new(VmActionHandler::new(VmAction::ResizeZone(Arc::default()))));
|
||||||
r.routes.insert(endpoint!("/vm.restore"), Box::new(VmActionHandler::new(VmAction::Restore(Arc::default()))));
|
r.routes.insert(endpoint!("/vm.restore"), Box::new(VmActionHandler::new(VmAction::Restore(Arc::default()))));
|
||||||
r.routes.insert(endpoint!("/vm.resume"), Box::new(VmActionHandler::new(VmAction::Resume)));
|
r.routes.insert(endpoint!("/vm.resume"), Box::new(VmActionHandler::new(VmAction::Resume)));
|
||||||
r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown)));
|
r.routes.insert(endpoint!("/vm.shutdown"), Box::new(VmActionHandler::new(VmAction::Shutdown)));
|
||||||
|
@ -7,8 +7,8 @@ use crate::api::http::{error_response, EndpointHandler, HttpError};
|
|||||||
use crate::api::{
|
use crate::api::{
|
||||||
vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_vsock, vm_boot,
|
vm_add_device, vm_add_disk, vm_add_fs, vm_add_net, vm_add_pmem, vm_add_vsock, vm_boot,
|
||||||
vm_counters, vm_create, vm_delete, vm_info, vm_pause, vm_reboot, vm_remove_device, vm_resize,
|
vm_counters, vm_create, vm_delete, vm_info, vm_pause, vm_reboot, vm_remove_device, vm_resize,
|
||||||
vm_restore, vm_resume, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown, ApiRequest, VmAction,
|
vm_resize_zone, vm_restore, vm_resume, vm_shutdown, vm_snapshot, vmm_ping, vmm_shutdown,
|
||||||
VmConfig,
|
ApiRequest, VmAction, VmConfig,
|
||||||
};
|
};
|
||||||
use micro_http::{Body, Method, Request, Response, StatusCode, Version};
|
use micro_http::{Body, Method, Request, Response, StatusCode, Version};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
@ -132,6 +132,13 @@ impl EndpointHandler for VmActionHandler {
|
|||||||
)
|
)
|
||||||
.map_err(HttpError::VmResize),
|
.map_err(HttpError::VmResize),
|
||||||
|
|
||||||
|
ResizeZone(_) => vm_resize_zone(
|
||||||
|
api_notifier,
|
||||||
|
api_sender,
|
||||||
|
Arc::new(serde_json::from_slice(body.raw())?),
|
||||||
|
)
|
||||||
|
.map_err(HttpError::VmResizeZone),
|
||||||
|
|
||||||
Restore(_) => vm_restore(
|
Restore(_) => vm_restore(
|
||||||
api_notifier,
|
api_notifier,
|
||||||
api_sender,
|
api_sender,
|
||||||
|
@ -109,6 +109,9 @@ pub enum ApiError {
|
|||||||
/// The VM could not be resized
|
/// The VM could not be resized
|
||||||
VmResize(VmError),
|
VmResize(VmError),
|
||||||
|
|
||||||
|
/// The memory zone could not be resized.
|
||||||
|
VmResizeZone(VmError),
|
||||||
|
|
||||||
/// The device could not be added to the VM.
|
/// The device could not be added to the VM.
|
||||||
VmAddDevice(VmError),
|
VmAddDevice(VmError),
|
||||||
|
|
||||||
@ -156,6 +159,12 @@ pub struct VmResizeData {
|
|||||||
pub desired_ram_w_balloon: Option<u64>,
|
pub desired_ram_w_balloon: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Serialize, Default)]
|
||||||
|
pub struct VmResizeZoneData {
|
||||||
|
pub id: String,
|
||||||
|
pub desired_ram: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize, Default)]
|
#[derive(Clone, Deserialize, Serialize, Default)]
|
||||||
pub struct VmRemoveDeviceData {
|
pub struct VmRemoveDeviceData {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
@ -236,6 +245,9 @@ pub enum ApiRequest {
|
|||||||
/// Resize the VM.
|
/// Resize the VM.
|
||||||
VmResize(Arc<VmResizeData>, Sender<ApiResponse>),
|
VmResize(Arc<VmResizeData>, Sender<ApiResponse>),
|
||||||
|
|
||||||
|
/// Resize the memory zone.
|
||||||
|
VmResizeZone(Arc<VmResizeZoneData>, Sender<ApiResponse>),
|
||||||
|
|
||||||
/// Add a device to the VM.
|
/// Add a device to the VM.
|
||||||
VmAddDevice(Arc<DeviceConfig>, Sender<ApiResponse>),
|
VmAddDevice(Arc<DeviceConfig>, Sender<ApiResponse>),
|
||||||
|
|
||||||
@ -331,6 +343,9 @@ pub enum VmAction {
|
|||||||
/// Resize VM
|
/// Resize VM
|
||||||
Resize(Arc<VmResizeData>),
|
Resize(Arc<VmResizeData>),
|
||||||
|
|
||||||
|
/// Resize memory zone
|
||||||
|
ResizeZone(Arc<VmResizeZoneData>),
|
||||||
|
|
||||||
/// Restore VM
|
/// Restore VM
|
||||||
Restore(Arc<RestoreConfig>),
|
Restore(Arc<RestoreConfig>),
|
||||||
|
|
||||||
@ -362,6 +377,7 @@ fn vm_action(
|
|||||||
AddVsock(v) => ApiRequest::VmAddVsock(v, response_sender),
|
AddVsock(v) => ApiRequest::VmAddVsock(v, response_sender),
|
||||||
RemoveDevice(v) => ApiRequest::VmRemoveDevice(v, response_sender),
|
RemoveDevice(v) => ApiRequest::VmRemoveDevice(v, response_sender),
|
||||||
Resize(v) => ApiRequest::VmResize(v, response_sender),
|
Resize(v) => ApiRequest::VmResize(v, response_sender),
|
||||||
|
ResizeZone(v) => ApiRequest::VmResizeZone(v, response_sender),
|
||||||
Restore(v) => ApiRequest::VmRestore(v, response_sender),
|
Restore(v) => ApiRequest::VmRestore(v, response_sender),
|
||||||
Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender),
|
Snapshot(v) => ApiRequest::VmSnapshot(v, response_sender),
|
||||||
};
|
};
|
||||||
@ -478,6 +494,14 @@ pub fn vm_resize(
|
|||||||
vm_action(api_evt, api_sender, VmAction::Resize(data))
|
vm_action(api_evt, api_sender, VmAction::Resize(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vm_resize_zone(
|
||||||
|
api_evt: EventFd,
|
||||||
|
api_sender: Sender<ApiRequest>,
|
||||||
|
data: Arc<VmResizeZoneData>,
|
||||||
|
) -> ApiResult<Option<Body>> {
|
||||||
|
vm_action(api_evt, api_sender, VmAction::ResizeZone(data))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn vm_add_device(
|
pub fn vm_add_device(
|
||||||
api_evt: EventFd,
|
api_evt: EventFd,
|
||||||
api_sender: Sender<ApiRequest>,
|
api_sender: Sender<ApiRequest>,
|
||||||
|
@ -150,6 +150,22 @@ paths:
|
|||||||
404:
|
404:
|
||||||
description: The VM instance could not be resized because it is not created.
|
description: The VM instance could not be resized because it is not created.
|
||||||
|
|
||||||
|
/vm.resize-zone:
|
||||||
|
put:
|
||||||
|
summary: Resize a memory zone
|
||||||
|
requestBody:
|
||||||
|
description: The target size for the memory zone
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/VmResizeZone'
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
204:
|
||||||
|
description: The memory zone was successfully resized.
|
||||||
|
500:
|
||||||
|
description: The memory zone could not be resized.
|
||||||
|
|
||||||
/vm.add-device:
|
/vm.add-device:
|
||||||
put:
|
put:
|
||||||
summary: Add a new device to the VM
|
summary: Add a new device to the VM
|
||||||
@ -774,6 +790,16 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
format: int64
|
format: int64
|
||||||
|
|
||||||
|
VmResizeZone:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
desired_ram:
|
||||||
|
description: desired memory zone size in bytes
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
|
||||||
VmAddDevice:
|
VmAddDevice:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -517,6 +517,19 @@ impl Vmm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vm_resize_zone(&mut self, id: String, desired_ram: u64) -> result::Result<(), VmError> {
|
||||||
|
if let Some(ref mut vm) = self.vm {
|
||||||
|
if let Err(e) = vm.resize_zone(id, desired_ram) {
|
||||||
|
error!("Error when resizing VM: {:?}", e);
|
||||||
|
Err(e)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(VmError::VmNotRunning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn vm_add_device(&mut self, device_cfg: DeviceConfig) -> result::Result<Vec<u8>, VmError> {
|
fn vm_add_device(&mut self, device_cfg: DeviceConfig) -> result::Result<Vec<u8>, VmError> {
|
||||||
if let Some(ref mut vm) = self.vm {
|
if let Some(ref mut vm) = self.vm {
|
||||||
let info = vm.add_device(device_cfg).map_err(|e| {
|
let info = vm.add_device(device_cfg).map_err(|e| {
|
||||||
@ -786,6 +799,16 @@ impl Vmm {
|
|||||||
.map(|_| ApiResponsePayload::Empty);
|
.map(|_| ApiResponsePayload::Empty);
|
||||||
sender.send(response).map_err(Error::ApiResponseSend)?;
|
sender.send(response).map_err(Error::ApiResponseSend)?;
|
||||||
}
|
}
|
||||||
|
ApiRequest::VmResizeZone(resize_zone_data, sender) => {
|
||||||
|
let response = self
|
||||||
|
.vm_resize_zone(
|
||||||
|
resize_zone_data.id.clone(),
|
||||||
|
resize_zone_data.desired_ram,
|
||||||
|
)
|
||||||
|
.map_err(ApiError::VmResizeZone)
|
||||||
|
.map(|_| ApiResponsePayload::Empty);
|
||||||
|
sender.send(response).map_err(Error::ApiResponseSend)?;
|
||||||
|
}
|
||||||
ApiRequest::VmAddDevice(add_device_data, sender) => {
|
ApiRequest::VmAddDevice(add_device_data, sender) => {
|
||||||
let response = self
|
let response = self
|
||||||
.vm_add_device(add_device_data.as_ref().clone())
|
.vm_add_device(add_device_data.as_ref().clone())
|
||||||
|
@ -218,6 +218,9 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Could not find specified memory zone identifier from hash map.
|
/// Could not find specified memory zone identifier from hash map.
|
||||||
MissingZoneIdentifier,
|
MissingZoneIdentifier,
|
||||||
|
|
||||||
|
/// Resizing the memory zone failed.
|
||||||
|
ResizeZone,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ENABLE_FLAG: usize = 0;
|
const ENABLE_FLAG: usize = 0;
|
||||||
@ -1171,8 +1174,7 @@ impl MemoryManager {
|
|||||||
if self.use_zones {
|
if self.use_zones {
|
||||||
error!(
|
error!(
|
||||||
"Not allowed to resize guest memory when backed with user \
|
"Not allowed to resize guest memory when backed with user \
|
||||||
defined memory regions.\n Try adding new memory regions \
|
defined memory zones."
|
||||||
instead."
|
|
||||||
);
|
);
|
||||||
return Err(Error::InvalidResizeWithMemoryZones);
|
return Err(Error::InvalidResizeWithMemoryZones);
|
||||||
}
|
}
|
||||||
@ -1197,6 +1199,41 @@ impl MemoryManager {
|
|||||||
Ok(region)
|
Ok(region)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resize_zone(
|
||||||
|
&mut self,
|
||||||
|
id: &str,
|
||||||
|
desired_ram: u64,
|
||||||
|
config: &MemoryConfig,
|
||||||
|
) -> Result<Option<Arc<GuestRegionMmap>>, Error> {
|
||||||
|
if !self.use_zones {
|
||||||
|
error!(
|
||||||
|
"Not allowed to resize guest memory zone when no zone is \
|
||||||
|
defined."
|
||||||
|
);
|
||||||
|
return Err(Error::ResizeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(zones) = &config.zones {
|
||||||
|
for zone in zones.iter() {
|
||||||
|
if zone.id == id {
|
||||||
|
if desired_ram >= zone.size {
|
||||||
|
return self.virtiomem_resize(id, desired_ram - zone.size);
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Invalid to ask less ({}) than boot RAM ({}) for \
|
||||||
|
this memory zone",
|
||||||
|
desired_ram, zone.size,
|
||||||
|
);
|
||||||
|
return Err(Error::ResizeZone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("Could not find the memory zone {} for the resize", id);
|
||||||
|
Err(Error::ResizeZone)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub fn setup_sgx(&mut self, sgx_epc_config: Vec<SgxEpcConfig>) -> Result<(), Error> {
|
pub fn setup_sgx(&mut self, sgx_epc_config: Vec<SgxEpcConfig>) -> Result<(), Error> {
|
||||||
// Go over each EPC section and verify its size is a 4k multiple. At
|
// Go over each EPC section and verify its size is a 4k multiple. At
|
||||||
|
@ -922,6 +922,25 @@ impl Vm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resize_zone(&mut self, id: String, desired_memory: u64) -> Result<()> {
|
||||||
|
let new_region = self
|
||||||
|
.memory_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.resize_zone(&id, desired_memory, &self.config.lock().unwrap().memory)
|
||||||
|
.map_err(Error::MemoryManager)?;
|
||||||
|
|
||||||
|
if let Some(new_region) = &new_region {
|
||||||
|
self.device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.update_memory(&new_region)
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "pci_support"))]
|
#[cfg(not(feature = "pci_support"))]
|
||||||
pub fn add_device(&mut self, mut _device_cfg: DeviceConfig) -> Result<PciDeviceInfo> {
|
pub fn add_device(&mut self, mut _device_cfg: DeviceConfig) -> Result<PciDeviceInfo> {
|
||||||
Err(Error::NoPciSupport)
|
Err(Error::NoPciSupport)
|
||||||
|
Loading…
Reference in New Issue
Block a user