44//! automatic process cleanup, and SMBIOS credential injection.
55
66use std:: fs:: { File , OpenOptions } ;
7+ use std:: future:: Future ;
78use std:: io:: ErrorKind ;
89use std:: os:: fd:: { AsRawFd as _, OwnedFd } ;
910use std:: os:: unix:: process:: CommandExt as _;
10- use std:: process:: { Child , Command , Stdio } ;
11+ use std:: pin:: Pin ;
12+ use std:: process:: { Child , Command , Output , Stdio } ;
1113use std:: sync:: Arc ;
1214use std:: time:: Duration ;
1315
@@ -684,7 +686,7 @@ struct VsockCopier {
684686
685687pub struct RunningQemu {
686688 pub qemu_process : Child ,
687- pub virtiofsd_processes : Vec < tokio :: process :: Child > ,
689+ pub virtiofsd_processes : Vec < Pin < Box < dyn Future < Output = std :: io :: Result < Output > > > > > ,
688690 sd_notification : Option < VsockCopier > ,
689691}
690692
@@ -792,30 +794,54 @@ impl RunningQemu {
792794 . unwrap_or_default ( ) ;
793795
794796 // Spawn all virtiofsd processes first
795- let mut virtiofsd_processes = Vec :: new ( ) ;
796-
797- // Spawn main virtiofsd if configured
798- if let Some ( ref main_config) = config. main_virtiofs_config {
799- debug ! ( "Spawning main virtiofsd for: {:?}" , main_config. socket_path) ;
800- let process = spawn_virtiofsd_async ( main_config) . await ?;
801- virtiofsd_processes. push ( process) ;
802- // Wait for socket to be ready before proceeding
803- wait_for_virtiofsd_socket ( main_config. socket_path . as_str ( ) , Duration :: from_secs ( 10 ) )
804- . await ?;
797+ let mut awaiting_virtiofsd = Vec :: new ( ) ;
798+ let virtiofsd_configs = config
799+ . main_virtiofs_config
800+ . iter ( )
801+ . chain ( config. virtiofs_configs . iter ( ) ) ;
802+ for config in virtiofsd_configs {
803+ let process = spawn_virtiofsd_async ( config) . await ?;
804+ awaiting_virtiofsd. push ( ( process, config. socket_path . clone ( ) ) ) ;
805805 }
806806
807- // Spawn additional virtiofsd processes
808- for virtiofs_config in & config. virtiofs_configs {
809- debug ! ( "Spawning virtiofsd for: {:?}" , virtiofs_config. socket_path) ;
810- let process = spawn_virtiofsd_async ( virtiofs_config) . await ?;
811- virtiofsd_processes. push ( process) ;
812-
813- // Wait for socket to be ready before proceeding
814- wait_for_virtiofsd_socket (
815- virtiofs_config. socket_path . as_str ( ) ,
816- Duration :: from_secs ( 10 ) ,
817- )
818- . await ?;
807+ // Wait for all virtiofsd to be ready
808+ let mut virtiofsd_processes = Vec :: new ( ) ;
809+ while let Some ( ( proc, socket_path) ) = awaiting_virtiofsd. pop ( ) {
810+ let socket_path = & socket_path;
811+ let query_exists = async move {
812+ loop {
813+ if socket_path. exists ( ) {
814+ break ;
815+ }
816+ tokio:: time:: sleep ( Duration :: from_millis ( 100 ) ) . await ;
817+ }
818+ } ;
819+ tokio:: pin!( query_exists) ;
820+ let timeout_val = Duration :: from_secs ( 60 ) ;
821+ let timeout = tokio:: time:: sleep ( timeout_val) ;
822+ tokio:: pin!( timeout) ;
823+ debug ! ( "Waiting for socket at {socket_path}" ) ;
824+ let mut output: Pin < Box < dyn Future < Output = std:: io:: Result < Output > > > > =
825+ Box :: pin ( proc. wait_with_output ( ) ) ;
826+ tokio:: select! {
827+ output = & mut output => {
828+ tracing:: trace!( "virtiofsd exited" ) ;
829+ let output = output?;
830+ let status = output. status;
831+ let stderr = String :: from_utf8_lossy( & output. stderr) ;
832+ tracing:: trace!( "returnign spawn error" ) ;
833+ return Err ( eyre!(
834+ "virtiofsd failed to start for socket {socket_path}\n Exit status: {status:?}\n Output: {stderr}"
835+ ) ) ;
836+ }
837+ _ = timeout => {
838+ return Err ( eyre!( "timed out waiting for virtiofsd socket {} to be created (waited {timeout_val:?})" , socket_path) ) ;
839+ }
840+ _ = query_exists => {
841+ }
842+ }
843+ virtiofsd_processes. push ( output) ;
844+ tracing:: debug!( "virtiofsd socket created: {socket_path}" ) ;
819845 }
820846 // Spawn QEMU process with additional VSOCK credential if needed
821847 let qemu_process = spawn ( & config, & creds, vsockdata) ?;
@@ -827,11 +853,6 @@ impl RunningQemu {
827853 } )
828854 }
829855
830- /// Add a virtiofsd process to be managed by this QEMU instance
831- pub fn add_virtiofsd_process ( & mut self , process : tokio:: process:: Child ) {
832- self . virtiofsd_processes . push ( process) ;
833- }
834-
835856 /// Wait for QEMU process to exit
836857 pub async fn wait ( & mut self ) -> Result < std:: process:: ExitStatus > {
837858 let r = self . qemu_process . wait ( ) ?;
@@ -965,14 +986,8 @@ pub async fn spawn_virtiofsd_async(config: &VirtiofsConfig) -> Result<tokio::pro
965986 // but we want to be compatible with older virtiofsd too.
966987 cmd. arg ( "--inode-file-handles=fallback" ) ;
967988
968- // Redirect stdout/stderr to /dev/null unless debug mode is enabled
969- if !config. debug {
970- cmd. stdout ( std:: process:: Stdio :: null ( ) )
971- . stderr ( std:: process:: Stdio :: null ( ) ) ;
972- } else {
973- cmd. stdout ( std:: process:: Stdio :: piped ( ) )
974- . stderr ( std:: process:: Stdio :: piped ( ) ) ;
975- }
989+ cmd. stdout ( std:: process:: Stdio :: piped ( ) ) ;
990+ cmd. stderr ( std:: process:: Stdio :: piped ( ) ) ;
976991
977992 let child = cmd. spawn ( ) . with_context ( || {
978993 format ! (
0 commit comments