diff --git a/pkg/hostman/guestman/guesttasks.go b/pkg/hostman/guestman/guesttasks.go index fc79a3e154..108f413713 100644 --- a/pkg/hostman/guestman/guesttasks.go +++ b/pkg/hostman/guestman/guesttasks.go @@ -2606,6 +2606,7 @@ type SGuestHotplugCpuMemTask struct { addedCpuCount int addedVcpuIds []int cpuNumaPin []*desc.SCpuNumaPin + cpuList []monitor.HotpluggableCPU addedMemSize int memSlotNewIndex *int @@ -2643,6 +2644,12 @@ func NewGuestHotplugCpuMemTask( // First at all add cpu count, second add mem size func (task *SGuestHotplugCpuMemTask) Start() { if task.addCpuCount > 0 { + res, err := task.getHotpluggableCPUList() + if err != nil { + task.onFail(err.Error()) + return + } + task.cpuList = res task.startAddCpu() } else if task.addMemSize > 0 { task.startAddMem() @@ -2682,16 +2689,12 @@ func (task *SGuestHotplugCpuMemTask) buildVcpusMap() { } func (task *SGuestHotplugCpuMemTask) startAddCpusWithFreeVcpuSet(vcpuSet []int) { - if task.addedCpuCount >= task.addCpuCount { - task.startAddMem() - return - } - - vcpuId := vcpuSet[0] - cb := func(reason string) { - if len(reason) > 0 { - log.Errorln(reason) - task.onFail(reason) + for i := range vcpuSet { + vcpuId := vcpuSet[i] + err := task.AddCpu(task.cpuList, vcpuSet[i]) + if err != nil { + log.Errorf("failed add cpu %d: %s", vcpuSet[i], err) + task.onFail(err.Error()) return } @@ -2726,9 +2729,9 @@ func (task *SGuestHotplugCpuMemTask) startAddCpusWithFreeVcpuSet(vcpuSet []int) } task.addedCpuCount += 1 - task.startAddCpusWithFreeVcpuSet(vcpuSet[1:]) } - task.Monitor.AddCpu(vcpuId, cb) + + task.startAddMem() } func (task *SGuestHotplugCpuMemTask) onGetCpuCount(count int) { @@ -2738,7 +2741,12 @@ func (task *SGuestHotplugCpuMemTask) onGetCpuCount(count int) { func (task *SGuestHotplugCpuMemTask) doAddCpu() { if task.addedCpuCount < task.addCpuCount { - task.Monitor.AddCpu(task.originalCpuCount+task.addedCpuCount, task.onAddCpu) + err := task.AddCpu(task.cpuList, task.originalCpuCount+task.addedCpuCount) + ret := "" + if err != nil { + ret = err.Error() + } + task.onAddCpu(ret) } else { task.startAddMem() } diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index b80f403ffa..de58db4800 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -3061,8 +3061,57 @@ func (s *SKVMGuestInstance) doBlockIoThrottle() { } } -func (s *SKVMGuestInstance) startHotPlugVcpus(vcpuSet []int) error { +func (s *SKVMGuestInstance) AddCpu(cpuList []monitor.HotpluggableCPU, cpu int) error { var c = make(chan error) + cb := func(res string) { + var e error = nil + if len(res) > 0 { + e = errors.Errorf("failed add cpu %d: %s", cpu, res) + } + c <- e + } + if version.GT(s.QemuVersion, "4.0.2") { + var found = false + for i := range cpuList { + if cpuList[i].Props.SocketID == nil || cpuList[i].Props.CoreID == nil { + continue + } + if cpuList[i].QomPath != nil { + // cpu present + continue + } + cpusPerSocket := int(s.Desc.CpuDesc.MaxCpus / s.Desc.CpuDesc.Sockets) + coreId := int(*cpuList[i].Props.CoreID) + cpusPerSocket*int(*cpuList[i].Props.SocketID) + if coreId == cpu { + found = true + params := map[string]interface{}{ + "id": fmt.Sprintf("cpu-%d", cpu), + "core-id": cpu % cpusPerSocket, + "socket-id": *cpuList[i].Props.SocketID, + } + if cpuList[i].Props.ThreadID != nil { + params["thread-id"] = *cpuList[i].Props.ThreadID + } + s.Monitor.DeviceAddCpu(cpuList[i].Type, params, cb) + break + } + } + + if !found { + return errors.Errorf("hot pluggable cpu %d not found", cpu) + } + } else { + s.Monitor.AddCpu(cpu, cb) + } + err, _ := <-c + return err +} + +func (s *SKVMGuestInstance) startHotPlugVcpus(vcpuSet []int) error { + cpuList, err := s.getHotpluggableCPUList() + if err != nil { + return errors.Wrap(err, "getHotpluggableCPUList") + } for i := range vcpuSet { if vcpuSet[i] == 0 { @@ -3070,14 +3119,8 @@ func (s *SKVMGuestInstance) startHotPlugVcpus(vcpuSet []int) error { continue } - s.Monitor.AddCpu(vcpuSet[i], func(res string) { - var e error = nil - if len(res) > 0 { - e = errors.Errorf("failed add cpu %d: %s", vcpuSet[i], res) - } - c <- e - }) - if err, _ := <-c; err != nil { + err = s.AddCpu(cpuList, vcpuSet[i]) + if err != nil { return err } } diff --git a/pkg/hostman/monitor/monitor.go b/pkg/hostman/monitor/monitor.go index 598ac149d0..77539ef24a 100644 --- a/pkg/hostman/monitor/monitor.go +++ b/pkg/hostman/monitor/monitor.go @@ -220,6 +220,7 @@ type Monitor interface { ObjectAdd(objectType string, params map[string]string, callback StringCallback) DriveAdd(bus, node string, params map[string]string, callback StringCallback) DeviceAdd(dev string, params map[string]string, callback StringCallback) + DeviceAddCpu(dev string, params map[string]interface{}, callback StringCallback) XBlockdevChange(parent, node, child string, callback StringCallback) BlockStream(drive string, callback StringCallback) diff --git a/pkg/hostman/monitor/qmp.go b/pkg/hostman/monitor/qmp.go index ce49de2a08..c2ffeb8cfb 100644 --- a/pkg/hostman/monitor/qmp.go +++ b/pkg/hostman/monitor/qmp.go @@ -553,6 +553,27 @@ func (m *QmpMonitor) DeviceAdd(dev string, params map[string]string, callback St m.Query(cmd, cb) } +func (m *QmpMonitor) DeviceAddCpu(dev string, params map[string]interface{}, callback StringCallback) { + args := map[string]interface{}{ + "driver": dev, + } + + for k, v := range params { + args[k] = v + } + + cmd := &Command{ + Execute: "device_add", + Args: args, + } + + cb := func(res *Response) { + callback(m.actionResult(res)) + } + + m.Query(cmd, cb) +} + func (m *QmpMonitor) MigrateSetDowntime(dtSec float64, callback StringCallback) { m.HumanMonitorCommand(fmt.Sprintf("migrate_set_downtime %f", dtSec), callback) }