This commit is contained in:
wtootw 2025-08-12 19:49:55 +08:00 committed by GitHub
commit db14cec489
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 125 additions and 17 deletions

View File

@ -9,7 +9,7 @@ use std::fs::{self, File};
use std::io::{BufRead, BufReader};
use std::ops::Deref;
use std::path::Path;
use std::process::Command;
use anyhow::{anyhow, Context, Result};
use kata_sys_util::mount::{get_linux_mount_info, parse_mount_options};
use nix::mount::MsFlags;
@ -63,6 +63,52 @@ lazy_static! {
];
}
#[instrument]
pub async fn resize_file_system(mountpoint: &String, logger: &Logger) -> Result<()> {
let logger = logger.new(o!("subsystem" => "resize_file_system"));
match get_linux_mount_info(mountpoint) {
Ok(info) => {
info!(
logger,
"Resizing {} file system on device {:?}",
info.fs_type,
info.device
);
let status = match info.fs_type.as_str() {
"ext2" | "ext3" | "ext4" => {
Command::new("resize2fs")
.arg(&info.device)
.status()
.context("Failed to execute resize2fs")?
}
"xfs" => {
Command::new("xfs_growfs")
.arg(&info.path)
.status()
.context("Failed to execute xfs_growfs")?
}
other => {
return Err(anyhow!(
"Unsupported filesystem type: {} for device {}",
other,
info.device
));
}
};
if !status.success() {
return Err(anyhow!(
"Filesystem resize failed with exit code: {:?}",
status.code()
));
}
Ok(())
}
Err(e) => Err(anyhow!("Error getting mount info: {:?}", e)),
}
}
#[instrument]
pub fn baremount(
source: &Path,

View File

@ -7,7 +7,7 @@ use std::fmt;
use std::ops::Deref;
use std::str::FromStr;
use anyhow::anyhow;
use anyhow::{anyhow,Context};
// The PCI spec reserves 5 bits (0..31) for slot number (a.k.a. device
// number)
@ -18,11 +18,21 @@ const SLOT_MAX: u8 = (1 << SLOT_BITS) - 1;
const FUNCTION_BITS: u8 = 3;
const FUNCTION_MAX: u8 = (1 << FUNCTION_BITS) - 1;
const PCI_RESCAN_FILE: &str = "/sys/bus/pci/rescan";
const PCI_RESCAN_SIGNAL: &str = "1";
// Represents a PCI function's slot (a.k.a. device) and function
// numbers, giving its location on a single logical bus
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct SlotFn(u8);
pub async fn rescan_pci_meta() -> anyhow::Result<()> {
tokio::fs::write(PCI_RESCAN_FILE, PCI_RESCAN_SIGNAL)
.await
.context(format!(
"PCI rescan failed: writing '{}' to {}",
PCI_RESCAN_SIGNAL, PCI_RESCAN_FILE
))?;
Ok(())
}
impl SlotFn {
pub fn new<T, U>(ss: T, f: U) -> anyhow::Result<Self>
where

View File

@ -66,7 +66,7 @@ use crate::device::network_device_handler::wait_for_pci_net_interface;
use crate::device::{add_devices, handle_cdi_devices, update_env_pci};
use crate::features::get_build_features;
use crate::metrics::get_metrics;
use crate::mount::baremount;
use crate::mount::{baremount, resize_file_system};
use crate::namespace::{NSTYPEIPC, NSTYPEPID, NSTYPEUTS};
use crate::network::setup_guest_dns;
use crate::passfd_io;
@ -825,7 +825,17 @@ impl agent_ttrpc::AgentService for AgentService {
Ok(Empty::new())
}
async fn resize_volume(
&self,
ctx: &TtrpcContext,
req: protocols::agent::ResizeVolumeRequest,
) -> ttrpc::Result<Empty> {
trace_rpc_call!(ctx, "resize_volume", req);
is_allowed(&req).await?;
pci::rescan_pci_meta().await.map_ttrpc_err(same)?;
resize_file_system(&req.volume_guest_path, &sl()).await.map_ttrpc_err(same)?;
Ok(Empty::new())
}
async fn stats_container(
&self,
ctx: &TtrpcContext,

View File

@ -826,10 +826,18 @@ func (q *QMP) ExecuteBlockdevAddWithCache(ctx context.Context, blockDevice *Bloc
"direct": direct,
"no-flush": noFlush,
}
return q.executeCommand(ctx, "blockdev-add", blockdevArgs, nil)
}
func (q *QMP) ExecuteBlockdevResize(ctx context.Context, blockDeviceID string, size uint64) error {
blockdevArgs := map[string]interface{}{
"node-name": blockDeviceID,
"size": size,
}
return q.executeCommand(ctx, "block_resize", blockdevArgs, nil)
}
// ExecuteBlockdevAddWithDriverCache has three one parameter driver
// than ExecuteBlockdevAddWithCache.
// Parameter driver can set the driver of block device.

View File

@ -1144,7 +1144,9 @@ func (clh *cloudHypervisor) ResizeVCPUs(ctx context.Context, reqVCPUs uint32) (c
return currentVCPUs, newVCPUs, nil
}
func (clh *cloudHypervisor) ResizeBlock(ctx context.Context, deviceID string, size uint64) error {
return nil
}
func (clh *cloudHypervisor) Cleanup(ctx context.Context) error {
clh.Logger().WithField("function", "Cleanup").Info("Cleanup")
return nil

View File

@ -1183,6 +1183,9 @@ func (fc *firecracker) ResizeMemory(ctx context.Context, reqMemMB uint32, memory
func (fc *firecracker) ResizeVCPUs(ctx context.Context, reqVCPUs uint32) (currentVCPUs uint32, newVCPUs uint32, err error) {
return 0, 0, nil
}
func (fc *firecracker) ResizeBlock(ctx context.Context, deviceID string, size uint64) error {
return nil
}
// This is used to apply cgroup information on the host.
//

View File

@ -1124,6 +1124,7 @@ type Hypervisor interface {
HotplugRemoveDevice(ctx context.Context, devInfo interface{}, devType DeviceType) (interface{}, error)
ResizeMemory(ctx context.Context, memMB uint32, memoryBlockSizeMB uint32, probe bool) (uint32, MemoryDevice, error)
ResizeVCPUs(ctx context.Context, vcpus uint32) (uint32, uint32, error)
ResizeBlock(ctx context.Context, deviceID string, size uint64) error
GetTotalMemoryMB(ctx context.Context) uint32
GetVMConsole(ctx context.Context, sandboxID string) (string, string, error)
Disconnect(ctx context.Context)

View File

@ -104,7 +104,9 @@ func (m *mockHypervisor) ResizeMemory(ctx context.Context, memMB uint32, memoryS
func (m *mockHypervisor) ResizeVCPUs(ctx context.Context, cpus uint32) (uint32, uint32, error) {
return 0, 0, nil
}
func (m *mockHypervisor) ResizeBlock(ctx context.Context, deviceID string, size uint64) error {
return nil
}
func (m *mockHypervisor) GetTotalMemoryMB(ctx context.Context) uint32 {
return m.config.MemorySize
}

View File

@ -2573,6 +2573,10 @@ func (q *qemu) ResizeMemory(ctx context.Context, reqMemMB uint32, memoryBlockSiz
return currentMemory, addMemDevice, nil
}
func (q *qemu) ResizeBlock(ctx context.Context, deviceID string, size uint64) error {
return q.qmpMonitorCh.qmp.ExecuteBlockdevResize(ctx, deviceID, size)
}
// genericAppendBridges appends to devices the given bridges
// nolint: unused, deadcode
func genericAppendBridges(devices []govmmQemu.Device, bridges []types.Bridge, machineType string) []govmmQemu.Device {

View File

@ -228,7 +228,9 @@ func (rh *remoteHypervisor) GetTotalMemoryMB(ctx context.Context) uint32 {
func (rh *remoteHypervisor) ResizeVCPUs(ctx context.Context, vcpus uint32) (uint32, uint32, error) {
return vcpus, vcpus, nil
}
func (rh *remoteHypervisor) ResizeBlock(ctx context.Context, deviceID string, size uint64) error {
return nil
}
func (rh *remoteHypervisor) GetVMConsole(ctx context.Context, sandboxID string) (string, string, error) {
return "", "", notImplemented("GetVMConsole")
}

View File

@ -2665,7 +2665,7 @@ func (s *Sandbox) SetPolicy(ctx context.Context, policy string) error {
// GuestVolumeStats return the filesystem stat of a given volume in the guest.
func (s *Sandbox) GuestVolumeStats(ctx context.Context, volumePath string) ([]byte, error) {
guestMountPath, err := s.guestMountPath(volumePath)
_, guestMountPath, err := s.getMountDetails(volumePath)
if err != nil {
return nil, err
}
@ -2674,30 +2674,47 @@ func (s *Sandbox) GuestVolumeStats(ctx context.Context, volumePath string) ([]by
// ResizeGuestVolume resizes a volume in the guest.
func (s *Sandbox) ResizeGuestVolume(ctx context.Context, volumePath string, size uint64) error {
// TODO: https://github.com/kata-containers/kata-containers/issues/3694.
guestMountPath, err := s.guestMountPath(volumePath)
id, guestMountPath, err := s.getMountDetails(volumePath)
if err != nil {
return err
}
device := s.devManager.GetDeviceByID(id)
if device == nil {
s.Logger().WithField("device", id).Error("failed to find device by id")
return fmt.Errorf("failed to find device by id (id=%s)", id)
}
d, ok := device.GetDeviceInfo().(*config.BlockDrive)
if !ok || d == nil {
s.Logger().WithField("device", device).Error("device is not a block drive or is nil")
return fmt.Errorf("device is not a block drive or is nil")
}
if err := s.hypervisor.ResizeBlock(ctx, d.ID, size); err != nil {
s.Logger().WithError(err).Error("Failed to resize block device in hypervisor")
return err
}
return s.agent.resizeGuestVolume(ctx, guestMountPath, size)
}
func (s *Sandbox) guestMountPath(volumePath string) (string, error) {
func (s *Sandbox) getMountDetails(volumePath string) (string, string, error) {
// verify the device even exists
if _, err := os.Stat(volumePath); err != nil {
s.Logger().WithError(err).WithField("volume", volumePath).Error("Cannot get stats for volume that doesn't exist")
return "", err
return "", "", err
}
// verify that we have a mount in this sandbox who's source maps to this
for _, c := range s.containers {
for _, m := range c.mounts {
if volumePath == m.Source {
return m.GuestDeviceMount, nil
return m.BlockDeviceID, m.GuestDeviceMount, nil
}
}
}
return "", fmt.Errorf("mount %s not found in sandbox", volumePath)
return "", "", fmt.Errorf("mount %s not found in sandbox", volumePath)
}
// getSandboxCPUSet returns the union of each of the sandbox's containers' CPU sets'

View File

@ -1169,7 +1169,9 @@ func (s *stratovirt) ResizeMemory(ctx context.Context, reqMemMB uint32, memoryBl
func (s *stratovirt) ResizeVCPUs(ctx context.Context, reqVCPUs uint32) (currentVCPUs uint32, newVCPUs uint32, err error) {
return 0, 0, nil
}
func (s *stratovirt) ResizeBlock(ctx context.Context, deviceID string, size uint64) error {
return nil
}
func (s *stratovirt) GetVMConsole(ctx context.Context, id string) (string, string, error) {
span, _ := katatrace.Trace(ctx, s.Logger(), "GetVMConsole", stratovirtTracingTags, map[string]string{"sandbox_id": s.id})
defer span.End()

View File

@ -29,6 +29,7 @@ default ReadStreamRequest := false
default RemoveContainerRequest := true
default RemoveStaleVirtiofsShareMountsRequest := true
default ReseedRandomDevRequest := false
default ResizeVolumeRequest := false
default ResumeContainerRequest := false
default SetGuestDateTimeRequest := false
default SetPolicyRequest := false