func (info DeviceInfo) Load() (Device, error) { // Find the appropriate driver. driver, ok := drivers[info.Driver] if !ok { return nil, DriverUnknown(info.Driver) } // Load the driver. device, err := driver(&info) if err != nil { return nil, err } if info.Data != nil { // Scratch data. buffer := bytes.NewBuffer(nil) // Encode the original object. encoder := utils.NewEncoder(buffer) err = encoder.Encode(info.Data) if err != nil { return nil, err } // Decode a new object. // This will override all the default // settings in the initialized object. decoder := utils.NewDecoder(buffer) log.Printf("Loading %s...", device.Name()) err = decoder.Decode(device) if err != nil { return nil, err } } // Save the original device. // This will allow us to implement a // simple Save() method that serializes // the state of this device as it exists. info.Data = device // We're done. return device, nil }
func (control *Control) handle( conn_fd int, server *rpc.Server) { control_file := os.NewFile(uintptr(conn_fd), "control") defer control_file.Close() // Read single header. // Our header is exactly 9 characters, and we // expect the last character to be a newline. // This is a simple plaintext protocol. header_buf := make([]byte, 9, 9) n, err := control_file.Read(header_buf) if n != 9 || header_buf[8] != '\n' { if err != nil { control_file.Write([]byte(err.Error())) } else { control_file.Write([]byte("invalid header")) } return } header := string(header_buf) // We read a special header before diving into RPC // mode. This is because for the novmrun case, we turn // the socket into a stream of input/output events. // These are simply JSON serialized versions of the // events for the guest RPC interface. if header == "NOVM RUN\n" { decoder := utils.NewDecoder(control_file) encoder := utils.NewEncoder(control_file) var start noguest.StartCommand err := decoder.Decode(&start) if err != nil { // Poorly encoded command. encoder.Encode(err.Error()) return } // Grab our client. client, err := control.Ready() if err != nil { encoder.Encode(err.Error()) return } // Call start. result := noguest.StartResult{} err = client.Call("Server.Start", &start, &result) if err != nil { encoder.Encode(err.Error()) return } // Save our pid. pid := result.Pid inputs := make(chan error) outputs := make(chan error) exitcode := make(chan int) // This indicates we're okay. encoder.Encode(nil) // Wait for the process to exit. go func() { wait := noguest.WaitCommand{ Pid: pid, } var wait_result noguest.WaitResult err := client.Call("Server.Wait", &wait, &wait_result) if err != nil { exitcode <- 1 } else { exitcode <- wait_result.Exitcode } }() // Read from stdout & stderr. go func() { read := noguest.ReadCommand{ Pid: pid, N: 4096, } var read_result noguest.ReadResult for { err := client.Call("Server.Read", &read, &read_result) if err != nil { inputs <- err return } err = encoder.Encode(read_result.Data) if err != nil { inputs <- err return } } }() // Write to stdin. go func() { write := noguest.WriteCommand{ Pid: pid, } var write_result noguest.WriteResult for { err := decoder.Decode(&write.Data) if err != nil { outputs <- err return } err = client.Call("Server.Write", &write, &write_result) if err != nil { outputs <- err return } } }() // Wait till exit. status := <-exitcode encoder.Encode(status) // Wait till EOF. <-inputs // Send a notice and close the socket. encoder.Encode(nil) } else if header == "NOVM RPC\n" { // Run as JSON RPC connection. codec := jsonrpc.NewServerCodec(control_file) server.ServeCodec(codec) } }
func main() { // Start processing signals. // Our setup can take a little while, so we // want to ensure we aren't using the default // handlers from the beginning. signals := make(chan os.Signal, 1) signal.Notify( signals, utils.SigShutdown, utils.SigRestart, utils.SigSpecialRestart) // Parse all command line options. flag.Parse() // Are we doing a special restart? // This will STOP the current process, and // wait for a CONT signal before resuming. // The STOP signal is not maskable, so the // runtime isn't capable of preventing this. // The whole point of this restart is as follows: // * killall -USR2 novmm // * upgrade kvm // * killall -CONT novmm if *stop { syscall.Kill(syscall.Getpid(), syscall.SIGSTOP) } // Create VM. vm, err := platform.NewVm() if err != nil { utils.Die(err) } defer vm.Dispose() // Create the machine model. model, err := machine.NewModel(vm) if err != nil { utils.Die(err) } // Load our machine state. state_file := os.NewFile(uintptr(*statefd), "state") decoder := utils.NewDecoder(state_file) state := new(control.State) err = decoder.Decode(&state) if err != nil { utils.Die(err) } // We're done with the state file. state_file.Close() // Load all devices. log.Printf("Creating devices...") proxy, err := model.CreateDevices(vm, state.Devices, *debug) if err != nil { utils.Die(err) } // Load all vcpus. log.Printf("Creating vcpus...") vcpus, err := vm.CreateVcpus(state.Vcpus) if err != nil { utils.Die(err) } if len(vcpus) == 0 { utils.Die(NoVcpus) } // Load all model state. log.Printf("Loading model...") err = model.Load(vm) if err != nil { utils.Die(err) } // Pause all devices and vcpus if requested. if *paused { err = model.Pause(true) if err != nil { utils.Die(err) } err = vm.Pause(true) if err != nil { utils.Die(err) } } // Enable stepping if requested. if *step { for _, vcpu := range vcpus { vcpu.SetStepping(true) } } // Remember whether or not this is a load. // If it's a load, then we have to sync the // control interface. If it's not, then we // should skip the control interface sync. is_load := false // Load given kernel and initrd. var sysmap loader.SystemMap var convention *loader.Convention if *vmlinux != "" { log.Printf("Loading linux...") sysmap, convention, err = loader.LoadLinux( vcpus[0], model, *boot_params, *vmlinux, *initrd, *cmdline, *system_map) if err != nil { utils.Die(err) } // This is a fresh boot. is_load = true } // Create our tracer with the map and convention. tracer := loader.NewTracer(sysmap, convention) if *trace { tracer.Enable() } // Create our RPC server. log.Printf("Starting control server...") control, err := control.NewControl( *control_fd, *real_init, model, vm, tracer, proxy, is_load) if err != nil { utils.Die(err) } go control.Serve() // Start all VCPUs. // None of these will actually come online // until the primary VCPU below delivers the // appropriate IPI to start them up. log.Printf("Starting vcpus...") vcpu_err := make(chan error) for _, vcpu := range vcpus { go func(vcpu *platform.Vcpu) { err := Loop(vm, vcpu, model, tracer) vcpu_err <- err }(vcpu) } // Wait until we get a TERM signal, or all the VCPUs are dead. // If we receive a HUP signal, then we will re-exec with the // appropriate device state and vcpu state. This is essentially // a live upgrade (i.e. the binary has been replaced, we rerun). vcpus_alive := len(vcpus) for { select { case err := <-vcpu_err: vcpus_alive -= 1 if err != nil { log.Printf("Vcpu died: %s", err.Error()) } case sig := <-signals: switch sig { case utils.SigShutdown: log.Printf("Shutdown.") os.Exit(0) case utils.SigRestart: fallthrough case utils.SigSpecialRestart: // Make sure we have control sync'ed. _, err := control.Ready() if err != nil { utils.Die(err) } // This is a bit of a special case. // We don't log a fatal message here, // but rather unpause and keep going. err = restart( model, vm, tracer.IsEnabled(), sig == utils.SigSpecialRestart) log.Printf("Restart failed: %s", err.Error()) } } // Everything died? if vcpus_alive == 0 { utils.Die(NoVcpus) } } }