diff --git a/qemu/qemu.go b/qemu/qemu.go index b65983cce9..8bf0c3bd06 100644 --- a/qemu/qemu.go +++ b/qemu/qemu.go @@ -980,6 +980,10 @@ type SMP struct { // Sockets is the number of sockets made available to qemu. Sockets uint32 + + // MaxCPUs is the maximum number of VCPUs that a VM can have. + // This value, if non-zero, MUST BE equal to or greater than CPUs + MaxCPUs uint32 } // Memory is the guest memory configuration structure. @@ -1203,7 +1207,7 @@ func (config *Config) appendMemory() { } } -func (config *Config) appendCPUs() { +func (config *Config) appendCPUs() error { if config.SMP.CPUs > 0 { var SMPParams []string @@ -1221,9 +1225,19 @@ func (config *Config) appendCPUs() { SMPParams = append(SMPParams, fmt.Sprintf(",sockets=%d", config.SMP.Sockets)) } + if config.SMP.MaxCPUs > 0 { + if config.SMP.MaxCPUs < config.SMP.CPUs { + return fmt.Errorf("MaxCPUs %d must be equal to or greater than CPUs %d", + config.SMP.MaxCPUs, config.SMP.CPUs) + } + SMPParams = append(SMPParams, fmt.Sprintf(",maxcpus=%d", config.SMP.MaxCPUs)) + } + config.qemuParams = append(config.qemuParams, "-smp") config.qemuParams = append(config.qemuParams, strings.Join(SMPParams, "")) } + + return nil } func (config *Config) appendRTC() { @@ -1360,7 +1374,6 @@ func LaunchQemu(config Config, logger QMPLog) (string, error) { config.appendCPUModel() config.appendQMPSockets() config.appendMemory() - config.appendCPUs() config.appendDevices() config.appendRTC() config.appendGlobalParam() @@ -1369,6 +1382,10 @@ func LaunchQemu(config Config, logger QMPLog) (string, error) { config.appendKernel() config.appendBios() + if err := config.appendCPUs(); err != nil { + return "", err + } + return LaunchCustomQemu(config.Ctx, config.Path, config.qemuParams, config.fds, nil, logger) } diff --git a/qemu/qemu_test.go b/qemu/qemu_test.go index 51269eabbf..bf7376da6a 100644 --- a/qemu/qemu_test.go +++ b/qemu/qemu_test.go @@ -52,7 +52,9 @@ func testAppend(structure interface{}, expected string, t *testing.T) { case SMP: config.SMP = s - config.appendCPUs() + if err := config.appendCPUs(); err != nil { + t.Fatalf("Unexpected error: %v\n", err) + } case QMPSocket: config.QMPSockets = []QMPSocket{s} @@ -356,7 +358,7 @@ func TestAppendMemory(t *testing.T) { testAppend(memory, memoryString, t) } -var cpusString = "-smp 2,cores=1,threads=2,sockets=2" +var cpusString = "-smp 2,cores=1,threads=2,sockets=2,maxcpus=6" func TestAppendCPUs(t *testing.T) { smp := SMP{ @@ -364,11 +366,28 @@ func TestAppendCPUs(t *testing.T) { Sockets: 2, Cores: 1, Threads: 2, + MaxCPUs: 6, } testAppend(smp, cpusString, t) } +func TestFailToAppendCPUs(t *testing.T) { + config := Config{ + SMP: SMP{ + CPUs: 2, + Sockets: 2, + Cores: 1, + Threads: 2, + MaxCPUs: 1, + }, + } + + if err := config.appendCPUs(); err == nil { + t.Fatalf("Expected appendCPUs to fail") + } +} + var qmpSingleSocketServerString = "-qmp unix:cc-qmp,server,nowait" var qmpSingleSocketString = "-qmp unix:cc-qmp"