11use core:: f64;
22use std:: { convert:: TryFrom , fmt:: Debug , os:: raw:: c_void, pin:: Pin , ptr:: NonNull , str:: FromStr } ;
33
4+ use crate :: sleep:: mayastor_sleep;
45use byte_unit:: Byte ;
56use events_api:: event:: EventAction ;
67use futures:: channel:: oneshot;
78use nix:: errno:: Errno ;
89use pin_utils:: core_reexport:: fmt:: Formatter ;
910
1011use spdk_rs:: libspdk:: {
11- bdev_aio_rescan, spdk_bdev_update_bs_blockcnt , spdk_blob_store , spdk_bs_free_cluster_count ,
12- spdk_bs_get_cluster_size , spdk_bs_get_max_growable_size , spdk_bs_get_md_len ,
13- spdk_bs_get_page_size , spdk_bs_get_used_md , spdk_bs_total_data_cluster_count , spdk_lvol ,
14- spdk_lvol_opts , spdk_lvol_opts_init , spdk_lvol_store , spdk_lvs_grow_live ,
15- vbdev_get_lvol_store_by_name , vbdev_get_lvol_store_by_uuid , vbdev_get_lvs_bdev_by_lvs ,
16- vbdev_lvol_create_with_opts , vbdev_lvs_create , vbdev_lvs_create_with_uuid , vbdev_lvs_destruct ,
17- vbdev_lvs_import , vbdev_lvs_unload , LVOL_CLEAR_WITH_NONE , LVOL_CLEAR_WITH_UNMAP ,
18- LVS_CLEAR_WITH_NONE ,
12+ bdev_aio_rescan, bdev_uring_rescan , spdk_bdev_update_bs_blockcnt , spdk_blob_store ,
13+ spdk_bs_free_cluster_count , spdk_bs_get_cluster_size , spdk_bs_get_max_growable_size ,
14+ spdk_bs_get_md_len , spdk_bs_get_page_size , spdk_bs_get_used_md ,
15+ spdk_bs_total_data_cluster_count , spdk_lvol , spdk_lvol_opts , spdk_lvol_opts_init ,
16+ spdk_lvol_store , spdk_lvs_grow_live , vbdev_get_lvol_store_by_name ,
17+ vbdev_get_lvol_store_by_uuid , vbdev_get_lvs_bdev_by_lvs , vbdev_lvol_create_with_opts ,
18+ vbdev_lvs_create , vbdev_lvs_create_with_uuid , vbdev_lvs_destruct , vbdev_lvs_import ,
19+ vbdev_lvs_unload , LVOL_CLEAR_WITH_NONE , LVOL_CLEAR_WITH_UNMAP , LVS_CLEAR_WITH_NONE ,
1920} ;
2021use url:: Url ;
2122
@@ -879,32 +880,48 @@ impl Lvs {
879880 #[ tracing:: instrument( level = "debug" , err) ]
880881 pub async fn grow ( & self ) -> Result < ( ) , LvsError > {
881882 info ! ( "{self:?}: growing lvs..." ) ;
883+ let lvs_name = self . name ( ) ;
882884
883- let cname = self . base_bdev ( ) . name ( ) . into_cstring ( ) ;
884- let uri_str = & self . base_bdev ( ) . bdev_uri_str ( ) . unwrap_or_default ( ) ;
885- let url = Url :: parse ( uri_str) . map_err ( |source| LvsError :: InvalidBdev {
885+ let disk_bdev = self
886+ . base_bdev ( )
887+ . crypto_base_bdev ( )
888+ . map ( Bdev :: new)
889+ . unwrap_or_else ( || self . base_bdev ( ) ) ;
890+
891+ let uri_str = disk_bdev. bdev_uri_str ( ) . unwrap_or_default ( ) ;
892+ let url = Url :: parse ( & uri_str) . map_err ( |source| LvsError :: InvalidBdev {
886893 source : BdevError :: UriParseFailed {
887894 source,
888895 uri : uri_str. to_string ( ) ,
889896 } ,
890- name : self . name ( ) . to_string ( ) ,
897+ name : lvs_name . to_string ( ) ,
891898 } ) ?;
892- if url. scheme ( ) != "malloc" {
893- info ! (
894- "Attempting to rescan bdev {:?} part of lvs {:?}, uri {:?}" ,
895- self . base_bdev( ) . name( ) ,
896- self . name( ) ,
897- self . base_bdev( ) . bdev_uri_str( ) . unwrap_or_default( )
898- ) ;
899899
900- let errno = unsafe { bdev_aio_rescan ( cname. as_ptr ( ) as * mut std:: os:: raw:: c_char ) } ;
900+ let bdev = disk_bdev. name ( ) . into_cstring ( ) ;
901+ info ! ( "Attempting to rescan bdev: {uri_str} part of lvs {lvs_name}" ) ;
901902
902- if errno != 0 {
903- return Err ( LvsError :: BdevRescanFailed {
904- source : BsError :: from_i32 ( errno) ,
905- name : self . base_bdev ( ) . name ( ) . to_string ( ) ,
906- } ) ;
907- }
903+ // Performs a rescan only for uring or aio devices, this is a no-op for other device types.
904+ let errno = match url. scheme ( ) {
905+ "uring" => unsafe { bdev_uring_rescan ( bdev. as_ptr ( ) . cast ( ) ) } ,
906+ "aio" => unsafe { bdev_aio_rescan ( bdev. as_ptr ( ) . cast ( ) ) } ,
907+ _ => 0 ,
908+ } ;
909+
910+ if errno != 0 {
911+ return Err ( LvsError :: BdevRescanFailed {
912+ source : BsError :: from_i32 ( errno) ,
913+ name : self . base_bdev ( ) . name ( ) . to_string ( ) ,
914+ } ) ;
915+ }
916+
917+ if self . encrypted ( ) && !self . crypto_vbdev_resized ( ) . await {
918+ error ! (
919+ "crypto bdev {} has not resized" ,
920+ self . base_bdev( ) . name( ) . to_string( )
921+ ) ;
922+ return Err ( LvsError :: CryptoBdevNotResized {
923+ name : self . base_bdev ( ) . name ( ) . to_string ( ) ,
924+ } ) ;
908925 }
909926
910927 let capacity_before_grow = self . capacity ( ) ;
@@ -925,7 +942,7 @@ impl Lvs {
925942 . expect ( "callback gone while growing lvs" )
926943 . to_result ( |e| LvsError :: Grow {
927944 source : BsError :: from_i32 ( e) ,
928- name : self . name ( ) . to_string ( ) ,
945+ name : lvs_name . to_string ( ) ,
929946 } ) ?;
930947
931948 if self . capacity ( ) == capacity_before_grow {
@@ -939,6 +956,31 @@ impl Lvs {
939956 Ok ( ( ) )
940957 }
941958
959+ /// When the underlying AIO bdev is resized, crypto bdev receives SPDK_BDEV_EVENT_RESIZE
960+ /// event. The crypto bdev then adjusts its block count accordingly. To ensure that this resize
961+ /// operation completes before proceeding, we wait briefly for the crypto bdev to update.
962+ /// This delay gives the crypto bdev time to process the resize event asynchronously.
963+ async fn crypto_vbdev_resized ( & self ) -> bool {
964+ for _i in 1 ..=30 {
965+ let base_bdev = self . base_bdev ( ) ;
966+ let disk_bdev = base_bdev
967+ . crypto_base_bdev ( )
968+ . map ( Bdev :: new)
969+ . unwrap_or_else ( || self . base_bdev ( ) ) ;
970+ let disk_bdev_size = disk_bdev. num_blocks ( ) * disk_bdev. block_len ( ) as u64 ;
971+ let crypto_bdev_size = base_bdev. num_blocks ( ) * base_bdev. block_len ( ) as u64 ;
972+ if crypto_bdev_size == disk_bdev_size {
973+ return true ;
974+ } else {
975+ let rx = mayastor_sleep ( std:: time:: Duration :: from_millis ( 100 ) ) ;
976+ if rx. await . is_err ( ) {
977+ error ! ( "failed to wait for mayastor_sleep" ) ;
978+ }
979+ }
980+ }
981+ false
982+ }
983+
942984 /// return an iterator for enumerating all snapshots that reside on the pool
943985 pub fn snapshots ( & self ) -> Option < impl Iterator < Item = LvolSnapshotDescriptor > > {
944986 if let Some ( bdev) = UntypedBdev :: bdev_first ( ) {
0 commit comments