mirror of
				https://github.com/kata-containers/kata-containers.git
				synced 2025-10-31 09:26:52 +00:00 
			
		
		
		
	runtime-rs: umount and permission controls in sandbox level
This commit implemented umonut controls and permission controls. When a volume is no longer referenced, it will be umounted immediately. When a volume mounted with readonly permission and a new coming container needs readwrite permission, the volume should be upgraded to readwrite permission. On the contrary, if a volume with readwrite permission and no container needs readwrite, then the volume should be downgraded. Fixes: #5588 Signed-off-by: Xuewei Niu <justxuewei@apache.org>
This commit is contained in:
		| @@ -15,7 +15,7 @@ pub use utils::{do_get_guest_path, do_get_guest_share_path, get_host_rw_shared_p | |||||||
| mod virtio_fs_share_mount; | mod virtio_fs_share_mount; | ||||||
| use virtio_fs_share_mount::VirtiofsShareMount; | use virtio_fs_share_mount::VirtiofsShareMount; | ||||||
|  |  | ||||||
| use std::{path::PathBuf, sync::Arc}; | use std::{fmt::Debug, path::PathBuf, sync::Arc}; | ||||||
|  |  | ||||||
| use agent::Storage; | use agent::Storage; | ||||||
| use anyhow::{anyhow, Context, Ok, Result}; | use anyhow::{anyhow, Context, Ok, Result}; | ||||||
| @@ -38,18 +38,26 @@ pub const PASSTHROUGH_FS_DIR: &str = "passthrough"; | |||||||
| const RAFS_DIR: &str = "rafs"; | const RAFS_DIR: &str = "rafs"; | ||||||
|  |  | ||||||
| #[async_trait] | #[async_trait] | ||||||
| pub trait ShareFs: Send + Sync { | pub trait ShareFs: Send + Sync + Debug { | ||||||
|     fn get_share_fs_mount(&self) -> Arc<dyn ShareFsMount>; |     fn get_share_fs_mount(&self) -> Arc<dyn ShareFsMount>; | ||||||
|     async fn setup_device_before_start_vm(&self, h: &dyn Hypervisor) -> Result<()>; |     async fn setup_device_before_start_vm(&self, h: &dyn Hypervisor) -> Result<()>; | ||||||
|     async fn setup_device_after_start_vm(&self, h: &dyn Hypervisor) -> Result<()>; |     async fn setup_device_after_start_vm(&self, h: &dyn Hypervisor) -> Result<()>; | ||||||
|     async fn get_storages(&self) -> Result<Vec<Storage>>; |     async fn get_storages(&self) -> Result<Vec<Storage>>; | ||||||
|  |  | ||||||
|     /// Get mounted info from ShareFs. |     /// Get a mounted info from ShareFs. | ||||||
|     /// The source is an original path on the host (not in the `/run/kata-containers/...`). |     /// The source is an original path on the host (not in the `/run/kata-containers/...`). | ||||||
|     async fn get_mounted_info(&self, source: &str) -> Option<MountedInfo>; |     async fn get_mounted_info(&self, source: &str) -> Option<MountedInfo>; | ||||||
|     /// Set mounted info to ShareFS. |     /// Set a mounted info to ShareFS. | ||||||
|     /// The source is an original path on the host (not in the `/run/kata-containers/...`). |     /// The source is the same as get_mounted_info's. | ||||||
|     async fn set_mounted_info(&self, source: &str, mounted_info: MountedInfo) -> Result<()>; |     async fn set_mounted_info(&self, source: &str, mounted_info: MountedInfo) -> Result<()>; | ||||||
|  |     /// Remove a mounted info from ShareFs. | ||||||
|  |     /// The source is the same as get_mounted_info's. | ||||||
|  |     async fn rm_mounted_info(&self, source: &str) -> Result<Option<MountedInfo>>; | ||||||
|  |     /// Get a mounted info by guest path. | ||||||
|  |     async fn get_mounted_info_by_guest_path( | ||||||
|  |         &self, | ||||||
|  |         guest_path: &str, | ||||||
|  |     ) -> Option<(String, MountedInfo)>; | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| @@ -109,7 +117,7 @@ impl MountedInfo { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // File/dir name in the form of "sandbox-<uuid>-<file/dir name>" |     // File/dir name in the form of "sandbox-<uuid>-<file/dir name>" | ||||||
|     pub fn name(&self) -> Result<String> { |     pub fn file_name(&self) -> Result<String> { | ||||||
|         match self.guest_path.file_name() { |         match self.guest_path.file_name() { | ||||||
|             Some(file_name) => match file_name.to_str() { |             Some(file_name) => match file_name.to_str() { | ||||||
|                 Some(file_name) => Ok(file_name.to_owned()), |                 Some(file_name) => Ok(file_name.to_owned()), | ||||||
| @@ -124,13 +132,15 @@ impl MountedInfo { | |||||||
| } | } | ||||||
|  |  | ||||||
| #[async_trait] | #[async_trait] | ||||||
| pub trait ShareFsMount: Send + Sync { | pub trait ShareFsMount: Send + Sync + Debug { | ||||||
|     async fn share_rootfs(&self, config: ShareFsRootfsConfig) -> Result<ShareFsMountResult>; |     async fn share_rootfs(&self, config: ShareFsRootfsConfig) -> Result<ShareFsMountResult>; | ||||||
|     async fn share_volume(&self, config: ShareFsVolumeConfig) -> Result<ShareFsMountResult>; |     async fn share_volume(&self, config: ShareFsVolumeConfig) -> Result<ShareFsMountResult>; | ||||||
|     /// Upgrade to readwrite permission |     /// Upgrade to readwrite permission | ||||||
|     async fn upgrade(&self, file_name: &str) -> Result<()>; |     async fn upgrade(&self, file_name: &str) -> Result<()>; | ||||||
|     /// Downgrade to readonly permission |     /// Downgrade to readonly permission | ||||||
|     async fn downgrade(&self, file_name: &str) -> Result<()>; |     async fn downgrade(&self, file_name: &str) -> Result<()>; | ||||||
|  |     /// Umount the volume | ||||||
|  |     async fn umount(&self, file_name: &str) -> Result<()>; | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn new(id: &str, config: &SharedFsInfo) -> Result<Arc<dyn ShareFs>> { | pub fn new(id: &str, config: &SharedFsInfo) -> Result<Arc<dyn ShareFs>> { | ||||||
|   | |||||||
| @@ -30,11 +30,12 @@ pub struct ShareVirtioFsInlineConfig { | |||||||
|     pub id: String, |     pub id: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Default)] | #[derive(Default, Debug)] | ||||||
| pub struct ShareVirtioFsInlineInner { | pub struct ShareVirtioFsInlineInner { | ||||||
|     mounted_info_set: HashMap<String, MountedInfo>, |     mounted_info_set: HashMap<String, MountedInfo>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
| pub struct ShareVirtioFsInline { | pub struct ShareVirtioFsInline { | ||||||
|     config: ShareVirtioFsInlineConfig, |     config: ShareVirtioFsInlineConfig, | ||||||
|     share_fs_mount: Arc<dyn ShareFsMount>, |     share_fs_mount: Arc<dyn ShareFsMount>, | ||||||
| @@ -90,7 +91,7 @@ impl ShareFs for ShareVirtioFsInline { | |||||||
|  |  | ||||||
|     async fn get_mounted_info(&self, source: &str) -> Option<MountedInfo> { |     async fn get_mounted_info(&self, source: &str) -> Option<MountedInfo> { | ||||||
|         let inner = self.inner.read().await; |         let inner = self.inner.read().await; | ||||||
|         inner.mounted_info_set.get(source).map(|m| m.clone()) |         inner.mounted_info_set.get(source).cloned() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn set_mounted_info(&self, source: &str, mounted_info: MountedInfo) -> Result<()> { |     async fn set_mounted_info(&self, source: &str, mounted_info: MountedInfo) -> Result<()> { | ||||||
| @@ -100,4 +101,21 @@ impl ShareFs for ShareVirtioFsInline { | |||||||
|             .insert(source.to_owned(), mounted_info.clone()); |             .insert(source.to_owned(), mounted_info.clone()); | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async fn rm_mounted_info(&self, source: &str) -> Result<Option<MountedInfo>> { | ||||||
|  |         let mut inner = self.inner.write().await; | ||||||
|  |         Ok(inner.mounted_info_set.remove(source)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async fn get_mounted_info_by_guest_path( | ||||||
|  |         &self, | ||||||
|  |         guest_path: &str, | ||||||
|  |     ) -> Option<(String, MountedInfo)> { | ||||||
|  |         let inner = self.inner.read().await; | ||||||
|  |         inner | ||||||
|  |             .mounted_info_set | ||||||
|  |             .iter() | ||||||
|  |             .find(|m| m.1.guest_path.as_os_str().to_str().unwrap() == guest_path) | ||||||
|  |             .map(|m| (m.0.to_owned(), m.1.clone())) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -38,11 +38,13 @@ pub struct ShareVirtioFsStandaloneConfig { | |||||||
|     pub virtio_fs_extra_args: Vec<String>, |     pub virtio_fs_extra_args: Vec<String>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Default)] | #[derive(Default, Debug)] | ||||||
| struct ShareVirtioFsStandaloneInner { | struct ShareVirtioFsStandaloneInner { | ||||||
|     pid: Option<u32>, |     pid: Option<u32>, | ||||||
|     mounted_info_set: HashMap<String, MountedInfo>, |     mounted_info_set: HashMap<String, MountedInfo>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
| pub(crate) struct ShareVirtioFsStandalone { | pub(crate) struct ShareVirtioFsStandalone { | ||||||
|     inner: Arc<RwLock<ShareVirtioFsStandaloneInner>>, |     inner: Arc<RwLock<ShareVirtioFsStandaloneInner>>, | ||||||
|     config: ShareVirtioFsStandaloneConfig, |     config: ShareVirtioFsStandaloneConfig, | ||||||
| @@ -176,7 +178,7 @@ impl ShareFs for ShareVirtioFsStandalone { | |||||||
|  |  | ||||||
|     async fn get_mounted_info(&self, source: &str) -> Option<MountedInfo> { |     async fn get_mounted_info(&self, source: &str) -> Option<MountedInfo> { | ||||||
|         let inner = self.inner.read().await; |         let inner = self.inner.read().await; | ||||||
|         inner.mounted_info_set.get(source).map(|m| m.clone()) |         inner.mounted_info_set.get(source).cloned() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn set_mounted_info(&self, source: &str, mounted_info: MountedInfo) -> Result<()> { |     async fn set_mounted_info(&self, source: &str, mounted_info: MountedInfo) -> Result<()> { | ||||||
| @@ -186,4 +188,21 @@ impl ShareFs for ShareVirtioFsStandalone { | |||||||
|             .insert(source.to_owned(), mounted_info.clone()); |             .insert(source.to_owned(), mounted_info.clone()); | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async fn rm_mounted_info(&self, source: &str) -> Result<Option<MountedInfo>> { | ||||||
|  |         let mut inner = self.inner.write().await; | ||||||
|  |         Ok(inner.mounted_info_set.remove(source)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async fn get_mounted_info_by_guest_path( | ||||||
|  |         &self, | ||||||
|  |         guest_path: &str, | ||||||
|  |     ) -> Option<(String, MountedInfo)> { | ||||||
|  |         let inner = self.inner.read().await; | ||||||
|  |         inner | ||||||
|  |             .mounted_info_set | ||||||
|  |             .iter() | ||||||
|  |             .find(|m| m.1.guest_path.as_os_str().to_str().unwrap() == guest_path) | ||||||
|  |             .map(|m| (m.0.to_owned(), m.1.clone())) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -115,17 +115,3 @@ pub(crate) fn do_get_host_path( | |||||||
|     }; |     }; | ||||||
|     path.to_str().unwrap().to_string() |     path.to_str().unwrap().to_string() | ||||||
| } | } | ||||||
|  |  | ||||||
| // /// Get the bind mounted path on the host that will be shared to the guest in |  | ||||||
| // /// **sandbox level**. |  | ||||||
| // /// The filename is in format of "sandbox-{uuid}-examplename". |  | ||||||
| // pub(crate) fn do_get_sandbox_level_host_path(sid: &str, filename: &str, readonly: bool) -> String { |  | ||||||
| //     do_get_host_path(filename, sid, "", true, readonly) |  | ||||||
| // } |  | ||||||
|  |  | ||||||
| // /// Get the bind mounted path on the guest that will be shared from the host in |  | ||||||
| // /// **sandbox level**. |  | ||||||
| // /// The filename is in format of "sandbox-{uuid}-examplename". |  | ||||||
| // pub(crate) fn do_get_sandbox_level_guest_path(filename: &str) -> String { |  | ||||||
| //     do_get_guest_any_path(filename, "", true, false) |  | ||||||
| // } |  | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| use agent::Storage; | use agent::Storage; | ||||||
| use anyhow::{anyhow, Context, Result}; | use anyhow::{anyhow, Context, Result}; | ||||||
| use async_trait::async_trait; | use async_trait::async_trait; | ||||||
| use kata_sys_util::mount::bind_remount; | use kata_sys_util::mount::{bind_remount, umount_timeout}; | ||||||
| use kata_types::k8s::is_watchable_mount; | use kata_types::k8s::is_watchable_mount; | ||||||
| use kata_types::mount; | use kata_types::mount; | ||||||
| use nix::sys::stat::stat; | use nix::sys::stat::stat; | ||||||
| @@ -25,6 +25,7 @@ use super::{ | |||||||
|     KATA_GUEST_SHARE_DIR, PASSTHROUGH_FS_DIR, |     KATA_GUEST_SHARE_DIR, PASSTHROUGH_FS_DIR, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
| pub struct VirtiofsShareMount { | pub struct VirtiofsShareMount { | ||||||
|     id: String, |     id: String, | ||||||
| } | } | ||||||
| @@ -192,4 +193,12 @@ impl ShareFsMount for VirtiofsShareMount { | |||||||
|             .context("remount readonly directory with readonly permission")?; |             .context("remount readonly directory with readonly permission")?; | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async fn umount(&self, file_name: &str) -> Result<()> { | ||||||
|  |         let host_dest = do_get_host_path(file_name, &self.id, "", true, false); | ||||||
|  |         umount_timeout(&host_dest, 0).context("Umount readonly host dest")?; | ||||||
|  |         let host_dest = do_get_host_path(file_name, &self.id, "", true, true); | ||||||
|  |         umount_timeout(&host_dest, 0).context("Umount readwrite host dest")?; | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,9 +5,11 @@ | |||||||
| // | // | ||||||
|  |  | ||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
|  | use async_trait::async_trait; | ||||||
|  |  | ||||||
| use super::Volume; | use super::Volume; | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
| pub(crate) struct BlockVolume {} | pub(crate) struct BlockVolume {} | ||||||
|  |  | ||||||
| /// BlockVolume: block device volume | /// BlockVolume: block device volume | ||||||
| @@ -17,6 +19,7 @@ impl BlockVolume { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[async_trait] | ||||||
| impl Volume for BlockVolume { | impl Volume for BlockVolume { | ||||||
|     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { |     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { | ||||||
|         todo!() |         todo!() | ||||||
| @@ -26,8 +29,9 @@ impl Volume for BlockVolume { | |||||||
|         todo!() |         todo!() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn cleanup(&self) -> Result<()> { |     async fn cleanup(&self) -> Result<()> { | ||||||
|         todo!() |         warn!(sl!(), "Cleaning up BlockVolume is still unimplemented."); | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,9 +5,11 @@ | |||||||
| // | // | ||||||
|  |  | ||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
|  | use async_trait::async_trait; | ||||||
|  |  | ||||||
| use super::Volume; | use super::Volume; | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
| pub(crate) struct DefaultVolume { | pub(crate) struct DefaultVolume { | ||||||
|     mount: oci::Mount, |     mount: oci::Mount, | ||||||
| } | } | ||||||
| @@ -21,6 +23,7 @@ impl DefaultVolume { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[async_trait] | ||||||
| impl Volume for DefaultVolume { | impl Volume for DefaultVolume { | ||||||
|     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { |     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { | ||||||
|         Ok(vec![self.mount.clone()]) |         Ok(vec![self.mount.clone()]) | ||||||
| @@ -30,7 +33,8 @@ impl Volume for DefaultVolume { | |||||||
|         Ok(vec![]) |         Ok(vec![]) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn cleanup(&self) -> Result<()> { |     async fn cleanup(&self) -> Result<()> { | ||||||
|         todo!() |         warn!(sl!(), "Cleaning up DefaultVolume is still unimplemented."); | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ mod block_volume; | |||||||
| mod default_volume; | mod default_volume; | ||||||
| mod share_fs_volume; | mod share_fs_volume; | ||||||
| mod shm_volume; | mod shm_volume; | ||||||
|  | use async_trait::async_trait; | ||||||
|  |  | ||||||
| use std::{sync::Arc, vec::Vec}; | use std::{sync::Arc, vec::Vec}; | ||||||
|  |  | ||||||
| @@ -16,10 +17,11 @@ use tokio::sync::RwLock; | |||||||
|  |  | ||||||
| use crate::share_fs::ShareFs; | use crate::share_fs::ShareFs; | ||||||
|  |  | ||||||
| pub trait Volume: Send + Sync { | #[async_trait] | ||||||
|  | pub trait Volume: Send + Sync + std::fmt::Debug { | ||||||
|     fn get_volume_mount(&self) -> Result<Vec<oci::Mount>>; |     fn get_volume_mount(&self) -> Result<Vec<oci::Mount>>; | ||||||
|     fn get_storage(&self) -> Result<Vec<agent::Storage>>; |     fn get_storage(&self) -> Result<Vec<agent::Storage>>; | ||||||
|     fn cleanup(&self) -> Result<()>; |     async fn cleanup(&self) -> Result<()>; | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Default)] | #[derive(Default)] | ||||||
|   | |||||||
| @@ -7,10 +7,11 @@ | |||||||
| use std::{ | use std::{ | ||||||
|     path::{Path, PathBuf}, |     path::{Path, PathBuf}, | ||||||
|     str::FromStr, |     str::FromStr, | ||||||
|     sync::Arc, |     sync::{Arc, Weak}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| use anyhow::{anyhow, Context, Result}; | use anyhow::{anyhow, Context, Result}; | ||||||
|  | use async_trait::async_trait; | ||||||
|  |  | ||||||
| use super::Volume; | use super::Volume; | ||||||
| use crate::share_fs::{MountedInfo, ShareFs, ShareFsVolumeConfig}; | use crate::share_fs::{MountedInfo, ShareFs, ShareFsVolumeConfig}; | ||||||
| @@ -22,7 +23,9 @@ use kata_types::mount; | |||||||
| // only regular files in /dev. It does not make sense to pass the host | // only regular files in /dev. It does not make sense to pass the host | ||||||
| // device nodes to the guest. | // device nodes to the guest. | ||||||
| // skip the volumes whose source had already set to guest share dir. | // skip the volumes whose source had already set to guest share dir. | ||||||
|  | #[derive(Debug)] | ||||||
| pub(crate) struct ShareFsVolume { | pub(crate) struct ShareFsVolume { | ||||||
|  |     share_fs: Option<Weak<dyn ShareFs>>, | ||||||
|     mounts: Vec<oci::Mount>, |     mounts: Vec<oci::Mount>, | ||||||
|     storages: Vec<agent::Storage>, |     storages: Vec<agent::Storage>, | ||||||
| } | } | ||||||
| @@ -38,7 +41,7 @@ impl ShareFsVolume { | |||||||
|         let file_name = generate_mount_path("sandbox", file_name); |         let file_name = generate_mount_path("sandbox", file_name); | ||||||
|  |  | ||||||
|         let mut volume = Self { |         let mut volume = Self { | ||||||
|             // share_fs: share_fs.as_ref().map(Arc::clone), |             share_fs: share_fs.as_ref().map(Arc::downgrade), | ||||||
|             mounts: vec![], |             mounts: vec![], | ||||||
|             storages: vec![], |             storages: vec![], | ||||||
|         }; |         }; | ||||||
| @@ -84,7 +87,11 @@ impl ShareFsVolume { | |||||||
|                             "The mount will be upgraded, mount = {:?}, cid = {}", m, cid |                             "The mount will be upgraded, mount = {:?}, cid = {}", m, cid | ||||||
|                         ); |                         ); | ||||||
|                         share_fs_mount |                         share_fs_mount | ||||||
|                             .upgrade(&mounted_info.name().context("get name of mounted info")?) |                             .upgrade( | ||||||
|  |                                 &mounted_info | ||||||
|  |                                     .file_name() | ||||||
|  |                                     .context("get name of mounted info")?, | ||||||
|  |                             ) | ||||||
|                             .await |                             .await | ||||||
|                             .context("upgrade mount")?; |                             .context("upgrade mount")?; | ||||||
|                     } |                     } | ||||||
| @@ -145,6 +152,7 @@ impl ShareFsVolume { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[async_trait] | ||||||
| impl Volume for ShareFsVolume { | impl Volume for ShareFsVolume { | ||||||
|     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { |     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { | ||||||
|         Ok(self.mounts.clone()) |         Ok(self.mounts.clone()) | ||||||
| @@ -154,8 +162,76 @@ impl Volume for ShareFsVolume { | |||||||
|         Ok(self.storages.clone()) |         Ok(self.storages.clone()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn cleanup(&self) -> Result<()> { |     async fn cleanup(&self) -> Result<()> { | ||||||
|         todo!() |         if self.share_fs.is_none() { | ||||||
|  |             return Ok(()); | ||||||
|  |         } | ||||||
|  |         let share_fs = match self.share_fs.as_ref().unwrap().upgrade() { | ||||||
|  |             Some(share_fs) => share_fs, | ||||||
|  |             None => return Err(anyhow!("The share_fs was released unexpectedly")), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         for m in self.mounts.iter() { | ||||||
|  |             let (host_source, mut mounted_info) = | ||||||
|  |                 match share_fs.get_mounted_info_by_guest_path(&m.source).await { | ||||||
|  |                     Some(entry) => entry, | ||||||
|  |                     None => { | ||||||
|  |                         warn!( | ||||||
|  |                             sl!(), | ||||||
|  |                             "The mounted info for guest path {} not found", m.source | ||||||
|  |                         ); | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |             let old_readonly = mounted_info.readonly(); | ||||||
|  |  | ||||||
|  |             if m.options.iter().any(|opt| *opt == "ro") { | ||||||
|  |                 mounted_info.ro_ref_count -= 1; | ||||||
|  |             } else { | ||||||
|  |                 mounted_info.rw_ref_count -= 1; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             debug!( | ||||||
|  |                 sl!(), | ||||||
|  |                 "Ref count for {} was updated to {} due to volume cleanup", | ||||||
|  |                 host_source, | ||||||
|  |                 mounted_info.ref_count() | ||||||
|  |             ); | ||||||
|  |             let share_fs_mount = share_fs.get_share_fs_mount(); | ||||||
|  |             let file_name = mounted_info.file_name()?; | ||||||
|  |  | ||||||
|  |             if mounted_info.ref_count() > 0 { | ||||||
|  |                 // Downgrade to readonly if no container needs readwrite permission | ||||||
|  |                 if !old_readonly && mounted_info.readonly() { | ||||||
|  |                     info!(sl!(), "Downgrade {} to readonly due to no container that needs readwrite permission", host_source); | ||||||
|  |                     share_fs_mount | ||||||
|  |                         .downgrade(&file_name) | ||||||
|  |                         .await | ||||||
|  |                         .context("Downgrade volume")?; | ||||||
|  |                 } | ||||||
|  |                 share_fs | ||||||
|  |                     .set_mounted_info(&host_source, mounted_info) | ||||||
|  |                     .await | ||||||
|  |                     .context("Update mounted info")?; | ||||||
|  |             } else { | ||||||
|  |                 info!( | ||||||
|  |                     sl!(), | ||||||
|  |                     "The path will be umounted due to no references, host_source = {}", host_source | ||||||
|  |                 ); | ||||||
|  |                 share_fs | ||||||
|  |                     .rm_mounted_info(&host_source) | ||||||
|  |                     .await | ||||||
|  |                     .context("Rm mounted info due to no reference")?; | ||||||
|  |                 // Umount the volume | ||||||
|  |                 share_fs_mount | ||||||
|  |                     .umount(&file_name) | ||||||
|  |                     .await | ||||||
|  |                     .context("Umount volume")? | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ | |||||||
| use std::path::Path; | use std::path::Path; | ||||||
|  |  | ||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
|  | use async_trait::async_trait; | ||||||
|  |  | ||||||
| use super::Volume; | use super::Volume; | ||||||
| use crate::share_fs::DEFAULT_KATA_GUEST_SANDBOX_DIR; | use crate::share_fs::DEFAULT_KATA_GUEST_SANDBOX_DIR; | ||||||
| @@ -19,6 +20,7 @@ pub const DEFAULT_SHM_SIZE: u64 = 65536 * 1024; | |||||||
| // KATA_EPHEMERAL_DEV_TYPE creates a tmpfs backed volume for sharing files between containers. | // KATA_EPHEMERAL_DEV_TYPE creates a tmpfs backed volume for sharing files between containers. | ||||||
| pub const KATA_EPHEMERAL_DEV_TYPE: &str = "ephemeral"; | pub const KATA_EPHEMERAL_DEV_TYPE: &str = "ephemeral"; | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
| pub(crate) struct ShmVolume { | pub(crate) struct ShmVolume { | ||||||
|     mount: oci::Mount, |     mount: oci::Mount, | ||||||
|     storage: Option<agent::Storage>, |     storage: Option<agent::Storage>, | ||||||
| @@ -82,6 +84,7 @@ impl ShmVolume { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[async_trait] | ||||||
| impl Volume for ShmVolume { | impl Volume for ShmVolume { | ||||||
|     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { |     fn get_volume_mount(&self) -> anyhow::Result<Vec<oci::Mount>> { | ||||||
|         Ok(vec![self.mount.clone()]) |         Ok(vec![self.mount.clone()]) | ||||||
| @@ -96,8 +99,9 @@ impl Volume for ShmVolume { | |||||||
|         Ok(s) |         Ok(s) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn cleanup(&self) -> Result<()> { |     async fn cleanup(&self) -> Result<()> { | ||||||
|         todo!() |         warn!(sl!(), "Cleaning up ShmVolume is still unimplemented."); | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -258,7 +258,7 @@ impl Container { | |||||||
|         signal: u32, |         signal: u32, | ||||||
|         all: bool, |         all: bool, | ||||||
|     ) -> Result<()> { |     ) -> Result<()> { | ||||||
|         let inner = self.inner.read().await; |         let mut inner = self.inner.write().await; | ||||||
|         inner.signal_process(container_process, signal, all).await |         inner.signal_process(container_process, signal, all).await | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -180,8 +180,6 @@ impl ContainerInner { | |||||||
|                 } |                 } | ||||||
|             })?; |             })?; | ||||||
|  |  | ||||||
|         // TODO(justxuewei): clean mount |  | ||||||
|  |  | ||||||
|         // close the exit channel to wakeup wait service |         // close the exit channel to wakeup wait service | ||||||
|         // send to notify watchers who are waiting for the process exit |         // send to notify watchers who are waiting for the process exit | ||||||
|         self.init_process.stop().await; |         self.init_process.stop().await; | ||||||
| @@ -235,7 +233,7 @@ impl ContainerInner { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub(crate) async fn signal_process( |     pub(crate) async fn signal_process( | ||||||
|         &self, |         &mut self, | ||||||
|         process: &ContainerProcess, |         process: &ContainerProcess, | ||||||
|         signal: u32, |         signal: u32, | ||||||
|         all: bool, |         all: bool, | ||||||
| @@ -249,6 +247,9 @@ impl ContainerInner { | |||||||
|         self.agent |         self.agent | ||||||
|             .signal_process(agent::SignalProcessRequest { process_id, signal }) |             .signal_process(agent::SignalProcessRequest { process_id, signal }) | ||||||
|             .await?; |             .await?; | ||||||
|  |  | ||||||
|  |         self.clean_volumes().await.context("clean volumes")?; | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -270,4 +271,18 @@ impl ContainerInner { | |||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async fn clean_volumes(&mut self) -> Result<()> { | ||||||
|  |         let mut unhandled = Vec::new(); | ||||||
|  |         for v in self.volumes.iter() { | ||||||
|  |             if let Err(err) = v.cleanup().await { | ||||||
|  |                 unhandled.push(Arc::clone(v)); | ||||||
|  |                 warn!(sl!(), "Failed to clean volume {:?}, error = {:?}", v, err); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if !unhandled.is_empty() { | ||||||
|  |             self.volumes = unhandled; | ||||||
|  |         } | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user