@@ -81,6 +81,7 @@ pub trait VhostUserBackendReqHandler {
8181 fd : File ,
8282 ) -> Result < Option < File > > ;
8383 fn check_device_state ( & self ) -> Result < ( ) > ;
84+ fn get_shmem_config ( & self ) -> Result < VhostUserShMemConfig > ;
8485 #[ cfg( feature = "postcopy" ) ]
8586 fn postcopy_advice ( & self ) -> Result < File > ;
8687 #[ cfg( feature = "postcopy" ) ]
@@ -146,6 +147,7 @@ pub trait VhostUserBackendReqHandlerMut {
146147 fd : File ,
147148 ) -> Result < Option < File > > ;
148149 fn check_device_state ( & mut self ) -> Result < ( ) > ;
150+ fn get_shmem_config ( & self ) -> Result < VhostUserShMemConfig > ;
149151 #[ cfg( feature = "postcopy" ) ]
150152 fn postcopy_advice ( & mut self ) -> Result < File > ;
151153 #[ cfg( feature = "postcopy" ) ]
@@ -289,6 +291,10 @@ impl<T: VhostUserBackendReqHandlerMut> VhostUserBackendReqHandler for Mutex<T> {
289291 self . lock ( ) . unwrap ( ) . check_device_state ( )
290292 }
291293
294+ fn get_shmem_config ( & self ) -> Result < VhostUserShMemConfig > {
295+ self . lock ( ) . unwrap ( ) . get_shmem_config ( )
296+ }
297+
292298 #[ cfg( feature = "postcopy" ) ]
293299 fn postcopy_advice ( & self ) -> Result < File > {
294300 self . lock ( ) . unwrap ( ) . postcopy_advice ( )
@@ -679,6 +685,15 @@ impl<S: VhostUserBackendReqHandler> BackendReqHandler<S> {
679685 } ;
680686 self . send_reply_message ( & hdr, & msg) ?;
681687 }
688+ Ok ( FrontendReq :: GET_SHMEM_CONFIG ) => {
689+ self . check_proto_feature ( VhostUserProtocolFeatures :: SHMEM ) ?;
690+ let res = self . backend . get_shmem_config ( ) ;
691+ let msg = match res {
692+ Ok ( mem) => mem,
693+ Err ( _) => VhostUserShMemConfig :: default ( ) ,
694+ } ;
695+ self . send_reply_message ( & hdr, & msg) ?;
696+ }
682697 #[ cfg( feature = "postcopy" ) ]
683698 Ok ( FrontendReq :: POSTCOPY_ADVISE ) => {
684699 self . check_proto_feature ( VhostUserProtocolFeatures :: PAGEFAULT ) ?;
@@ -1038,4 +1053,111 @@ mod tests {
10381053 handler. check_state ( ) . unwrap_err ( ) ;
10391054 assert ! ( handler. as_raw_fd( ) >= 0 ) ;
10401055 }
1056+
1057+ #[ test]
1058+ fn test_get_shmem_config_max_regions ( ) {
1059+ // Create a configuration with maximum number of regions (8)
1060+ let memory_sizes = [
1061+ 0x1000 , 0x2000 , 0x3000 , 0x4000 , 0x5000 , 0x6000 , 0x7000 , 0x8000 ,
1062+ ] ;
1063+ let config = VhostUserShMemConfig :: new ( 8 , & memory_sizes) ;
1064+
1065+ let ( p1, p2) = UnixStream :: pair ( ) . unwrap ( ) ;
1066+ let mut dummy_backend = DummyBackendReqHandler :: new ( ) ;
1067+ dummy_backend. set_shmem_config ( config) ;
1068+ let backend = Arc :: new ( Mutex :: new ( dummy_backend) ) ;
1069+ let mut handler = BackendReqHandler :: new (
1070+ Endpoint :: < VhostUserMsgHeader < FrontendReq > > :: from_stream ( p1) ,
1071+ backend,
1072+ ) ;
1073+ handler. acked_protocol_features = VhostUserProtocolFeatures :: SHMEM . bits ( ) ;
1074+
1075+ let mut frontend_endpoint = Endpoint :: < VhostUserMsgHeader < FrontendReq > > :: from_stream ( p2) ;
1076+
1077+ let handle = std:: thread:: spawn ( move || {
1078+ let hdr = VhostUserMsgHeader :: new ( FrontendReq :: GET_SHMEM_CONFIG , 0 , 0 ) ;
1079+ frontend_endpoint
1080+ . send_message ( & hdr, & VhostUserEmpty , None )
1081+ . unwrap ( ) ;
1082+
1083+ let ( reply_hdr, reply_config, rfds) = frontend_endpoint
1084+ . recv_body :: < VhostUserShMemConfig > ( )
1085+ . unwrap ( ) ;
1086+ assert_eq ! ( reply_hdr. get_code( ) . unwrap( ) , FrontendReq :: GET_SHMEM_CONFIG ) ;
1087+ assert ! ( reply_hdr. is_reply( ) ) ;
1088+ assert ! ( rfds. is_none( ) ) ;
1089+ reply_config
1090+ } ) ;
1091+
1092+ handler. handle_request ( ) . unwrap ( ) ;
1093+
1094+ let reply_config = handle. join ( ) . unwrap ( ) ;
1095+ assert_eq ! ( reply_config. nregions, 8 ) ;
1096+ for i in 0 ..8 {
1097+ assert_eq ! ( reply_config. memory_sizes[ i] , ( i as u64 + 1 ) * 0x1000 ) ;
1098+ }
1099+ }
1100+
1101+ #[ test]
1102+ fn test_get_shmem_config_non_continuous_regions ( ) {
1103+ // Create a configuration with non-continuous regions
1104+ let memory_sizes = [ 0x10000 , 0 , 0x20000 , 0 , 0 , 0 , 0 , 0 ] ;
1105+ let config = VhostUserShMemConfig :: new ( 2 , & memory_sizes) ;
1106+
1107+ let ( p1, p2) = UnixStream :: pair ( ) . unwrap ( ) ;
1108+ let mut dummy_backend = DummyBackendReqHandler :: new ( ) ;
1109+ dummy_backend. set_shmem_config ( config) ;
1110+ let backend = Arc :: new ( Mutex :: new ( dummy_backend) ) ;
1111+ let mut handler = BackendReqHandler :: new (
1112+ Endpoint :: < VhostUserMsgHeader < FrontendReq > > :: from_stream ( p1) ,
1113+ backend,
1114+ ) ;
1115+ handler. acked_protocol_features = VhostUserProtocolFeatures :: SHMEM . bits ( ) ;
1116+
1117+ let mut frontend_endpoint = Endpoint :: < VhostUserMsgHeader < FrontendReq > > :: from_stream ( p2) ;
1118+
1119+ let handle = std:: thread:: spawn ( move || {
1120+ let hdr = VhostUserMsgHeader :: new ( FrontendReq :: GET_SHMEM_CONFIG , 0 , 0 ) ;
1121+ frontend_endpoint
1122+ . send_message ( & hdr, & VhostUserEmpty , None )
1123+ . unwrap ( ) ;
1124+
1125+ let ( reply_hdr, reply_config, rfds) = frontend_endpoint
1126+ . recv_body :: < VhostUserShMemConfig > ( )
1127+ . unwrap ( ) ;
1128+ assert_eq ! ( reply_hdr. get_code( ) . unwrap( ) , FrontendReq :: GET_SHMEM_CONFIG ) ;
1129+ assert ! ( reply_hdr. is_reply( ) ) ;
1130+ assert ! ( rfds. is_none( ) ) ;
1131+ reply_config
1132+ } ) ;
1133+
1134+ handler. handle_request ( ) . unwrap ( ) ;
1135+
1136+ let reply_config = handle. join ( ) . unwrap ( ) ;
1137+ assert_eq ! ( reply_config. nregions, 2 ) ;
1138+ assert_eq ! ( reply_config. memory_sizes[ 0 ] , 0x10000 ) ;
1139+ assert_eq ! ( reply_config. memory_sizes[ 1 ] , 0 ) ;
1140+ assert_eq ! ( reply_config. memory_sizes[ 2 ] , 0x20000 ) ;
1141+ for i in 3 ..8 {
1142+ assert_eq ! ( reply_config. memory_sizes[ i] , 0 ) ;
1143+ }
1144+ }
1145+
1146+ #[ test]
1147+ fn test_get_shmem_config_feature_not_negotiated ( ) {
1148+ // Test that the request fails when SHMEM protocol feature is not negotiated
1149+ let ( p1, p2) = UnixStream :: pair ( ) . unwrap ( ) ;
1150+ let backend = Arc :: new ( Mutex :: new ( DummyBackendReqHandler :: new ( ) ) ) ;
1151+ let mut handler = BackendReqHandler :: new (
1152+ Endpoint :: < VhostUserMsgHeader < FrontendReq > > :: from_stream ( p1) ,
1153+ backend,
1154+ ) ;
1155+ let mut frontend_endpoint = Endpoint :: < VhostUserMsgHeader < FrontendReq > > :: from_stream ( p2) ;
1156+
1157+ std:: thread:: spawn ( move || {
1158+ let hdr = VhostUserMsgHeader :: new ( FrontendReq :: GET_SHMEM_CONFIG , 0 , 0 ) ;
1159+ let _ = frontend_endpoint. send_message ( & hdr, & VhostUserEmpty , None ) ;
1160+ } ) ;
1161+ assert ! ( handler. handle_request( ) . is_err( ) ) ;
1162+ }
10411163}
0 commit comments